iic.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include "iic.h"
  2. // 宏定义
  3. #define SDA_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET)
  4. #define SDA_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET)
  5. #define SCL_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET)
  6. #define SCL_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET)
  7. #define SDA_READ() HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)
  8. void I2C_Delay(void) {
  9. for (volatile int i = 0; i < 120; i++); // 简单延时
  10. }
  11. void I2C_Start(void) {
  12. SDA_HIGH();
  13. SCL_HIGH();
  14. I2C_Delay();
  15. SDA_LOW();// 当SCL为高电平时,SDA从高变低表示开始信号
  16. I2C_Delay();
  17. SCL_LOW();// 开始信号传送完毕,拉低SCL准备数据传输
  18. }
  19. void I2C_Stop(void) {
  20. SDA_LOW();
  21. SCL_HIGH();// 当SCL为高电平时,SDA从低变高表示停止信号
  22. I2C_Delay();
  23. SDA_HIGH();
  24. I2C_Delay();
  25. }
  26. void I2C_SendByte(uint8_t byte) {
  27. for (uint8_t i = 0; i < 8; i++) {
  28. if (byte & 0x80) {
  29. SDA_HIGH();
  30. } else {
  31. SDA_LOW();
  32. }
  33. SCL_HIGH();// 在SCL上升沿时,数据稳定在SDA线上
  34. I2C_Delay();
  35. SCL_LOW();// 在SCL下降沿时,SDA可以改变状态
  36. I2C_Delay();
  37. byte <<= 1;
  38. }
  39. }
  40. //uint8_t I2C_ReadByte(void) {
  41. // uint8_t byte = 0;
  42. // SDA_HIGH(); // Release SDA for reading
  43. // for (uint8_t i = 0; i < 8; i++) {
  44. // SCL_HIGH();
  45. // I2C_Delay();
  46. // byte = (byte << 1) | SDA_READ();
  47. // SCL_LOW();
  48. // I2C_Delay();
  49. // }
  50. // return byte;
  51. //}
  52. uint8_t I2C_WaitAck(void) {
  53. uint8_t ack;
  54. SDA_HIGH(); // 释放 SDA 线,准备接收ACK
  55. SDA_InputMode(); // 切换为输入模式,接收ACK
  56. SCL_HIGH();
  57. I2C_Delay();
  58. ack = SDA_READ(); // 读取ACK信号
  59. SCL_LOW();
  60. SDA_OutputMode(); // 恢复 SDA 为输出模式
  61. return (ack == GPIO_PIN_RESET); // 返回ACK状态
  62. }
  63. void Soft_I2C_Write(uint8_t devAddr, uint8_t regAddr, uint8_t data) {
  64. I2C_Start();
  65. I2C_SendByte(devAddr << 1); // 发送设备地址+写位
  66. if (!I2C_WaitAck()) return; // 等待ACK
  67. I2C_SendByte(regAddr); // 发送寄存器地址
  68. if (!I2C_WaitAck()) return; // 等待ACK
  69. I2C_SendByte(data); // 发送数据
  70. if (!I2C_WaitAck()) return; // 等待ACK
  71. I2C_Stop();
  72. }
  73. void Soft_I2C_Read(uint8_t devAddr, uint8_t regAddr, uint8_t *data) {
  74. I2C_Start();
  75. I2C_SendByte(devAddr << 1); // 发送设备地址+写位
  76. if (!I2C_WaitAck()) return; // 等待ACK
  77. I2C_SendByte(regAddr); // 发送寄存器地址
  78. if (!I2C_WaitAck()) return; // 等待ACK
  79. I2C_Start(); // 重启总线
  80. I2C_SendByte((devAddr << 1) | 1); // 发送设备地址+读位
  81. if (!I2C_WaitAck()) return; // 等待ACK
  82. *data = I2C_ReadByte(); // 读取数据
  83. I2C_Stop();
  84. }
  85. void Soft_I2C_ReadMulti(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t count) {
  86. I2C_Start();
  87. I2C_SendByte(devAddr << 1); // 发送设备地址+写位
  88. if (!I2C_WaitAck()) return; // 等待ACK
  89. I2C_SendByte(regAddr); // 发送寄存器地址
  90. if (!I2C_WaitAck()) return; // 等待ACK
  91. I2C_Start(); // 重启总线
  92. I2C_SendByte((devAddr << 1) | 1); // 发送设备地址+读位
  93. if (!I2C_WaitAck()) return; // 等待ACK
  94. while (count--) {
  95. *data++ = I2C_ReadByte(); // 读取多字节数据
  96. }
  97. I2C_Stop();
  98. }
  99. void SDA_InputMode(void) {
  100. GPIO_InitTypeDef GPIO_InitStruct = {0};
  101. GPIO_InitStruct.Pin = GPIO_PIN_1;
  102. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  103. GPIO_InitStruct.Pull = GPIO_NOPULL;
  104. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  105. }
  106. void SDA_OutputMode(void) {
  107. GPIO_InitTypeDef GPIO_InitStruct = {0};
  108. GPIO_InitStruct.Pin = GPIO_PIN_1;
  109. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  110. GPIO_InitStruct.Pull = GPIO_NOPULL;
  111. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  112. }
  113. uint8_t I2C_ReadByte(void) {
  114. uint8_t byte = 0;
  115. SDA_InputMode(); // 切换SDA为输入模式
  116. for (uint8_t i = 0; i < 8; i++) {
  117. SCL_HIGH();
  118. I2C_Delay();
  119. byte = (byte << 1) | SDA_READ();// 从MSB开始读取
  120. SCL_LOW();
  121. I2C_Delay();
  122. }
  123. SDA_OutputMode(); // 恢复SDA为输出模式
  124. return byte;
  125. }