分享

PIC单片机实例二:基于I2C的SAA1064数码管显示

 ZLM_图书馆 2014-07-15

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

一.原理图

实现功能:四个数码管分为两组,四个按键也对应分为两组,每组控制对应数码管显示数据的加减,数据在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,所以如有不对的地方请大家告之.如有更好的思路也欢迎交流.

        

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多