找回密码
 立即注册
查看: 56|回复: 4

利用硬件I2C实现高效率无阻塞读写方法 | 还可以 DMA-I2C

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-07 15:25:14
已绑定手机

3

主题

4

回帖

81

积分

注册会员

积分
81
发表于 3 天前 | 显示全部楼层 |阅读模式
I2C读写巨慢, 即使在400kbit/s下, 读写一个字节数据也要花费20多us, 这太慢了, 每读写一次设备的寄存器数据, 还要设备地址和寄存器地址, 又加了两个字节数据, 我就读了个传感器的两个字节数据而已, 动辄还要花费100us的阻塞时间, 这太浪费资源了
针对这个问题, 我利用硬件I2C及中断配合, 实现了这个没有任何阻塞MCU来读写I2C设备的方法, 效率大大提升
单片机采用stc32g8k64, 主频为40Mhz, 读写LDC1612电感涡流传感器为例来测试异步读写I2C数据

  1. /**
  2. * stc32g8k64 硬件i2c 实现 无阻塞异步执行
  3. * ldc1612 i2c异步读写测试
  4. */
  5. #include <STC32G.h>
  6. #include <stdio.h>
  7. #define FOSC 40000000UL // 主频40M
  8. void Delay1ms(void) //@40.000MHz
  9. {
  10.   unsigned char data i, j;
  11.   i = 39;
  12.   j = 230;
  13.   do
  14.   {
  15.     while (--j)
  16.       ;
  17.   } while (--i);
  18. }
  19. void delay(uint16 ms)
  20. {
  21.   while (ms--)
  22.   {
  23.     Delay1ms();
  24.   }
  25. }
  26. // ---------------------- uart1打印测试用 开始----------------------------
  27. bit busy;
  28. char wptr;
  29. char rptr;
  30. char buffer[16];
  31. void Uart1_Isr(void) interrupt 4
  32. {
  33.   if (TI)
  34.   {
  35.     TI = 0;
  36.     busy = 0;
  37.   }
  38.   if (RI)
  39.   {
  40.     RI = 0;
  41.     buffer[wptr++] = SBUF;
  42.     wptr &= 0x0f;
  43.   }
  44. }
  45. void Uart1_Init(void) // 1000000bps@40.000MHz
  46. {
  47.   SCON = 0x50;  // 8位数据,可变波特率
  48.   AUXR |= 0x40; // 定时器时钟1T模式
  49.   AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器
  50.   TMOD &= 0x0F; // 设置定时器模式
  51.   TL1 = 0xF6;   // 设置定时初始值
  52.   TH1 = 0xFF;   // 设置定时初始值
  53.   ET1 = 0;      // 禁止定时器中断
  54.   TR1 = 1;      // 定时器1开始计时
  55.   ES = 1;       // 使能串口1中断
  56. }
  57. void UartSend(char dat)
  58. {
  59.   while (busy)
  60.     ;
  61.   busy = 1;
  62.   SBUF = dat;
  63. }
  64. void UartSendStr(char *p)
  65. {
  66.   while (*p)
  67.   {
  68.     UartSend(*p++);
  69.   }
  70. }
  71. char sendNumberCharArr[20];
  72. // 实现一个uint32转char的方法
  73. void numberToChar(uint32 number, char *buffer)
  74. {
  75.   char temp[12]; // Maximum digits for uint32 + null terminator
  76.   int i = 0;
  77.   int j = 0;
  78.   // Handle zero case
  79.   if (number == 0)
  80.   {
  81.     buffer[0] = '0';
  82.     buffer[1] = '\0';
  83.     return;
  84.   }
  85.   // Extract digits in reverse order
  86.   while (number > 0)
  87.   {
  88.     temp[i++] = (number % 10) + '0';
  89.     number /= 10;
  90.   }
  91.   // Reverse the string to correct order
  92.   while (i > 0)
  93.   {
  94.     buffer[j++] = temp[--i];
  95.   }
  96.   buffer[j] = '\0'; // Null terminate
  97. }
  98. // ---------------------- uart1打印测试用 结束----------------------------
  99. //------------------------------- I2C异步执行栈 开始 -----------------------------
  100. sbit ET4 = IE2 ^ 6;
  101. typedef void (*AsyncFunc)(void);
  102. AsyncFunc AsyncFuncNext_callback = NULL;
  103. // 延时执行下一个任务
  104. void AsyncFuncNext(AsyncFunc callback, uint16 usDelay)
  105. {
  106.   uint16 totalTime = 0xffff - usDelay;
  107.   T4T3M &= ~0x80;
  108.   ET4 = 0;
  109.   T4L = totalTime & 0xff; // 设置定时初始值
  110.   T4H = totalTime >> 8;   // 设置定时初始值
  111.   AsyncFuncNext_callback = callback;
  112.   T4T3M |= 0x80; // 定时器4开始计时
  113.   ET4 = 1;       // 使能中断
  114. }
  115. // 定时器用于异步执行
  116. void Timer4_Init(void) //@40.000MHz
  117. {
  118.   // 1us计时一个数字
  119.   TM4PS = 0x27;   // 设置定时器时钟预分频
  120.   T4T3M |= 0x20;  // 定时器时钟1T模式
  121.   T4L = 0x00;     // 设置定时初始值
  122.   T4H = 0x00;     // 设置定时初始值
  123.   T4T3M &= ~0x80; // 定时器4停止计时
  124.   ET4 = 0;
  125. }
  126. // 定时器4用作异步执行定时器, 延时触发下一步的执行函数
  127. void Timer4_async_next_isr() interrupt 20
  128. {
  129.   T4T3M &= ~0x80;
  130.   ET4 = 0;
  131.   if (AsyncFuncNext_callback != NULL)
  132.   {
  133.     AsyncFuncNext_callback();
  134.   }
  135. }
  136. AsyncFunc I2C_Isr_callback = NULL; // I2C中断回调函数
  137. void I2C_Isr() interrupt 24        // I2C中断
  138. {
  139.   if (I2CMSST & 0x40)
  140.   {
  141.     I2CMSST &= ~0x40; // 清中断标志
  142.     if (I2C_Isr_callback != NULL)
  143.     {
  144.       I2C_Isr_callback();
  145.     }
  146.   }
  147. }
  148. //------------------------------- 异步执行栈 结束 -----------------------------
  149. //------------------------------- I2C寄存器操作 开始 --------------------------
  150. void Wait_I2C()
  151. {
  152.   while (!(I2CMSST & 0x40))
  153.     ;
  154.   I2CMSST &= ~0x40;
  155. }
  156. uint8 i2c_readRegister16Async_addr = 0;               // readRegister16Async 地址参数
  157. uint8 i2c_readRegister16Async_reg = 0;                // readRegister16Async 寄存器参数
  158. uint8 i2c_readRegister16Async_step = 0;               // readRegister16Async 异步执行步骤
  159. uint16 i2c_readRegister16Async_value = 0;             // readRegister16Async 读取数据返回值
  160. AsyncFunc i2c_readRegister16Async_endCallback = NULL; // readRegister16Async 读取数据完成回调
  161. void i2c_readRegister16Async_timeout()
  162. {
  163.   i2c_readRegister16Async_value = 0;
  164.   i2c_readRegister16Async_step = 0;
  165.   I2C_Isr_callback = NULL;
  166.   I2CMSST = 0x00;
  167.   if (i2c_readRegister16Async_endCallback != NULL)
  168.   {
  169.     i2c_readRegister16Async_endCallback();
  170.   }
  171. }
  172. // I2C异步读取, 16位寄存器
  173. void i2c_readRegister16Async()
  174. {
  175.   if (i2c_readRegister16Async_step == 1)
  176.   {
  177.     I2CTXD = i2c_readRegister16Async_addr << 1; // 发送i2c地址
  178.     I2CMSCR = 0x89;                             // 中断使能, 发送起始信号+设备地址+写信号
  179.     i2c_readRegister16Async_step++;
  180.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  181.     return;
  182.   }
  183.   if (i2c_readRegister16Async_step == 2)
  184.   {
  185.     I2CTXD = i2c_readRegister16Async_reg; // 发送读取寄存器地址
  186.     I2CMSCR = 0x8A;                       // 中断使能,  发送数据命令+接收ACK命令
  187.     i2c_readRegister16Async_step++;
  188.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  189.     return;
  190.   }
  191.   if (i2c_readRegister16Async_step == 3)
  192.   {
  193.     I2CTXD = i2c_readRegister16Async_addr << 1 | 0x01; // 发送i2c地址+读取数据
  194.     I2CMSCR = 0x89;                                    // 中断使能,  发送起始信号+设备地址+写信号
  195.     i2c_readRegister16Async_step++;
  196.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  197.     return;
  198.   }
  199.   if (i2c_readRegister16Async_step == 4)
  200.   {
  201.     I2CMSST = 0x00; // 设置 ACK 信号
  202.     I2CMSCR = 0x8B; // 中断使能, 接收数据命令+发送ACK(0)命令
  203.     i2c_readRegister16Async_step++;
  204.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  205.     return;
  206.   }
  207.   if (i2c_readRegister16Async_step == 5)
  208.   {
  209.     i2c_readRegister16Async_value = I2CRXD;
  210.     i2c_readRegister16Async_value <<= 8;
  211.     I2CMSST = 0x01; // 设置 NAK 信号
  212.     I2CMSCR = 0x8C; // 中断使能, 接收数据命令+发送NAK(1)命令
  213.     i2c_readRegister16Async_step++;
  214.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  215.     return;
  216.   }
  217.   if (i2c_readRegister16Async_step == 6)
  218.   {
  219.     i2c_readRegister16Async_value |= I2CRXD;
  220.     i2c_readRegister16Async_step++;
  221.     I2CMSCR = 0x86; // 中断使能, 发送 STOP 命令
  222.     AsyncFuncNext(i2c_readRegister16Async_timeout, 200);
  223.     return;
  224.   }
  225.   if (i2c_readRegister16Async_step == 7)
  226.   {
  227.     I2C_Isr_callback = NULL;
  228.     i2c_readRegister16Async_step = 0;
  229.     AsyncFuncNext(i2c_readRegister16Async_endCallback, 20);
  230.     return;
  231.   }
  232. }
  233. // 使用异步来读取i2c数据
  234. void i2c_readRegister16Async_start(uint8 addr, uint8 reg, AsyncFunc readEndCallback)
  235. {
  236.   i2c_readRegister16Async_addr = addr;
  237.   i2c_readRegister16Async_reg = reg;
  238.   i2c_readRegister16Async_value = 0;
  239.   i2c_readRegister16Async_step = 1;
  240.   I2C_Isr_callback = i2c_readRegister16Async;
  241.   i2c_readRegister16Async_endCallback = readEndCallback;
  242.   i2c_readRegister16Async();
  243. }
  244. // I2C同步读取, 16位寄存器
  245. uint16 i2c_readRegister16(uint8 addr, uint8 reg)
  246. {
  247.   uint16 readDataValue = 0;
  248.   I2CTXD = addr << 1; // 写数据到数据缓冲区
  249.   I2CMSCR = 0x09;     // 发送起始信号+设备地址+写信号
  250.   Wait_I2C();
  251.   I2CTXD = reg;   // 写数据到数据缓冲区
  252.   I2CMSCR = 0x0A; // 发送数据命令+接收ACK命令
  253.   Wait_I2C();
  254.   I2CTXD = addr << 1 | 0x01; // 发送i2c地址+读取数据
  255.   I2CMSCR = 0x09;            // 发送起始信号+设备地址+写信号
  256.   Wait_I2C();
  257.   I2CMSST = 0x00; // 设置 ACK 信号
  258.   I2CMSCR = 0x0B; // 接收数据命令+发送ACK(0)命令
  259.   Wait_I2C();
  260.   readDataValue = I2CRXD;
  261.   readDataValue <<= 8;
  262.   I2CMSST = 0x01; // 设置 NAK 信号
  263.   I2CMSCR = 0x0C; // 接收数据命令+发送NAK(1)命令
  264.   Wait_I2C();
  265.   readDataValue |= I2CRXD;
  266.   I2CMSCR = 0x06; // 发送 STOP 命令
  267.   Wait_I2C();
  268.   return readDataValue;
  269. }
  270. uint8 i2c_writeRegister16Async_addr = 0;               // writeRegister16Async 地址参数
  271. uint8 i2c_writeRegister16Async_reg = 0;                // writeRegister16Async 寄存器参数
  272. uint8 i2c_writeRegister16Async_step = 0;               // writeRegister16Async 异步执行步骤
  273. uint16 i2c_writeRegister16Async_value = 0;             // writeRegister16Async 写入数据
  274. AsyncFunc i2c_writeRegister16Async_endCallback = NULL; // writeRegister16Async 读取数据完成回调
  275. // 异步写16位寄存器超时
  276. void i2c_writeRegister16Async_timeout()
  277. {
  278.   i2c_writeRegister16Async_value = 0;
  279.   i2c_writeRegister16Async_step = 0;
  280.   I2C_Isr_callback = NULL;
  281.   I2CMSST = 0x00;
  282.   if (i2c_writeRegister16Async_endCallback != NULL)
  283.   {
  284.     i2c_writeRegister16Async_endCallback();
  285.   }
  286. }
  287. // 异步写16位寄存器
  288. void i2c_writeRegister16Async()
  289. {
  290.   if (i2c_writeRegister16Async_step == 1)
  291.   {
  292.     I2CTXD = i2c_writeRegister16Async_addr << 1; // 写数据到数据缓冲区
  293.     I2CMSCR = 0x89;                              // 发送起始信号+设备地址+写信号
  294.     i2c_writeRegister16Async_step++;
  295.     AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);
  296.     return;
  297.   }
  298.   if (i2c_writeRegister16Async_step == 2)
  299.   {
  300.     I2CTXD = i2c_writeRegister16Async_reg; // 写数据到数据缓冲区
  301.     I2CMSCR = 0x8A;                        // 发送数据命令+接收ACK命令
  302.     i2c_writeRegister16Async_step++;
  303.     AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);
  304.     return;
  305.   }
  306.   if (i2c_writeRegister16Async_step == 3)
  307.   {
  308.     I2CTXD = (i2c_writeRegister16Async_value >> 8) & 0xFF; // 写数据到数据缓冲区
  309.     I2CMSCR = 0x8A;                                        // 发送数据命令+接收ACK命令
  310.     i2c_writeRegister16Async_step++;
  311.     AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);
  312.     return;
  313.   }
  314.   if (i2c_writeRegister16Async_step == 4)
  315.   {
  316.     I2CTXD = i2c_writeRegister16Async_value & 0xFF; // 写数据到数据缓冲区
  317.     I2CMSCR = 0x8A;                                 // 发送数据命令+接收ACK命令
  318.     i2c_writeRegister16Async_step++;
  319.     AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);
  320.     return;
  321.   }
  322.   if (i2c_writeRegister16Async_step == 5)
  323.   {
  324.     I2CMSCR = 0x86; // 发送 STOP 命令
  325.     i2c_writeRegister16Async_step++;
  326.     AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);
  327.     return;
  328.   }
  329.   if (i2c_writeRegister16Async_step == 6)
  330.   {
  331.     I2C_Isr_callback = NULL;
  332.     i2c_writeRegister16Async_step = 0;
  333.     AsyncFuncNext(i2c_writeRegister16Async_endCallback, 20);
  334.     return;
  335.   }
  336. }
  337. // 使用异步来写入i2c数据
  338. void i2c_writeRegister16Async_start(uint8 addr, uint8 reg, uint16 value, AsyncFunc writeEndCallback)
  339. {
  340.   i2c_writeRegister16Async_addr = addr;
  341.   i2c_writeRegister16Async_reg = reg;
  342.   i2c_writeRegister16Async_value = value;
  343.   I2C_Isr_callback = i2c_writeRegister16Async;
  344.   i2c_writeRegister16Async_endCallback = writeEndCallback;
  345.   i2c_writeRegister16Async_step = 1;
  346.   i2c_writeRegister16Async();
  347. }
  348. // 同步写16位寄存器
  349. void i2c_writeRegister16(uint8 addr, uint8 reg, uint16 value)
  350. {
  351.   I2CTXD = addr << 1; // 写数据到数据缓冲区
  352.   I2CMSCR = 0x09;     // 发送起始信号+设备地址+写信号
  353.   Wait_I2C();
  354.   I2CTXD = reg;   // 写数据到数据缓冲区
  355.   I2CMSCR = 0x0A; // 发送数据命令+接收ACK命令
  356.   Wait_I2C();
  357.   I2CTXD = (value >> 8) & 0xFF; // 写数据到数据缓冲区
  358.   I2CMSCR = 0x0A;               // 发送数据命令+接收ACK命令
  359.   Wait_I2C();
  360.   I2CTXD = value & 0xFF; // 写数据到数据缓冲区
  361.   I2CMSCR = 0x0A;        // 发送数据命令+接收ACK命令
  362.   Wait_I2C();
  363.   I2CMSCR = 0x06; // 发送 STOP 命令
  364.   Wait_I2C();
  365. }
  366. //------------------------------- I2C寄存器操作 结束 --------------------------
  367. //------------------------------- LDC1612操作 开始 ----------------------------
  368. #define SD_PIN P1_6    // SD引脚
  369. #define INTB_PIN P1_7  // 数据就绪中断
  370. #define CLKIN_PIN P1_3 // 外部时钟引脚
  371. // LDC1612 寄存器地址
  372. #define LDC1612_ADDR 0x2A           // I2C地址 (ADDR接地时)
  373. #define REG_DATA_MSB_CH0 0x00       // 通道0数据高16位
  374. #define REG_DATA_LSB_CH0 0x01       // 通道0数据低16位
  375. #define REG_DATA_MSB_CH1 0x02       // 通道1数据高16位
  376. #define REG_DATA_LSB_CH1 0x03       // 通道1数据低16位
  377. #define REG_RCOUNT_CH0 0x08         // 通道0转换计数
  378. #define REG_RCOUNT_CH1 0x09         // 通道1转换计数
  379. #define REG_SETTLE_CNT_CH0 0x10     // 通道0稳定计数
  380. #define REG_SETTLE_CNT_CH1 0x11     // 通道1稳定计数
  381. #define REG_CLOCK_DIVIDERS_CH0 0x14 // 通道0时钟分频
  382. #define REG_CLOCK_DIVIDERS_CH1 0x15 // 通道1时钟分频
  383. #define REG_STATUS 0x18             // 状态寄存器
  384. #define REG_ERROR_CONFIG 0x19       // 错误配置
  385. #define REG_CONFIG 0x1A             // 配置寄存器
  386. #define REG_MUX_CONFIG 0x1B         // 多路复用配置
  387. #define REG_RESET_DEV 0x1C          // 设备复位
  388. #define REG_DRIVE_CURRENT_CH0 0x1E  // 通道0驱动电流
  389. #define REG_DRIVE_CURRENT_CH1 0x1F  // 通道1驱动电流
  390. // 配置常量
  391. #define CONVERSION_TIME 0x0850 // 转换时间设置
  392. #define SETTLE_TIME 0x0400     // 稳定时间设置
  393. #define CLOCK_DIVIDER 0x1001   // 时钟分频设置
  394. #define DRIVE_CURRENT 0x1C00   // 驱动电流设置 (最大电流)
  395. // 全局变量
  396. uint32 ch0_value = 0;
  397. uint32 ch1_value = 0;
  398. uint8 LDC1612_read_ready = 0;
  399. uint8 LDC1612_data_ready = 0;
  400. uint16 LDC1612_readDataAsync_msb = 0;
  401. uint16 LDC1612_readDataAsync_lsb = 0;
  402. uint16 LDC1612_readDataAsync_step = 0;
  403. uint8 LDC1612_readDataAsync_isStart = 0;
  404. // 异步读取传感器数据
  405. void LDC1612_readDataAsync()
  406. {
  407.   if (LDC1612_readDataAsync_step == 1)
  408.   {
  409.     LDC1612_readDataAsync_step++;
  410.     AsyncFuncNext(LDC1612_readDataAsync, 100);
  411.     i2c_readRegister16Async_start(LDC1612_ADDR, REG_STATUS, LDC1612_readDataAsync);
  412.     return;
  413.   }
  414.   if (LDC1612_readDataAsync_step == 2)
  415.   {
  416.     LDC1612_readDataAsync_step++;
  417.     i2c_readRegister16Async_start(LDC1612_ADDR, REG_DATA_MSB_CH0, LDC1612_readDataAsync);
  418.     return;
  419.   }
  420.   if (LDC1612_readDataAsync_step == 3)
  421.   {
  422.     LDC1612_readDataAsync_step++;
  423.     LDC1612_readDataAsync_msb = i2c_readRegister16Async_value;
  424.     i2c_readRegister16Async_start(LDC1612_ADDR, REG_DATA_LSB_CH0, LDC1612_readDataAsync);
  425.     return;
  426.   }
  427.   if (LDC1612_readDataAsync_step == 4)
  428.   {
  429.     LDC1612_readDataAsync_step = 0;
  430.     LDC1612_readDataAsync_lsb = i2c_readRegister16Async_value;
  431.     ch0_value = ((uint32)LDC1612_readDataAsync_msb << 16) | LDC1612_readDataAsync_lsb;
  432.     ch0_value &= 0x0FFFFFFF; // 保留28位有效数据
  433.     ch0_value >>= 12;        // 转为16位数据
  434.     LDC1612_data_ready = 1;  // 读取数据完成
  435.     return;
  436.   }
  437. }
  438. // 同步读取传感器数据
  439. void LDC1612_readData()
  440. {
  441.   uint16 msb = 0;
  442.   uint16 lsb = 0;
  443.   // 读取状态寄存器
  444.   uint16 status = i2c_readRegister16(LDC1612_ADDR, REG_STATUS);
  445.   // 检查错误标志
  446.   if (status & 0x0008)
  447.   {
  448.     // Serial.println("Error: Amplitude too low!");
  449.   }
  450.   if (status & 0x0010)
  451.   {
  452.     // Serial.println("Error: Timeout occurred!");
  453.   }
  454.   // 读取通道0数据
  455.   msb = i2c_readRegister16(LDC1612_ADDR, REG_DATA_MSB_CH0);
  456.   lsb = i2c_readRegister16(LDC1612_ADDR, REG_DATA_LSB_CH0);
  457.   ch0_value = ((uint32)msb << 16) | lsb;
  458.   ch0_value &= 0x0FFFFFFF; // 保留28位有效数据
  459.   ch0_value >>= 12;
  460.   LDC1612_data_ready = 1; // 读取数据完成
  461. }
  462. uint8 LDC1612_writeInitReg_step = 0;
  463. // 异步方法写入寄存器值
  464. void LDC1612_writeInitRegAsync()
  465. {
  466.   // 配置通道0
  467.   if (LDC1612_writeInitReg_step == 1)
  468.   {
  469.     LDC1612_writeInitReg_step++;
  470.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_RCOUNT_CH0, CONVERSION_TIME, LDC1612_writeInitRegAsync);
  471.     return;
  472.   }
  473.   if (LDC1612_writeInitReg_step == 2)
  474.   {
  475.     LDC1612_writeInitReg_step++;
  476.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_SETTLE_CNT_CH0, SETTLE_TIME, LDC1612_writeInitRegAsync);
  477.     return;
  478.   }
  479.   if (LDC1612_writeInitReg_step == 3)
  480.   {
  481.     LDC1612_writeInitReg_step++;
  482.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_CLOCK_DIVIDERS_CH0, CLOCK_DIVIDER, LDC1612_writeInitRegAsync);
  483.     return;
  484.   }
  485.   if (LDC1612_writeInitReg_step == 4)
  486.   {
  487.     LDC1612_writeInitReg_step++;
  488.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_DRIVE_CURRENT_CH0, DRIVE_CURRENT, LDC1612_writeInitRegAsync);
  489.     return;
  490.   }
  491.   // 配置错误检测
  492.   if (LDC1612_writeInitReg_step == 5)
  493.   {
  494.     LDC1612_writeInitReg_step++;
  495.     // 启用数据输出错误检测
  496.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_ERROR_CONFIG, 0x0001, LDC1612_writeInitRegAsync);
  497.     return;
  498.   }
  499.   // 配置多路复用器 - 只启用通道0
  500.   if (LDC1612_writeInitReg_step == 6)
  501.   {
  502.     LDC1612_writeInitReg_step++;
  503.     // 只扫描通道0,去抖动计数=1
  504.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_MUX_CONFIG, 0x0208, LDC1612_writeInitRegAsync);
  505.     return;
  506.   }
  507.   // 配置主配置寄存器
  508.   if (LDC1612_writeInitReg_step == 7)
  509.   {
  510.     LDC1612_writeInitReg_step++;
  511.     // 启用传感器,单通道模式
  512.     i2c_writeRegister16Async_start(LDC1612_ADDR, REG_CONFIG, 0x1401, LDC1612_writeInitRegAsync);
  513.     return;
  514.   }
  515.   // 初始化完成
  516.   if (LDC1612_writeInitReg_step == 8)
  517.   {
  518.     LDC1612_writeInitReg_step = 0;
  519.     return;
  520.   }
  521. }
  522. // 同步方法写入寄存器值
  523. void LDC1612_writeInitReg()
  524. {
  525.   // 配置通道0
  526.   i2c_writeRegister16(LDC1612_ADDR, REG_RCOUNT_CH0, CONVERSION_TIME);
  527.   i2c_writeRegister16(LDC1612_ADDR, REG_SETTLE_CNT_CH0, SETTLE_TIME);
  528.   i2c_writeRegister16(LDC1612_ADDR, REG_CLOCK_DIVIDERS_CH0, CLOCK_DIVIDER);
  529.   i2c_writeRegister16(LDC1612_ADDR, REG_DRIVE_CURRENT_CH0, DRIVE_CURRENT);
  530.   // 配置错误检测
  531.   i2c_writeRegister16(LDC1612_ADDR, REG_ERROR_CONFIG, 0x0001); // 启用数据输出错误检测
  532.   // 配置多路复用器 - 只启用通道0
  533.   i2c_writeRegister16(LDC1612_ADDR, REG_MUX_CONFIG, 0x0208); // 只扫描通道0,去抖动计数=1
  534.   // 配置主配置寄存器
  535.   i2c_writeRegister16(LDC1612_ADDR, REG_CONFIG, 0x1401); // 启用传感器,单通道模式
  536. }
  537. // LDC1612 中断服务程序 (数据就绪)
  538. void LDC1612_ready_isr() interrupt 38
  539. {
  540.   unsigned char intf;
  541.   intf = P1INTF;
  542.   if (intf)
  543.   {
  544.     P1INTF = 0x00;
  545.     // P1.7 口中断
  546.     if (intf & 0x80)
  547.     {
  548.       LDC1612_read_ready = 1;
  549.     }
  550.   }
  551. }
  552. void initI2C()
  553. {
  554.   P_SW2 = 0x80; // 使能访问XFR
  555.   P1PU |= 0x30; // P1.4和P1.5使能4K上拉电阻
  556.   P1M1 |= 0x10;
  557.   P1M0 |= 0x10; // P1.4(SDA)开漏输出
  558.   P1M1 |= 0x20;
  559.   P1M0 |= 0x20; // P1.5(SCL)开漏输出
  560.   // I2C总线速度计算: SYSCLK / 2 / (MSSPEED * 2 + 4)
  561.   // 对于400KHz: MSSPEED = (40M / 400K / 2 - 4) / 2 = 23 (0x17)
  562.   I2CCFG = 0x80 | 0x40 | 0x17; // 使能I2C + 主机模式 + 400KHz速度
  563.   I2CMSST = 0x00;              // 清除状态寄存器
  564.   IP2H |= 0x40;                // 设置I2c中断的优先级为高
  565.   IP2 |= 0x40;                 // 设置I2c中断的优先级为高
  566. }
  567. // LDC1612初始化
  568. void initLDC1612()
  569. {
  570.   // p1.6 SD
  571.   P1M1 &= ~0x40;
  572.   P1M0 |= 0x40; // 推挽输出
  573.   // p1.3 CLKIN_PIN
  574.   P1M1 &= ~0x08;
  575.   P1M0 |= 0x08; // 推挽输出
  576.   // p1.7 INTB 数据准备好中断
  577.   P1M1 |= 0x80;
  578.   P1M0 &= ~0x80; // 高阻输入
  579.   SD_PIN = 0;    // 低电平使能ldc1612
  580.   CLKIN_PIN = 0; // 禁用外部时钟引脚
  581.   P1IM0 = 0x00;  // 下降沿中断
  582.   P1IM1 = 0x00;
  583.   P1INTE = 0x80; // 使能 p1.7 口中断
  584.   Timer4_Init();
  585.   initI2C();
  586.   delay(50);
  587.   // 同步方法写入寄存器
  588.   // LDC1612_writeInitReg();
  589.   // 异步方式写入寄存器
  590.   LDC1612_writeInitReg_step = 1;
  591.   LDC1612_writeInitRegAsync();
  592. }
  593. //------------------------------- LDC1612操作 结束 ----------------------------
  594. void main(void)
  595. {
  596.   P_SW2 = 0x80; // 使能访问XFR
  597.   WTST = 0;     // 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  598.   CKCON = 0;    // 提高访问XRAM速度
  599.   Uart1_Init(); // 初始化串口 1M波特率
  600.   EA = 1;       // 允许总中断
  601.   initLDC1612();
  602.   UartSendStr("setup\n");
  603.   while (1)
  604.   {
  605.     if (LDC1612_read_ready == 1)
  606.     {
  607.       LDC1612_read_ready = 0;
  608.       // 同步读取传感器数据
  609.       // LDC1612_readData();
  610.       // i2c无阻塞异步读取传感器数据
  611.       LDC1612_readDataAsync_step = 1;
  612.       LDC1612_readDataAsync();
  613.     }
  614.     if (LDC1612_data_ready == 1)
  615.     {
  616.       LDC1612_data_ready = 0;
  617.       UartSendStr("LDC1612 data:");
  618.       numberToChar(ch0_value, sendNumberCharArr);
  619.       UartSendStr(sendNumberCharArr);
  620.       UartSendStr("\n");
  621.     }
  622.   }
  623. }
复制代码





回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:152
  • 最近打卡:2025-08-08 08:22:43

766

主题

1万

回帖

1万

积分

管理员

积分
18594
发表于 前天 08:21 | 显示全部楼层
还可以 DMA-I2C
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-07 15:25:14
已绑定手机

3

主题

4

回帖

81

积分

注册会员

积分
81
发表于 前天 09:31 | 显示全部楼层
我看官方的demo读取数据时,
DMA-I2C在发送设备地址和寄存器地址时还是是阻塞的,
后边的数据传输是启动的DMA,
写入时可以全部使用DMA来操作, 我试试

screenshot-20250806-092927.png

点评

这个是硬件外设的查询模式,不是DMA阻塞 [attachimg]110877[/attachimg]  详情 回复 发表于 前天 23:37
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:261
  • 最近打卡:2025-08-08 08:57:29
已绑定手机

78

主题

2819

回帖

5829

积分

荣誉版主

无情的代码机器

积分
5829
发表于 前天 23:37 | 显示全部楼层
chen*** 发表于 2025-8-6 09:31
我看官方的demo读取数据时,
DMA-I2C在发送设备地址和寄存器地址时还是是阻塞的,
后边的数据传输是启动的D ...

这个是硬件外设的查询模式,不是DMA阻塞

截图202508062337219727.jpg
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-07 15:25:14
已绑定手机

3

主题

4

回帖

81

积分

注册会员

积分
81
发表于 昨天 15:25 | 显示全部楼层
erci*** 发表于 2025-8-6 23:37
这个是硬件外设的查询模式,不是DMA阻塞

我知道这是查询模式清零的, I2C读取数据之前得需要先写入设备地址和寄存器地址, 后面的读取数据是走dma,没有阻塞, 但是开头需要先发送设备地址和寄存器地址, 按照这样写的话, 就又成为阻塞形式了, 期间cpu啥也干不了, 我想要的是没有任何while死循环的零阻塞I2C数据读写
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-8-8 15:30 , Processed in 0.126655 second(s), 77 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表