[MM32软件] IIC协议通信解析

[复制链接]
1261|1
 楼主| rosemoore 发表于 2023-11-18 23:30 | 显示全部楼层 |阅读模式


  1. // 该代码用于测试没问题

  2. #define I2C_SCL_PORT  GPIOB
  3. #define I2C_SCL_Pin   GPIO_Pin_8

  4. #define I2C_SDA_PORT  GPIOB
  5. #define I2C_SDA_Pin   GPIO_Pin_9

  6. #define OUTPUT 0
  7. #define INPUT 1

  8. static void I2C_Tail(void); //发送结束标志
  9. static void I2C_Head(unsigned short Addrs); // 发送起始标志

  10. static void hal_I2C_Config(void); // 模拟I2C配置函数
  11. static void hal_I2C_SCL_SET(unsigned char i);  // 设置时钟引脚
  12. static void hal_I2C_SDA_SET(unsigned char i);  // 设置数据引脚
  13. static void hal_I2C_Start(void);  // 起始标志
  14. static void hal_I2C_Stop(void);   // 结束标志
  15. static void I2C_Delay(unsigned short t);
  16. static void I2C_ACK(void);   // 有ACK应答
  17. static void I2C_NOACK(void); // 无ACK应答
  18. static void I2C_SendByte(unsigned char data);   // 写一个byte数据时序
  19. static void I2C_WriteByte(unsigned short Addr, unsigned char data); // 发送一个byte
  20. static unsigned char I2C_RecvByte(void); // 读一个字节时序
  21. static unsigned char I2C_WaitAck(void);  // 返回0,无应答数据 。返回1,有应答数据

  22. void hal_I2C_SDA_IO_SET(unsigned char IOMode); // OUTPUT 或者 INPUT
  23. unsigned char hal_IC_SDA_INPUT(void);
  24. unsigned char I2C_ReadByte(unsigned short Addr); // 读一个字节数据


  25. void hal_eeprom_Init(void)
  26. {
  27.   hal_I2C_Config();
  28. }

  29. unsigned char I2C_ReadByte(unsigned short Addr)
  30. {
  31.   unsigned char dat;
  32.         hal_I2C_Start();
  33.         I2C_SendByte(0xA0);
  34.         I2C_WaitAck();
  35.        
  36.         I2C_SendByte((Addr>>8)&0xFF);
  37.         I2C_WaitAck();
  38.        
  39.         I2C_SendByte(Addr&0xFF);
  40.         I2C_WaitAck();
  41.        
  42.         hal_I2C_Start();
  43.         I2C_SendByte(0xA1); // 发送 1010 0001 最低位的1代表从该芯片读取数据
  44.         I2C_WaitAck();
  45.        
  46.         dat = I2C_RecvByte();
  47.         I2C_NOACK();
  48.         hal_I2C_Stop();
  49.         return dat;
  50. }

  51. static unsigned char I2C_RecvByte(void)
  52. {
  53.    unsigned char i = 0;
  54.          unsigned char RecvByte = 0;
  55.        
  56.    hal_I2C_SCL_SET(0);
  57.          I2C_Delay(1);
  58.          hal_I2C_SDA_SET(1);
  59.          hal_I2C_SDA_IO_SET(INPUT);
  60.          
  61.          for(; i < 8; i++)
  62.         {
  63.              RecvByte<<=1;
  64.                   I2C_Delay(1);
  65.                   hal_I2C_SCL_SET(1);
  66.                   I2C_Delay(1);
  67.                   if(hal_IC_SDA_INPUT()) {
  68.                           RecvByte |= 0x01;
  69.                         }
  70.                         hal_I2C_SCL_SET(0);
  71.         }
  72.         hal_I2C_SDA_IO_SET(OUTPUT);
  73.         I2C_Delay(1);
  74.         return RecvByte;
  75. }

  76. void hal_I2C_Read( unsigned short Addrs, unsigned char *pBuf, unsigned short Len)
  77. {
  78.   unsigned short i = 0;
  79.        
  80.         I2C_Head(Addrs);
  81.        
  82.         hal_I2C_Start();
  83.         I2C_SendByte(0xA1); // 发送 1010 0001 最低位的1代表从该芯片读取数据
  84.         I2C_WaitAck();
  85.        
  86.         for( i = 0; i < Len; i++)
  87.         {
  88.           pBuf[i] = I2C_RecvByte();
  89.                 if(i == Len - 1) I2C_NOACK();
  90.                 else I2C_ACK();
  91.         }
  92.        
  93.         hal_I2C_Stop();
  94. }

  95. static void I2C_WriteByte(unsigned short Addr, unsigned char data)
  96. {
  97.   hal_I2C_Start(); // 发送有效数据起始标志
  98.        
  99.         // 该芯片最低位的一个bit位代表读/写:0 代表写入数据 || 1 代表读出数据
  100.         I2C_SendByte(0xA0); // 发送需要通信的硬件地址(对应的硬件手册上有!!!!!)
  101.         I2C_WaitAck();
  102.        
  103.         I2C_SendByte((Addr>>8)&0xFF); // 发送写入的地址(高字节地址)
  104.         I2C_WaitAck();
  105.        
  106.         I2C_SendByte(Addr&0xFF);    // 发送写入的地址(低字节地址)
  107.         I2C_WaitAck();
  108.        
  109.         I2C_SendByte(data);
  110.         I2C_WaitAck();
  111.        
  112.         hal_I2C_Stop();  // 发送有效数据结束标志
  113.         I2C_Delay(20000);
  114. }


  115. static unsigned char I2C_WaitAck(void)
  116. {
  117.   hal_I2C_SDA_SET(1);
  118.         hal_I2C_SDA_IO_SET(INPUT);  // 设置SDA引脚为输入引脚
  119.         hal_I2C_SCL_SET(1);
  120.         I2C_Delay(1);
  121.         if(hal_IC_SDA_INPUT()) { // 该引脚为高电平,代表无应答
  122.                 hal_I2C_SDA_IO_SET(OUTPUT);  // 设置SDA引脚为输出引脚
  123.           return 0;
  124.         }
  125.        
  126.         hal_I2C_SCL_SET(0);
  127.         hal_I2C_SDA_IO_SET(OUTPUT);
  128.         I2C_Delay(1);
  129.         return 1;
  130. }

  131. static void I2C_Head(unsigned short Addrs)
  132. {
  133.     hal_I2C_Start(); // 发送有效数据起始标志
  134.        
  135.           // 该芯片最低位的一个bit位代表读/写:0 代表写入数据 || 1 代表读出数据
  136.           I2C_SendByte(0xA0); // 发送需要通信的硬件地址(对应的硬件手册上有!!!!!)
  137.           I2C_WaitAck();
  138.        
  139.           I2C_SendByte((Addrs>>8)&0xFF); // 发送写入的地址(高字节地址)
  140.           I2C_WaitAck();
  141.        
  142.           I2C_SendByte(Addrs&0xFF);    // 发送写入的地址(低字节地址)
  143.           I2C_WaitAck();
  144. }

  145. static void I2C_Tail(void)
  146. {
  147.   hal_I2C_Stop();  // 发送有效数据结束标志
  148.         I2C_Delay(20000);
  149. }

  150. void hal_I2C_Write(unsigned short Addrs, unsigned char* pBuf, unsigned short Len)
  151. {
  152.         unsigned short tmp = 0;
  153.         unsigned short i = 0, j = 0;
  154.         unsigned short page = 0;
  155.         unsigned short size;
  156.        
  157.         if(Addrs%EEPROM_PAGE_SIZE)
  158.         {
  159.           tmp = EEPROM_PAGE_SIZE-(Addrs%EEPROM_PAGE_SIZE); // 拿到当前页还有多少字节可写入
  160.                 if(tmp > Len)
  161.                 {
  162.              tmp = Len;        // 后续写入操作,需要tmp来做循环因子
  163.                 }
  164.         }
  165.         // 先将数据写入当前页
  166.         if(tmp)
  167.         {
  168.                 I2C_Head(Addrs);
  169.                 // 正式写入数据
  170.                 for(i = 0; i < tmp; i++)
  171.                 {
  172.                   I2C_SendByte(pBuf[i]);
  173.                         I2C_WaitAck();
  174.                 }
  175.                 I2C_Tail();
  176.         }
  177.        
  178.         Len -= tmp;   // 将已经发送过的数据个数减掉
  179.         Addrs += tmp; // 将写入的地址更新
  180.        
  181.         page = Len/EEPROM_PAGE_SIZE; // int整形除法,只会得到整数
  182.         size = Len%EEPROM_PAGE_SIZE; // 不足一页还有几个字节
  183.        
  184.         for(i = 0; i < page; i++)
  185.         {
  186.           I2C_Head(Addrs);
  187.                
  188.                 for(j = 0; j < EEPROM_PAGE_SIZE; j++)
  189.                 {
  190.                   I2C_SendByte(pBuf[tmp + j]);
  191.                         I2C_WaitAck();
  192.                 }
  193.                 I2C_Tail();
  194.                 Addrs += EEPROM_PAGE_SIZE;
  195.                 tmp += EEPROM_PAGE_SIZE;
  196.         }
  197.        
  198.         if(size)
  199.         {
  200.           I2C_Head(Addrs);
  201.                
  202.                 for(i = 0; i < size; i++)
  203.                 {
  204.                   I2C_SendByte(pBuf[tmp + i]);
  205.                         I2C_WaitAck();
  206.                 }
  207.                 I2C_Tail();
  208.         }
  209.        
  210. }

  211. static void I2C_SendByte(unsigned char data)
  212. {
  213.   unsigned char i = 0;
  214.         for(; i < 8; i++)
  215.         {
  216.                 hal_I2C_SCL_SET(0);
  217.                 I2C_Delay(1);
  218.           if(data&0x80){
  219.                   hal_I2C_SDA_SET(1);
  220.                 } else {
  221.                   hal_I2C_SDA_SET(0);
  222.                 }
  223.                 I2C_Delay(1);
  224.                 hal_I2C_SCL_SET(1);
  225.                 I2C_Delay(1);
  226.                 data<<=1;
  227.         }
  228.        
  229.         hal_I2C_SCL_SET(0);
  230.   I2C_Delay(1);
  231.         hal_I2C_SDA_SET(1);
  232.   I2C_Delay(1);
  233. }


  234. static void I2C_ACK(void)
  235. {
  236.    hal_I2C_SCL_SET(0);
  237.          I2C_Delay(1);
  238.          hal_I2C_SDA_SET(0); // SDA数据线置低,进行数据位应答。
  239.          I2C_Delay(1);
  240.          hal_I2C_SCL_SET(1);
  241.          I2C_Delay(1);
  242.          hal_I2C_SCL_SET(0);
  243.          I2C_Delay(1);
  244. }


  245. static void I2C_NOACK(void)
  246. {
  247.    hal_I2C_SCL_SET(0);
  248.          I2C_Delay(1);
  249.          hal_I2C_SDA_SET(1); // SDA数据线置高,不进行数据应答。
  250.          I2C_Delay(1);
  251.          hal_I2C_SCL_SET(1);
  252.          I2C_Delay(1);
  253.          hal_I2C_SCL_SET(0);
  254.          I2C_Delay(1);
  255. }

  256. static void hal_I2C_Start(void)
  257. {
  258.   hal_I2C_SDA_SET(1);
  259.         I2C_Delay(1);
  260.         hal_I2C_SCL_SET(1);
  261.         I2C_Delay(1);
  262.         hal_I2C_SDA_SET(0);
  263.         I2C_Delay(1);
  264. }

  265. static void hal_I2C_Stop(void)
  266. {
  267.   hal_I2C_SDA_SET(0);
  268.         I2C_Delay(1);
  269.         hal_I2C_SCL_SET(1);
  270.         I2C_Delay(1);
  271.         hal_I2C_SDA_SET(1);
  272.         I2C_Delay(1);
  273. }


  274. static void hal_I2C_Config(void)
  275. {
  276.    GPIO_InitTypeDef GPIO_Struct;
  277.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  278.          
  279.          GPIO_Struct.GPIO_Mode = GPIO_Mode_Out_OD;
  280.          GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
  281.          GPIO_Struct.GPIO_Pin = I2C_SCL_Pin | I2C_SDA_Pin;
  282.          GPIO_Init(GPIOB, &GPIO_Struct);
  283.        
  284.          hal_I2C_SDA_SET(1);
  285.          hal_I2C_SCL_SET(1);
  286.        
  287. }


  288. void hal_I2C_SDA_IO_SET(unsigned char IOMode)
  289. {
  290.   if(0 == IOMode) {
  291.          GPIO_InitTypeDef GPIO_Struct;
  292.          GPIO_Struct.GPIO_Mode = GPIO_Mode_Out_OD;
  293.          GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
  294.          GPIO_Struct.GPIO_Pin =  I2C_SDA_Pin;
  295.          GPIO_Init(GPIOB, &GPIO_Struct);
  296.         }
  297.         if(1 == IOMode) {
  298.          GPIO_InitTypeDef GPIO_Struct;
  299.          GPIO_Struct.GPIO_Mode = GPIO_Mode_IPU;
  300.          GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
  301.          GPIO_Struct.GPIO_Pin =  I2C_SDA_Pin;
  302.          GPIO_Init(GPIOB, &GPIO_Struct);
  303.         }
  304. }


  305. static void hal_I2C_SDA_SET(unsigned char i)
  306. {
  307.   if(i) {
  308.            GPIO_SetBits(I2C_SDA_PORT,I2C_SDA_Pin);
  309.          } else {
  310.            GPIO_ResetBits(I2C_SDA_PORT,I2C_SDA_Pin);
  311.          }
  312. }


  313. static void hal_I2C_SCL_SET(unsigned char i)
  314. {
  315.    if(i) {
  316.            GPIO_SetBits(I2C_SCL_PORT,I2C_SCL_Pin);
  317.          } else {
  318.            GPIO_ResetBits(I2C_SCL_PORT,I2C_SCL_Pin);
  319.          }
  320. }

  321. static void I2C_Delay(unsigned short t)
  322. {
  323.   unsigned short i=50,j,c;
  324.    c = t;
  325.    for(j=0; j<c; j++)
  326.    {
  327.            while(i)
  328.            {
  329.                                 i--;
  330.            }
  331.         }
  332. }

  333. unsigned char hal_IC_SDA_INPUT(void)
  334. {
  335.   return GPIO_ReadInputDataBit(I2C_SDA_PORT, I2C_SDA_Pin);
  336. }


单片小菜 发表于 2023-11-24 17:16 | 显示全部楼层
我还是认为软件的I2C更香,至少通用性更强一些。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

64

主题

1605

帖子

2

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