[PIC®/AVR®/dsPIC®产品] 【CuriosityNano测评报告】+模拟I2C驱动AT24C32EEPROM

[复制链接]
1619|13
 楼主| hu9jj 发表于 2020-11-28 15:47 | 显示全部楼层 |阅读模式
    上篇完成了模拟I2C驱动DS1307日历模块后,因我购买的日历模块上同时还带有一块AT24C32EEPROM,所以顺带完成I2C驱动AT24C32的测试,这块EEPROM芯片是32K容量,其储存地址超过了8位,要用到16位地址,也就是说在读写操作时发送的是两个字节的地址,其他过程与驱动DS1307相同。
    16位数据的定义通常使用uint16_t作为符号,而MCC生成的代码中似乎没有对这种符号作定义,起先我也没有注意,结果在编译出错,提示uint16_t未定义。因为我是在i2c.h文件中进行过定义,当时我没有考虑作用范围,还弄不清楚出错的原因,只是想我已经定义过,为什么还会说未定义,而且我在文件开始处包含了i2C.h头文件,同时定义过16位的变量,编译都已经通过,百思不得其解,只好将16位地址拆解成高8位和低8位分别传送参数。后来冷静下来思考,才发现应该是作用范围的问题,于是我将这个定义移到mcc.h文件中,这才解决了问题。
    我的测试是每秒生成一次16位的时期和时间数据的字符串,作为测试数据进行读写操作,每次写一个页面,从1到10页面轮流写入。每次先读出上次写入数据显示在LCD屏幕上,然后将即时的数据写入下一个页面内,如此循环。下面是测试过程的照片:


    下面是逻辑分析仪抓取的读数据时的时序截图:


    从截图的右下窗口可以清楚的看到读出了D2020112...字符数据。
    下面是模拟I2C的单字节、单个和多个数据的读写操作函数,以及双字节、单个和多个数据的读写操作函数。按说EEPROM的多字节读写有特殊的要求,即不能跨页操作,但在我的代码中没有对这个要求进行处理,也就是说在使用这段代码时要注意这个问题。
  1. /******************************************************************************************
  2. * 函数名称: I2C_8bitByteRead()
  3. * 功能说明: 从指定地址addr开始获取1个字节的数据
  4. * 输    入: uint8_t I2Caddr 器件地址
  5. *           uint8_t addr        数据地址
  6. * 输    出: uint8_t 返回读取的数值
  7. * 备    注:
  8. ******************************************************************************************/
  9. uint8_t SI2C_8bitByteRead(uint8_t I2Caddr,uint8_t addr)
  10. {
  11.     uint8_t dat;

  12.     SI2C_Start();                   //产生起始信号
  13.     SI2C_Send(I2Caddr);             //发送器件地址及读写位,0表示写
  14.     if(SI2CIsAck())                 //检测从设备是否有响应
  15.     {
  16.         SI2C_Stop();                //产生停止信号
  17.                 return 2;
  18.     }
  19.     SI2C_Send(addr);                //发送读取数据的起始地址
  20.     if(SI2CIsAck())                 //检测从设备是否有响应
  21.     {
  22.         SI2C_Stop();                    //产生停止信号
  23.         return 3;
  24.     }

  25.     SI2C_Start();                   //产生Repeated Start
  26.     SI2C_Send(I2Caddr|1);           //发送从设备芯片地址及读写位,1表示读
  27.     if(SI2CIsAck())                 //检测从设备是否有响应
  28.     {
  29.         SI2C_Stop();                //产生停止信号
  30.         return 4;
  31.     }

  32.     dat = SI2C_Receive();
  33.     SI2CDoAck();

  34.     SI2CNoAck();                    //从设备要求必须使用NOAck来结束数据读取

  35.     SI2C_Stop();                    //产生停止信号

  36.         return dat;
  37. }

  38. /******************************************************************************************
  39. * 函数名称: I2C_8bitByteWrite()
  40. * 功能说明: 从指定地址addr开始写入1个字节的数据
  41. * 输    入: uint8_t I2Caddr 器件地址
  42. *           uint8_t addr        数据地址
  43. * 输    出: uint8_t 返回读取的数值
  44. * 备    注:
  45. ******************************************************************************************/
  46. uint8_t SI2C_8bitByteWrite(uint8_t I2Caddr,uint8_t addr,uint8_t dat)
  47. {
  48.     SI2C_Start();                   //产生起始信号
  49.     SI2C_Send(I2Caddr|0);           //发送从设备芯片地址及读写位,0表示写
  50.     if(SI2CIsAck())                 //检测从设备是否有响应
  51.     {
  52.         SI2C_Stop();                //产生停止信号
  53.         return 1;
  54.         }

  55.     SI2C_Send(addr);                //发送数据要写入的地址
  56.     if(SI2CIsAck())                 //检测从设备是否有响应
  57.     {
  58.         SI2C_Stop();                //产生停止信号
  59.         return 2;
  60.     }

  61.     SI2C_Send(dat);
  62.     if(SI2CIsAck())                 //检测从设备是否有响应
  63.     {
  64.         SI2C_Stop();                //产生停止信号
  65.         return 3;
  66.     }

  67.     SI2C_Stop();                    //产生停止信号
  68.    
  69.     return 0;

  70. }


  71. /******************************************************************************************
  72. * 函数名称: I2C_8bitBuffRead()
  73. * 功能说明: 从指定地址addr开始获取size个字节的数据,获取的数据存储在全局变量数组I2C_Buff中
  74. * 输    入: uint8_t I2Caddr 器件地址
  75. *           uint8_t addr        获取数据从addr开始
  76. *                        uint8_t size        要获取的数据个数(1~8)
  77. * 输    出: uint8_t 操作状态
  78. * 备    注:长度不得超过16个字节
  79. ******************************************************************************************/
  80. uint8_t SI2C_8bitBuffRead(uint8_t I2Caddr,uint8_t addr,uint8_t size,uint8_t *buff)
  81. {
  82.     uint8_t i;

  83.     SI2C_Start();                   //产生起始信号
  84.     SI2C_Send(I2Caddr);             //发送器件地址及读写位,0表示写
  85.     if(SI2CIsAck())                 //检测从设备是否有响应
  86.     {
  87.         SI2C_Stop();                //产生停止信号
  88.                 return 2;
  89.     }
  90.     SI2C_Send(addr);                //发送读取数据的起始地址
  91.     if(SI2CIsAck())                 //检测从设备是否有响应
  92.     {
  93.         SI2C_Stop();                    //产生停止信号
  94.         return 3;
  95.     }

  96.     SI2C_Start();                   //产生Repeated Start
  97.     SI2C_Send(I2Caddr|1);           //发送从设备芯片地址及读写位,1表示读
  98.     if(SI2CIsAck())                 //检测从设备是否有响应
  99.     {
  100.         SI2C_Stop();                //产生停止信号
  101.         return 4;
  102.     }

  103.     for(i=0;i<size;i++)             //从addr处读取size个字节的数据
  104.     {
  105.         buff[i] = SI2C_Receive();
  106.         SI2CDoAck();
  107.     }
  108.     SI2CNoAck();                    //从设备要求必须使用NOAck来结束数据读取

  109.     SI2C_Stop();                    //产生停止信号
  110.    
  111.     return *buff;
  112. }

  113. /**********************************************************************************************
  114. * 函数名称:        I2C_8bitBuffWrite()
  115. * 功能说明: 向I2C器件的地址addr开始写入size个字节的数据,将要写入的数据存储在全局变量数组I2C_Buff中
  116. * 输    入: uint8_t addr        数据被写入从addr开始的地址处
  117. *                        uint8_t size        要设置的数据个数(1~8)
  118. * 输    出: uint8_t                0= 成功  1=出现错误
  119. **********************************************************************************************/
  120. uint8_t SI2C_8bitBuffWrite(uint8_t I2Caddr,uint8_t addr,uint8_t size,uint8_t *buff)
  121. {
  122.     uint8_t i = 0;
  123.        
  124.     SI2C_Start();                   //产生起始信号
  125.     SI2C_Send(I2Caddr|0);           //发送从设备芯片地址及读写位,0表示写
  126.     if(SI2CIsAck())                 //检测从设备是否有响应
  127.     {
  128.         SI2C_Stop();                //产生停止信号
  129.         return 1;
  130.         }

  131.     SI2C_Send(addr);                //发送数据要写入的地址
  132.     if(SI2CIsAck())                 //检测从设备是否有响应
  133.     {
  134.         SI2C_Stop();                //产生停止信号
  135.         return 2;
  136.     }

  137.     for(i=0;i<size;i++)
  138.     {
  139.         SI2C_Send(buff[i]);
  140.         if(SI2CIsAck())             //检测从设备是否有响应
  141.         {
  142.             SI2C_Stop();            //产生停止信号
  143.             return 3;
  144.         }
  145.     }

  146.     SI2C_Stop();                    //产生停止信号

  147.     return 0;
  148. }


  149. /******************************************************************************************
  150. * 函数名称: I2C_16bitByteRead()
  151. * 功能说明: 从指定地址addr开始获取1个字节的数据
  152. * 输    入: uint8_t I2Caddr 器件地址
  153. *           uint16_t addr        双字节数据地址
  154. * 输    出: uint8_t 返回读取的数值
  155. * 备    注:
  156. ******************************************************************************************/
  157. uint8_t SI2C_16bitByteRead(uint8_t I2Caddr,uint16_t addr)
  158. {
  159.     uint8_t dat;

  160.     SI2C_Start();                   //产生起始信号
  161.     SI2C_Send(I2Caddr);             //发送器件地址及读写位,0表示写
  162.     if(SI2CIsAck())                 //检测从设备是否有响应
  163.     {
  164.         SI2C_Stop();                //产生停止信号
  165.                 return 2;
  166.     }
  167.     SI2C_Send(addr>>8);             //发送读取数据的起始地址
  168. //    SI2C_Send(addrH);
  169.     if(SI2CIsAck())                 //检测从设备是否有响应
  170.     {
  171.         SI2C_Stop();                    //产生停止信号
  172.         return 3;
  173.     }
  174.         SI2C_Send(addr|0x0F);           //发送读取数据的起始地址低8位
  175. //        SI2C_Send(addrL);
  176.     if(SI2CIsAck())                 //检测器件是否有响应
  177.     {
  178.         SI2C_Stop();                //产生停止信号
  179.         return 3;
  180.     }
  181.    
  182.     SI2C_Start();                   //产生Repeated Start
  183.     SI2C_Send(I2Caddr|1);           //发送从设备芯片地址及读写位,1表示读
  184.     if(SI2CIsAck())                 //检测从设备是否有响应
  185.     {
  186.         SI2C_Stop();                //产生停止信号
  187.         return 4;
  188.     }

  189.     dat = SI2C_Receive();
  190.     SI2CDoAck();

  191.     SI2CNoAck();                    //从设备要求必须使用NOAck来结束数据读取

  192.     SI2C_Stop();                    //产生停止信号

  193.         return dat;
  194. }


  195. /******************************************************************************************
  196. * 函数名称: I2C_16bitByteWrite()
  197. * 功能说明: 从指定地址addr开始写入1个字节的数据
  198. * 输    入: uint8_t I2Caddr 器件地址
  199. *           uint16_t addr        双字节数据地址
  200. * 输    出: uint8_t 返回读取的数值
  201. * 备    注:
  202. ******************************************************************************************/
  203. uint8_t SI2C_16bitByteWrite(uint8_t I2Caddr,uint16_t addr,uint8_t dat)
  204. {
  205.     SI2C_Start();                   //产生起始信号
  206.     SI2C_Send(I2Caddr|0);           //发送从设备芯片地址及读写位,0表示写
  207.     if(SI2CIsAck())                 //检测从设备是否有响应
  208.     {
  209.         SI2C_Stop();                //产生停止信号
  210.         return 1;
  211.         }
  212.     SI2C_Send(addr>>8);             //发送读取数据的起始地址
  213. //    SI2C_Send(addrH);               //发送读取数据的起始地址
  214.     if(SI2CIsAck())                 //检测从设备是否有响应
  215.     {
  216.         SI2C_Stop();                    //产生停止信号
  217.         return 3;
  218.     }
  219.         SI2C_Send(addr|0x0F);           //发送读取数据的起始地址低8位
  220. //    SI2C_Send(addrL);               //发送读取数据的起始地址低8位
  221.     if(SI2CIsAck())                 //检测器件是否有响应
  222.     {
  223.         SI2C_Stop();                //产生停止信号
  224.         return 3;
  225.     }

  226.     SI2C_Send(dat);
  227.     if(SI2CIsAck())                 //检测从设备是否有响应
  228.     {
  229.         SI2C_Stop();                //产生停止信号
  230.         return 3;
  231.     }

  232.     SI2C_Stop();                    //产生停止信号
  233.    
  234.     return 0;

  235. }


  236. /******************************************************************************************
  237. * 函数名称: I2C_16bitBuffRead()
  238. * 功能说明: 从指定地址addr开始获取size个字节的数据,获取的数据存储在全局变量数组I2C_Buff中
  239. * 输    入: uint8_t I2Caddr 器件地址
  240. *           uint16_t addr        获取数据从addr开始(16位地址)
  241. *                        uint8_t size        要获取的数据个数(1~8)
  242. * 输    出: uint8_t 操作状态
  243. * 备    注:长度不得超过16个字节
  244. ******************************************************************************************/
  245. uint8_t SI2C_16bitBuffRead(uint8_t I2Caddr,uint16_t addr,uint8_t size,uint8_t *buff)
  246. {
  247.     uint8_t i;

  248.     SI2C_Start();                   //产生起始信号
  249.     SI2C_Send(I2Caddr);             //发送器件地址及读写位,0表示写
  250.     if(SI2CIsAck())                 //检测从设备是否有响应
  251.     {
  252.         SI2C_Stop();                //产生停止信号
  253.                 return 2;
  254.     }
  255.    
  256.     SI2C_Send(addr>>8);             //发送读取数据的起始地址
  257. //    SI2C_Send(addrH);
  258.     if(SI2CIsAck())                 //检测从设备是否有响应
  259.     {
  260.         SI2C_Stop();                    //产生停止信号
  261.         return 3;
  262.     }
  263.         SI2C_Send(addr|0x0F);           //发送读取数据的起始地址低8位
  264. //    SI2C_Send(addrL);
  265.     if(SI2CIsAck())                 //检测器件是否有响应
  266.     {
  267.         SI2C_Stop();                //产生停止信号
  268.         return 3;
  269.     }

  270.     SI2C_Start();                   //产生Repeated Start
  271.     SI2C_Send(I2Caddr|1);           //发送从设备芯片地址及读写位,1表示读
  272.     if(SI2CIsAck())                 //检测从设备是否有响应
  273.     {
  274.         SI2C_Stop();                //产生停止信号
  275.         return 4;
  276.     }

  277.     for(i=0;i<size;i++)             //从addr处读取size个字节的数据
  278.     {
  279.         buff[i] = SI2C_Receive();
  280.         SI2CDoAck();
  281.     }
  282.     SI2CNoAck();                    //从设备要求必须使用NOAck来结束数据读取

  283.     SI2C_Stop();                    //产生停止信号
  284.    
  285.     return *buff;
  286. }


  287. /**********************************************************************************************
  288. * 函数名称:        I2C_16bitBuffWrite()
  289. * 功能说明: 向I2C器件的地址addr开始写入size个字节的数据,将要写入的数据存储在全局变量数组I2C_Buff中
  290. * 输    入: uint16_t addr        数据被写入从addr开始的16位地址处
  291. *                        uint8_t size        要设置的数据个数(1~8)
  292. * 输    出: uint8_t                0= 成功  1=出现错误
  293. **********************************************************************************************/
  294. uint8_t SI2C_16bitBuffWrite(uint8_t I2Caddr,uint16_t addr,uint8_t size,uint8_t *buff)
  295. {
  296.     uint8_t i = 0;
  297.        
  298.     SI2C_Start();                   //产生起始信号
  299.     SI2C_Send(I2Caddr|0);           //发送从设备芯片地址及读写位,0表示写
  300.     if(SI2CIsAck())                 //检测从设备是否有响应
  301.     {
  302.         SI2C_Stop();                //产生停止信号
  303.         return 1;
  304.         }

  305.     SI2C_Send(addr>>8);             //发送读取数据的起始地址
  306.     if(SI2CIsAck())                 //检测从设备是否有响应
  307.     {
  308.         SI2C_Stop();                    //产生停止信号
  309.         return 3;
  310.     }
  311.         SI2C_Send(addr|0x0F);           //发送读取数据的起始地址低8位
  312.     if(SI2CIsAck())                 //检测器件是否有响应
  313.     {
  314.         SI2C_Stop();                //产生停止信号
  315.         return 3;
  316.     }

  317.     for(i=0;i<size;i++)
  318.     {
  319.         SI2C_Send(buff[i]);
  320.         if(SI2CIsAck())             //检测从设备是否有响应
  321.         {
  322.             SI2C_Stop();            //产生停止信号
  323.             return 3;
  324.         }
  325.     }

  326.     SI2C_Stop();                    //产生停止信号

  327.     return 0;
  328. }


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
和下土 发表于 2020-11-29 12:16 | 显示全部楼层
又学到了,EEPROM的多字节读写有特殊的要求,不能跨页操作
和下土 发表于 2020-11-29 12:19 | 显示全部楼层
在使用这段代码时要注意这个问题。
 楼主| hu9jj 发表于 2020-11-29 12:44 | 显示全部楼层
和下土 发表于 2020-11-29 12:19
在使用这段代码时要注意这个问题。

EEPROM的数据手册会有说明的,使用时首先要了解该EEPROM的相关要求。
MianQi 发表于 2020-12-3 18:21 | 显示全部楼层
这款逻辑分析仪不错,多少钱买地?
 楼主| hu9jj 发表于 2020-12-4 08:19 | 显示全部楼层
MianQi 发表于 2020-12-3 18:21
这款逻辑分析仪不错,多少钱买地?

好象是28元吧,2016年买的。

评论

给个链接地址。  发表于 2020-12-4 08:55
晓伍 发表于 2020-12-4 13:04 | 显示全部楼层
实测iic接口运行稳定吗
磨砂 发表于 2020-12-4 13:07 | 显示全部楼层
请问mcc的头文件里边都定义了哪些变量呢
木木guainv 发表于 2020-12-4 13:10 | 显示全部楼层
这个逻辑分析仪跟电脑的接口是什么接口
xiaoqizi 发表于 2020-12-4 13:12 | 显示全部楼层
非常不错 这是用的硬件iic吧
 楼主| hu9jj 发表于 2020-12-4 14:05 | 显示全部楼层
晓伍 发表于 2020-12-4 13:04
实测iic接口运行稳定吗

运行稳定。
 楼主| hu9jj 发表于 2020-12-4 14:07 | 显示全部楼层
木木guainv 发表于 2020-12-4 13:10
这个逻辑分析仪跟电脑的接口是什么接口

USB接口,在电脑上运行相应的程序就可以截取引脚的时序。
 楼主| hu9jj 发表于 2020-12-4 14:08 | 显示全部楼层
xiaoqizi 发表于 2020-12-4 13:12
非常不错 这是用的硬件iic吧

硬件I2C仍未调通,目前还是使用模拟I2C。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:Microchip
简介:让我们来为您提供帮助。我们可提供各种资源来帮助您解决一切问题。是否需要与我们的客户支持团队联系?您可以通过电话、在线聊天功能或电子邮件与他们联系。

151

主题

1063

帖子

11

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