找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2648|回复: 0
打印 上一主题 下一主题
收起左侧

单片机iic连续读取epprom出错的问题解决

[复制链接]
跳转到指定楼层
楼主
现象:单个读取字符正确,连续读取字符出错环境:stc89c52单片机  24C02的epprom
我的解决办法:
IIC_wirte 8bit时等待ack,如无ack,则stop-->start 重新发起信号,结果解决问题,下面贴出代码:

  1. #include <reg52.h>
  2. #include "intrins.h"
  3. #include "type.h"
  4. #include "i2c.h"

  5. sbit SCL=P2^1;
  6. sbit SDA=P2^0;

  7. #define IIC_WRITE 0xA0
  8. #define IIC_READ 0xA1

  9. static void delay10Us(u16 i)
  10. {
  11.         while(i--);
  12. }

  13. /*******************************************************************************
  14. * 函数名         : Delay10us()
  15. * 函数功能                   : 延时10us
  16. * 输入           : 无
  17. * 输出                  : 无
  18. *******************************************************************************/
  19. /*
  20. void Delay10us()
  21. {
  22. }
  23. */
  24. /*******************************************************************************
  25. * 函数名         : I2cStart()
  26. * 函数功能                 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
  27. * 输入           : 无
  28. * 输出                  : 无
  29. * 备注           : 起始之后SDA和SCL都为0
  30. *******************************************************************************/

  31. void I2cStart()
  32. {
  33.         SCL=0;
  34.         delay10Us(1);
  35.         SDA=1;
  36.         SCL=1;
  37.         delay10Us(1);//建立时间是SDA保持时间>4.7us
  38.         SDA=0;
  39.         delay10Us(1);//保持时间是>4us
  40. }
  41. /*******************************************************************************
  42. * 函数名         : I2cStop()
  43. * 函数功能                 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
  44. * 输入           : 无
  45. * 输出                  : 无
  46. * 备注           : 结束之后保持SDA和SCL都为1;表示总线空闲
  47. *******************************************************************************/

  48. void I2cStop()
  49. {
  50.         SCL=0;
  51.         delay10Us(1);
  52.         SDA=0;
  53.         SCL=1;
  54.         delay10Us(1);
  55.         SDA=1;
  56.         delay10Us(1);
  57. }
  58. /*******************************************************************************
  59. * 函数名         : I2cSendByte(unsigned char dat)
  60. * 函数功能                 : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定
  61. * 输入           : num
  62. * 输出                  : 0或1。发送成功返回1,发送失败返回0
  63. * 备注           : 发送完一个字节SCL=0,SDA=1
  64. *******************************************************************************/

  65. unsigned char I2cSendByte(unsigned char dat)
  66. {
  67.         unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。        
  68.         SCL=0;
  69.         delay10Us(1);
  70.         for(a=0;a<8;a++)//要发送8位,从最高位开始
  71.         {
  72.                 SDA = dat>>7;         //起始信号之后SCL=0,所以可以直接改变SDA信号
  73.                 dat = dat<<1;
  74.                 delay10Us(1);
  75.                 SCL=1;
  76.                 delay10Us(2);
  77.                 SCL=0;
  78.                 delay10Us(1);               
  79.         }
  80.         SDA=1;
  81.         delay10Us(1);
  82.         SCL=1;
  83.         while(SDA)//等待应答,也就是等待从设备把SDA拉低
  84.         {
  85.                 b++;
  86.                 if(b>200)         //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
  87.                 {
  88.                         return 0;
  89.                 }
  90.                 delay10Us(1);
  91.         }
  92.         
  93.          return 1;               
  94. }
  95. /*******************************************************************************
  96. * 函数名         : I2cReadByte()
  97. * 函数功能                   : 使用I2c读取一个字节
  98. * 输入           : 无
  99. * 输出                  : dat
  100. * 备注           : 接收完一个字节SCL=0,SDA=1.
  101. *******************************************************************************/

  102. unsigned char I2cReadByte()
  103. {
  104.         unsigned char a=0,dat=0;
  105.         SCL = 0;
  106.         delay10Us(1);
  107.         SDA=1;                        //起始和发送一个字节之后SCL都是0
  108.         delay10Us(1);
  109.         for(a=0;a<8;a++)//接收8个字节
  110.         {
  111.                 SCL=1;
  112.                 delay10Us(2);
  113.                 dat<<=1;
  114.                 dat|=SDA;
  115.                 SCL=0;
  116.                 delay10Us(1);
  117.         }
  118.         return dat;               
  119. }


  120. /*******************************************************************************
  121. * 函数名         : void At24c02Write(unsigned char addr,unsigned char dat)
  122. * 函数功能                   : 往24c02的一个地址写入一个数据
  123. * 输入           : 无
  124. * 输出                  : 无
  125. *******************************************************************************/

  126. void At24c02Write(unsigned char addr,unsigned char dat)
  127. {
  128.         unsigned char ret;
  129. again:
  130.         I2cStart();
  131.         ret = I2cSendByte(IIC_WRITE);//发送写器件地址
  132.         if(!ret){
  133.                 I2cStop();
  134.                 goto again;
  135.         }
  136.         ret = I2cSendByte(addr);//发送要写入内存地址
  137.         if(!ret){
  138.                 I2cStop();
  139.                 goto again;
  140.         }
  141.         ret = I2cSendByte(dat);        //发送数据
  142.         if(!ret){
  143.                 I2cStop();
  144.                 goto again;
  145.         }
  146.         I2cStop();
  147. }

  148. /*******************************************************************************
  149. * 函数名         : unsigned char At24c02Read(unsigned char addr)
  150. * 函数功能                   : 读取24c02的一个地址的一个数据
  151. * 输入           : 无
  152. * 输出                  : 无
  153. *******************************************************************************/

  154. unsigned char At24c02Read(unsigned char addr)
  155. {
  156.         unsigned char num;
  157.         unsigned char ret;
  158. again:
  159.         I2cStart();
  160.         ret = I2cSendByte(IIC_WRITE); //发送器件写地址
  161.         if(!ret){
  162.                 I2cStop();
  163.                 goto again;
  164.         }
  165.         ret = I2cSendByte(addr); //发送要读取的地址
  166.         if(!ret){
  167.                 I2cStop();
  168.                 goto again;
  169.         }
  170.         I2cStart();
  171.         ret = I2cSendByte(IIC_READ); //发送读器件地址
  172.         if(!ret){
  173.                 I2cStop();
  174.                 goto again;
  175.         }
  176.         num=I2cReadByte(); //读取数据
  177.         NoAck();
  178.         I2cStop();
  179.         return num;        
  180. }

  181. /*
  182. 非应答
  183. */
  184. void NoAck(void)
  185. {
  186.         SCL=0;
  187.         SDA=1;
  188.         delay10Us(1);
  189.         SCL=1;
  190.         delay10Us(2);
  191. }

  192. /*
  193. 应答信号
  194. */
  195. void Ack(void)
  196. {
  197.         SCL=0;
  198.         SDA=0;
  199.         delay10Us(1);
  200.         SCL=1;
  201.         delay10Us(2);
  202. }
  203. /*******************************************************************************
  204. * 函数名         : unsigned char At24c02Read(unsigned char addr)
  205. * 函数功能                   : 读取24c02的一个地址的一个数据
  206. * 输入           : 无
  207. * 输出                  : -1:error 0:success
  208. *******************************************************************************/

  209. void At24c02ReadBytes(unsigned char addr,unsigned char *dat,unsigned char n)
  210. {
  211.         //unsigned char num = n;
  212.         unsigned char ret;
  213. again:
  214.         I2cStart();
  215.         ret=I2cSendByte(0xa0); //发送写器件地址
  216.         if(!ret){
  217.                 I2cStop();
  218.                 goto again;
  219.         }
  220.         ret=I2cSendByte(addr); //发送要读取的地址
  221.         if(!ret){
  222.                 I2cStop();
  223.                 goto again;
  224.         }
  225.         I2cStart();
  226.         ret=I2cSendByte(0xa1); //发送读器件地址
  227.         if(!ret){
  228.                 I2cStop();
  229.                 goto again;
  230.         }
  231.         if(addr + n >256)
  232.         {
  233.                 n = 256 - addr;
  234.         }
  235.         while(n--)
  236.         {
  237.                 *dat = I2cReadByte(); //读取数据
  238.                 if(n!=0) Ack();
  239.                 dat++;
  240.         }
  241.         I2cStop();
  242.         //return num;        
  243. }

  244. /*******************************************************************************
  245. * 函数名         : unsigned char At24c02Read(unsigned char addr)
  246. * 函数功能                   : 读取24c02的一个地址的一个数据
  247. * 输入           : 无
  248. * 输出                  : 无
  249. *******************************************************************************/

  250. /*******************************************************************************
  251. * 函数名         : void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
  252. * 函数功能                 : 从地址addr开始,连续读取n个字符,读取字符放入dat中
  253. * 输入           : 无
  254. * 输出                  : 无
  255. *******************************************************************************/

  256. void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
  257. {
  258.         unsigned char i;
  259.         for(i=0;i<n;i++)
  260.                 dat[i]= At24c02Read(addr+i);
  261. }
  262. /*******************************************************************************
  263. * 函数名         : void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
  264. * 函数功能                 : 将dat中的字符写入addr开始的epprom中去,写入n个
  265. * 输入           : 无
  266. * 输出                  : 无
  267. *******************************************************************************/

  268. void At24c02WriteBytes(unsigned char addr,unsigned char *dat,unsigned char n)
  269. {
  270.         unsigned char i;
  271.         for(i=0;i<n;i++)
  272.         {
  273.                 At24c02Write(addr+i,dat[i]);
  274.         }
  275. }
复制代码
上诉代码的关键点在 I2cSendByte 这个方法有返回值,当I2cSendByte的返回值是1说明成功
1、在At24c02Write函数中利用goto语句来处理出错;
2、At24c02Read 利用goto语句来处理地址写出错
3、At24c02ReadBytes 同上
总结:
1、在iic的连续read过程一定要有ACK
2、起始信号之后的器件地址写,存储器地址、器件地址读 这三个地址时,确保收到epprom发来的ack

单片机交流学习群:

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表