首先說明:
1.SMBus和I2C的區別
? ? ? ? 我曾嘗試用江科大的I2C底層去直接讀取該模塊,但是無法成功,之后AI生成的的代碼也無法成功。
? ? ? ? 思來想去最大的可能就是SMBus這個協議的問題,根據百度得到的結果如下:

鏈接:
smbus協議_百度百科https://baike.baidu.com/item/smbus%E5%8D%8F%E8%AE%AE/56360572.個人見解(希望有知道的可以補充說明或糾錯):
? ? ? ? ①SMBus協議是I2C的pro版本,對時序要求更加嚴格。
? ? ? ? ②特別是在超時方面,I2C可能是在SCL的對應電平下改變SDA的電平,那就能正常操作,不在意時間多久;但SMBus則是要求了SCL在對應電平下,SDA應該在什么時候做出改變,否則超時。
? ? ? ? ? ? ? ?
代碼:
以下是我用STM32F103C8T6能讀取到我認為正常數據的代碼,若不滿足讀者要求,請自行微調。
若對你有幫助,請點贊收藏~
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"//************** 宏定義 **************
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB#define Nack_counter 10
#define uint unsigned int
#define uchar unsigned char//************** 全局變量 **************
volatile uchar DataH, DataL, Pecreg;
volatile uint temp;
//************** 函數聲明 **************
void I2C_GPIO_Init(void);
void start_bit(void);
void stop_bit(void);
void send_bit(uchar bit_val);
uchar rx_byte(void);
uchar tx_byte(uchar dat_byte);
void delay_us(uint us);
uint memread(void);//************** GPIO初始化 **************
void I2C_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB時鐘// SCL和SDA配置為開漏輸出GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 開漏輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);// 初始狀態拉高GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN);
}//************** 延時函數(72MHz主頻)**************
void delay_us(uint us) {us *= 72/5; // 72MHz下1us需要72個周期(實測需校準)while(us--) {__NOP();}
}//************** I2C起始信號 **************
void start_bit(void) {GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(5); // 保持時間≥4.7usGPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);delay_us(5);GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
}//************** I2C停止信號 **************
void stop_bit(void) {GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);delay_us(5);GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(5);GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
}//************** 發送單bit **************
void send_bit(uchar bit_val) {if(bit_val) {GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);} else {GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);}delay_us(2);GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(5); // SCL高電平≥4.0usGPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(2);
}//************** 接收單bit **************
uchar receive_bit(void) {uchar bit_val;GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN); // 釋放SDA線delay_us(2);GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(5);bit_val = GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN);GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);delay_us(2);return bit_val;
}//************** 發送單字節 **************
//void tx_byte(uchar dat_byte) {
// uchar i, n = Nack_counter;
//
//TX_again:
// for(i = 0; i < 8; i++) {
// send_bit((dat_byte & 0x80) ? 1 : 0);
// dat_byte <<= 1;
// }
//
// if(receive_bit()) { // 檢測NACK
// stop_bit();
// if(n--) {
// start_bit();
// goto TX_again;
// }
// }
//}uchar tx_byte(uchar dat_byte)
{for(uchar i = 0; i < 8; i++) {send_bit((dat_byte & 0x80) ? 1 : 0);dat_byte <<= 1;}return !receive_bit(); // 返回1=ACK, 0=NACK
}//************** 接收單字節 **************
uchar rx_byte(void) {uchar i, dat = 0;for(i = 0; i < 8; i++) {dat <<= 1;if(receive_bit()) dat |= 0x01;}send_bit(0); // 發送ACKreturn dat;
}//************** 讀取溫度數據 **************
//uint memread(void) {
// start_bit();
// tx_byte(0x00); // MLX90614地址+寫
// tx_byte(0x07); // 讀取RAM命令
//
// start_bit();
// tx_byte(0xB5); // MLX90614地址+讀
//
// DataL = rx_byte();
// DataH = rx_byte();
// Pecreg = rx_byte();
//
// stop_bit();
// return (DataH << 8) | DataL;
//}
uint memread(void) {start_bit();if (!tx_byte(0xB4)) { // 發送地址+寫stop_bit();return 0xFFFF;}if (!tx_byte(0x07)) { // 發送命令(讀取RAM)stop_bit();return 0xFFFF;}start_bit();if (!tx_byte(0xB5)) { // 發送地址+讀stop_bit();return 0xFFFF;}DataL = rx_byte(); // 低字節DataH = rx_byte(); // 高字節Pecreg = rx_byte(); // PEC(可選)stop_bit();return ((DataH << 8) | DataL)*0.02 - 273.15;
}//************** 主函數 **************
int main(void) {SystemInit(); // 系統時鐘配置為72MHzI2C_GPIO_Init();while(1) {temp = memread();// 此處添加溫度處理代碼delay_us(20000); // 延時20ms}
}
使用方法:
①直接copy到自己的main.c
②下載到STM32F103C8T6板子上,并保持連接。根據下面代碼接線,供電3.3V
#define I2C_SCL_PIN ? ?GPIO_Pin_6
#define I2C_SDA_PIN ? ?GPIO_Pin_7
#define I2C_GPIO_PORT ?GPIOB
③使用debug模式查看數據,具體如下:
若點擊運行后temp數據不變,則需要進行下面這一步: