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