This program makes a sort of animation with the 4 led lights that resembles a wave motion. Because of my obsessive development, it is quite long and complicated, but very fun and educational for begginers (like I was a few days ago). Uses terminal program like putty for interaction.
main.cpp@0:403b6acd3179, 2011-09-06 (annotated)
- Committer:
- emollison
- Date:
- Tue Sep 06 16:01:35 2011 +0000
- Revision:
- 0:403b6acd3179
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
emollison | 0:403b6acd3179 | 1 | /* |
emollison | 0:403b6acd3179 | 2 | Programmer: Eric Mollison |
emollison | 0:403b6acd3179 | 3 | Date: 9-6-2011 |
emollison | 0:403b6acd3179 | 4 | Hardware: only mbed |
emollison | 0:403b6acd3179 | 5 | Description: "LED Wave" makes the 4 LEDs on the mbed shift in brightness |
emollison | 0:403b6acd3179 | 6 | with PWM (pulse width modulation) so as to appear to move |
emollison | 0:403b6acd3179 | 7 | smoothly to a side. LEDs are updated with a Ticker interrupt |
emollison | 0:403b6acd3179 | 8 | so that most of the processor capacity can collect input from |
emollison | 0:403b6acd3179 | 9 | a keyboard (if you installed the driver for the mbed |
emollison | 0:403b6acd3179 | 10 | communicating with the pc). Optimized with precomputed values |
emollison | 0:403b6acd3179 | 11 | so that each step takes ~14us. |
emollison | 0:403b6acd3179 | 12 | Note: |
emollison | 0:403b6acd3179 | 13 | To use interactively, look up: |
emollison | 0:403b6acd3179 | 14 | http://mbed.org/handbook/SerialPC |
emollison | 0:403b6acd3179 | 15 | to find where to install drivers and putty or another terminal program |
emollison | 0:403b6acd3179 | 16 | Also note: |
emollison | 0:403b6acd3179 | 17 | You don't need to declare: |
emollison | 0:403b6acd3179 | 18 | "Serial pc(USBTX, USBRX);" |
emollison | 0:403b6acd3179 | 19 | probably because the code is in the mbed.h to autoinitialize |
emollison | 0:403b6acd3179 | 20 | i/o functions like printf, putc getc, etc. (so I guess) |
emollison | 0:403b6acd3179 | 21 | */ |
emollison | 0:403b6acd3179 | 22 | |
emollison | 0:403b6acd3179 | 23 | |
emollison | 0:403b6acd3179 | 24 | #include "mbed.h" |
emollison | 0:403b6acd3179 | 25 | #define PULSEWIDTH 18000 //time(us) for each pulse from the PWM |
emollison | 0:403b6acd3179 | 26 | //flicker undetectable at pw <= 20000 |
emollison | 0:403b6acd3179 | 27 | //a pw too low will make too few brightness levels making another type of flicker |
emollison | 0:403b6acd3179 | 28 | #define PI 3.1415926 //used to calculate sine from angle(radians): -PI/2 to PI/2 |
emollison | 0:403b6acd3179 | 29 | |
emollison | 0:403b6acd3179 | 30 | #define OSCIQUAR 500 //steps per quarter of a circle of angle |
emollison | 0:403b6acd3179 | 31 | //5925 is max (wont work with too large of an array) |
emollison | 0:403b6acd3179 | 32 | //11898 is max short array size that ever worked |
emollison | 0:403b6acd3179 | 33 | //suspect malloc can do better |
emollison | 0:403b6acd3179 | 34 | //can be smooth but fast at as low as 10 |
emollison | 0:403b6acd3179 | 35 | |
emollison | 0:403b6acd3179 | 36 | //OSCIQUAR * 2 = array size, and * 4 = steps or steps per cycle |
emollison | 0:403b6acd3179 | 37 | #define STEPTIME 20000 //time(us) for each timed update or step of the lights |
emollison | 0:403b6acd3179 | 38 | //no noticable flicker at 20ms step time |
emollison | 0:403b6acd3179 | 39 | //13 us is the minimum (step takes >=13 microseconds) |
emollison | 0:403b6acd3179 | 40 | //20 us is minimum to allow for keyboard input |
emollison | 0:403b6acd3179 | 41 | //1 or 0 will freeze |
emollison | 0:403b6acd3179 | 42 | |
emollison | 0:403b6acd3179 | 43 | #define LEDSTEP1(Num) { \ |
emollison | 0:403b6acd3179 | 44 | led##Num##.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt##Num##)); \ |
emollison | 0:403b6acd3179 | 45 | pwpt##Num##+=stepRate; \ |
emollison | 0:403b6acd3179 | 46 | if(pwpt##Num >= OSCIQUAR*4) pwpt##Num##-=OSCIQUAR*4; \ |
emollison | 0:403b6acd3179 | 47 | else if(pwpt##Num < 0) pwpt##Num##+=OSCIQUAR*4; \ |
emollison | 0:403b6acd3179 | 48 | } |
emollison | 0:403b6acd3179 | 49 | |
emollison | 0:403b6acd3179 | 50 | #define DEBUGINT(Int) printf("%s = %d\n", #Int, Int); |
emollison | 0:403b6acd3179 | 51 | |
emollison | 0:403b6acd3179 | 52 | |
emollison | 0:403b6acd3179 | 53 | //prototypes |
emollison | 0:403b6acd3179 | 54 | void setpws(int qlen, int max); |
emollison | 0:403b6acd3179 | 55 | void setpws_subt(int qlen, int max); |
emollison | 0:403b6acd3179 | 56 | short getValFromCirc(int qlen, int cpt); |
emollison | 0:403b6acd3179 | 57 | void step(); |
emollison | 0:403b6acd3179 | 58 | |
emollison | 0:403b6acd3179 | 59 | static int maxStepRate = OSCIQUAR*4*STEPTIME/1000000+1; //set so that cycles take at least 1 second |
emollison | 0:403b6acd3179 | 60 | static int stepAccel = maxStepRate/50+1; //change in velocity with each keypress |
emollison | 0:403b6acd3179 | 61 | static int stepRate = maxStepRate/10+1; //initial velocity of moving light |
emollison | 0:403b6acd3179 | 62 | |
emollison | 0:403b6acd3179 | 63 | |
emollison | 0:403b6acd3179 | 64 | PwmOut led1(LED1); //pwmout sets up the leds for pulse width modulation |
emollison | 0:403b6acd3179 | 65 | PwmOut led2(LED2); |
emollison | 0:403b6acd3179 | 66 | PwmOut led3(LED3); |
emollison | 0:403b6acd3179 | 67 | PwmOut led4(LED4); |
emollison | 0:403b6acd3179 | 68 | Timer timer; //timer is for testing performance |
emollison | 0:403b6acd3179 | 69 | Ticker t_step; //t_step controls the updates to brightness |
emollison | 0:403b6acd3179 | 70 | static short *pwvals; //array of precomputed brightnesses |
emollison | 0:403b6acd3179 | 71 | //used short instead of int to save ram |
emollison | 0:403b6acd3179 | 72 | |
emollison | 0:403b6acd3179 | 73 | int main() |
emollison | 0:403b6acd3179 | 74 | { |
emollison | 0:403b6acd3179 | 75 | |
emollison | 0:403b6acd3179 | 76 | printf("\nInitializing LED wave program...\n"); |
emollison | 0:403b6acd3179 | 77 | pwvals = new short[OSCIQUAR*2]; |
emollison | 0:403b6acd3179 | 78 | timer.start(); //begin counting time |
emollison | 0:403b6acd3179 | 79 | int begin, end; |
emollison | 0:403b6acd3179 | 80 | led4=1; |
emollison | 0:403b6acd3179 | 81 | |
emollison | 0:403b6acd3179 | 82 | begin = timer.read_us(); //find time to pre-compute |
emollison | 0:403b6acd3179 | 83 | setpws_subt(OSCIQUAR, PULSEWIDTH); |
emollison | 0:403b6acd3179 | 84 | end = timer.read_us(); |
emollison | 0:403b6acd3179 | 85 | |
emollison | 0:403b6acd3179 | 86 | printf("intializing array of %d takes %d us\n", OSCIQUAR*2, end - begin); |
emollison | 0:403b6acd3179 | 87 | |
emollison | 0:403b6acd3179 | 88 | led1.period_us(PULSEWIDTH); //sets period for all leds on pwm |
emollison | 0:403b6acd3179 | 89 | |
emollison | 0:403b6acd3179 | 90 | t_step.attach_us(&step, STEPTIME); //make ticker update LED |
emollison | 0:403b6acd3179 | 91 | printf("Successfully started cycling LEDs\n"); |
emollison | 0:403b6acd3179 | 92 | printf("\nPush '=' or '+' to accelerate shift to the left.\n"); |
emollison | 0:403b6acd3179 | 93 | printf("Push '-' to accelerate right.\n"); |
emollison | 0:403b6acd3179 | 94 | printf("Push '0'(zero), 's' or 'S' to stop motion.\n\n"); |
emollison | 0:403b6acd3179 | 95 | while(1) //keyboard read loop |
emollison | 0:403b6acd3179 | 96 | { |
emollison | 0:403b6acd3179 | 97 | char c = getc(stdin); |
emollison | 0:403b6acd3179 | 98 | if (c=='=' || c=='+') |
emollison | 0:403b6acd3179 | 99 | { |
emollison | 0:403b6acd3179 | 100 | if(stepRate<maxStepRate) |
emollison | 0:403b6acd3179 | 101 | { |
emollison | 0:403b6acd3179 | 102 | stepRate+=stepAccel; |
emollison | 0:403b6acd3179 | 103 | if(stepRate>maxStepRate)stepRate=maxStepRate; |
emollison | 0:403b6acd3179 | 104 | DEBUGINT(stepRate) |
emollison | 0:403b6acd3179 | 105 | } |
emollison | 0:403b6acd3179 | 106 | } |
emollison | 0:403b6acd3179 | 107 | else if (c=='-') |
emollison | 0:403b6acd3179 | 108 | { |
emollison | 0:403b6acd3179 | 109 | if(stepRate>-maxStepRate) |
emollison | 0:403b6acd3179 | 110 | { |
emollison | 0:403b6acd3179 | 111 | stepRate-=stepAccel; |
emollison | 0:403b6acd3179 | 112 | if(stepRate<-maxStepRate)stepRate=-maxStepRate; |
emollison | 0:403b6acd3179 | 113 | DEBUGINT(stepRate) |
emollison | 0:403b6acd3179 | 114 | } |
emollison | 0:403b6acd3179 | 115 | } |
emollison | 0:403b6acd3179 | 116 | else if (c=='s' || c=='S' || c=='0') |
emollison | 0:403b6acd3179 | 117 | { |
emollison | 0:403b6acd3179 | 118 | stepRate=0; |
emollison | 0:403b6acd3179 | 119 | DEBUGINT(stepRate) |
emollison | 0:403b6acd3179 | 120 | } |
emollison | 0:403b6acd3179 | 121 | //wait_ms(10); |
emollison | 0:403b6acd3179 | 122 | |
emollison | 0:403b6acd3179 | 123 | }//end keyboard read loop |
emollison | 0:403b6acd3179 | 124 | |
emollison | 0:403b6acd3179 | 125 | } |
emollison | 0:403b6acd3179 | 126 | |
emollison | 0:403b6acd3179 | 127 | /* |
emollison | 0:403b6acd3179 | 128 | repeated function run by Ticker which updates the lights at regular intervals |
emollison | 0:403b6acd3179 | 129 | so that they appear to smoothly shift with "anti-aliasing" |
emollison | 0:403b6acd3179 | 130 | */ |
emollison | 0:403b6acd3179 | 131 | void step() |
emollison | 0:403b6acd3179 | 132 | { |
emollison | 0:403b6acd3179 | 133 | static int pwpt1=0, pwpt2=OSCIQUAR, pwpt3=OSCIQUAR*2, pwpt4=OSCIQUAR*3; |
emollison | 0:403b6acd3179 | 134 | static int step_counter=0, time=0; |
emollison | 0:403b6acd3179 | 135 | const int check_interval=1000; //if over 100M, may overflow time |
emollison | 0:403b6acd3179 | 136 | if(++step_counter==check_interval) |
emollison | 0:403b6acd3179 | 137 | { |
emollison | 0:403b6acd3179 | 138 | printf("Time(us) to step = %8f\n", (float)time/check_interval); |
emollison | 0:403b6acd3179 | 139 | step_counter=0; |
emollison | 0:403b6acd3179 | 140 | time=0; |
emollison | 0:403b6acd3179 | 141 | } |
emollison | 0:403b6acd3179 | 142 | time-=timer.read_us(); |
emollison | 0:403b6acd3179 | 143 | |
emollison | 0:403b6acd3179 | 144 | //just showing how to shorten code with macros |
emollison | 0:403b6acd3179 | 145 | #ifdef LEDSTEP |
emollison | 0:403b6acd3179 | 146 | LEDSTEP(1) |
emollison | 0:403b6acd3179 | 147 | LEDSTEP(2) |
emollison | 0:403b6acd3179 | 148 | LEDSTEP(3) |
emollison | 0:403b6acd3179 | 149 | LEDSTEP(4) |
emollison | 0:403b6acd3179 | 150 | #else |
emollison | 0:403b6acd3179 | 151 | led1.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt1)); |
emollison | 0:403b6acd3179 | 152 | led2.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt2)); |
emollison | 0:403b6acd3179 | 153 | led3.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt3)); |
emollison | 0:403b6acd3179 | 154 | led4.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt4)); |
emollison | 0:403b6acd3179 | 155 | |
emollison | 0:403b6acd3179 | 156 | pwpt1+=stepRate; |
emollison | 0:403b6acd3179 | 157 | pwpt2+=stepRate; |
emollison | 0:403b6acd3179 | 158 | pwpt3+=stepRate; |
emollison | 0:403b6acd3179 | 159 | pwpt4+=stepRate; |
emollison | 0:403b6acd3179 | 160 | |
emollison | 0:403b6acd3179 | 161 | if(pwpt1 >= OSCIQUAR*4) pwpt1-=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 162 | else if(pwpt1 < 0) pwpt1+=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 163 | if(pwpt2 >= OSCIQUAR*4) pwpt2-=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 164 | else if(pwpt2 < 0) pwpt2+=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 165 | if(pwpt3 >= OSCIQUAR*4) pwpt3-=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 166 | else if(pwpt3 < 0) pwpt3+=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 167 | if(pwpt4 >= OSCIQUAR*4) pwpt4-=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 168 | else if(pwpt4 < 0) pwpt4+=OSCIQUAR*4; |
emollison | 0:403b6acd3179 | 169 | #endif |
emollison | 0:403b6acd3179 | 170 | |
emollison | 0:403b6acd3179 | 171 | time+=timer.read_us(); |
emollison | 0:403b6acd3179 | 172 | |
emollison | 0:403b6acd3179 | 173 | } |
emollison | 0:403b6acd3179 | 174 | |
emollison | 0:403b6acd3179 | 175 | /* |
emollison | 0:403b6acd3179 | 176 | initializes the array of pre-computed values for light intensity |
emollison | 0:403b6acd3179 | 177 | applied by the PWM such that lights turn completely off for an instant |
emollison | 0:403b6acd3179 | 178 | */ |
emollison | 0:403b6acd3179 | 179 | void setpws_subt(int qlen, int max) |
emollison | 0:403b6acd3179 | 180 | { |
emollison | 0:403b6acd3179 | 181 | int i=0; |
emollison | 0:403b6acd3179 | 182 | float tempsin, tempexp; |
emollison | 0:403b6acd3179 | 183 | float tempsinadd=.5-qlen; |
emollison | 0:403b6acd3179 | 184 | float tempsinmul=(PI/(OSCIQUAR*2)); |
emollison | 0:403b6acd3179 | 185 | float expmul=4; |
emollison | 0:403b6acd3179 | 186 | float subtractor=(exp(-2*expmul))-.99/max; |
emollison | 0:403b6acd3179 | 187 | int newmax=max+(int)(subtractor*max); |
emollison | 0:403b6acd3179 | 188 | |
emollison | 0:403b6acd3179 | 189 | do |
emollison | 0:403b6acd3179 | 190 | { |
emollison | 0:403b6acd3179 | 191 | tempsin = sin((i+tempsinadd)*tempsinmul); |
emollison | 0:403b6acd3179 | 192 | tempexp = exp((tempsin-1)*expmul)-subtractor; |
emollison | 0:403b6acd3179 | 193 | pwvals[i] = (short)(tempexp*newmax); |
emollison | 0:403b6acd3179 | 194 | //pwvals[i] = (short)(exp((sin((i+tempsinadd)*tempsinmul)-1)*4)*max); |
emollison | 0:403b6acd3179 | 195 | }while(++i<2*qlen); |
emollison | 0:403b6acd3179 | 196 | } |
emollison | 0:403b6acd3179 | 197 | |
emollison | 0:403b6acd3179 | 198 | /* |
emollison | 0:403b6acd3179 | 199 | initializes the array of pre-computed values for light intensity |
emollison | 0:403b6acd3179 | 200 | applied by the PWM. Setpws_subt is an alternative. |
emollison | 0:403b6acd3179 | 201 | */ |
emollison | 0:403b6acd3179 | 202 | void setpws(int qlen, int max) |
emollison | 0:403b6acd3179 | 203 | { |
emollison | 0:403b6acd3179 | 204 | int i=0; |
emollison | 0:403b6acd3179 | 205 | float tempsin, tempexp; |
emollison | 0:403b6acd3179 | 206 | float tempsinadd=.5-qlen; |
emollison | 0:403b6acd3179 | 207 | float tempsinmul=(PI/(OSCIQUAR*2)); |
emollison | 0:403b6acd3179 | 208 | float expmul=4; |
emollison | 0:403b6acd3179 | 209 | |
emollison | 0:403b6acd3179 | 210 | do |
emollison | 0:403b6acd3179 | 211 | { |
emollison | 0:403b6acd3179 | 212 | //currently ~2000 cycles per loop |
emollison | 0:403b6acd3179 | 213 | |
emollison | 0:403b6acd3179 | 214 | tempsin = sin((i+tempsinadd)*tempsinmul); |
emollison | 0:403b6acd3179 | 215 | tempexp = exp((tempsin-1)*expmul); |
emollison | 0:403b6acd3179 | 216 | pwvals[i] = (short)(tempexp*max); |
emollison | 0:403b6acd3179 | 217 | //pwvals[i] = (short)(exp((sin((i+tempsinadd)*tempsinmul)-1)*expmul)*max); |
emollison | 0:403b6acd3179 | 218 | }while(++i<2*qlen); |
emollison | 0:403b6acd3179 | 219 | } |
emollison | 0:403b6acd3179 | 220 | |
emollison | 0:403b6acd3179 | 221 | /* |
emollison | 0:403b6acd3179 | 222 | selects a value from an array by position on a circle from -PI/2 to (3/2)*PI |
emollison | 0:403b6acd3179 | 223 | when the array is for -PI/2 to PI/2 and reverses from PI/2 to (3/2)*PI |
emollison | 0:403b6acd3179 | 224 | */ |
emollison | 0:403b6acd3179 | 225 | short getValFromCirc(int qlen, int cpt) |
emollison | 0:403b6acd3179 | 226 | { |
emollison | 0:403b6acd3179 | 227 | if (cpt < 2*qlen) |
emollison | 0:403b6acd3179 | 228 | { |
emollison | 0:403b6acd3179 | 229 | return pwvals[cpt]; |
emollison | 0:403b6acd3179 | 230 | } |
emollison | 0:403b6acd3179 | 231 | else |
emollison | 0:403b6acd3179 | 232 | { |
emollison | 0:403b6acd3179 | 233 | return pwvals[4*qlen-cpt-1]; |
emollison | 0:403b6acd3179 | 234 | } |
emollison | 0:403b6acd3179 | 235 | } |