PIC单片机实例二:基于I2C的SAA1064数码管显示
扫描二维码
随时随地手机看文章
一.原理图
实现功能:四个数码管分为两组,四个按键也对应分为两组,每组控制对应数码管显示数据的加减,数据在0--99间循环显示,并具有掉电保护功能,通过24LC01B保存掉电前的数据.程序简单易读,是初学者的福音(因为我也是菜鸟)!
二.器件介绍
1.概述
SAA1064是Philips公司生产的4位LED驱动器,为双极型电路,具有I2C接口。该电路是特别为驱动4位带有小数点的七段显示器而设计的,通过多路开关可对两个2位显示器进行切换显示。该器件内部带有I2C总线从发送接收器,可以通过地址引脚ADR的输入电平编程为4个不同的从器件地址。内部的模式控制器可以控制LED的各个位以使其能够工作于静态模式、动态模式、熄灭模式及段测试模式。
2.引脚功能及封装形式
SAA1064采用24脚DIP和SOT两种封装形式,图1所示为24脚DIP封装的引脚排列。各主要引脚的功能如下:
ADR(1):地址输入线;
CEXT(2):内部振荡器电容输入端,典型值为2.7nF;
P8~P1(3~10):段数据输出口1;
P9~P16(15~22):段数据输出口2;
MX1(11):多路选择开关输出1;
MX2(14):多路选择开关输出2:
VEE(12):地;
VCC(13):电源;
SDA(23):I2C总线串行数据线;
SCL(24):I2C总线串行时钟线;
3.功能说明
3.1 通讯规约
主器件CPU通过I2C总线对SAA1064进行读或写,读/写方式中I2C总线上的信息传送格式如图2所示,图中:S为启动信号;P为结束信号;A为响应位;X为任意值;A1A0由ADR输入电位确定2位地址位;SC SB SA为单元地址位;C6~C0为控制位;PR为上电复位标志。
3.2 SAA1064的从地址
SAA1064的从地址是由引脚ADR上的输入电平决定的。ADR引脚在接VEE、3/8VCC、5/8VCC和VCC时分别对应于4个不同的从地址(A1A0=00、01、10、11)。在写方式时,它们对应的从地址字节值为70H、72H、74H、76H,而在读方式时,它们对应的从地址字节值为71H、73H、75H、77H。其他的地址不为该器件所响应。
3.3 状态字节
SAA1064的状态字节中只用1位:即上电复位标志位PR,它为逻辑“1”时,表示从上次读状态以后出现过掉电和加电,而在读状态字节操作完成以后,该标志清0。
3.4 单元地址
用位SC、SB、SA形成1个指针以确定指令字节以后的数据字节写入哪个寄存器,而其它的数据依次写入后继单元中,这种特性称为单元地址增量。单元地址指针范围为0~7。单元地址分配如表1所列。
3.5 控制字节
控制字节各位(C0~C6)的含义如下:
C0=0 静态显示,数字位1和2可以连续显示;
C0=1动态显示,数字位1、3和2、4交替显示;
C1=0/1数字位1、3暗/亮选择位;
C2=0/1数字位2、4暗/亮选择位;
C3=1 所有段导通以便段测试,其电流由C4、C5、C6所决定;
C4=1 段输出电流增加3mA;
C5=1 段输出电流增加6mA;
C6=1 段输出电流增加12mA;
3.6 数据字节
数据字节中数据为1时为对应的段导通(亮),数据字节D17~D10、D27~D20、D37~D30、D47~D40分别对应于位1、2、3和4的显示器,高位对应于输出端P8或P16,低位对应于输出端P1或P9,显示器1~4显示的数据对应于单元地址1~4的内容。
3.7 SDA、SCL
SDA、SCL分别为总线的数据线和时钟线。为防止这些引脚上出现过压脉冲,应接一个稳压管(5.5V)至,即正常的线电压不应超过5.5V。正常情况下,数据在响应位的时钟上跳变锁存。
3.8 上电复位
上电复位信号是在SAA1064芯片的内部产生的,该信号能使内部各位清0而显示全暗,此时只有掉电标志置位。
3.9 外部定时控制电容
在SAA1064的引脚(2脚)上接一个定时电容到地可使内部多路转换的振荡器工作。在静态工作方式中,因为不需要振荡器工作,因此,该引脚可接或浮空。
3.10 段数据输出端
P1~P16是吸收电流可控的段数据输出端,可用相应的数字位控制其导通,并由C4、C5、C6控制位控制其电流的大小。
3.11 多路输出端
SAA1064的多路输出端MX1和MX2在动态显示方式中交替导通,它们均由内部时钟的分频信号驱动。
在静态方式中,MX1总是导通,其输出由内部射极跟随器组成,可直接驱动2位显示器的公共极,如果超过了电路的总功耗,应当用晶体管把11脚和14脚相连在一起。
三,程序(PICC调通)
//Use for DN-100 Cotroller
//Date:from 2007.12.7 to
//Author:wujie
//Company:Wuxi Zhouxiang complete set of welding equipment CO.LTD
//Introduce:
//MCU:p16f73
//display IC:SAA1064 addr:0x70
//START
#include
__CONFIG(XT&WDTDIS&BORDIS);
//程序声明
void initial(void);
void display(char cur_hex,char time_hex);
void button_test(void);
void start_iic();
void stop_iic(void);
void ack_iic();
void nack_iic();
void send_iic(char c);
char receive_iic(void);
//预定义
#define nop() asm("nop")
#define SDA RC4
#define SCL RC3
unsigned int i,rxbuf;
char cur,time;
//初始化
void initial(void)
{
TRISA=0X3F; //ALL PORTS ARE INPUT
PORTA=0X00;
TRISB=0X03; //RB0,RB1 ARE INPUTS
PORTB=0X00;
TRISC=0XE7; // RC3,RC4, ARE outPUTS
PORTC=0X18; //RC3,RC4 ARE IN HIGH
cur=0;
time=0;
}
//显示子程序
void display(char cur_hex,char time_hex)
{
char d1buf,d2buf,d3buf,d4buf;
//数组存储显示7段码
char bit_dis[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0xee,0x3e,0x9c,0x7a,0x9e,0x8e,0x00};
d2buf=bit_dis[cur_hex%10];//CUR的个位
d1buf=bit_dis[cur_hex%100/10];//CUR的十位
d4buf=bit_dis[time_hex%10];//TIME的个位
d3buf=bit_dis[time_hex%100/10];//TIME的十位
nop();
start_iic();
nop();
send_iic(0x70);//SAA1064的地址
send_iic(0x00);
send_iic(0x37);//查上面资料
send_iic(d1buf);
send_iic(d2buf);
send_iic(d3buf);
send_iic(d4buf);
nop();
stop_iic();
}
//write 24cl01b subroutine
void w_24cl01b(unsigned char cur_tmp,unsigned char time_tmp)
{
start_iic();
send_iic(0xa0);
send_iic(0x10);
send_iic(cur_tmp);
send_iic(time_tmp);
stop_iic();
for(i=0;i<500;i++);
}
//read 24cl01b subroutine
char r_24cl01b()
{
start_iic();
send_iic(0xa0);
send_iic(0x10);
start_iic();
send_iic(0xa1);
cur=receive_iic();
ack_iic();
time=receive_iic();
nack_iic();
stop_iic();
display(cur,time);
for(i=0;i<10000;i++);
}
//按键检测
void button_test(void)
{
if(RC1==1)
{
for(i=0;i<=2000;i++);//延时 20mS
if(RC1==1)
{
cur++;
cur=cur%100;//让CUR<100,因为只能显示2位
w_24cl01b(cur,time);
}
}
if(RC2==1)
{
for(i=0;i<=2000;i++);
if(RC2==1)
{
cur--;
if(cur<=0)
w_24cl01b(cur,time);//写入24LC01B保存
{
cur=cur+100;//让CUR>0,因为只能显示2位
}
}
}
if(RC5==1)
{
for(i=0;i<=2000;i++);
if(RC5==1)
{
time++;
time=time%100;//让TIME<100,因为只能显示2位
w_24cl01b(cur,time);
}
}
if(RC6==1)
{
for(i=0;i<=2000;i++);
if(RC6==1)
{
time--;
if(time<=0)
{
time=time+100;//让TIME>0,因为只能显示2位
}
w_24cl01b(cur,time);
}
}
display(cur,time);
for(i=0;i<10000;i++);
}
//I2C协议
//开始信号
void start_iic()
{
SDA=1;
SCL=1;
nop();
nop();
nop();
nop();
SDA=0;
nop();
nop();
SCL=0;//it is ready to send data
nop();
}
//停止信号
void stop_iic(void)
{
SDA=0;
SCL=1;
nop();
nop();
nop();
nop();
SDA=1;
nop();
}
//发送应答
void ack_iic()
{
SDA=0;
nop();
nop();
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
nop();
}
//发送一个字节
void send_iic(char c)
{
for(i=0;i<8;i++)
{
SCL=0;
if((c<{
SDA=1;
}
else
{
SDA=0;
}
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
}
SDA=1;
TRISC4=1;//置输入状态,等待应答
SCL=1;//认为应答一直有
nop();
nop();
nop();
nop();
SCL=0;
nop();
TRISC4=0;//恢复为输出
}
//接受一个字节
char receive_iic(void)
{
SDA=1;
rxbuf=0;
TRISC4=1;//注意:一定要置输入
for(i=0;i<8;i++)
{
SCL=0;
nop();
nop();
nop();
nop();
SCL=1;
nop();
rxbuf=rxbuf<<1;
if(SDA==1)
{
rxbuf=rxbuf+1;
}
}
nop();
nop();
SCL=0;
nop();
TRISC4=0;//恢复为输出
return (rxbuf);
}
//主程序
void main(void)
{
initial();
r_24cl01b();//读出掉电前保存在24LC01B内的数据
while(1)
{
button_test();
}
}
四.总结
上面程序中紫色标注的地方一定要注意,我曾经吃过他的亏,而网上的所谓调通的程序恰恰在这些地方没有注意,这就导致程序不能正常的按设想运行.