Back to www.micro-examples.com

LED Light Sensor C Source Code

Here is the MikroC source code :

Back to project page


/*
 *******************************************************************************
 * 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
                }
        }