一些前置知识
IIC的基本原理
IIC串行总线有两根信号线,一根是双向的数据线SDA ,另一根是时钟线SCL。两条线都接上拉电阻,以确保 总线空闲时刻为高电平 ,其中时钟信号是由主控器件产生。IIC总线支持多设备连接,允许多主机存在,对于并联在一条总线上的每个IIC设备都有唯一的地址**(即靠地址来区分每一个IIC设备)。**
起始信号
当时钟线(SCL)为高平时,数据线(SDA)从高电平跳变到低电平。
终止信号
当时钟线(SCL)为高平时,数据线(SDA)从低电平跳变到高电平。
应答信号
主机每发送一个字节(8个bit),就在第9个时钟脉冲期间释放数据线(SDA) ,由从机反馈一个应答信号。
IIC的三种模式
类似串口,iic同时也有相应的三种通信模式。
轮询模式
从上至下一次为速度模式(标准100000,快速400000),其余一般不动。
主要用到的HAL库代码
1 2 3 4 5 HAL_I2C_Master_Receive(&hic1,AHT20_ADDRESS,&readBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是获取数据的地址,第三个为接收的数组地址,第四个是接收数据的长度,第五个是最长等待时间 HAL_I2C_Master_Transmit(&hic1,AHT20_ADDRESS,&sendBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是将发送数据的地址,第三个为发送的数组地址,第四个是发送数据的长度,第五个是最长等待时间
实践一:AHT20的读取串口发送
首先,移植相应的AHT20驱动,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ... AHT20_Init();//初始化AHT20 float temperature = 0.0, humidity = 0.0; char message[50];//定义相关的变量、数组名称 ... while (1) { AHT20_Measure();//读取AHT20 temperature = AHT20_Tempurature(); humidity = AHT20_Humidity(); sprintf(message, "Temperature: %.2f, Humidity: %.2f%%\r\n", temperature, humidity); //拼接字符串 HAL_UART_Transmit(&huart2, (uint8_t *)message, strlen(message), HAL_MAX_DELAY); HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }
中断模式
状态机的概念
在实际对一个模块的操作中,我们需要将其完成的工作模块化,这样方便我们对于它运行的状态进行判定。
中断模式代码
开启中断模式
所用到的HAL库函数
1 2 3 4 5 6 7 8 9 10 11 12 13 __weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){ //接收完成中断 } __weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){ //发送完成中断 } HAL_I2C_Master_Receive_IT(&hic1,AHT20_ADDRESS,&readBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是获取数据的地址,第三个为接收的数组地址,第四个是接收数据的长度,第五个是最长等待时间 HAL_I2C_Master_Transmit_IT(&hic1,AHT20_ADDRESS,&sendBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是将发送数据的地址,第三个为发送的数组地址,第四个是发送数据的长度,第五个是最长等待时间
实践一:AHT20的读取串口发送
i2c.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 /* USER CODE BEGIN 0 */ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){ if(hi2c == &hi2c1){ aht20_State == 2; }//发送信息完成中断 void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){ if(hi2c == &hi2c1){ aht20_State == 4; }//接收信息完成中断 /* USER CODE END 0 */
main.h
1 2 3 4 5 6 /* USER CODE BEGIN EC */ extern uint8_t aht20_State;//提前变量,以便全局使用 /* USER CODE END EC */
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ... AHT20_Init(); float temperature = 0.0, humidity = 0.0; char message[50]; /* USER CODE END 2 */ ... while (1) { if(aht20_State == 0){ AHT20_Measure(); aht20_State == 1; }else if(aht20_State == 2){ HAL_Delay(75); AHT20_Get(); aht20_State == 3; }else if(aht20_State == 4){ AHT20_Analysis(&temperature,&humidity); sprintf(message, "Temperature: %.2f, Humidity: %.2f%%\r\n", temperature, humidity); HAL_UART_Transmit(&huart2, (uint8_t *)message, strlen(message), HAL_Delay(1000); aht20_State == 0; } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } ...
DMA模式
开启DMA模式
所用到的HAL库函数
1 2 3 4 5 6 7 8 9 10 11 12 13 __weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){ //接收完成中断 } __weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){ //发送完成中断 } HAL_I2C_Master_Receive_DMA(&hic1,AHT20_ADDRESS,&readBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是获取数据的地址,第三个为接收的数组地址,第四个是接收数据的长度,第五个是最长等待时间 HAL_I2C_Master_Transmit_DMA(&hic1,AHT20_ADDRESS,&sendBUffer,3,HAL_MAX_DELAY); //接收函数,第一个是iic的地址指针,第二个是将发送数据的地址,第三个为发送的数组地址,第四个是发送数据的长度,第五个是最长等待时间
代码实践
实践一:结合OLED和AHT20制作简易温湿度计
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 /* USER CODE BEGIN Includes */ #include "oled.h" #include "aht20.h" #include "stdio.h" #include "string.h" /* USER CODE END Includes */ /* USER CODE BEGIN 2 */ HAL_Delay(20); OLED_Init(); AHT20_Init(); float temperature = 0.0, humidity = 0.0; char message[50];//初始化相应的的变量和函数 /* USER CODE END 2 */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ AHT20_Measure(); temperature=AHT20_Temperature(); humidity=AHT20_Humidity(); OLED_NewFrame();//准备新的图像 OLED_DrawImage(15,0,&temperatureImgImg,OLED_COLOR_NORMAL); //画图,x,y,图像指针,字符颜色 sprintf(message,"%.1f℃",temperature);//拼接字符串 OLED_PrintString(45,15,message,&font16x16,OLED_COLOR_NORMAL); //打印字符串,x,y,字符串指针地址,字符颜色 OLED_DrawImage(15,30,&humidityImgImg,OLED_COLOR_NORMAL); sprintf(message,"%.1f%%",humidity); OLED_PrintString(45,40,message,&font16x16,OLED_COLOR_NORMAL); OLED_ShowFrame();//展示图像
字体、图片需要用取模助手取模,放在font.c文件中,图片名称需要extern 提前变量在font.h中,以便全局调用。
一些参考资料
1.【STM32入门教程-2024】第12集 IIC通信与温湿度传感器AHT20(DHT20)_哔哩哔哩_bilibili
2.【STM32入门教程-2024】第13集 IIC的中断与DMA以及状态机编程_哔哩哔哩_bilibili
3.【STM32入门教程-2024】第14集 如何在OLED屏幕上挥毫_哔哩哔哩_bilibili
4.【STM32·番外】挑战5分钟制作温湿度计(A/DHT20+OLED)_哔哩哔哩_bilibili
5.STM32之IIC_stm32 iic-CSDN博客