Home PIC 18F248 18F248 w/A6276 and 2-digit 7-seg LED

Main Menu

18F248 w/A6276 and 2-digit 7-seg LED
Article Index
18F248 w/A6276 and 2-digit 7-seg LED
Adding a DS18B20/DS18S20
All Pages
thumbI recently ordered some Allegro A6276 LED drivers and wanted to try one out. The resulting project was fun to build, educational and will be useful in future for something, I'm sure. I used another el-cheapo obsolete 18F248 SOIC chip and an SOIC A6276 on a DipMicro PB4 board. The displays are Lite-On LSHD-5601 .56" green common-anode.

 

 

 

 

 

Here's a pic of the "completed" board (left) and a view of the underside (right). As you can see, the only place for the second crystal loading capacitor is the underside of the board. PB4 circuit boards are tight for space!

The A6276 LED driver chip really simplifies things. Using it cuts the amount of wiring and components to a minimum. LED current is controlled by just one resistor! It only needs two or three MCU pins for control. I have a fourth line connected so I can PWM my displays.

It has a 16-bit shift register inside so it can easily control two digits per chip without multiplexing (full brightness). The chips are cascadable so you can easily build larger displays. I didn't have room on this board for 4 displays, unfortunately. I tried everything, but it just wouldn't fit.

Completed Board Underside

 

On the left that's a Grayhill 25LB10-Q rotary quadrature encoder (Digikey Part#GH3071-ND). It attaches to RB4 and RB5 and uses the RB port change interrupt to adjust PWM for the display. On the right is the A6276 chip and the displays.

Quadrature Encoder Displays

 

Here's the schematic (click for full size):

Schematic

 

Here's the current test code in BoostC. The A6276 is being bit-banged, rather than using the 18F248's MSSP module for SPI. There's no particular reason for this. The hardware SPI works fine too.

Scroll down for a hardware SPI version of the same code.

Scroll even further down for a version of the code that changes the numbers with the encoder.

And at the very bottom there's a fun little program that switches between various display demos with the encoder.

Bit-Banged SPI Version

#include <system.h>
#pragma CLOCK_FREQ 20000000
#pragma DATA _CONFIG1H, _HS_OSC_1H & _OSCS_ON_1H
#pragma DATA _CONFIG2H, _WDT_OFF_2H
#pragma DATA _CONFIG4L, _LVP_OFF_4L
#define latch latc.0
#define clock latc.3
#define data latc.5
#define outenable latc.2

unsigned char alpha1[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x76,0x79,0x38,0x73};
unsigned char time=1;
unsigned char pwmset=0;
unsigned char quadold;

void main(void)
{
unsigned char x,bits,ten,one;
trisb=0b00110000; //portb.4 and 5 are inputs
trisc=0;
quadold=(portb&0b00110000)>>4;
pr2=0x3f; //set PWM period
ccp1con=0b00001100; //turn on PWM
ccpr1l=pwmset;
t2con=0b00000100; //turn on timer2
rcon.IPEN=0; //no interrupt priority levels
intcon2.RBPU=0; //enable weak pullups on portb
intcon=0b00001000; //RB port change interrupt enable
intcon.GIE=1; //global interrupt enable
outenable=0;
latch=0;
clock=0;

while(1){
for(x=0;x<20;x++){
one=alpha1[x];
for(bits=0;bits<8;bits++){
ten=one<<bits;
data=ten.7;
clock=1;clock=0;
}
one=alpha1[x];
for(bits=0;bits<8;bits++){
ten=one<<bits;
data=ten.7;
clock=1;clock=0;
}
latch=1;latch=0;
delay_s(time);
}
}
}

void interrupt(void)
{
unsigned char quadnew,a_new,b_old;
quadnew=(portb&0b00110000)>>4;
a_new=quadnew&1;
b_old=quadold>>1;
if(quadnew!=quadold){
if(b_old^a_new){
if(pwmset>1)
pwmset-=2;
}
else{
if(pwmset<119)
pwmset+=2;
}
}
ccpr1l=pwmset; //set new PWM
quadold=quadnew;
intcon.RBIF=0;
}

 

Here's the hardware SPI version:

Hardware SPI Version

#include <system.h>
#pragma CLOCK_FREQ 20000000
#pragma DATA _CONFIG1H, _HS_OSC_1H & _OSCS_ON_1H
#pragma DATA _CONFIG2H, _WDT_OFF_2H
#pragma DATA _CONFIG4L, _LVP_OFF_4L
void spi_out(unsigned char);
#define latch latc.0

unsigned char alpha1[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x76,0x79,0x38,0x73};
unsigned char time=1;
unsigned char pwmset=0;
unsigned char quadold;

void main(void)
{
unsigned char x,ten,one;
trisb=0b00110000;
trisc=0;
quadold=(portb&0b00110000)>>4;
pr2=0x3f; //set up PWM
ccp1con=0b00001100;
ccpr1l=pwmset;
t2con=0b00000100;
sspstat=0b01000000; //set up SPI
sspcon1=0b00000010;
sspcon1.SSPEN=1;
rcon.IPEN=0; //no interrupt priority levels
intcon2.RBPU=0; //enable weak pullups on portb
intcon=0b00001000; //RB port change interrupt enable
intcon.GIE=1; //global interrupt enable
latch=1;

while(1){
for(x=0;x<20;x++){
one=alpha1[x];
spi_out(one);
ten=alpha1[x];
spi_out(ten);
delay_s(time);
}
}
}


void spi_out(unsigned char digit)
{
unsigned char junk;
sspbuf=digit;
while(!sspstat.BF);
junk=sspbuf;
}

void interrupt(void)
{
unsigned char quadnew,anew,bold;
quadnew=(portb&0b00110000)>>4;
anew=quadnew&1;
bold=quadold>>1;
if(quadnew!=quadold){
if(bold^anew){
if(pwmset>1)
pwmset-=2;
}
else{
if(pwmset<119)
pwmset+=2;
}
}
ccpr1l=pwmset; //set new PWM
quadold=quadnew;
intcon.RBIF=0;
}

 

Encoder number change version

#include <system.h>
#pragma CLOCK_FREQ 20000000
#pragma DATA _CONFIG1H, _HS_OSC_1H & _OSCS_ON_1H
#pragma DATA _CONFIG2H, _WDT_OFF_2H
#pragma DATA _CONFIG4L, _LVP_OFF_4L
void spi_out(unsigned char,unsigned char);
#define latch latc.0
#define outenable latc.2

unsigned char alpha1[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x76,0x79,0x38,0x73};
unsigned char time=255;
unsigned char count=0;
unsigned char quadold;

void main(void)
{
unsigned char x,temp,temp2,ten,one;
trisb=0b00110000;
trisc=0;
quadold=(portb&0b00110000)>>4;
sspstat=0b01000000; //set up SPI
sspcon1=0b00000010;
sspcon1.SSPEN=1;
rcon.IPEN=0; //no interrupt priority levels
intcon2.RBPU=0; //enable weak pullups on portb
intcon=0b00001000; //RB port change interrupt enable
intcon.GIE=1; //global interrupt enable
latch=1;
outenable=0;

while(1){
temp=count&0x0f;
temp2=(count&0xf0)>>4;
one=alpha1[temp];
ten=alpha1[temp2];
spi_out(one,ten);
delay_ms(time);
}
}


void spi_out(unsigned char ten,unsigned char one)
{
unsigned char junk;
sspbuf=ten;
while(!sspstat.BF);
junk=sspbuf;
sspbuf=one;
while(!sspstat.BF);
junk=sspbuf;
}

void interrupt(void)
{
unsigned char quadnew,a_new,b_old;
quadnew=(portb&0b00110000)>>4;
a_new=quadnew&1;
b_old=quadold>>1;
if(quadnew!=quadold){
if(b_old^a_new){
if(count<0xff)
count++;
}
else{
if(count>0)
count--;
}
}
quadold=quadnew;
intcon.RBIF=0;
}

 

Fun Demo

#include <system.h>
#pragma CLOCK_FREQ 20000000
#pragma DATA _CONFIG1H, _HS_OSC_1H & _OSCS_ON_1H
#pragma DATA _CONFIG2H, _WDT_OFF_2H
#pragma DATA _CONFIG4L, _LVP_OFF_4L
void spi_out(unsigned char,unsigned char);
void spi_byte(unsigned char);
void circles(void);
void rows(void);
void columns(void);
void bigeight(void);
void help(void);
void count(void);
#define latch latc.0

unsigned char alpha1[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x76,0x79,0x38,0x73};
unsigned char quadold,one,ten;
unsigned char switcher=0;
bit outflag=0;

void main(void)
{
unsigned char x,temp,temp2;
trisb=0b00110000;
trisc=0;
quadold=(portb&0b00110000)>>4;
sspstat=0b01000000; //set up SPI
sspcon1=0b00000010;
sspcon1.SSPEN=1;
rcon.IPEN=0; //no interrupt priority levels
intcon2.RBPU=0; //enable weak pullups on portb
intcon=0b00001000; //RB port change interrupt enable
intcon.GIE=1; //global interrupt enable
latch=1;

while(1){
if(switcher==0)
circles();
if(switcher==1)
rows();
if(switcher==2)
columns();
if(switcher==3)
bigeight();
if(switcher==4)
help();
if(switcher==5)
count();
}
}

void circles(void)
{
unsigned char x;
while(1){
if(outflag)
break;
for(x=0;x<6;x++){
one=ten=1;
ten=ten<<x;
one=one<<x;
spi_out(one,ten);
delay_ms(70);
}
}
outflag=0;
}

void rows(void)
{
while(1){
if(outflag)
break;
one=ten=1;
spi_out(one,ten);
delay_ms(70);
one=ten=0x40;
spi_out(one,ten);
delay_ms(70);
one=ten=0x08;
spi_out(one,ten);
delay_ms(70);
}
outflag=0;
}

void columns(void)
{
while(1){
if(outflag)
break;
ten=0x30;one=0;
spi_out(one,ten);
delay_ms(70);
ten=0x06;one=0;
spi_out(one,ten);
delay_ms(70);
ten=0;one=0x30;
spi_out(one,ten);
delay_ms(70);
ten=0;one=0x06;
spi_out(one,ten);
delay_ms(70);
}
outflag=0;
}

void bigeight(void)
{
while(1){
if(outflag)
break;
ten=0x01;one=0;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x01;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x02;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x40;
spi_out(one,ten);
delay_ms(50);
ten=0x40;one=0;
spi_out(one,ten);
delay_ms(50);
ten=0x10;one=0;
spi_out(one,ten);
delay_ms(50);
ten=0x08;one=0;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x08;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x04;
spi_out(one,ten);
delay_ms(50);
ten=0;one=0x40;
spi_out(one,ten);
delay_ms(50);
ten=0x40;one=0;
spi_out(one,ten);
delay_ms(50);
ten=0x20;one=0;
spi_out(one,ten);
delay_ms(50);
}
outflag=0;
}

void help(void)
{
while(1){
if(outflag)
break;
one=alpha1[0x10];
spi_byte(one);
delay_ms(250);
one=alpha1[0x11];
spi_byte(one);
delay_ms(250);
one=alpha1[0x12];
spi_byte(one);
delay_ms(250);
one=alpha1[0x13];
spi_byte(one);
delay_ms(250);
}
outflag=0;
}

void count(void)
{
unsigned char x,temp,temp2;
while(1){
if(outflag)
break;
for(x=0;x<255;x++){
if(outflag)
break;
temp=x&0x0f;
temp2=(x&0xf0)>>4;
one=alpha1[temp];
ten=alpha1[temp2];
spi_out(one,ten);
delay_ms(255);
}
}
outflag=0;
}

void fix(unsigned char dec2)
{
unsigned char count=0;
while(dec2>10){
dec2-=10;
count++;
}
ten=count;
one=dec2;
}

void spi_out(unsigned char ten,unsigned char one)
{
unsigned char junk;
sspbuf=ten;
while(!sspstat.BF);
junk=sspbuf;
sspbuf=one;
while(!sspstat.BF);
junk=sspbuf;
}

void spi_byte(unsigned char one)
{
unsigned char junk;
sspbuf=one;
while(!sspstat.BF);
junk=sspbuf;
}

void interrupt(void)
{
unsigned char quadnew,a_new,b_old;
quadnew=(portb&0b00110000)>>4;
a_new=quadnew&1;
b_old=quadold>>1;
if(quadnew!=quadold)
{
if(b_old^a_new)
{
if(switcher<5){
switcher=switcher+1;
outflag=1;
}
}
if(b_old==a_new)
{
if(switcher>0){
switcher=switcher-1;
outflag=1;
}
}
}
quadold=quadnew;
intcon.RBIF=0;
}