The assignment for this week is add an output device to a microcontroller board you've designed and program it to do something. We covered examples of RGB color changing LEDs, Charlieplexing an array of LEDs, LCD displays, video, sound, DC motors, servo motors, stepper motors and more. I was most curious about the Charlieplexing so I decided to make a circuit that used only 5 pins to control a linear array of 20 LEDs.
hello.array.44 example with the various circuit paths color coded.
ladder diagram of 20 Charlieplexed LEDs
ladder diagram with red dots where circuit points overlap.
Circuit traces
Some of the gaps between traces were too small for the 1/64" endmill to fit. Note the hole to the left side was 1/64"
There were three areas that did not cut the way I needed them to.
Just a few modifications solved the problems. I also made most of the traces wider.
Notice alternating orientation of each LED. This matches the ladder diagram.
//
//
// linear.array.44.pbv1.c
//
// Charlieplex LED array hello-world
//
// Neil Gershenfeld
// 11/13/10
//
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//
// Modified 4/22/2014 by Scott Zitek
#include < avr/io.h >
#include < util/delay.h >
#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define input_port PORTB
#define input_direction DDRB
#define input_pin (1 << PB2)
#define input_pins PINB
#define led_delay() _delay_ms(1) // LED delay
#define led_port PORTA
#define led_direction DDRA
#define A (1 << PA1) // row 1
#define B (1 << PA2) // row 2
#define C (1 << PA3) // row 3
#define D (1 << PA4) // row 4
#define E (1 << PA5) // row 5
uint8_t pbstate; //button state
uint8_t pblast; //button last pass
uint8_t pboneshot; //button pressed oneshot
uint8_t mode; //0-5
void flash(uint8_t from, uint8_t to, uint8_t delay) {
//
// source from, sink to, flash
//
static uint8_t i;
set(led_port,from);
clear(led_port,to);
output(led_direction,from);
output(led_direction,to);
for (i = 0; i < delay; ++i)
led_delay();
input(led_direction,from);
input(led_direction,to);
}
void led_cycle(uint8_t number, uint8_t delay) {
//
// cycle through LEDs
//
uint8_t i;
for (i = 0; i < number; ++i) {
// LEDs 20 to 1
flash(D,E,delay); // LED20
flash(E,D,delay); // LED19
flash(C,D,delay); // LED18
flash(D,C,delay); // LED17
flash(B,C,delay); // LED16
flash(C,B,delay); // LED15
flash(A,B,delay); // LED14
flash(B,A,delay); // LED13
flash(C,E,delay); // LED12
flash(E,C,delay); // LED11
flash(A,C,delay); // LED10
flash(C,A,delay); // LED9
flash(B,D,delay); // LED8
flash(D,B,delay); // LED7
flash(B,E,delay); // LED6
flash(E,B,delay); // LED5
flash(A,D,delay); // LED4
flash(D,A,delay); // LED3
flash(A,E,delay); // LED2
flash(E,A,delay); // LED1
// LEDs 1 to 20
flash(E,A,delay); // LED1
flash(A,E,delay); // LED2
flash(D,A,delay); // LED3
flash(A,D,delay); // LED4
flash(E,B,delay); // LED5
flash(B,E,delay); // LED6
flash(D,B,delay); // LED7
flash(B,D,delay); // LED8
flash(C,A,delay); // LED9
flash(A,C,delay); // LED10
flash(E,C,delay); // LED11
flash(C,E,delay); // LED12
flash(B,A,delay); // LED13
flash(A,B,delay); // LED14
flash(C,B,delay); // LED15
flash(B,C,delay); // LED16
flash(D,C,delay); // LED17
flash(C,D,delay); // LED18
flash(E,D,delay); // LED19
flash(D,E,delay); // LED20
}
}
void led_cycle2(uint8_t number, uint8_t delay) {
//
// cycle through LEDs
//
uint8_t i;
for (i = 0; i < number; ++i) {
// LEDs alternate sides towards center
flash(D,E,delay); // LED20
flash(E,A,delay); // LED1
flash(E,D,delay); // LED19
flash(A,E,delay); // LED2
flash(C,D,delay); // LED18
flash(D,A,delay); // LED3
flash(D,C,delay); // LED17
flash(A,D,delay); // LED4
flash(B,C,delay); // LED16
flash(E,B,delay); // LED5
flash(C,B,delay); // LED15
flash(B,E,delay); // LED6
flash(A,B,delay); // LED14
flash(D,B,delay); // LED7
flash(B,A,delay); // LED13
flash(B,D,delay); // LED8
flash(C,E,delay); // LED12
flash(C,A,delay); // LED9
flash(E,C,delay); // LED11
flash(A,C,delay); // LED10
// LEDs alternate sides towards outside
flash(A,C,delay); // LED10
flash(E,C,delay); // LED11
flash(C,A,delay); // LED9
flash(C,E,delay); // LED12
flash(B,D,delay); // LED8
flash(B,A,delay); // LED13
flash(D,B,delay); // LED7
flash(A,B,delay); // LED14
flash(B,E,delay); // LED6
flash(C,B,delay); // LED15
flash(E,B,delay); // LED5
flash(B,C,delay); // LED16
flash(A,D,delay); // LED4
flash(D,C,delay); // LED17
flash(D,A,delay); // LED3
flash(C,D,delay); // LED18
flash(A,E,delay); // LED2
flash(E,D,delay); // LED19
flash(E,A,delay); // LED1
flash(D,E,delay); // LED20
}
}
void led_cycle3(uint8_t number, uint8_t delay) {
//
// cycle through LEDs
//
uint8_t i;
for (i = 0; i < number; ++i) {
// LEDs 20 to 1
flash(D,E,delay); // LED20
flash(E,D,delay); // LED19
flash(C,D,delay); // LED18
flash(D,C,delay); // LED17
flash(B,C,delay); // LED16
flash(C,B,delay); // LED15
flash(A,B,delay); // LED14
flash(B,A,delay); // LED13
flash(C,E,delay); // LED12
flash(E,C,delay); // LED11
flash(A,C,delay); // LED10
flash(C,A,delay); // LED9
flash(B,D,delay); // LED8
flash(D,B,delay); // LED7
flash(B,E,delay); // LED6
flash(E,B,delay); // LED5
flash(A,D,delay); // LED4
flash(D,A,delay); // LED3
flash(A,E,delay); // LED2
flash(E,A,delay); // LED1
// LEDs 1 to 20
flash(E,A,delay); // LED1
flash(A,E,delay); // LED2
flash(D,A,delay); // LED3
flash(A,D,delay); // LED4
flash(E,B,delay); // LED5
flash(B,E,delay); // LED6
flash(D,B,delay); // LED7
flash(B,D,delay); // LED8
flash(C,A,delay); // LED9
flash(A,C,delay); // LED10
flash(E,C,delay); // LED11
flash(C,E,delay); // LED12
flash(B,A,delay); // LED13
flash(A,B,delay); // LED14
flash(C,B,delay); // LED15
flash(B,C,delay); // LED16
flash(D,C,delay); // LED17
flash(C,D,delay); // LED18
flash(E,D,delay); // LED19
flash(D,E,delay); // LED20
// LEDs alternate sides towards center
flash(D,E,delay); // LED20
flash(E,A,delay); // LED1
flash(E,D,delay); // LED19
flash(A,E,delay); // LED2
flash(C,D,delay); // LED18
flash(D,A,delay); // LED3
flash(D,C,delay); // LED17
flash(A,D,delay); // LED4
flash(B,C,delay); // LED16
flash(E,B,delay); // LED5
flash(C,B,delay); // LED15
flash(B,E,delay); // LED6
flash(A,B,delay); // LED14
flash(D,B,delay); // LED7
flash(B,A,delay); // LED13
flash(B,D,delay); // LED8
flash(C,E,delay); // LED12
flash(C,A,delay); // LED9
flash(E,C,delay); // LED11
flash(A,C,delay); // LED10
// LEDs alternate sides towards outside
flash(A,C,delay); // LED10
flash(E,C,delay); // LED11
flash(C,A,delay); // LED9
flash(C,E,delay); // LED12
flash(B,D,delay); // LED8
flash(B,A,delay); // LED13
flash(D,B,delay); // LED7
flash(A,B,delay); // LED14
flash(B,E,delay); // LED6
flash(C,B,delay); // LED15
flash(E,B,delay); // LED5
flash(B,C,delay); // LED16
flash(A,D,delay); // LED4
flash(D,C,delay); // LED17
flash(D,A,delay); // LED3
flash(C,D,delay); // LED18
flash(A,E,delay); // LED2
flash(E,D,delay); // LED19
flash(E,A,delay); // LED1
flash(D,E,delay); // LED20
}
}
int main(void) {
//
// set clock divider to /1
//
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
//
// initialize pins
//
input(input_direction, input_pin);
//
// main loop
//
while (1) {
pbstate=pin_test(input_pins,input_pin);//read button & store
pboneshot=pbstate && !pblast; //oneshot
pblast=pbstate; //remember last pass result
if(pboneshot){
mode++;
if(mode > 11) mode=0;
}
switch(mode){
case 0: led_cycle(1,100); break;
case 1: led_cycle(3,20); break;
case 2: led_cycle(5,10); break;
case 3: led_cycle(10,1); break;
case 4: led_cycle2(1,100); break;
case 5: led_cycle2(3,20); break;
case 6: led_cycle2(5,10); break;
case 7: led_cycle2(10,1); break;
case 8: led_cycle3(1,100); break;
case 9: led_cycle3(3,20); break;
case 10: led_cycle3(5,10); break;
case 11: led_cycle3(10,1); break;
}
_delay_ms(400); // Debouncing - delay longer than bounce time
}
}
I did eventually figure out how to use pushbuttons to select various modes as part of my final project.
For the "interface and applications programming" assignment I created a GUI program to display values from a FTDI interface. This made it much easier to understand what the microcontroller program was doing in situations like these. This interface made it easy to view in near real time how the program modified certain variables. So it very useful in testing and debugging.
I also realized that occasionally when I flashed a program to the microcontroller, it didn't always "take". The program did not update for some reason and microcontroller continues to run the previous program. I have witnessed this happen a few times since when the results of the program change would be obvious. If so, this would explain some of the problems I initially had with this assignment.