實現目標
1、掌握IIC總線基礎知識;
2、會使用軟件模擬IIC總線和使用STM32硬件IIC總線;
3、 學會STM32CubeMX軟件關于IIC的配置;
4、掌握SHT20溫濕度傳感器的驅動;
5、具體目標:(1)用STM32硬件IIC驅動SHT20,上位機串口助手打印溫濕度;(2)用軟件模擬IIC驅動SHT20,上位機串口助手打印溫濕度(只提供代碼)。
一、IIC概述
1.1 IIC定義
IIC , 即? I2C,全稱 Inter-Integrated Circuit,是I2C Bus簡稱,中文叫集成電路總線 ,它是一種串行通信總線,使用多主從架構,由飛利浦公司在1980年代為了讓主板、嵌入式系統或手機用以連接低速周邊設備而發展。
1.2 IIC通信連接
IIC總線只有兩根雙向信號線。一根是數據線SDA,另一根是時鐘線SCL。IIC總線通過上拉電阻接正電源(上拉電阻常用是4.7K,一般在4.7k-10k之間),要求兩根線都使用?開漏輸出接上拉電阻?的配置。當總線空閑時,兩根線均為高電平。連到總線上的任一器件輸出的低電平,都將使總線的信號變低,即各器件的SDA及SCL都是線“與”關系。
1.3 IIC特點
- 簡單和靈活的連接:占用空間小,芯片管腳的數量少,無需片選信號,價格低。。
- 總線的長度可達7.6m,傳送速度:快速?400kbps ,標準?100kbps,高速3.4Mbps。
- 最大主設備數:無限制;最大從機數:理論上是127。
- 信方式為同步半雙工,同一時間只可以單向通信。
- 雙線制:I2C使用兩根信號線進行通信,包括時鐘線(SCL)和數據線(SDA)。
- 多從機:多個從機設備可以連接到同一條I2C總線上,每個從機都有唯一的地址。
- 多主機:多個主機設備可以通過I2C總線進行并行通信,通過仲裁機制實現多主機沖突的解決。
1.4 硬件IIC和軟件IIC的區別
硬件IIC和軟件IIC都是I2C總線通信的方式,但它們實現的方式有所不同:
硬件IIC:硬件IIC是通過專門的硬件模塊實現的,通常是通過IIC控制器或者外部IIC芯片來實現的,具有高可靠性、傳輸速度快、占用CPU資源少等優點。硬件IIC協議實現比較簡單,只需要在芯片上添加I2C控制器就可以實現IIC通信,適用于傳輸數據量較大、傳輸速度要求較高的場景。
軟件IIC:軟件IIC是通過軟件模擬實現的,通常是在單片機的GPIO上實現的,具有低成本、可擴展性強等優點。軟件IIC的實現需要占用CPU資源,因此傳輸速度相對較慢,可靠性也不如硬件IIC。軟件IIC適用于傳輸數據量較小、傳輸速度要求不高的場景。
二、IIC協議層
????????在IIC總線上每一位數據都由一個同步時鐘所對應,也就是在SCL串行時鐘的配合下,數據在SDA上從高位向低位一次串行傳送每一位數據。IIC通信時序圖如下:
2.1 數據有效性
??IIC 的數據讀取動作都在?SCL為高?時產生,SCL為低時是數據改變的時期,無論SDA如何變化都不影響讀取。所以,傳輸數據的過程中,當SCL為高時,數據應當保持穩定,避免數據的采集出錯。
2.2?開始信號、結束信號
開始信號:SCL 為高電平時,SDA 由高電平向低電平跳變,開始傳送數據。
結束信號:SCL 為高電平時,SDA 由低電平向高電平跳變,結束傳送數據。
2.3?字節格式
SDA數據線上的每個字節必須是8位,對于每次傳輸的字節數沒有限制。每個字節(8位)數據傳送完后緊跟著應答信號(ACK,第9位)。數據的先后順序為:高位在前?。
2.4 應答信號
應答信號:主/從機在之后的數據通信中,數據接收方(可能是主機也可能是從機)收到傳輸的一個字節數據后,需要給出響應,此時處在第九個時鐘,發送端釋放?SDA?線控制權,將?SDA?電平拉高,由接收方控制。應答信號分為兩種:
1)當第9位(應答位)為?低電平?時,為?ACK??(Acknowledge)???信號
2)當第9位(應答位)為?高電平?時,為?NACK(Not Acknowledge)信號
2.5 數據傳輸(以地址7bit為例)
一個完整的7-bit通信過程如圖所示:
在START信號后的首字節由7位從機地址和1位讀寫位組成,結構如下圖:
發送完這個字節之后,主機釋放SDA總線等待從機給出ACK應答。如果從機給出了ACK應答,表示從機地址正確(有從機響應)并且已知曉是讀還是寫,便可以開始讀寫數據。如果從機沒有給出ACK應答,則說明接收設備可能沒有收到數據(如尋址的設備不存在或是設備正在忙碌)或無法解析收到的數據,如果是這樣,則由master來決定如何處理(STOP或ReSTART)。
2.5.1. 主機寫-從機收,傳輸方向不變
??主機對從機發送數據時,主機對從機發送一個開始字節,然后即可一直發送數據。以示例來講解,其第一幀數據為要操作的寄存器地址,所以為:“[1-Byte]開始字節(寫) + [1-Byte]寄存器地址 + [1-Byte]寄存器數據”。
2.5.2. 主機讀-從機發,傳輸方向改變
??主機對向從機讀取數據時,方式同發送數據有所不同,要多一次通信過程。
??主機需要先向從機發送一次信號,告訴從機”我要讀取數據“,然后重開一次通信,等待從機主動返回數據。以示例來講解,發送 “[1-Byte]開始字節(寫) + [1-Byte]要讀取的寄存器的地址”,之后結束通信,或者重開始,來進入到第二次通信中,先發送 [1-Byte]開始字節(讀),然后等待讀取從機發送過來的 [1-Byte]數據 即可。
三、SHT20概述
3.1 SHT20簡介
SHT20, 新一代 Sensirion 濕度和溫度傳感器。標準 I 2 C 格式。SHT20 配有一個全新設計的 CMOSens?芯片、一個經過改進的電容式濕度傳感元件和一個標準的能隙溫度傳感元件。SHT20的分辨率可以通過輸入命令進行改變(8/12bit乃至12/14bit的 RH/T),傳感器可以檢測到電池低電量狀態,并且輸出校驗和,有助于提高通信的可靠性。
3.2? SHT20 引腳
3.3?SHT20采用的I2C通信,基本命令
開始傳輸后,隨后先傳輸首字節包括I2C設備地址(7bit)和一個SDA方向位(R:1, W:0)。一個時鐘發送一個位,在第8個下降沿之后,通過拉低SDA引腳(ACK位 為0),只是傳感器數據接收正常。在發出測量命令之后(‘1110’‘0011’代表溫度測量,‘1110’‘0101’代表相對濕度測量 ,這種為主機模式),MCU必須等待測量完成。
3.4?保持主模式測量時序圖
?測量過程中,SCL線被封鎖(由傳感器控制),在測量時,SHT2x將SCL拉低強制主機進入等待狀態。當釋放SCL線,表示傳感器內部工作接收,可以繼續進行數據傳送。
首先發送寫地址,再發送命令,然后是讀地址,隨后等待測量即可,測量時間如下圖,傳感器內部設置的默認分辨率為相對濕度 12位和溫度 14位。45發送NACK時可取消校驗。
3.5?無保持主模式測量時序圖
量過程中,SCL線是開發狀態,可進行其它通信,可以在總線上處理其它I2C總線通信任務。?
3.6 軟復位
軟復位命令是用于無需關閉和再次打開電源的情況下,重新啟動傳感器系統,重新初始化并恢復默認設置狀態。所需要的時間不超過15ms。由MCU發起軟復位命令為1111 1110
3.7? 溫濕度計算
傳感器內部設置的默認分辨率為相對濕度12位和溫度14位。SDA的輸出數據被轉換成兩個字節的數據包,高字節MSB在前(左對齊)。每個字節后面都跟隨一個應答位。兩個狀態位,即 LSB的后兩位在進行物理計算前須置0。
(1)濕度
(2)溫度
四、原理圖設計
五、STM32CubeMX 配置
5.1 串口USART1配置
USART1:異步模式,波特率115200,功能:用于打印調試信息
5.2 IIC1配置
配置1:主模式特性? 和? 從模式特性 配置
Master features??主模式特性
I2C Speed Mode: IIC模式設置 快速模式和標準模式。
I2C Clock Speed: I2C傳輸速率,默認為100KHz
Slave?features??從模式特性
Clock?No?Stretch?Mode:?時鐘沒有擴展模式
IIC時鐘拉伸(Clock stretching)
clock stretching通過將SCL線拉低來暫停一個傳輸.直到釋放SCL線為高電平,傳輸才繼續進行.
clock stretching是可選的,實際上大多數從設備不包括SCL驅動,所以它們不能stretch時鐘.
Primary?Address?Length?selection:?從設備地址長度 設置從設備的地址是7bit還是10bit 大部分為7bit
Dual?Address?Acknowledged:?雙地址確認
Primary?slave?address:??從設備初始地址?
配置2:開啟IIC中斷
六、程序設計
6.1 串口重定向
#include "stdio.h"int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t *) &ch, 1, 0xFFFF);return ch;
}
6.2 移植sht20.h文件至工程
#ifndef _SHT20_H_
#define _SHT20_H_/*SHT20 設備操作相關宏定義,詳見手冊*/
#define SHT20_ADDRESS 0X40
#define SHT20_Write_Add 0x80
#define SHT20_Read_Add 0x81
#define SHT20_Measurement_RH_HM 0XE5
#define SHT20_Measurement_T_HM 0XE3
#define SHT20_Measurement_RH_NHM 0XF5 //非主機模式地址
#define SHT20_Measurement_T_NHM 0XF3 //非主機模式地址
#define SHT20_READ_REG 0XE7
#define SHT20_WRITE_REG 0XE6
#define SHT20_SOFT_RESET 0XFEtypedef struct
{float tempreture;float humidity;
} SHT20_INFO;extern SHT20_INFO sht20_info;
void SHT20_GetValue(void);#endif
6.3 移植sht20.c文件至工程
//頭文件
#include "stm32f1xx_hal.h"
#include "sht20.h"
#include "i2c.h"const int16_t POLYNOMIAL = 0x131;
SHT20_INFO sht20_info;// 函數功能: SHT20復位
void SHT20_reset(void)
{ HAL_I2C_Mem_Write(&hi2c1, SHT20_Write_Add, SHT20_SOFT_RESET, I2C_MEMADD_SIZE_8BIT,(void*)0, 1, 1000);HAL_Delay(15);
}//函數功能: SHT20讀取用戶寄存器
unsigned char SHT20_read_user_reg(void)
{ unsigned char val = 0; HAL_I2C_Mem_Read(&hi2c1, SHT20_Read_Add, SHT20_READ_REG, I2C_MEMADD_SIZE_8BIT,&val, 1, 1000); return val;
}//函數功能: 檢查數據正確性
char SHT2x_CheckCrc(char data[], char nbrOfBytes, char checksum)
{ char crc = 0;char bit = 0;char byteCtr = 0; //calculates 8-Bit checksum with given polynomialfor(byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr){crc ^= (data[byteCtr]);for ( bit = 8; bit > 0; --bit){if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;else crc = (crc << 1);}} if(crc != checksum)return 1;elsereturn 0;
}//* 函數功能: 溫度計算
float SHT2x_CalcTemperatureC(unsigned short u16sT)
{float temperatureC = 0; // variable for resultu16sT &= ~0x0003; // clear bits [1..0] (status bits)//-- calculate temperature [℃] --temperatureC = -46.85 + 175.72 / 65536 * (float)u16sT; //T= -46.85 + 175.72 * ST/2^16 return temperatureC;
}// 函數功能: 濕度計算
float SHT2x_CalcRH(unsigned short u16sRH)
{float humidityRH = 0; // variable for resultu16sRH &= ~0x0003; // clear bits [1..0] (status bits)//-- calculate relative humidity [%RH] --//humidityRH = -6.0 + 125.0/65536 * (float)u16sRH; // RH= -6 + 125 * SRH/2^16humidityRH = ((float)u16sRH * 0.00190735) - 6; return humidityRH;
}//函數功能: 測量溫濕度
float SHT2x_MeasureHM(unsigned char cmd, unsigned short *pMeasurand)
{char checksum = 0; //checksumchar data[2]; //data array for checksum verificationunsigned char addr = 0;unsigned short tmp = 0;float t = 0;HAL_I2C_Mem_Read(&hi2c1, SHT20_Read_Add, cmd, I2C_MEMADD_SIZE_8BIT,data,2, 0xFFFF);SHT2x_CheckCrc(data, 2, checksum);tmp = (data[0] << 8) + data[1];if(cmd == SHT20_Measurement_T_HM){t = SHT2x_CalcTemperatureC(tmp);}else{t = SHT2x_CalcRH(tmp);} if(pMeasurand){*pMeasurand = (unsigned short)t;} return t;
}
//函數功能: 獲取溫濕度數據
void SHT20_GetValue(void)
{sht20_info.tempreture = SHT2x_MeasureHM(SHT20_Measurement_T_HM, (void *)0);HAL_Delay(70); sht20_info.humidity = SHT2x_MeasureHM(SHT20_Measurement_RH_HM, (void *)0);HAL_Delay(25);SHT20_reset();
}
6.4 在main.c中打印溫濕度值
while (1){SHT20_GetValue();printf( "Temperature:%0.1fC, Humidity:%0.1f%%\r\n", sht20_info.tempreture, sht20_info.humidity);HAL_Delay(1000); /* USER CODE END WHILE *//* USER CODE BEGIN 3 */}