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_Write 0x00
#define I2C_Bit8_Read 0x01#define I2C_Delay (uint16_t)200
#define I2C_Bit_Delay (uint16_t)50#define I2C_Dev_SDA_High(dev) ((dev->SDA_Port)->BSRR) = ((uint32_t)(dev->SDA_Pin))
#define I2C_Dev_SDA_Low(dev) ((dev->SDA_Port)->BRR) = ((uint32_t)(dev->SDA_Pin))#define I2C_Dev_SCL_High(dev) ((dev->SCL_Port)->BSRR) = ((uint32_t)(dev->SCL_Pin))
#define I2C_Dev_SCL_Low(dev) ((dev->SCL_Port)->BRR) = ((uint32_t)(dev->SCL_Pin))#define I2C_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[];#define AHT20_Dev 0x00void 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_#define AHT20_Slave_Address 0x38typedef 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的单片机,一个模拟主机,另一个使用硬件从机模块,参考官方提供的例程,然后用示波器来看波形,现在想想那个时候居然能乱搞出点东西来真的是运气在里面的,现在让我直接在这个环境下复现一下是不太可能的
STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据相关推荐
- MicroPython ESP32 读取DHT11温湿度传感器数据
MicroPython ESP32 读取DHT11温湿度传感器数据 DHT11温湿度传感器 接线说明 ESP32 ----- DHT11 3.3V ----- VCC GND ----- GND GP ...
- 模拟IIC读取SHT30温湿度传感器数据
文章目录 1 i2c.c 2 i2c.h 3 crc.c 4 crc.h 1 i2c.c /*** @brief SHT30温湿度传感器相关,使用模拟IIC进行数据的读取*/#include < ...
- STM32F103单片机软件模拟IIC并读取TMP112数字温度传感器
本文利用STM32F103系列单片机读取TMP112数字温度传感器的温度信息,TMP112数字传感器采用IIC总线协议通信.STM32自身含有硬件IIC资源,分别是PB6-->SCL.PB7-- ...
- STM32单片机硬件I2C读取AHT10温湿度传感器数据
STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上. 我用的单片机是STM32F103C8T6,程序用的是ST标准库写的. STM32使用硬件I2C读取SHTC3温 ...
- AHT20温湿度传感器STM32-I2C驱动,替代DHT11/DHT12/AM2320/SHT20/SHT30,IIC代码兼容AHT10/15-MEMS温湿度传感器
AHT20是国内奥松生成的I2C接口的MEMS温湿度传感器,ADC位数为20Bit,具有体积小.精度高.成本低等优点.相较于AHT10,最显著的变化是体积由 5*4*1.6mm,缩小到 3*3*1.0 ...
- 基于I2C协议的AHT20温湿度传感器的数据采集
文章目录 一.I2C相关 1.I2C总线简介 工作原理 总线特征 2.I2C协议简介 软件I2C 硬件I2C 二者比较 二.基于I2C的AHT20温湿度采集实验 AHT20简介 1.实验要求 2.实验 ...
- 基于I2C的AHT20温湿度传感器的数据采集
一.I2C简介 二.软件I2C和硬件I2C 三.AHT20简介 四.基于stm32的AHT20温湿度传感器的数据采集 五.总结 一.I2C简介 I2C(芯片间)总线接口连接微控制器和串行I2C总线.它 ...
- STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出
文章目录 前言 一.I2C总线通信协议 1.I2C总线 2.工作原理 3.I2C特点 4.I2C模式选择 5.软件I2C和硬件I2C 二.串口输出温湿度传感器的数据 1.核心代码分析 2.硬件实操连接 ...
- STM32F103基于I2C协议的AHT20温湿度传感器的数据采集
目录 一.I2C 1.I2C 协议简介 2.I2C 物理层 3.协议层 通讯的起始和停止信号 数据有效性 响应 4. 软件I2C"和"硬件I2C 二.实现AHT20采集程序 1.A ...
最新文章
- pytorch笔记:policy gradient
- @Transactional 注解的失效场景
- 控制SAP Spartacus shipping address页面spinner显示的逻辑
- C#LeetCode刷题之#171-Excel表列序号(Excel Sheet Column Number)
- 洛谷 P2257 YY的GCD
- Visual Assist X Options 常用宏
- python结束线程类_Python线程指南(转)
- 【Computer Organization笔记13】指令流水中的结构冲突和数据冲突
- 一周最新示例代码回顾 (4/9–4/15)
- 学用计算机 关机,电脑关机命令是什么?快速关机必备(你学会了吗)
- PHP读取txt文件自动分成指定行数
- 1.2.1流动与传热的通用控制方程(OpenFOAM理论笔记系列)
- 自己动手编译最新Android源码及SDK
- win7连接远程桌面时出现黑屏的解决方法(亲测有效)——终于找到解决办法了
- 又发福利!日历小程序源码
- oracle数据库监听说法正确,Oracle数据库错题合集
- caffe/ windows 10 /Can't parse message of type caffe.NetParameter because it is missing required
- 作为建筑设计师,这8款渲染软件一定要知道
- 面试时,不知如何和面试官谈期望薪资
- 基于Java的保险管理系统
热门文章
- 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)
- 你他喵的告诉我标题怎么起!
- Java 行业的相关就业前景分析
- 引导魔女之力,征服星辰大海 升级篇: 重要事情说三遍: 升级!升级!!升满级!!! 简述: 1.本篇仅升级,涉及到的技巧全职业都可以参考; 2.考虑到萌新刚玩通关护卫者系统等级不高,故
- mysql 文本 挖掘_GitHub - myseve/dianping_textmining: 大众点评评论文本挖掘,包括点评数据爬取、数据清洗入库、数据分析、评论情感分析等的完整挖掘项目...
- 怎么给图片添加水印?教你一个图片加水印小妙招
- XPS如何在线转Word格式
- validation插件
- 贴片LED不良品的常见问题分析
- 工图怎么进行三维标注