Here is the MikroC source code :
/* ******************************************************************************* * PIC PWM LED DISPLAY DIMMER WITH SIMPLE LIGHT SENSOR ******************************************************************************* * * how to dimm automaticaly a 7-segment multiplexed LED display * with only another LED used as light sensor * * the dimmer is made with software PWM to control LEDs brightness * * source code example for MikroC * feel free to use this code at your own risks * * target : PIC16F877A * crystal frequency : 8 Mhz * HS clock, all flags to mC default values * * EP2/EP3 settings : * enable the 4 7-segments LED display * enable PORTC LEDs * pull-down on PORTD * pull-up on KEYBOARD * * this programm has been tested with some classic LEDs of different sizes & colors : * red, green, yellow, with different diameters * * instructions for use : * - connect the anode of the LED sensor to the ground * - connect the cathod of the LED sensor to the RA5 pin * - turn on the board * - the 7 segment LEDs will display "HIGH" when the LED sensor is in the light * - the 7 segment LEDs will display "DIMM" when the LED sensor is in the dark * - adjust the dimm level by pressing the RD0 button (brighter) or the RD1 button (darker) * - the dimm level is shown on PORTC LEDs * - the dimm level is 6 step wide from 0% to 100% of brightness * * Author : Bruno Gavand, May 2006 * see more details on http://www.micro-examples.com * ******************************************************************************* */ /* * key definition */ #define INCVALUE PORTD.F0 #define DECVALUE PORTD.F1 /* * segment definition */ #define SA 1 #define SB 2 #define SC 4 #define SD 8 #define SE 16 #define SF 32 #define SG 64 #define DP 128 /* * 7 segment symbols */ #define segH SB+SC+SE+SF+SG #define segI SB+SC #define segG SA+SC+SD+SE+SF+SG #define segD SB+SC+SD+SE+SG #define segM SA+SB+SC+SE+SF /* * this counter is incremented on each TIMER0 overflow */ long cntr ; /* * display table */ unsigned char data[4] ; /* * current digit to display */ unsigned char dcurr ; unsigned char dimm = 0 ; // limit for PWM unsigned char dimmValue = 7 ; // dimmer level, 0 : 0% brightness, 31 or greater : 100% brightness unsigned char duty ; // current position in duty cycle /* * interrupt routine, called on each timer0 overflow */ void interrupt(void) { if(INTCON.T0IF) // timer 0 overflow ? { cntr++ ; // increment counter dcurr++ ; // next digit PORTB = 0 ; // turn digit off if(dcurr == 4) // last digit ? { PORTA = 0b00000001 ; // light the first digit dcurr = 0 ; } else { PORTA <<= 1 ; // light the next digit } PORTB = data[dcurr] ; // assign 7 segments value /* * software PWM */ if(duty <= dimm) // within pulse work space ? { if(dimm > 1) TRISB = 0 ; // yes, light the display if the dimmer allows } else { TRISB = 0xff ; // no, turn display off } duty++ ; // make duty cycle progress duty &= 0b00111111 ; // duty cycle has 6 bits accuracy INTCON.T0IF = 0 ; // done } } main() { unsigned int v ; // adv value TRISA = 0xf0 ; // set PORTA IO direction, low nibble is 7 segments cathode control, bit 5 is ADC TRISB = 0 ; // set PORTB as output : 7 segments display PORTB = 0 ; TRISC = 0 ; // set PORTC as output : dimmer value display TRISD = 0xff ; // set PORTD as input : keyboard OPTION_REG = 0x80 ; // start timer 0, no prescaler INTCON = 0xA0 ; // allow timer 0 overflow interrupt for(;;) // forever { if(cntr >= 7812) // if enough time since last reading (1 second) { /* * read the light sensor */ ADCON1 = 0x00 ; // set PORTA as analog input v = Adc_Read(4) ; // read AN4 ADC (RA5) ADCON1 = 0x07 ; // set PORTA as digital IO /* * you may adjust here the trigger levels, * keep some hysteresys if you do */ if(v < 8) // sensor in the light ? { dimm = 255 ; // yes, brightness = 100% data[0] = segH ; // display "HIGH" on 7 segments data[1] = segI ; data[2] = segG ; data[3] = segH ; } else if(v > 16) // sensor in the dark ? { dimm = dimmValue ; // yes, brightness is dimmed data[0] = segD ; // display "DIMM" on 7 segments data[1] = segI ; data[2] = segM ; data[3] = segM ; } cntr = 0 ; // reset counter } if(PORTD) // a key is pressed ? { if(INCVALUE) // increment dimmer key ? { if(dimmValue != 0x3f) // maximum value already reached ? { dimmValue <<= 1 ; // no, we can increase it by 2 dimmValue |= 1 ; // fill with 1's } } else if(DECVALUE) // decrement dimmer key ? { if(dimmValue != 0x01) // minimum value already reached ? { dimmValue >>= 1 ; // no, decrease it } } while(PORTD) ; // wait for the key to be released } PORTC = dimmValue >> 1 ; // display dimmer level on PORTC } }