这是今天花一天时间写的,拿出来给像我一样的菜鸟参考,希望大家一起提高.
一.原理图

实现功能:四个数码管分为两组,四个按键也对应分为两组,每组控制对应数码管显示数据的加减,数据在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 <pic.h>
__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<<i)&0x80) { 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(); } }
四.总结
上面程序中紫色标注的地方一定要注意,我曾经吃过他的亏,而网上的所谓调通的程序恰恰在这些地方没有注意,这就导致程序不能正常的按设想运行.
由于我也是刚刚在学PICC,所以如有不对的地方请大家告之.如有更好的思路也欢迎交流.
|