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
- Committer:
- emollison
- Date:
- 2011-09-06
- Revision:
- 0:403b6acd3179
File content as of revision 0:403b6acd3179:
/* Programmer: Eric Mollison Date: 9-6-2011 Hardware: only mbed Description: "LED Wave" makes the 4 LEDs on the mbed shift in brightness with PWM (pulse width modulation) so as to appear to move smoothly to a side. LEDs are updated with a Ticker interrupt so that most of the processor capacity can collect input from a keyboard (if you installed the driver for the mbed communicating with the pc). Optimized with precomputed values so that each step takes ~14us. Note: To use interactively, look up: http://mbed.org/handbook/SerialPC to find where to install drivers and putty or another terminal program Also note: You don't need to declare: "Serial pc(USBTX, USBRX);" probably because the code is in the mbed.h to autoinitialize i/o functions like printf, putc getc, etc. (so I guess) */ #include "mbed.h" #define PULSEWIDTH 18000 //time(us) for each pulse from the PWM //flicker undetectable at pw <= 20000 //a pw too low will make too few brightness levels making another type of flicker #define PI 3.1415926 //used to calculate sine from angle(radians): -PI/2 to PI/2 #define OSCIQUAR 500 //steps per quarter of a circle of angle //5925 is max (wont work with too large of an array) //11898 is max short array size that ever worked //suspect malloc can do better //can be smooth but fast at as low as 10 //OSCIQUAR * 2 = array size, and * 4 = steps or steps per cycle #define STEPTIME 20000 //time(us) for each timed update or step of the lights //no noticable flicker at 20ms step time //13 us is the minimum (step takes >=13 microseconds) //20 us is minimum to allow for keyboard input //1 or 0 will freeze #define LEDSTEP1(Num) { \ led##Num##.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt##Num##)); \ pwpt##Num##+=stepRate; \ if(pwpt##Num >= OSCIQUAR*4) pwpt##Num##-=OSCIQUAR*4; \ else if(pwpt##Num < 0) pwpt##Num##+=OSCIQUAR*4; \ } #define DEBUGINT(Int) printf("%s = %d\n", #Int, Int); //prototypes void setpws(int qlen, int max); void setpws_subt(int qlen, int max); short getValFromCirc(int qlen, int cpt); void step(); static int maxStepRate = OSCIQUAR*4*STEPTIME/1000000+1; //set so that cycles take at least 1 second static int stepAccel = maxStepRate/50+1; //change in velocity with each keypress static int stepRate = maxStepRate/10+1; //initial velocity of moving light PwmOut led1(LED1); //pwmout sets up the leds for pulse width modulation PwmOut led2(LED2); PwmOut led3(LED3); PwmOut led4(LED4); Timer timer; //timer is for testing performance Ticker t_step; //t_step controls the updates to brightness static short *pwvals; //array of precomputed brightnesses //used short instead of int to save ram int main() { printf("\nInitializing LED wave program...\n"); pwvals = new short[OSCIQUAR*2]; timer.start(); //begin counting time int begin, end; led4=1; begin = timer.read_us(); //find time to pre-compute setpws_subt(OSCIQUAR, PULSEWIDTH); end = timer.read_us(); printf("intializing array of %d takes %d us\n", OSCIQUAR*2, end - begin); led1.period_us(PULSEWIDTH); //sets period for all leds on pwm t_step.attach_us(&step, STEPTIME); //make ticker update LED printf("Successfully started cycling LEDs\n"); printf("\nPush '=' or '+' to accelerate shift to the left.\n"); printf("Push '-' to accelerate right.\n"); printf("Push '0'(zero), 's' or 'S' to stop motion.\n\n"); while(1) //keyboard read loop { char c = getc(stdin); if (c=='=' || c=='+') { if(stepRate<maxStepRate) { stepRate+=stepAccel; if(stepRate>maxStepRate)stepRate=maxStepRate; DEBUGINT(stepRate) } } else if (c=='-') { if(stepRate>-maxStepRate) { stepRate-=stepAccel; if(stepRate<-maxStepRate)stepRate=-maxStepRate; DEBUGINT(stepRate) } } else if (c=='s' || c=='S' || c=='0') { stepRate=0; DEBUGINT(stepRate) } //wait_ms(10); }//end keyboard read loop } /* repeated function run by Ticker which updates the lights at regular intervals so that they appear to smoothly shift with "anti-aliasing" */ void step() { static int pwpt1=0, pwpt2=OSCIQUAR, pwpt3=OSCIQUAR*2, pwpt4=OSCIQUAR*3; static int step_counter=0, time=0; const int check_interval=1000; //if over 100M, may overflow time if(++step_counter==check_interval) { printf("Time(us) to step = %8f\n", (float)time/check_interval); step_counter=0; time=0; } time-=timer.read_us(); //just showing how to shorten code with macros #ifdef LEDSTEP LEDSTEP(1) LEDSTEP(2) LEDSTEP(3) LEDSTEP(4) #else led1.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt1)); led2.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt2)); led3.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt3)); led4.pulsewidth_us(getValFromCirc(OSCIQUAR,pwpt4)); pwpt1+=stepRate; pwpt2+=stepRate; pwpt3+=stepRate; pwpt4+=stepRate; if(pwpt1 >= OSCIQUAR*4) pwpt1-=OSCIQUAR*4; else if(pwpt1 < 0) pwpt1+=OSCIQUAR*4; if(pwpt2 >= OSCIQUAR*4) pwpt2-=OSCIQUAR*4; else if(pwpt2 < 0) pwpt2+=OSCIQUAR*4; if(pwpt3 >= OSCIQUAR*4) pwpt3-=OSCIQUAR*4; else if(pwpt3 < 0) pwpt3+=OSCIQUAR*4; if(pwpt4 >= OSCIQUAR*4) pwpt4-=OSCIQUAR*4; else if(pwpt4 < 0) pwpt4+=OSCIQUAR*4; #endif time+=timer.read_us(); } /* initializes the array of pre-computed values for light intensity applied by the PWM such that lights turn completely off for an instant */ void setpws_subt(int qlen, int max) { int i=0; float tempsin, tempexp; float tempsinadd=.5-qlen; float tempsinmul=(PI/(OSCIQUAR*2)); float expmul=4; float subtractor=(exp(-2*expmul))-.99/max; int newmax=max+(int)(subtractor*max); do { tempsin = sin((i+tempsinadd)*tempsinmul); tempexp = exp((tempsin-1)*expmul)-subtractor; pwvals[i] = (short)(tempexp*newmax); //pwvals[i] = (short)(exp((sin((i+tempsinadd)*tempsinmul)-1)*4)*max); }while(++i<2*qlen); } /* initializes the array of pre-computed values for light intensity applied by the PWM. Setpws_subt is an alternative. */ void setpws(int qlen, int max) { int i=0; float tempsin, tempexp; float tempsinadd=.5-qlen; float tempsinmul=(PI/(OSCIQUAR*2)); float expmul=4; do { //currently ~2000 cycles per loop tempsin = sin((i+tempsinadd)*tempsinmul); tempexp = exp((tempsin-1)*expmul); pwvals[i] = (short)(tempexp*max); //pwvals[i] = (short)(exp((sin((i+tempsinadd)*tempsinmul)-1)*expmul)*max); }while(++i<2*qlen); } /* selects a value from an array by position on a circle from -PI/2 to (3/2)*PI when the array is for -PI/2 to PI/2 and reverses from PI/2 to (3/2)*PI */ short getValFromCirc(int qlen, int cpt) { if (cpt < 2*qlen) { return pwvals[cpt]; } else { return pwvals[4*qlen-cpt-1]; } }