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