100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据

STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据

时间:2020-04-21 04:34:40

相关推荐

STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据

关于STM32的IIC

一开始是用硬件内置的IIC来读取数据的,没有什么问题,但是不知道为什么后续断电上电之后一直没有数据,仿真看的话发现卡死在这些循环里面,我才反应过来网上一直说的硬件IIC有问题是这个。

I2C_Send7bitAddress(I2C1, (AHT20_Address << 1), I2C_Direction_Transmitter);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));I2C_SendData(I2C1, 0xAC);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, 0x33);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, 0x00);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

由于位置原因导致数据传输异常,IIC的数据总线一直处于忙状态,没有办法检测到想要的标志位,所以直接卡在那个while循环里面出不来了。按照网上的几种解决方法,我这边都试了,没有解决问题。

后续就是断电再上电,没有工作多久就会出现这种问题,只能用程序去模拟主机发送数据来通信了。

多个IIC从机管理

参考资料:STM32上如何轻松管理多条模拟IIC总线

先说最重要的一点,这个不属于那种,只用两根线,然后不同IIC从机并联在这上面通信的情况。而是属于每个从机设备各自用两根线,但是可以通过传参的方法共用同一套驱动程序这种。

一开始的想法假如一个系统里面只有一个IIC,先写好一套IIC的驱动直接调用就行了,但是如果有两个IIC从机设备,难道要多写一套程序类似于:AHT20_I2C_Start()Digital_I2C_Start()这种?

肯定是不合适的。也不止IIC吧,类似的模块驱动程序,如果存在两套不同的设备但是要用到同一套程序,像之前我用HT8开发个人库的时候,管理GPIO的KEY,LED模块,也是用到类似的方法,核心就是同一套模块驱动程序,然后把需要管理的设备弄成可以转变成可以变成函数参数的形式。因为HT8的频率最高只有16M,调用这么多东西来实现这种做法是很不划算的,所以我打算用在主频相对较高的MCU平台。

参考程序

I2C.c

#include "stm32f10x_conf.h"#include "common.h"#include "I2C.h"I2C_Dev_T I2C_Dev[1] = {[AHT20_Dev] = {.SCL_Port = GPIOB,.SCL_Pin = GPIO_Pin_6,.SDA_Port = GPIOB,.SDA_Pin = GPIO_Pin_7,},};void I2C_GPIO_Init(){GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStruct.GPIO_Pin = I2C_Dev[AHT20_Dev].SCL_Pin | I2C_Dev[AHT20_Dev].SDA_Pin;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(I2C_Dev[AHT20_Dev].SCL_Port, &GPIO_InitStruct);}void I2C_Dev_Start(I2C_Dev_T *dev){I2C_Dev_SDA_High(dev);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Delay);I2C_Dev_SDA_Low(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_Low(dev);}void I2C_Dev_Stop(I2C_Dev_T *dev){I2C_Dev_SDA_Low(dev);I2C_Dev_SCL_Low(dev);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SDA_High(dev);SysTick_Delay_us(I2C_Delay);}void I2C_Dev_SDA_Control(I2C_Dev_T *dev, I2C_SDA_Control_T sta){GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = dev->SDA_Pin;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;if(sta == I2C_SDA_Input){GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;}else{GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;}GPIO_ResetBits(dev->SDA_Port, dev->SDA_Pin);GPIO_Init(dev->SDA_Port, &GPIO_InitStruct);}uint8_t I2C_Dev_Check_Ack(I2C_Dev_T *dev){u8 check_recnt = 20;u8 flag = I2C_NACK;I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Control(dev,I2C_SDA_Input);while(check_recnt != 0){SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);if(I2C_Dev_Read_SDA(dev) == I2C_ACK){flag = I2C_ACK;I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Control(dev, I2C_SDA_Output);return flag;}check_recnt -= 1;}I2C_Dev_SDA_Control(dev, I2C_SDA_Output);I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Low(dev);return flag;}void I2C_Dev_Write_Byte(I2C_Dev_T *dev,uint8_t data){uint8_t index = 0x80;do{if(data & index)I2C_Dev_SDA_High(dev);elseI2C_Dev_SDA_Low(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_Low(dev);index >>= 1;}while(index != 0);}uint8_t I2C_Dev_Read_Byte(I2C_Dev_T *dev, I2C_Ack_Flag_T flag){uint8_t data = 0;uint8_t index = 0x80;I2C_Dev_SDA_Control(dev, I2C_SDA_Input);SysTick_Delay_us(I2C_Bit_Delay);do{I2C_Dev_SCL_High(dev);if(I2C_Dev_Read_SDA(dev) == 1)data |= index;index >>= 1;SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_Low(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);}while(index != 0);I2C_Dev_SDA_Control(dev, I2C_SDA_Output);I2C_Dev_SDA_High(dev);SysTick_Delay_us(I2C_Bit_Delay);if(flag == I2C_ACK){I2C_Dev_SDA_Low(dev);}SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_Low(dev);return data;}

I2C.h

#ifndef_I2C_H_#define_I2C_H_#include <stdint.h>#define I2C_Bit8_Write0x00#defineI2C_Bit8_Read0x01#defineI2C_Delay(uint16_t)200#defineI2C_Bit_Delay(uint16_t)50#defineI2C_Dev_SDA_High(dev)((dev->SDA_Port)->BSRR) = ((uint32_t)(dev->SDA_Pin))#defineI2C_Dev_SDA_Low(dev)((dev->SDA_Port)->BRR) = ((uint32_t)(dev->SDA_Pin))#defineI2C_Dev_SCL_High(dev)((dev->SCL_Port)->BSRR) = ((uint32_t)(dev->SCL_Pin))#defineI2C_Dev_SCL_Low(dev)((dev->SCL_Port)->BRR) = ((uint32_t)(dev->SCL_Pin))#defineI2C_Dev_Read_SDA(dev)GPIO_ReadInputDataBit((dev->SDA_Port),(dev->SDA_Pin))typedef enum{I2C_ACK = 0x00,I2C_NACK = 0x01,}I2C_Ack_Flag_T;typedef enum{I2C_SDA_Input = 0x00,I2C_SDA_Output = 0x01,}I2C_SDA_Control_T;typedef struct{GPIO_TypeDef *SCL_Port;uint16_t SCL_Pin;GPIO_TypeDef *SDA_Port;uint16_t SDA_Pin;}I2C_Dev_T;extern I2C_Dev_T I2C_Dev[];#defineAHT20_Dev0x00void I2C_Dev_Start(I2C_Dev_T *dev);void I2C_Dev_Stop(I2C_Dev_T *dev);void I2C_Dev_SDA_Control(I2C_Dev_T *dev, I2C_SDA_Control_T sta);uint8_t I2C_Dev_Check_Ack(I2C_Dev_T *dev);void I2C_Dev_Write_Byte(I2C_Dev_T *dev,uint8_t data);uint8_t I2C_Dev_Read_Byte(I2C_Dev_T *dev, I2C_Ack_Flag_T flag);#endif

AHT20.c

#include "stm32f10x_conf.h"#include "I2C.h"#include "AHT20.h"#include "common.h"#include "string.h"AHT20_Data_T AHT20_Data;void AHT20_Init(){GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStruct.GPIO_Pin = I2C_Dev[AHT20_Dev].SCL_Pin | I2C_Dev[AHT20_Dev].SDA_Pin;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(I2C_Dev[AHT20_Dev].SCL_Port, &GPIO_InitStruct);/* 初始化数据结构体 */memset(&AHT20_Data.Rx_Humidity, 0, 3);memset(&AHT20_Data.Rx_Temperature, 0, 3);AHT20_Data.Sensor_Status = 0;AHT20_Data.CRC_Data = 0;AHT20_Data.Humidity = 0.000000;AHT20_Data.Temperature = 0.000000;}void AHT20_Measure_Start(){I2C_Dev_Start(&I2C_Dev[AHT20_Dev]);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], (AHT20_Slave_Address << 1) | I2C_Bit8_Write);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0xAC);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0x33);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0x00);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}void AHT20_Get_SensorData(){I2C_Dev_Start(&I2C_Dev[AHT20_Dev]);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], (AHT20_Slave_Address << 1) | I2C_Bit8_Read);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Sensor_Status = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[0] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[1] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[2] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[0] = AHT20_Data.Rx_Humidity[2] & 0x0F;AHT20_Data.Rx_Humidity[2] >>= 4;/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[1] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[2] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.CRC_Data = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_NACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);AHT20_Data.Humidity = (AHT20_Data.Rx_Humidity[0] << 12) + (AHT20_Data.Rx_Humidity[1] << 4) + AHT20_Data.Rx_Humidity[2];AHT20_Data.Humidity = AHT20_Data.Humidity / 1048576;AHT20_Data.Temperature = (AHT20_Data.Rx_Temperature[0] << 16) + (AHT20_Data.Rx_Temperature[1] << 8) + AHT20_Data.Rx_Temperature[2];AHT20_Data.Temperature = ((AHT20_Data.Temperature * 25) / 131072) - 50;return ;}

AHT20.h

#ifndef_AHT20_H_#define_AHT20_H_#defineAHT20_Slave_Address0x38typedef struct{uint8_t Rx_Humidity[3];uint8_t Rx_Temperature[3];uint8_t Sensor_Status;uint8_t CRC_Data;float Humidity;float Temperature;}AHT20_Data_T;extern AHT20_Data_T AHT20_Data;void AHT20_Init(void);void AHT20_Measure_Start(void);void AHT20_Get_SensorData(void);#endif

AHT20驱动原理

参考手册:

AHT20手册

讲道理,很久没有跟传感器打交道了,但是又不是很想用跟DS18B20这种偏简单的,有时候刷淘宝刷到这个的模块,我看了一下电路反正也简单,自己搞一个也行,主要是没有用过DFN这种封装,想练练手。而且当时IIC用的也不是很熟,或者说IIC的项目实战就是在这个模块上面展开的,算是对IIC的使用打下基础,主要是这个模块通信起来也不是太难。

但是官方手册里面读取数据这一块,我不是很明白,我都已经把IIC主机设置成读的状态了,读取传感器的那个byte之后为什么是从机发过来的应答?我自己的程序里面改成,是主机给应答,通信是正常的。

还有一个点是,按照手册提供的步骤,读取数据之前要读那个状态位,获取到传感器空闲的时候才能读数据,不然的话就证明传感器还在测量,读的数据可能是有问题的。但是因为我给了足够的延时,所以我就省略了这一步,正经开发项目的话应该要加上这个判断。

一开始我不是用STM32来当主机的,用的HT8,因为编译器不同所以我在那边用那个float变量异常小心,同时也弄明白了float类型在二进制的表达形式,稍微是有一点复杂的,但是其实不会这个也不影响使用,后面有空可以写一下心得。

注意事项

官方提供的那个手册已经写得很详细了,我这边没必要写这么多了。个人觉得需要注意的事项:

先读取到的数据是高位的,以湿度数据为例,第1byte数据读到的话要往左挪12个位,第2byte数据要挪4个位,第3byte数据只有4bit不用处理,温度的话也差不多,第1byte数据只有4bit,左移16位。

这个是仿真读到的数据,那个湿度是小数部分,要转成百分比来看的话也就是x100%的意思。

IIC驱动原理

以前初学IIC的时候觉得很复杂,那是因为找错路子了。

最开始是用两个HT8的单片机,一个模拟主机,另一个使用硬件从机模块,参考官方提供的例程,然后用示波器来看波形,现在想想那个时候居然能乱搞出点东西来真的是运气在里面的,现在让我直接在这个环境下复现一下是不太可能的🙃

学这些通信协议可以用逻辑分析仪代替示波器,看波形抓数据解析数据非常方便,不用自己对着示波器一个一个数。

另外就是IIC的从机最好使用这种协议简单明了的成品模块,本来就不了解这些东西,还自己手写从机程序这不是给自己找麻烦吗😤当时就是出了问题来回切换工程和板子找问题,是真的难受。

现在觉得主要是模拟好主机的波形就差不多了。主要是以下几点比较重要的:

除了起始和终止信号,中间这个过程,SDA要在SCL低电平的时候翻转。非数据通信状态时,SCL恢复低电平是最稳妥的。比如接收完应答数据之后等下一个byte数据的时候,SCL要先拉低。没了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。