[ARM入门] 【每周分享】I2C原理代码结合(干货)看图易懂

[复制链接]
 楼主| 虚幻的是灵魂 发表于 2024-10-15 15:13 | 显示全部楼层 |阅读模式
本帖最后由 虚幻的是灵魂 于 2024-10-15 15:19 编辑

#申请原创#
@21小跑堂
I2C通讯规则

I2C总线包括两根信号线:SDA(串行数据线)和SCL(串行时钟线)。这两根信号线共用一个总线,因此在总线上可以连接多个设备。在I2C总线上,每个设备都有一个唯一的地址,用于标识设备。

SCL线是时钟线,用于控制数据传输的速度和时序;SDA线是数据线,用于传输实际的数据。

I2C写操作

流程如下:

  • 开始。
  • 发送设备地址,等待从设备响应
  • 发送寄存器地址,等待从设备响应
  • 发送一个字节,等待从设备响应。这个操作是循环执行,直到没有数据。
  • 停止。


I2C读流程

流程如下:

  • 开始。
  • 发送设备地址(写地址),等待从设备响应
  • 发送寄存器地址,等待从设备响应。
  • 开始
  • 发送设备地址(读地址),等待从设备响应
  • 接收一个字节,发送响应给从设备。这个操作是循环执行,直到没有数据。当是最后一个数据时,发送空响应。
  • 停止。

通讯信号开始

Start代码表示
  1. static void start() {
  2.     SDA_OUT();

  3.     SDA(1);
  4.     delay_1us(5);
  5.     SCL(1);
  6.     delay_1us(5);

  7.     SDA(0);
  8.     delay_1us(5);
  9.     SCL(0);
  10.     delay_1us(5);
  11. }
结束


Stop代码表示
  1. static void stop() {
  2.     SDA_OUT();

  3.     SCL(0);
  4.     SDA(0);

  5.     SCL(1);
  6.     delay_1us(5);
  7.     SDA(1);
  8.     delay_1us(5);
  9. }
发送数据bit发送


数据有效性:
  • SCL上升沿到下降沿这个阶段,SDA电平的高低,表示数据bit的1和0
  • 如果SDA电平在这个阶段发生变化,则无效,参考start和stop信号。

Byte发送

基于数据有效性,将byte按bit位变化为高低电平,发送出去。

发送byte表示

  1. static void send(uint8_t data) {
  2.     uint8_t i;
  3.     SDA_OUT();

  4.     for(i = 0; i < 8; i++) {
  5.         if(data & 0x80) {
  6.             SDA(1);
  7.         } else {
  8.             SDA(0);
  9.         }
  10.         SCL(1);
  11.         delay_1us(5);
  12.         SCL(0);
  13.         delay_1us(5);
  14.         data <<= 1;
  15.     }
  16. }

等待响应
wait ack:Acknowledge character。表示等待响应,每发送一个数据,需要确认对方是否收到,就需要等待对方响应。



等待响应表示
  1. static uint8_t wait_ack() {
  2.     int8_t retry = 10;

  3.     SCL(0);
  4.     SDA(1);
  5.     SDA_IN();
  6.     delay_1us(5);
  7.     SCL(1);
  8.     delay_1us(5);

  9.     while(SDA_STATE() == 1 && retry > 0) {
  10.         retry --;
  11.         delay_1us(5);
  12.     }

  13.     if(retry <= 0) {
  14.         stop();
  15.         return 1;
  16.     } else {
  17.         SCL(0);
  18.         SDA_OUT();
  19.     }
  20.     return 0;
  21. }
结合代码

接收数据bit接收

Byte接收

逻辑分析仪测的:

说明: 在上升沿写入数据时,会获取从设备控制权,   上升沿写入数据; SCL在高电平时,会释放从设备控制权, 直到从设备被拉低后,主设备才响应成功。


接收byte代码表示

  1. static uint8_t recv() {
  2.     uint8_t i, data;
  3.     SDA_IN();
  4.     data = 0;
  5.     for(i = 0; i < 8; i++) {
  6.         SCL(0);
  7.         delay_1us(5);
  8.         SCL(1);
  9.         delay_1us(5);

  10.         data <<= 1;

  11.         data |= SDA_STATE();

  12.         delay_1us(5);
  13.     }
  14.     SCL(0);
  15.     return data;
  16. }

发送响应


发送ACK
  1. static void send_ack() {
  2.     SDA_OUT();
  3.     SCL(0);
  4.     SDA(0);
  5.     delay_1us(5);

  6.     SDA(0);

  7.     SCL(1);
  8.     delay_1us(5);
  9.     SCL(0);
  10.     SDA(1);
  11. }
发送NACK

  1. static void send_nack() {
  2.     SDA_OUT();
  3.     SCL(0);
  4.     SDA(0);
  5.     delay_1us(5);

  6.     SDA(1);

  7.     SCL(1);
  8.     delay_1us(5);
  9.     SCL(0);
  10.     SDA(1);
  11. }
软件I2C开发流程
  • 引脚初始化
  • 引脚功能定义
  • 实现读操作
  • 实现写操作

GD32软件I2C初始化

  1. void SoftI2C_init() {
  2.     // 时钟配置
  3.     rcu_periph_clock_enable(SCL_RCU);
  4.     // 设置输出模式
  5.     gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCL_PIN);
  6.     gpio_output_options_set(SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SCL_PIN);

  7.     // 时钟配置
  8.     rcu_periph_clock_enable(SDA_RCU);
  9.     // 设置输出模式
  10.     gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN);
  11.     gpio_output_options_set(SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SDA_PIN);
  12. }
  • I2C引脚高低电平
GD32软件I2C引脚功能
  1. #define SCL_RCU                RCU_GPIOB
  2. #define SCL_PORT        GPIOB
  3. #define SCL_PIN                GPIO_PIN_6
  4. #define SCL_AF                GPIO_AF_4

  5. #define SDA_RCU                RCU_GPIOB
  6. #define SDA_PORT        GPIOB
  7. #define SDA_PIN                GPIO_PIN_7
  8. #define SDA_AF                GPIO_AF_4

  9. /************** io ***************/
  10. #define SCL(BIT)                 gpio_bit_write(SCL_PORT, SCL_PIN, BIT?SET:RESET)
  11. #define SDA(BIT)                 gpio_bit_write(SDA_PORT, SDA_PIN, BIT?SET:RESET)
  12. #define SDA_STATE()         gpio_input_bit_get(SDA_PORT, SDA_PIN)

  13. #define SDA_IN()          gpio_mode_set(SDA_PORT, GPIO_MODE_INPUT,  GPIO_PUPD_NONE, SDA_PIN)
  14. #define SDA_OUT()         gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN)
  • IO引脚定义
  • 引脚输出模式高低电平输出:SCL高和低,SDA高和低
  • SDA模式配置:SDA输出模式,SDA输入模式
  • SDA输入模式状态读取。
写操作


代码:
  1. uint8_t SoftI2C_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  2.     start();

  3.     send(addr << 1);                        //发送设备写地址
  4.     if(wait_ack()) return 1;        //等待响应

  5.     send(reg);                                        //发送寄存器地址
  6.     if(wait_ack()) return 2;        //等待响应

  7.     do {
  8.         send(*data++);
  9.         if(wait_ack()) return 3;
  10.     } while(--len);

  11.     stop();
  12.     return 0;
  13. }
读操作

代码:
  1. uint8_t SoftI2C_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  2.     start();

  3.     send(addr << 1);                                //发送设备写地址
  4.     if(wait_ack()) return 1;                //等待响应

  5.     send(reg);                                                //发送寄存器地址
  6.     if(wait_ack()) return 2;                //等待响应

  7.     start();
  8.     send((addr << 1) | 0x01);                //发送设备读地址
  9.     if(wait_ack()) return 3;                //等待响应

  10.     do {
  11.         *data = recv();
  12.         data++;
  13.         if(len != 1) send_ack();        // 发送 NACK
  14.     } while(--len);
  15.     send_nack();                                        // 发送 NACK
  16.     stop();

  17.     return 0;
  18. }
逻辑分析仪解析:

说明:读取时,会有两个开始标记。从设备会获取控制权,获取数据并发送给主设备。





硬件I2C-GD32F4系列初始化操作
  1. uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
  2. uint32_t i2cx_scl_port = GPIOB;
  3. uint32_t i2cx_scl_pin = GPIO_PIN_6;
  4. uint32_t i2cx_scl_af = GPIO_AF_4;

  5. uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
  6. uint32_t i2cx_sda_port = GPIOB;
  7. uint32_t i2cx_sda_pin = GPIO_PIN_7;
  8. uint32_t i2cx_sda_af = GPIO_AF_4;

  9. uint32_t i2cx = I2C0;
  10. uint32_t i2cx_rcu = RCU_I2C0;
  11. uint32_t i2cx_speed = 400000;
  12. /****************** GPIO config **********************/
  13. // 时钟配置
  14. rcu_periph_clock_enable(i2cx_scl_port_rcu);
  15. // 设置复用功能
  16. gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
  17. // 设置输出模式
  18. gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
  19. gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);

  20. // 时钟配置
  21. rcu_periph_clock_enable(i2cx_sda_port_rcu);
  22. // 设置复用功能
  23. gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
  24. // 设置输出模式
  25. gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
  26. gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);

  27. /****************** I2C config  **********************/
  28. i2c_deinit(i2cx);
  29. // 时钟配置
  30. rcu_periph_clock_enable(i2cx_rcu);
  31. // I2C速率配置
  32. i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);

  33. // 使能i2c
  34. i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
  35. i2c_enable(i2cx);

  36. // i2c ack enable
  37. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  • 哪个I2C
  • SCL是哪个引脚
  • SDA是哪个引脚
  • 速度是多快
写操作流程开始
  1. /************* start ***********************/
  2. // 等待I2C闲置
  3. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

  4. // start
  5. i2c_start_on_bus(i2cx);

  6. // 等待I2C主设备成功发送起始信号
  7. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
发送设备地址
  1. /************* device address **************/
  2. // 发送设备地址
  3. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  4. // 等待地址发送完成
  5. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  6. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
发送寄存器地址
  1. /************ register address ************/
  2. // 寄存器地址
  3. // 等待发送数据缓冲区为空
  4. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;

  5. // 发送数据
  6. i2c_data_transmit(i2cx, reg);

  7. // 等待数据发送完成
  8. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
数据发送
  1. /***************** data ******************/
  2. // 发送数据
  3. uint32_t i;
  4. for(i = 0; i < data_len; i++) {
  5.     uint32_t d = data[i];

  6.     // 等待发送数据缓冲区为空
  7.     if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

  8.     // 发送数据
  9.     i2c_data_transmit(i2cx, d);

  10.     // 等待数据发送完成
  11.     if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  12. }
停止
  1. /***************** stop ********************/
  2. // stop
  3. i2c_stop_on_bus(i2cx);
  4. if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
读操作流程开始
  1. /************* start ***********************/
  2. // 等待I2C空闲
  3. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

  4. // 发送启动信号
  5. i2c_start_on_bus(i2cx);
  6. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
发送设备地址(写)
  1. /************* device address **************/
  2. // 发送从设备地址
  3. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);

  4. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  5. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
发送寄存器地址
  1. /********** register address **************/
  2. // 等待发送缓冲区        
  3. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;

  4. // 发送寄存器地址
  5. i2c_data_transmit(i2cx, reg);

  6. // 等待发送数据完成        
  7. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;

  8. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
开始
  1. /************* start ***********************/
  2. // 发送再启动信号
  3. i2c_start_on_bus(i2cx);

  4. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;
发送设备地址(读)
  1. /************* device address **************/
  2. // 发送从设备地址
  3. i2c_master_addressing(i2cx, address, I2C_RECEIVER);
  4. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
  5. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

  6. //ack
  7. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  8. i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  9. if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;
数据读取
  1. /************* data **************/
  2. //ack
  3. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  4. i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  5. if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;

  6. // 读取数据
  7. uint8_t i;
  8. for (i = 0; i < len; i++) {
  9.     if(i != len - 1) {
  10.         // 等待接收缓冲区        
  11.         if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
  12.     }

  13.     // 等待ACK数据发送完成
  14.     // 等待接收缓冲区        
  15.     if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
  16.     data[i] = i2c_data_receive(i2cx);

  17.     if (i == len - 1) {
  18.         // 在读取最后一个字节之前,禁用ACK,并发送停止信号
  19.         // 配置自动NACK
  20.         i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  21.     }
  22. }
结束
  1. /***************** stop ********************/
  2. i2c_stop_on_bus(i2cx);
  3. if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
完整代码

I2C0.H

  1. #ifndef __I2C0_H__
  2. #define __I2C0_H__

  3. #include "systick.h"
  4. #include "gd32f4xx.h"

  5. void I2C0_init();

  6. uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);

  7. uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);

  8. uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);

  9. void I2C0_deinit();

  10. #endif

I2C.C

  1. #include "I2C0.h"

  2. void I2C0_init() {
  3.                 uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
  4.     uint32_t i2cx_scl_port = GPIOB;
  5.     uint32_t i2cx_scl_pin = GPIO_PIN_6;
  6.     uint32_t i2cx_scl_af = GPIO_AF_4;

  7.     uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
  8.     uint32_t i2cx_sda_port = GPIOB;
  9.     uint32_t i2cx_sda_pin = GPIO_PIN_7;
  10.     uint32_t i2cx_sda_af = GPIO_AF_4;

  11.     uint32_t i2cx = I2C0;
  12.     uint32_t i2cx_rcu = RCU_I2C0;
  13.     uint32_t i2cx_speed = 400000;
  14.     /****************** GPIO config **********************/
  15.     // 时钟配置
  16.     rcu_periph_clock_enable(i2cx_scl_port_rcu);
  17.                 // 设置复用功能
  18.     gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
  19.                 // 设置输出模式
  20.     gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
  21.     gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);
  22.    
  23.     // 时钟配置
  24.     rcu_periph_clock_enable(i2cx_sda_port_rcu);
  25.     // 设置复用功能
  26.     gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
  27.                 // 设置输出模式
  28.     gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
  29.     gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);
  30.    
  31.     /****************** I2C config  **********************/
  32.     i2c_deinit(i2cx);
  33.     // 时钟配置
  34.     rcu_periph_clock_enable(i2cx_rcu);
  35.     // I2C速率配置
  36.     i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);

  37.     // 使能i2c
  38.     i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
  39.     i2c_enable(i2cx);

  40.     // i2c ack enable
  41.                 i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  42.     //i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  43.         
  44. }

  45. static uint8_t I2C_wait(uint32_t i2cx, uint32_t flag) {
  46.     uint16_t TIMEOUT = 50000;
  47.     uint16_t cnt = 0;

  48.     while(!i2c_flag_get(i2cx, flag)) {
  49.         cnt++;
  50.         if(cnt > TIMEOUT) return 1;
  51.     }
  52.     return 0;
  53. }

  54. static uint8_t I2C_waitn(uint32_t i2cx, uint32_t flag) {
  55.     uint16_t TIMEOUT = 50000;
  56.     uint16_t cnt = 0;

  57.     while(i2c_flag_get(i2cx, flag)) {
  58.         cnt++;
  59.         if(cnt > TIMEOUT) return 1;
  60.     }
  61.                 return 0;
  62. }


  63. uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {
  64.                 uint32_t i2cx = I2C0;
  65.     uint8_t address = addr << 1;
  66.                
  67.                 /************* start ***********************/
  68.                 // 等待I2C闲置
  69.     if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  70.         
  71.     // start
  72.     i2c_start_on_bus(i2cx);
  73.                
  74.                  // 等待I2C主设备成功发送起始信号
  75.     if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
  76.         
  77.                 /************* device address **************/
  78.     // 发送设备地址
  79.     i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  80.                  // 等待地址发送完成
  81.     if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  82.     i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  83.         
  84.                 /************ register address ************/
  85.     // 寄存器地址
  86.     // 等待发送数据缓冲区为空
  87.     if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  88.                
  89.                 // 发送数据
  90.     i2c_data_transmit(i2cx, reg);

  91.     // 等待数据发送完成
  92.     if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  93.                
  94.                 /***************** data ******************/
  95.     // 发送数据
  96.     uint32_t i;
  97.     for(i = 0; i < data_len; i++) {
  98.         uint32_t d = data[i];

  99.         // 等待发送数据缓冲区为空
  100.         if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

  101.         // 发送数据
  102.         i2c_data_transmit(i2cx, d);

  103.         // 等待数据发送完成
  104.         if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  105.     }
  106.                
  107.                 /***************** stop ********************/
  108.     // stop
  109.     i2c_stop_on_bus(i2cx);
  110.     if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
  111.         
  112.                 return 0;
  113. }

  114. uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {
  115.     uint32_t i2cx = I2C0;
  116.     uint8_t address = addr << 1;
  117.                
  118.                 /************* start ***********************/
  119.                 // 等待I2C闲置
  120.     if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  121.         
  122.     // start
  123.     i2c_start_on_bus(i2cx);
  124.                
  125.                  // 等待I2C主设备成功发送起始信号
  126.     if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
  127.         
  128.                 /************* device address **************/
  129.     // 发送设备地址
  130.     i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  131.                  // 等待地址发送完成
  132.     if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  133.     i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  134.         
  135.                 /************ register address ************/
  136.     // 寄存器地址
  137.     // 等待发送数据缓冲区为空
  138.     if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  139.                
  140.                 // 发送数据
  141.     i2c_data_transmit(i2cx, reg);

  142.     // 等待数据发送完成
  143.     if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  144.                
  145.                 /***************** data ******************/
  146.     // 发送数据
  147.                 do {
  148.         // 等待发送数据缓冲区为空
  149.         if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

  150.         // 发送数据
  151.         i2c_data_transmit(i2cx, *data);
  152.                                 data += offset;

  153.         // 等待数据发送完成
  154.         if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  155.     } while(--len);
  156.                
  157.                 /***************** stop ********************/
  158.     // stop
  159.     i2c_stop_on_bus(i2cx);
  160.     if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
  161.         
  162.                 return 0;
  163. }


  164. void I2C0_deinit() {
  165.         
  166. }


  167. uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  168.                 uint32_t i2cx = I2C0;
  169.                 uint8_t address = addr << 1;
  170.                
  171.                 /************* start ***********************/
  172.     // 等待I2C空闲
  173.                 if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

  174.     // 发送启动信号
  175.     i2c_start_on_bus(i2cx);
  176.                 if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

  177.                 /************* device address **************/
  178.     // 发送从设备地址
  179.     i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  180.                
  181. //                //ack
  182. //                i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  183. //                i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  184. //                if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
  185. //                // i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  186.                
  187.                 if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  188.                 i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

  189.                 /********** register address **************/
  190.                 // 等待发送缓冲区        
  191.     if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  192.    
  193.                 // 发送寄存器地址
  194.     i2c_data_transmit(i2cx, reg);
  195.                
  196.                 // 等待发送数据完成        
  197.     if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;        
  198.                 if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

  199.                 /************* start ***********************/
  200.     // 发送再启动信号
  201.     i2c_start_on_bus(i2cx);
  202.                
  203.                
  204.                 if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;

  205.                 /************* device address **************/
  206.     // 发送从设备地址
  207.     i2c_master_addressing(i2cx, address, I2C_RECEIVER);
  208.                 if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
  209.                 i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);


  210.                 /************* data **************/
  211.                 //ack
  212.                 i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  213.                 i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  214.                 if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;
  215.                
  216.     // 读取数据
  217.                 uint8_t i;
  218.     for (i = 0; i < len; i++) {
  219.                                 if(i != len - 1) {
  220.                                                 // 等待ACK发送完成        
  221.                                                 if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
  222.                                 }
  223.                         
  224.                                 // 等待ACK数据发送完成
  225.                                 // 等待接收缓冲区        
  226.                                 if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
  227.         data[i] = i2c_data_receive(i2cx);
  228.                         
  229.         if (i == len - 1) {
  230.             // 在读取最后一个字节之前,禁用ACK,并发送停止信号
  231.                                                 // 配置自动NACK
  232.                                                 //i2c_ackpos_config(i2cx, I2C_ACKPOS_NEXT);
  233.                                                 //if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 9;
  234.                                                 i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  235.         }
  236.     }
  237.                
  238.                 /***************** stop ********************/
  239.                 i2c_stop_on_bus(i2cx);
  240.                 if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
  241.     return 0;
  242. }













本帖子中包含更多资源

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

×

评论

字数未满800字不予审核  发表于 2024-10-16 13:53
呐咯密密 发表于 2024-10-30 10:12 | 显示全部楼层
请教一下,这个时序图和流程图是用什么软件做的
yangjiaxu 发表于 2024-10-31 21:21 | 显示全部楼层
话说,I2C的挂载数量跟什么有关系?巡检的时候也是点名的方式吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

118

帖子

2

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

15

主题

118

帖子

2

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