[文档下载] iic驱动(IO口模拟)

[复制链接]
1180|6
 楼主| mmbs 发表于 2023-12-17 21:42 | 显示全部楼层 |阅读模式
iic.c
  1. #include "includes.h"
  2. /*
  3.     iic知识
  4.     1. iic的启动信号
  5.         SCL为高,SDA从高到低,产生一个起始信号
  6.     2. iic的停止信号
  7.         SCL为高,SDA从低到高,产生一个停止信号
  8.     3. acknowledge(应答)
  9.         在数据或地址传输的第9个时钟,SDA线上的状态,0:ack, 1:no-ack,函数中需要封装ack发送函数。

  10. 注意:
  11.     1. iic的引脚配置,SCL配置为输出,SDA需要输出和输入在使用中进行切换
  12.     2. iic的数据按位进行传输,先高位后低位
  13. */
  14. /*
  15. 对应的函数接口:
  16.     1. 起始信号
  17.     2. 停止信号
  18.     3. 发送响应ACK(0:响应  1:非响应)
  19.     4. iic协议写一个字节
  20.         按位从高位到低位输出,第九位等待一个ack信号,此时SDA引脚切换为输入,ack为0:ack,1:no-ack
  21.     5. iic协议读一个字节
  22.         按位从高到低位输出,8个字节传输完后应该要发送ack信号,but 此处没有。。。
  23. —————————————————上部分和i2c协议严格相关—————————————————————
  24. ————————————————下部分更需要参考对应的器件手册—————————————————
  25.     6. iic发送单个字节(此处需要参考交互的器件手册)
  26.         - 先发送一个起始信号
  27.         - 发送器件地址
  28.         - 发送寄存器地址高位
  29.         - 发送寄存器地址低位
  30.         - 发送字节数据
  31.         - 发送停止位
  32.     数据发送完成后, 需要一定的延时,不然会出错,程序里设置8ms
  33.     6. iic接收单个字节
  34.         - 发送起始信号
  35.         - 发送器件地址(方向为写)
  36.         - 发送寄存器地址高位
  37.         - 发送寄存器地址低位
  38.         - 再次发送起始信号
  39.         - 发送器件地址(方向为读)
  40.         - 开始接收字节数据
  41.         - 发送非响应(ack=1)
  42.         - 发送停止信号

  43. 当然对于该器件,还支持页写和连续读。
  44. 需要注意的时,页写时,一次不能写入超过一页的数据(64bytes),否则会"roll over"该页之前的数据,不支持页自动加;
  45.     连续读时,超过器件的地址范围后(而不是页范围),word address will "roll over",the sequential read will continue.
  46.     器件的字节写/页写,字节读/连续读,不需要特定的设置,只需要按器件的时序图操作即可。
  47. */

  48. void iic_sda_output(void)
  49. {
  50.     GPIO_InitTypeDef GPIO_InitStructure;
  51.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  52.     // sda output
  53.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  54.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  55.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  56.     GPIO_Init(GPIOB,&GPIO_InitStructure);
  57. }
  58. void iic_sda_input(void)
  59. {
  60.     GPIO_InitTypeDef GPIO_InitStructure;
  61.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  62.     // sda input
  63.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  64.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  65.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  66.     GPIO_Init(GPIOB,&GPIO_InitStructure);
  67. }
  68. //1.
  69. void iic_gpio_config(void)
  70. {
  71.     //scl : pb6  sda :pb7
  72.     GPIO_InitTypeDef  GPIO_InitStructure;

  73.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  74.     //SCL  &&   SDA
  75.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  76.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  77.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  78.     GPIO_Init(GPIOB,&GPIO_InitStructure);
  79. }
  80. //2. iic init
  81. void iic_init(void)
  82. {
  83.     iic_gpio_config();
  84. }
  85. //2. iic start
  86. void iic_start_signal(void)
  87. {
  88.     iic_sda_output();
  89.     IIC_SCL_W(1);
  90.     IIC_SDA_W(1);
  91.     delay(10);
  92.     IIC_SDA_W(0);
  93.     delay(10);

  94.     IIC_SCL_W(0);

  95. }
  96. //3. iic stop
  97. void iic_stop_signal(void)
  98. {
  99.     iic_sda_output();
  100.     IIC_SDA_W(0);
  101.     delay(10);
  102.     IIC_SCL_W(1);
  103.     delay(10);
  104.     IIC_SDA_W(1);

  105. }
  106. //4. send ack
  107. void iic_send_ack(uint8_t ack)
  108. {
  109.     iic_sda_output();

  110.     IIC_SCL_W(0);
  111.     delay(10);

  112.     IIC_SDA_W(ack);
  113.     delay(10);

  114.     IIC_SCL_W(1);
  115.     delay(10);

  116. //  IIC_SCL_W(0);
  117. //  delay(10);

  118. }
  119. //5. iic write byte
  120. uint8_t iic_write_byte(uint8_t data)
  121. {
  122.   uint8_t i,ack;
  123.     iic_sda_output();  //
  124.     //IIC_SCL_W(0);
  125.     //delay(10);
  126.     for(i = 0;i<8;i++)
  127.     {
  128.          if(data&0x80)
  129.               IIC_SDA_W(1);
  130.          else
  131.               IIC_SDA_W(0);
  132.         data<<=1;
  133.         delay(10);     
  134.         IIC_SCL_W(1);
  135.         delay(10);
  136.         IIC_SCL_W(0);
  137.         delay(10);
  138.     }
  139.     //ack
  140.     iic_sda_input();  //
  141.     delay(10);   

  142.     IIC_SCL_W(1);
  143.     delay(10);
  144.     ack = IIC_SDA_R();
  145.     IIC_SCL_W(0);
  146.     delay(10);

  147.     iic_sda_output();//12
  148.     return ack;
  149. }
  150. //6. iic read byte
  151. uint8_t iic_read_byte(void)
  152. {
  153.     //读取那字节的数据
  154.     uint8_t i,temp = 0;
  155.     iic_sda_input();
  156.     for(i = 0;i<8;i++)
  157.     {
  158.         IIC_SCL_W(1);
  159.         delay(10);

  160.         temp<<=1;
  161.         if(IIC_SDA_R())
  162.              temp |= 0x01;
  163.         else
  164.              temp &= ~0x01;
  165.         IIC_SCL_W(0);
  166.         delay(10);
  167.     }
  168.     iic_sda_output();//12
  169.     //发送一个响应
  170.     return temp;
  171. }
  172. //7. send one byte
  173. void iic_send_byte(uint16_t addr,uint8_t dat)
  174. {
  175.     uint8_t ack =0;
  176.     //起始信号
  177.     iic_start_signal();
  178.     //写器件地址
  179.     ack = iic_write_byte(0xa0);
  180.     if(ack){
  181.         iic_stop_signal();
  182.         return;
  183.     }
  184.     //写器件地址
  185.     ack = iic_write_byte(AddrHigh(addr));
  186.     if(ack){
  187.         iic_stop_signal();
  188.         return;
  189.     }
  190.     ack = iic_write_byte(AddrLow(addr));
  191.   if(ack){
  192.         iic_stop_signal();
  193.         return;
  194.     }
  195.     //写数据
  196.     ack = iic_write_byte(dat);
  197.     if(ack){
  198.         iic_stop_signal();
  199.         return;
  200.     }
  201.     //写停止信号
  202.     iic_stop_signal();

  203.     sys_delay_ms(8);    //一个字节写完后,需要加延时,这个很重要!!!
  204. }
  205. //8.读取一个字节数据
  206. int iic_recv_byte(uint16_t addr)
  207. {
  208.     uint8_t temp = 0;
  209.     uint8_t ack = 0;
  210.     //起始信号
  211.     iic_start_signal();
  212.     //写器件地址
  213.     ack = iic_write_byte(0xa0);
  214.     if(ack){
  215.         iic_stop_signal();
  216.         return -2;
  217.     }
  218.     //写器件地址
  219.     ack = iic_write_byte(AddrHigh(addr));
  220.     if(ack){
  221.         iic_stop_signal();
  222.         return -2;
  223.     }
  224.     ack = iic_write_byte(AddrLow(addr));
  225.     if(ack){
  226.         iic_stop_signal();
  227.         return -2;
  228.     }
  229.     //起始信号
  230.     iic_start_signal();
  231.     //器件读地址
  232.     ack = iic_write_byte(0xa1);
  233.     if(ack){
  234.         iic_stop_signal();
  235.         return -2;
  236.     }
  237.     temp = iic_read_byte();
  238.     //发送一个非应答。器件读取完后,需要发送一个非应答
  239.     iic_send_ack(1);
  240.     //产生一个停止信号
  241.     iic_stop_signal();

  242.     return temp;
  243. }
  244. //9. 连续写入多个字节,但不超过一页
  245. void iic_write_buff(uint8_t *pbuff,uint16_t addr,uint8_t num)
  246. {
  247.     uint8_t i,ack;
  248.     //起始信号
  249.     iic_start_signal();
  250.     //写器件地址
  251.     ack = iic_write_byte(0xa0);
  252.     if(ack){
  253.         iic_stop_signal();
  254.         return;
  255.     }
  256.     //写寄存器地址
  257.     ack = iic_write_byte(AddrHigh(addr));
  258.     if(ack){
  259.         iic_stop_signal();
  260.         return;
  261.     }
  262.     ack = iic_write_byte(AddrLow(addr));
  263.     if(ack){
  264.         iic_stop_signal();
  265.         return;
  266.     }
  267.     //开始写入数据
  268.     for(i = 0;i<num;i++)
  269.     {
  270.         ack = iic_write_byte(pbuff[i]);
  271.         if(ack){
  272.             break;
  273.         }
  274.     }
  275.     //停止信号
  276.     iic_stop_signal();  
  277. }
  278. //10.连续读出多个字节
  279. void iic_read_buff(uint8_t *pbuff,uint16_t addr,uint8_t num)
  280. {
  281.     uint8_t i,ack;
  282.     //起始信号
  283.     iic_start_signal();
  284.     //写器件地址
  285.     ack = iic_write_byte(0xa0);
  286.     if(ack){
  287.         iic_stop_signal();
  288.         return;
  289.     }
  290.     //写寄存器地址
  291.     ack = iic_write_byte(AddrHigh(addr));
  292.     if(ack){
  293.         iic_stop_signal();
  294.         return;
  295.     }
  296.     ack = iic_write_byte(AddrLow(addr));
  297.     if(ack){
  298.         iic_stop_signal();
  299.         return;
  300.     }
  301.     //读数据
  302.     for(i = 0;i<num;i++)
  303.     {
  304.         pbuff[i] = iic_read_byte();
  305.         //发送一个应答
  306.         if(i == num-1)
  307.              iic_send_ack(1);   //最后一个字节发送非应答
  308.         else
  309.             iic_send_ack(0);    //前num-1个字节发送应答
  310.     }
  311.     //停止信号
  312.     iic_stop_signal();
  313. }

  314. //iic test code
  315. void iic_sck_test(void)
  316. {
  317.     IIC_SDA_W(0);
  318.     delay(10);
  319.     IIC_SDA_W(1);
  320.     delay(10);
  321. }
  322. //iic 24lc128 test  0: success -1: failed
  323. int iic_24lc128_test(void)
  324. {
  325.     int i,j;
  326.     int iic_addr = 0;
  327.     uint8_t dat = 5;
  328.     printf("iic start test,start_time: %d\r\n",systick_ms_counter);

  329.     for(i = 0;i<64;i++){
  330.         for(j = 0;j<256;j++){  //写0-255
  331.             iic_send_byte(iic_addr,j);
  332.             iic_addr++;
  333.         }
  334.         for(j = 0;j<256;j++){  //读0-255
  335.             iic_addr--;
  336.             dat = iic_recv_byte(iic_addr);
  337. //          if(dat != (iic_addr%256)){
  338. //              printf("dat:%02x iic_addr:%04x\r\n",dat,iic_addr);
  339. //              return -1;
  340. //          }
  341.         }
  342.         iic_addr+=256;
  343.     }
  344.     printf("iic end test,end_time: %d\r\n",systick_ms_counter);

  345.     return 0;
  346. }
i2c.h
  1. #ifndef __IIC_H
  2. #define __IIC_H

  3. #define IIC_SCL_W(bitval)  GPIO_WriteBit(GPIOB,GPIO_Pin_6,(BitAction)bitval)
  4. #define IIC_SDA_W(bitval)  GPIO_WriteBit(GPIOB,GPIO_Pin_7,(BitAction)bitval)

  5. #define IIC_SDA_R()        (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7) == Bit_RESET ? 0:1)

  6. //declare of functions

  7. void iic_sda_output(void);
  8. void iic_sda_input(void);

  9. void iic_init(void);
  10. //random r&w
  11. void iic_send_byte(uint16_t addr,uint8_t dat);  //写数据
  12. int iic_recv_byte(uint16_t addr);               //读数据
  13. //page r&w
  14. void iic_write_buff(uint8_t *pbuff,uint16_t addr,uint8_t num);
  15. void iic_read_buff(uint8_t *pbuff,uint16_t addr,uint8_t num);

  16. //test code
  17. void iic_sck_test(void);
  18. int iic_24lc128_test(void);



  19. #endif


tpgf 发表于 2024-1-6 15:12 | 显示全部楼层
iic通讯可以在运行的过程中更改子模块的地址吗
nawu 发表于 2024-1-6 15:54 | 显示全部楼层
用io口模拟的iic有重发机制吗
zljiu 发表于 2024-1-6 16:36 | 显示全部楼层
为什么iic这么多的io模拟而其他串口通信方式没有很多实用io模拟的呢
tfqi 发表于 2024-1-6 22:01 | 显示全部楼层
相对来说iic接口还是比较容易模拟的
gwsan 发表于 2024-1-6 22:33 | 显示全部楼层
如果是使用io口模拟的话  数据传输速率就可以随意了吧
aoyi 发表于 2024-1-6 23:11 | 显示全部楼层
iic模拟的话 会不会受到其他代码的影响呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

197

主题

6923

帖子

3

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