[其他] HC89S105AC8读写PCF8563不正常

[复制链接]
 楼主| 比神乐 发表于 2024-10-7 11:17 | 显示全部楼层 |阅读模式
代码
PCF8563.C
  1. #include "HC89S105AC8.h"

  2. #include "PCF8563.h"

  3. void _nop1_(void)
  4. {
  5.         int i;
  6.         for(i=0;i<5;i++);
  7. }
  8. //----------------------------------------------------------------------------
  9. void PCF8563_INIT()  //初始化
  10. {
  11.         Delay8ms();                                //IIC总线从通电到开始操作要求8ms延时
  12.         Register_INIT();        //寄存器初始化
  13.         Time_INIT();                        //时间初始化
  14. }
  15. //----------------------------------------------------------------------------
  16. void Register_INIT()  //寄存器初始化
  17. {
  18.         CS1_Set();                        //设置控制/状态寄存器1
  19.         CS2_Set();                        //设置控制/状态寄存器1
  20.         DayA_Set();                        //设置天闹铃寄存器
  21.         WeekdayA_Set();        //设置周闹铃寄存器
  22.         CO_Set();                                //设置时钟输出寄存器
  23. }
  24. //----------------------------------------------------------------------------
  25. void CS1_Set(){        Write(CS1, 0x00);}  //CS1:寄存器地址,0x00:全部设为正常模式
  26. void CS2_Set(){        Write(CS2, 0x02);}  //0x02:开闹铃中断,关定时器中断
  27. void DayA_Set(){ Write(DayA, 0x00);}                                //关天闹铃
  28. void WeekdayA_Set(){ Write(WeekdayA, 0x00);}//关周闹铃
  29. void CO_Set(){Write(CO, 0x00);}                                                        //关时钟输出
  30. //----------------------------------------------------------------------------
  31. void Time_INIT()  //时间初始化,2015-05-01 Fri 12:30:00,压缩型BCD码格式
  32. {
  33.         Write(Year, 0x23);
  34.         Write(Month, 0x12);  //最高位表示世纪:0-20xx,1-19xx
  35.         Write(Weekday, 0x31);//周不会自动生成,需要自己确认并写入
  36.         Write(Day, 0x07);
  37.         Write(Hour, 0x23);
  38.         Write(Minute, 0x59);
  39.         Write(Second, 0x50);
  40. }
  41. //----------------------------------------------------------------------------
  42. uchar Sec_Read()
  43. {
  44.         uchar sec = Read(Second);
  45.         sec &= 0x7F;
  46.         return sec;
  47. }
  48. //----------------------------------------------------------------------------
  49. /*void Time_Read(uchar *buff)  //采用多字节连续读取方式,功能与下面函数一样,但两个只能存在一个
  50. {
  51.         Read_Sequence(Second, 7, buff);  //从sec单元开始,连续读取7字节,分别为:sec min hour day weekday month year
  52.         Time_Adjust(buff);
  53. }*/
  54. //----------------------------------------------------------------------------
  55. void Time_Read(uchar *buff)  //采用单字节读取方式,每次读取1字节,分多次读取,功能与上面函数一样,但两个只能存在一个
  56. {
  57.         uchar base_addr = Second;
  58.         uchar i, dat;
  59.         for (i=0; i<7; i++)
  60.           {
  61.                           dat = Read(base_addr + i);
  62.                           buff[i] = dat;
  63.           }
  64.   Time_Adjust(buff);
  65. }
  66. //----------------------------------------------------------------------------
  67. /*void Time_Write(uchar *buff)  //采用多字节连续读取方式,功能与下面函数一样,但两个只能存在一个
  68. {                             //时间写入,将缓冲区buff内的sec min hour day weekday month year写入PCF8563
  69.         Write_Sequence(Second, 7, buff);
  70. }*/
  71. //----------------------------------------------------------------------------
  72. void Time_Write(uchar *buff)  //采用单字节写入方式,每次写入1字节,分多次写入,功能与上面函数一样,但两个只能存在一个
  73. {                               //时间写入,将缓冲区buff内的sec min hour day weekday month year写入PCF8563
  74.         uchar base_addr = Second;
  75.         uchar i, dat;
  76.         for (i=0; i<7; i++)
  77.           {
  78.                         dat = buff[i];
  79.                         Write(base_addr + i, dat);
  80.                 }
  81. }
  82. //----------------------------------------------------------------------------
  83. void Time_Adjust(uchar *buff)  //时间调整,去除不必要的位,固定处理7字节
  84. {
  85.         buff[0] &= 0x7F;  //调整秒
  86.         buff[1] &= 0x7F;  //调整分
  87.         buff[2] &= 0x3F;  //调整时
  88.         buff[3] &= 0x3F;  //调整日
  89.         buff[4] &= 0x07;  //调整周
  90.         buff[5] &= 0x1F;  //调整月,年不用调整
  91. }
  92. //----------------------------------------------------------------------------
  93. void Alarm_Read(uchar *buff)  //闹钟时间读取,只开启了时,分闹铃
  94. {
  95.         Read_Sequence(MinuteA, 2, buff);  //从MinuteA单元开始,连续读取2字节,分别为分,时的闹钟时间值
  96. }
  97. //----------------------------------------------------------------------------
  98. void Alarm_Stop()  //停止闹铃
  99. {
  100.         uchar dat = Read(CS2);  //读取当前控制/状态寄存器2的值
  101.         dat &= 0xF7;                                                //清AF闹铃标志,AF在CS2第3位
  102.         Write(CS2, dat);
  103. }
  104. //----------------------------------------------------------------------------
  105. void Write(uchar RegAddr, uchar dat)  //向目标寄存器写入1字节数据
  106. {
  107.         Start();                                                                                        //开始信号
  108.         Write_8bits(PCF8563_WRITE);                //IIC写入8位,将写操作指令写入
  109.         Acknowledge();
  110.         Write_8bits(RegAddr);                                        //写入目标写入寄存器的地址
  111.         Acknowledge();
  112.         Write_8bits(dat);                                                        //将数值写入
  113.         Acknowledge();
  114.         Stop();                                                                                                //停止信号
  115. }
  116. //----------------------------------------------------------------------------
  117. uchar Read(uchar RegAddr)  //字节读取
  118. {
  119.         uchar dat;
  120.        
  121.         Start();
  122.         Write_8bits(PCF8563_WRITE);                //IIC写入8位,将写操作指令写入
  123.         Acknowledge();
  124.         Write_8bits(RegAddr);                                        //写入目标读取寄存器的地址
  125.         Acknowledge();
  126.         Start();
  127.         Write_8bits(PCF8563_READ);                //IIC写入8位,将读操作指令写入
  128.         Acknowledge();
  129.         dat = Read_8bits();                                                //读取数据1字节
  130.         MasterNoACK();
  131.         Stop();
  132.         return dat;
  133. }
  134. //----------------------------------------------------------------------------
  135. void Read_Sequence(uchar RegAddr, uchar n, uchar *buff)  //连续读取多字节,n<=16(pdf:P15of30fig14)
  136. {
  137.         uchar i;
  138.        
  139.         Start();
  140.         Write_8bits(PCF8563_WRITE);
  141.         Acknowledge();
  142.         Write_8bits(RegAddr);                                        //写入目标读取寄存器的地址
  143.         Acknowledge();
  144.         Start();
  145.         Write_8bits(PCF8563_READ);                //IIC写入8位,将读操作指令写入
  146.         Acknowledge();
  147.         for (i=0; i<n; i++)
  148.           {
  149.                         buff[i] = Read_8bits();
  150.                         if (i!=n-1)                                        //除最后一个字节外,主机需给从机ACK
  151.                                 MasterACK();
  152.                         else
  153.                                 MasterNoACK();                //最后一个字节读取完毕,主机需给从机NoACK,再给stop信号
  154.                 }
  155.         Stop();
  156. }
  157. //----------------------------------------------------------------------------
  158. void Write_Sequence(uchar RegAddr, uchar n, uchar *buff)  //连续写入多字节(pdf:P15of30fig13)
  159. {
  160.         uchar i;
  161.        
  162.         Start();
  163.         Write_8bits(PCF8563_WRITE);
  164.         Acknowledge();
  165.         Write_8bits(RegAddr);
  166.         Acknowledge();
  167.         for (i=0; i<n; i++)
  168.           {
  169.                         Write_8bits(buff[i]);
  170.                         Acknowledge();
  171.                 }
  172.         Stop();
  173. }
  174. //----------------------------------------------------------------------------
  175. void Write_8bits(uchar dat)  //写入8位
  176. {
  177.         uchar i, m = 0x80;
  178.        
  179.         for (i=0; i<8; i++)
  180.           {
  181.                         SCL = 0;                                                //在SCL低电平期间将数据送上SDA
  182.                         _nop1_();
  183.                         SDA = (dat&m)==0?0:1;
  184.                         _nop1_();
  185.                         SCL = 1;
  186.                         _nop1_();
  187.                         _nop1_();
  188.                         m /= 2;
  189.                 }
  190.         SCL = 0;
  191. }
  192. //----------------------------------------------------------------------------
  193. uchar Read_8bits()  //读取8位
  194. {
  195.         uchar i, dat=0;
  196.         P0M0=0X0E;
  197.         for(i=0;i<10;i++);
  198.         for (i=0; i<8; i++)
  199.           {
  200.                         SCL = 0;
  201.                         _nop1_();
  202.                         SCL = 1;  //SCL高电平时,读取SDA数据
  203.                         _nop1_();
  204.                         _nop1_();
  205.                         dat *= 2;
  206.                         dat += (SDA==1?1:0);
  207.                 }
  208.         SCL = 0;
  209.         P0M0=0XAA;
  210.         for(i=0;i<10;i++);
  211.         return dat;
  212. }
  213. //----------------------------------------------------------------------------
  214. void Start()
  215. {
  216.         SDA = 1;
  217.         SCL = 1;
  218.         _nop1_();
  219.         _nop1_();
  220.         SDA = 0;
  221.         _nop1_();
  222.         SCL = 0;
  223. }
  224. //----------------------------------------------------------------------------
  225. void Stop()
  226. {
  227.         _nop1_();
  228.         SDA = 0;
  229.         SCL = 1;
  230.         _nop1_();
  231.         SDA = 1;
  232. }
  233. //----------------------------------------------------------------------------
  234. void Acknowledge()  //从机应答查询
  235. {
  236.         uchar i;
  237.         _nop1_();
  238.         SDA = 1;                                //要查询应答信号,要先释放总线
  239.         SCL = 1;
  240.         _nop1_();
  241.         _nop1_();
  242.         P0M0=0X0E;
  243.         for(i=0;i<10;i++);
  244.         while(SDA==1){};        //对方以拉低SDA来表示应答
  245.         SCL = 0;
  246.         P0M0=0XAA;
  247.         for(i=0;i<10;i++);
  248. }
  249. //----------------------------------------------------------------------------
  250. void MasterACK()  //主机应答,见 PCF8563 pdf p14 fig.11
  251. {
  252.         _nop1_();
  253.         SDA = 0;
  254.         _nop1_();
  255.         SCL = 1;
  256.         _nop1_();
  257.         _nop1_();
  258.         SCL = 0;
  259.         SDA = 1;
  260. }
  261. //----------------------------------------------------------------------------
  262. void MasterNoACK()  //主机无应答,见 PCF8563 pdf p14 fig.11
  263. {
  264.         _nop1_();
  265.         SDA = 1;
  266.         _nop1_();
  267.         SCL = 1;
  268.         _nop1_();
  269.         _nop1_();
  270.         SCL = 0;
  271.         SDA = 1;
  272. }
  273. //----------------------------------------------------------------------------
  274. void Delay8ms()
  275. {
  276.         uint i;
  277.         for (i=0; i<20000; i++);//实际器件1000可运行,Proteus仿真是否太严格要求时间达标?
  278. }
  279. //----------------------------------------------------------------------------
PCF8563.H
  1. #define uchar unsigned char
  2. #define uint  unsigned int

  3. #define SCL P0_1  //时钟
  4. #define  SDA P0_0        //数据


  5. //PCF8563内部寄存器地址
  6. #define CS1                        0x00        //控制/状态寄存器1
  7. #define CS2                        0x01        //控制/状态寄存器2
  8. #define Second        0x02        //秒寄存器
  9. #define Minute        0x03        //分寄存器
  10. #define Hour                0x04        //时寄存器
  11. #define Day                        0x05        //天寄存器
  12. #define Weekday        0x06        //周寄存器
  13. #define Month                0x07        //月寄存器
  14. #define Year                0x08        //年寄存器
  15. #define MinuteA        0x09        //分闹铃寄存器
  16. #define HourA                0x0A        //时闹铃寄存器
  17. #define DayA                0x0B        //天闹铃寄存器
  18. #define WeekdayA 0x0C        //周闹铃寄存器
  19. #define CO                        0x0D        //时钟输出控制寄存器
  20. #define TimerCtrl        0x0E        //定时控制寄存器
  21. #define Timer                0x0F                //定时设置寄存器

  22. #define PCF8563_WRITE 0xA2        //写指令
  23. #define PCF8563_READ        0xA3        //读指令
  24. //----------------------------------------------------------------------------
  25. void PCF8563_INIT();        //初始化
  26. void Register_INIT();  //寄存器初始化
  27. void CS1_Set();
  28. void CS2_Set();
  29. void DayA_Set();
  30. void WeekdayA_Set();
  31. void CO_Set();
  32. void Time_INIT();
  33. uchar Sec_Read();
  34. void Time_Read(uchar *buff);
  35. void Time_Write(uchar *buff);
  36. void Alarm_Read(uchar *buff);
  37. void Time_Adjust(uchar *buff);
  38. void Alarm_Stop();
  39. void Write(uchar RegAddr, uchar dat);
  40. uchar Read(uchar RegAddr);
  41. void Read_Sequence(uchar RegAddr, uchar n, uchar *buff);
  42. void Write_Sequence(uchar RegAddr, uchar n, uchar *buff);
  43. void Write_8bits(uchar dat);
  44. uchar Read_8bits();
  45. void Start();
  46. void Stop();
  47. void Acknowledge();
  48. void MasterACK();
  49. void MasterNoACK();
  50. void Delay8ms();
  51. //----------------------------------------------------------------------------
主程序
  1. #define ALLOCATE_EXTERN
  2. #include "HC89S105AC8.h"
  3. #include "OLED.h"
  4. #include "pcf8563.h"

  5. #define LCD_SCL_0  P3_0=0 //_pc5
  6. #define LCD_SCL_1  P3_0=1 //_pc5
  7. #define LCD_SDA_0  P3_6=0
  8. #define LCD_SDA_1  P3_6=1
  9. #define LCD_RST_0  P3_4=0  //  _pc3
  10. #define LCD_RST_1  P3_4=1  //  _pc3
  11. #define LCD_DC_0   P3_2=0
  12. #define LCD_DC_1   P3_2=1

  13. #define XLevelL                0x00
  14. #define XLevelH                0x10
  15. #define XLevel                ((XLevelH&0x0F)*16+XLevelL)
  16. #define Max_Column        128
  17. #define Max_Row                64
  18. #define        Brightness        0xCF


  19. #define X_WIDTH 128
  20. #define Y_WIDTH 64

  21. unsigned char i,j;
  22. uchar buff[10];

  23. /***************************************************************************************
  24.   * @实现效果        设置各个IO口的工作状态
  25. ***************************************************************************************/
  26. void main(void)       
  27. {         
  28.         int k;
  29.         unsigned char shi,ge;
  30. /********************************系统初始化*******************************************/               
  31.         WDTCCR = 0x00;                           //关闭看门狗
  32.                                                            //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
  33.         CLKCON = 0x02;                           //选择内部高频RC为系统时钟, Fosc=32MHz
  34.         CLKDIV = 0x02;                           //Fosc 2分频得到Fcpu,Fcpu=16MHz
  35.        
  36. /***********************************设置IO口模式***************************************/
  37.        
  38.        
  39.        
  40.         //P0M0=0XAA;           //开漏带上拉输出       
  41.         LCD_Init();
  42.         LCD_CLS();
  43.        
  44.         LCD_P8x16Str(20,4,(u8*)"20  -  -  ");
  45.         LCD_P8x16Str(20,6,(u8*)"  :  :  ");
  46.         PCF8563_INIT();
  47.         //LCD_Rectangle(0,0,10,10,0);
  48.         //LCD_P8x16Str(10,10,'0');
  49.         while(1)
  50.         {
  51. //                SCL=0;
  52. //                SDA=0;
  53. //                for(k=0;k<2000;k++);
  54. //                SCL=1;
  55. //                SDA=1;
  56. //                for(k=0;k<2000;k++);
  57.                 Time_Read(buff);
  58.                 shi=(buff[0]>>4)+0x30;
  59.                 ge=(buff[0]&0x0f)+0x30;
  60.                 LCD_P8x16Char(68,6,shi);
  61.                 LCD_P8x16Char(76,6,ge);
  62.                 for(k=0;k<20000;k++);
  63.         }
  64. }

请问高手,哪里有错?谢谢
jcky001 发表于 2024-10-12 11:44 | 显示全部楼层
检查是否有连接不良或短路的情况。
elephant00 发表于 2024-10-12 11:46 | 显示全部楼层
调整I2C总线时序
elephant00 发表于 2024-10-12 11:47 | 显示全部楼层
用示波器检查是否存在时序错误或数据错误。
两只袜子 发表于 2024-10-12 13:00 | 显示全部楼层
起始条件、停止条件、数据位发送和接收的时序是否正确。
jcky001 发表于 2024-10-12 15:00 | 显示全部楼层
检查HC89S105AC8的读写代码是否正确实现了I2C通信协议。
suncat0504 发表于 2024-10-30 17:57 | 显示全部楼层
既然是I2C,建议你严重关注时钟周期。逻辑本身没问题的话,时钟频率会是最可能的因素。
suncat0504 发表于 2024-10-30 18:00 | 显示全部楼层
你可以先用能正常访问的,用示波器、逻辑分析仪、或者自制简单的计数器,获得SCL的周期;然后对比不正常,看看差多少。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

470

主题

3535

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部

470

主题

3535

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部