/********************************************************************
* *
* Project: 12F683 Test v1 *
* Source: 12F683_Test_v1.c *
* Author: Mike McLaren, K8LH *
* Date: 19-Jun-08 *
* Revised: 25-Jun-08 *
* *
* Charlieplexed 20 LED Demo with 32 PWM levels per LED *
* *
* *
* IDE: MPLAB 8.01 (tabs = 4) *
* Lang: SourceBoost BoostC v6.87, Lite/Free version *
* *
* *
********************************************************************/
#include <system.h>
#pragma DATA _CONFIG, _FCMEN_OFF&_IESO_OFF&_MCLRE_OFF&_WDT_OFF&_INTOSCIO
#pragma CLOCK_FREQ 8000000 //
//--< function prototypes >------------------------------------------
//--< type definitions >---------------------------------------------
//--< variables >----------------------------------------------------
unsigned char led[20]; // led matrix, pwm values 0..31
unsigned char shadow = 0; // isr, trisio shadow register
unsigned char colpos = 1; // isr, gpio column ring counter bit
unsigned char dcy = 15; // isr, duty cycle counter, 0..31
unsigned char dc0 = 0; // isr, row 0 (gp0) pwm value, 0..31
unsigned char dc1 = 0; // isr, row 1 (gp1) pwm value, 0..31
unsigned char dc2 = 0; // isr, row 2 (gp2) pwm value, 0..31
unsigned char dc3 = 0; // isr, row 3 (gp4) pwm value, 0..31
unsigned char addr = (unsigned char) &led;
//--< defines >------------------------------------------------------
#define end_of_period dcy.5 // isr, end of 32 pwm steps
#define end_of_cycle colpos.6 // isr, end of 5 column update cycle
//--< main >---------------------------------------------------------
void main()
{
osccon = 0b01110000; // set 8 MHz INTOSC
while(!osccon.HTS); // wait 'til oscillator stable
cmcon0 = 7; // comparator off, digital I/O
ansel = 0; // a2d module off, digital I/O
trisio = 0b00111111; // set all pins to inputs
gpio = 0; // set all output latches to '0'
// setup 100 usec Timer 2 interrupts (8 MHz clock)
pir1 = 0; // clear peripheral interrupt flags
pie1 = 0; // clear peripheral interrupt enables
pie1.TMR2IE = 1; // set Timer 2 interrupt enable bit
tmr2 = 0; // clear Timer 2 register
t2con = 0b00000100; // '0-------' unimplemented bit
// '-0000---' TOUTPS<3:0>, postscale 1
// '-----1--' TMR2ON, turn Timer 2 on
// '------00' T2CKPS<1:0>, prescale 1
pr2 = 200-1; // 200 x 500-nsec 'ticks' = 100 usecs
intcon = 0b11000000; // '1-------' GIE, enable global ints
// '-1------' PEIE, enable peripheral ints
// '--0-----' T0IE, TMR0 ints disabled
// '---0----' INTE, off
// '----0---' GPIE, IOC disabled
// '-----000' T0IF/INTF/GPIF flags
//
// simple led interface to pwm driver, duty cycle values of 0..31
//
led[0] = led[19] = 1; //
led[1] = led[18] = 1; //
led[2] = led[17] = 4; //
led[3] = led[16] = 0; //
led[4] = led[15] = 0; //
led[5] = led[14] = 1; //
led[6] = led[13] = 1; //
led[7] = led[12] = 0; //
led[8] = led[11] = 1; //
led[9] = led[10] = 1; //
while(1) //
{
}
}
/********************************************************************/
/* interrupt service routine */
/********************************************************************/
/* */
/* 100 usec Timer2 interrupts, 32 interrupts/column (3.2 msecs) */
/* for 32 pwm brightness levels. 160 interrupts (16 msecs) for a */
/* complete 5 column update cycle (62.5 Hz refresh rate). */
/* */
/* led array duty cycle parameter values of 0..31 produce actual */
/* duty cycles of 0% to 20% per LED in 0.625% (100 usec) steps. */
/* */
/* 57 to 84 cycles or approximately 42% "overhead" (8 MHz clock) */
/* */
/********************************************************************/
void interrupt()
{
if(dc0 == dcy) // if row 0 duty cycle match
shadow.0 = 0; // clear shadow bit (gp0)
if(dc1 == dcy) // if row 1 duty cycle match
shadow.1 = 0; // clear shadow bit (gp1)
if(dc2 == dcy) // if row 2 duty cycle match
shadow.2 = 0; // clear shadow bit (gp2)
if(dc3 == dcy) // if row 3 duty cycle match
shadow.4 = 0; // clear shadow bit (gp4)
dcy++; // increment duty cycle counter
asm
{ movf _colpos,W //
andwf _shadow,W // is the float bit required?
btfss _status,Z // no, skip, else
iorlw 0b00100000 // set the 'float' bit
iorwf _shadow,W // pick up led bits
iorwf _colpos,W // pick up column bit
xorlw 0b00111111 // invert all
movwf _trisio // update the column LEDs
}
if(end_of_period) // if all 32 pwm steps complete
{ dcy = 0; // reset duty cycle counter
asm
{ bcf _status,C // shift column bit mask
rlf _colpos,F //
btfsc _colpos,3 // if gp3 bit position
rlf _colpos,F // shift to gp4 bit position
}
if(end_of_cycle) // if all 5 columns have been updated
{ colpos = 1; // reset colpos bit to column 0
asm // reset led[] array address pointer
{ movlw _led //
movwf _addr // addr = (unsigned char) &led
}
}
shadow = 0b00010111; // setup shadow (all row bits "on")
gpio = colpos; // setup output latch, only 1 bit high
fsr = addr; // setup new column pwm work variables
dc0 = indf; // row 0 (gp0) pwm value, 0..31
fsr++; //
dc1 = indf; // row 1 (gp1) pwm value, 0..31
fsr++; //
dc2 = indf; // row 2 (gp2) pwm value, 0..31
fsr++; //
dc3 = indf; // row 3 (gp4) pwm value, 0..31
addr = fsr + 1; // save array address
}
}