[PIC®/AVR®/dsPIC®产品] 如何正确使用MCC生成的I2C库函数执行读取内存操作

[复制链接]
1999|3
 楼主| gaoyang9992006 发表于 2024-2-4 12:29 | 显示全部楼层 |阅读模式
本帖最后由 gaoyang9992006 于 2024-2-4 19:03 编辑

关于MCC生成的PIC18F系列的I2C库函数的写操作的应用可以查看下面的帖子
https://bbs.21ic.com/icview-3353486-1-1.html
关于IO模拟I2C的操作可以查看下面的帖子
https://bbs.21ic.com/icview-3343744-1-1.html
本帖讲解如何使用MCC生成的I2C库函数执行读内存操作。
MCC的使用方法和I2C的启用方法这里不再赘述。
这里我们使用函数
  1. /**
  2. * @ingroup i2c_host
  3. * [url=home.php?mod=space&uid=247401]@brief[/url] This function writes data from the writeData to the bus
  4. *        and then reads data from the Client and stores the received in the
  5. *        readData. The function generates a Start condition on the bus and
  6. *        will then send writeLength number of bytes contained in writeData.
  7. *        The function will then insert a Repeated start condition and
  8. *        proceed to read readLength number of bytes from the client.
  9. *        The received bytes are stored in readData buffer. A Stop condition
  10. *        is generated after the last byte has been received.
  11. *
  12. *        If the Client NAKs the request or a bus error was encountered on
  13. *        the bus, the transfer is terminated. The application can call
  14. *        I2C1_ErrorGet() function to know that cause of the error.
  15. *
  16. *        The function is non-blocking. It initiates bus activity and returns
  17. *        immediately. The transfer is then completed in the peripheral
  18. *        interrupt. For polling mode, user has to call  I2C1_Tasks
  19. *        in while loop. A transfer request cannot be placed when another
  20. *        transfer is in progress. Calling this function when another function
  21. *        is already in progress will cause the function to return false.
  22. *
  23. * @param [in] address     - 7-bit / 10-bit Client address.
  24. * @param [in] writeData   - pointer to write data buffer.
  25. * @param [in] writeLength - write data length in bytes.
  26. * @param [out] readData    - pointer to read data buffer.
  27. * @param [in] readLength  - read data length in bytes.

  28. * @return
  29. *         true  - The request was placed successfully and the bus activity was
  30. *                 initiated.
  31. *         false - The request fails,if there was already a transfer in
  32. *                 progress when this function was called
  33. */
  34. bool I2C1_WriteRead(uint16_t address, uint8_t *writeData, size_t writeLength, uint8_t *readData, size_t readLength);
该函数的执行过程是:往指定的地址的设备写入数据后,再从该地址的设备读取数据。
参数一共5个:芯片的I2C总线地址,要写入的数据,写入数据的长度,读取的数据,读取的长度。
请注意写入的数据和读取的数据通过指针实现。
我们查看库函数实现的方式
  1. bool I2C1_WriteRead(uint16_t address, uint8_t *writeData, size_t writeLength, uint8_t *readData, size_t readLength)
  2. {
  3.     bool retStatus = false;
  4.     if (!I2C1_IsBusy())
  5.     {
  6.         i2c1Status.busy = true;
  7.         i2c1Status.address = address;
  8.         i2c1Status.switchToRead = true;
  9.         i2c1Status.writePtr = writeData;
  10.         i2c1Status.writeLength = writeLength;
  11.         i2c1Status.readPtr = readData;
  12.         i2c1Status.readLength = readLength;
  13.         i2c1Status.errorState = I2C_ERROR_NONE;
  14.         I2C1_WriteStart();
  15.         retStatus = true;
  16.     }
  17.     return retStatus;
  18. }
通过以上代码我们了解到,这是一个非阻塞函数,进入函数后判断是否忙,如果不忙就执行相关的寄存器配置与执行操作并返回真,这里函数并未考虑到如果为假的情况,另外为真的话也未考虑是否执行成功。所以我们需要自己在程序里考虑这个问题,否则将会执行失败,或者错过执行。接下来我找一个I2C的芯片来执行读操作。

芯片的时序定义如上所示,可以看出读操作是标准的I2C时序。
示例代码如下:
  1. int main(void)
  2. {
  3.     uint8_t val=0;
  4.     uint8_t reg=0x00;   
  5.     SYSTEM_Initialize();

  6.     // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
  7.     // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
  8.     // Use the following macros to:

  9.     // Enable the Global Interrupts
  10.     INTERRUPT_GlobalInterruptEnable();

  11.     // Disable the Global Interrupts
  12.     //INTERRUPT_GlobalInterruptDisable();
  13. printf("Hello\n");
  14. DELAY_milliseconds(3000);
  15.     while(1)
  16.     {
  17.             DELAY_milliseconds(1000);
  18.             
  19.             I2C1_WriteRead(0x35,&reg,1,&val,1);
  20.             while(I2C1_IsBusy());
  21.             printf("REG%d=%x\n",reg,val);
  22.             reg++;
  23.             val=0;
  24.             if(reg>30) reg=0;
  25.             
  26.     }   
  27. }
我们往I2C地址为0x35的设备写入reg,并将读取的数据放到val,之后通过检测是否忙,如果忙就等待,等到写入完成后再执行打印结果的操作。
这里使用了阻塞的方式判断,也可以使用非阻塞方式,增加一个时间判断,防止程序卡死。
简单的示例如下所示:
  1. int main(void)
  2. {
  3.     uint8_t val=0;
  4.     uint8_t reg=0x00;
  5.     uint8_t delay_time=0;
  6.     SYSTEM_Initialize();

  7.     // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
  8.     // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
  9.     // Use the following macros to:

  10.     // Enable the Global Interrupts
  11.     INTERRUPT_GlobalInterruptEnable();

  12.     // Disable the Global Interrupts
  13.     //INTERRUPT_GlobalInterruptDisable();
  14. printf("Hello\n");
  15. DELAY_milliseconds(3000);
  16.     while(1)
  17.     {
  18.             DELAY_milliseconds(1000);
  19.             
  20.             I2C1_WriteRead(0x35,&reg,1,&val,1);
  21.             while(I2C1_IsBusy()&&(delay_time++<20));
  22.             printf("REG%d=%x\n",reg,val);
  23.             reg++;
  24.             val=0;
  25.             delay_time=0;
  26.             if(reg>30) reg=0;
  27.             
  28.     }   
  29. }


最后我们看看读取的效果

最后补充一个先写后读取的示例,并测试对应的寄存器哪些位可以进行写操作。

  1. int main(void)
  2. {
  3.     uint8_t val=0;
  4.     uint8_t reg=0x00;
  5.     uint8_t delay_time=0;
  6.     SYSTEM_Initialize();
  7.     uint8_t daa[2];
  8.     daa[0]=0x04;
  9.     daa[1]=0x00;
  10.     // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
  11.     // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
  12.     // Use the following macros to:

  13.     // Enable the Global Interrupts
  14.     INTERRUPT_GlobalInterruptEnable();

  15.     // Disable the Global Interrupts
  16.     //INTERRUPT_GlobalInterruptDisable();
  17. printf("Hello\n");
  18. DELAY_milliseconds(3000);
  19.     while(1)
  20.     {
  21.         DELAY_milliseconds(1000);  

  22.         I2C1_Write(0x35,daa,2);
  23.         while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
  24.         reg=0x04;        
  25.         I2C1_WriteRead(0x35,®,1,&val,1);
  26.         while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
  27.         printf("DAA[%x]---REG%d=%x\n",daa[1],reg,val);
  28.         daa[1]++;      
  29.     }   
  30. }

经过测试在0x04寄存器上,低4位中的BIT3是不能执行写操作的。

正常使用时候这么看明显的不好看,我们可以将函数进行封装使用,不仅方便阅读,还更容易调用,同时这么做不容易弄错。
  1. void KT_Byte_Write(uint8_t kt_reg,uint8_t kt_dat)
  2. {
  3.     uint8_t delay_time=0;
  4.     uint8_t dats[2];
  5.     dats[0] = kt_reg;
  6.     dats[1] = kt_dat;
  7.     I2C1_Write(0x35,dats,2);
  8.     while(I2C1_IsBusy()&&(delay_time++<20));
  9. }

  10. uint8_t KT_Byte_Read(uint8_t kt_reg)
  11. {
  12.     uint8_t val=0;
  13.     uint8_t delay_time=0;
  14.     I2C1_WriteRead(0x35,&kt_reg,1,&val,1);
  15.     while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
  16.     return val;
  17. }

  调用方式
  1. int main(void)
  2. {
  3.     SYSTEM_Initialize();
  4.     uint8_t i=0;
  5.     // Enable the Global Interrupts
  6.     INTERRUPT_GlobalInterruptEnable();

  7.     // Disable the Global Interrupts
  8.     //INTERRUPT_GlobalInterruptDisable();
  9. printf("Hello\n");
  10. DELAY_milliseconds(3000);
  11.     while(1)
  12.     {
  13.         for(i=0;i<10;i++)
  14.         {
  15.             DELAY_milliseconds(1000);
  16.             KT_Byte_Write(0x04,i);
  17.             printf("REG=%x\n",KT_Byte_Read(0x04));  
  18.         }
  19.     }   
  20. }

好了,基于我使用的这个芯片的I2C读写使用方式讲解完了,另外只要是标准I2C协议的芯片都可以这么使用。


本帖子中包含更多资源

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

×
caigang13 发表于 2024-2-4 12:37 来自手机 | 显示全部楼层
MCC还是差了点便捷性,还需继续优化。
 楼主| gaoyang9992006 发表于 2024-2-4 12:38 | 显示全部楼层
caigang13 发表于 2024-2-4 12:37
MCC还是差了点便捷性,还需继续优化。

是的,我刚更新了帖子。
幸福小强 发表于 2024-2-4 17:48 | 显示全部楼层
掌握住诀窍了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2052

主题

16403

帖子

222

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