/* //////////////// CharliePlexed Lighthouse BoostC Matt Casey : 15th June 2008 matt@catmacey.com PIC 12f683 12 Charlieplexed LEDs 1 Power button MCLR enabled //////////////// Notes: * Only plex's 2 LEDs at a time to give a 1/2 duty for each lit LED rather than 1/12 if plexing all LEDs. PIC max current source/sink is 20ma so that gives an average of around 10ma per LED * GP4 : controls power sim. Can be used to start/stop beacon. Hi starts, low stops. Uses weak pullup. //////////////// */ #pragma CLOCK_FREQ 8000000 #include #pragma DATA _CONFIG, _FCMEN_ON & _IESO_ON & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT //GPIO inputs #define btn0 gpio.4 //start stop button //GPIO charliplexing #define cp0 gpio.0 //Charliplex 0 #define cp1 gpio.1 //Charliplex 1 #define cp2 gpio.2 //Charliplex 2 #define cp3 gpio.5 //Charliplex 3 #define TRIS_DEFAULT 0b10111111 #define PWMMAX 31 //max pwm value #define PWMMASK 0b00011111 //mask for PWM // pattern for all 12 leds in sequential order. const char charlieBits[] = { 0b10000010 , 0b10100000 , 0b10000010 , 0b10000100 , 0b10000100 , 0b10100000 , 0b10000100 , 0b10000001 , 0b10000001 , 0b10100000 , 0b10000001 , 0b10000010 }; const char trisBits[] = { 0b10011101 , 0b10011101 , 0b10111001 , 0b10111001 , 0b10011011 , 0b10011011 , 0b10111010 , 0b10111010 , 0b10011110 , 0b10011110 , 0b10111100 , 0b10111100 }; unsigned char g_Intensity[12]; // pwm intensity value for each LED unsigned char g_LEDctr; // ctr used by isr to keep track of led it is currently pwming unsigned char g_pwm; // ISR pwm counter unsigned char g_ledInt; // ISR current LED's intensity (only look up once, at start of pwm cycle) unsigned char g_pwms[2]; // Array of LED indexes to pwm, only pwm 2 at a time unsigned char g_run; // Run the beacon unsigned char g_pwmCeil; // Max led intensity to display (simulates warm up/cool down) unsigned char g_db0; // Debouce for btn 0 //func prototypes void boot_up ( void ); void timer_isr ( void ); void ledOn ( unsigned char ledNum ); void ledOff ( void ); void interrupt (void){ //int unsigned char pwm; unsigned char ledIdx; if(test_bit(intcon, T0IF)){ //Timer 0 int pwm = g_pwm & PWMMASK; // Mask out 5 bits of pwm (31) g_pwm++; //increment pwm counter //turn off LED if(pwm >= g_ledInt) ledOff(); if(pwm == 0){ //Start of pwm cycle ledOff(); /* //////////////// * Do some work for main every 64 int: //////////////// */ if(g_pwm & 0b10000000){ if(g_run != 0){ //power up if(g_pwmCeil < PWMMAX){ g_pwmCeil++; } }else{ //power down if(g_pwmCeil > 0){ g_pwmCeil--; } } }//if //get the intensity value of the LED once every pwm cycle ledIdx = g_pwms[g_LEDctr]; g_ledInt = g_Intensity[ledIdx]; if(g_ledInt > g_pwmCeil) g_ledInt = g_pwmCeil; //if required value is higher than inertia allows. //set led on if not zero if(g_ledInt > 0) ledOn(ledIdx); //increment led counter for next time g_LEDctr++; if(g_LEDctr > 1){ g_LEDctr = 0; }//if }//if clear_bit( intcon, T0IF ); //clear TMR0 overflow flag } }//func void main( void ){ //Ceiling for LED intensity, might be higher than pwm ceiling. Exceeding PWM ceil gives a small delay at each LED before moving on to next. unsigned char ledMax = 0; unsigned char led = 0; unsigned char tmp = 0; boot_up(); //init the peripherals g_LEDctr = 0; g_pwm = 0; //Start up test routine. Lights each LED in turn at 100% intensity (no PWM) for(led=0; led<12; led++){ //for each led g_Intensity[led] = 0; //set zero trisio = TRIS_DEFAULT; gpio = charlieBits[led]; trisio = trisBits[led]; delay_ms(200); delay_s(1); } set_bit( intcon, GIE ); //Start ints led = 0; g_LEDctr = 0; //set starting index for ISR ledIdx g_pwmCeil = 0; //Set pwm ceiling to zero g_run = 1; //start running //Max amount of light in each bucket. ledMax = 40; //Main loop while(1){ //Fade all other leds for(tmp=0; tmp<12; tmp++){ //for each led that is not the current chosen one. if(tmp != led & g_Intensity[tmp] > 0){ g_Intensity[tmp]--; }//if }//for if(g_Intensity[led] < ledMax){ //Brighten chosen LED g_Intensity[led]++; }else{ //Bucket is full led++; //next bucket if(led > 11) led = 0; //Set PWM LED array g_pwms[0] = led; if(led == 0){ //special case g_pwms[1] = 11; }else{ //otherwise g_pwms[1] = led-1; } } if(btn0 != 0){ g_run = 1; }else{ g_run = 0; } //Increasing this delay will slow down the sweep of the beam. delay_ms(7); }//end while } /* Sets all LEDs off by setting charlie pins to high impedance */ void ledOff( void ){ //reset all charlie pins to high impedance (input) trisio = TRIS_DEFAULT; } /* Sets a given led on using charlieplexing */ void ledOn( unsigned char ledNum ){ //reset all charlie pins to high impedance (input) trisio = TRIS_DEFAULT; gpio = charlieBits[ledNum]; trisio = trisBits[ledNum]; } void boot_up( void ){ //Setup OSC osccon = 0b01110001; //8Mhz : Select internal Osc ansel = 0b00000000; //set all inputs as digital option_reg = 0b00000000; //Enable global weak pullups. Set all tmr0 stuff to zero (set tmr0 below) wpu = 0b00010000; //sets weak pullups cmcon0 = 0b00000111; //disable comparator, all gpio are IO cmcon1 = 0b00000000; //Semi irrelevant. Timer1 gate src = comparator t1con = 0b00000000; //Disable timer 1. Set tmr1 to internal clk. //Setup Ports gpio = 0b00000000; trisio = TRIS_DEFAULT; // 0= out, 1 = in //setup timer 0 clear_bit( option_reg, T0CS ); //enable timer clear_bit( option_reg, PSA ); //prescaler belongs to tmr0 clear_bit( option_reg, PS2 ); //set prescaler to 2 - 1 clear_bit( option_reg, PS1 ); clear_bit( option_reg, PS0 ); set_bit( intcon, T0IE ); //enable TMR0 overflow bit clear_bit( intcon, GIE ); //Disable ints for the mo delay_10us(10);//wait for stable }