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

Post a Comment

Copyright © Rough Record. Designed by OddThemes