iic.c 3.9 KB

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