1. IIC协议相关
- IIC协议实现可以是硬件IIC和软件IIC
1. 硬件IIC是需要发送命令给他,然后器件里面的集成电路,硬件实现IIC发送数据,
硬件接收到命令后,就会将数据保存到寄存器里面,然后就可以通过单片机实现的软件IIC来进行读取数据
2. 软件IIC就是通过操作单片机中的两个GPIO管脚来进行IIC时序的操作
硬件IIC的优点是直接通过硬件操作,速度比较快,一般是在一些传感器的器件中。
软件IIC一般都是在单片机中通过控制管脚来实现的,特点是比较灵活。
2. AHT20的温湿度读取
- 一般AHT20的地址是0x38
- 有关的一些命令是如下图
- 使用的流程图是
-
有关程序如下
软硬件环境
硬件:AHT20模块网上购买,单片机STM32F429 软件:keil V5
AHT20.h
#ifndef __AHT20_H
#define __AHT20_H
#include "system.h"
#include "myiic.h"
#include "SysTick.h"
#define ATH20_SLAVE_ADDRESS 0x38 /* I2C从机地址 */
//****************************************
// 定义 AHT20 内部地址
//****************************************
#define AHT20_STATUS_REG 0x71 //状态字 寄存器地址
#define AHT20_INIT_REG 0xBE //初始化 寄存器地址
#define AHT20_SoftReset 0xBA //软复位 单指令
#define AHT20_TrigMeasure_REG 0xAC //触发测量 寄存器地址
// 存储AHT20传感器信息的结构体
struct m_AHT20
{
uint8_t alive; // 0-器件不存在; 1-器件存在
uint8_t flag; // 读取/计算错误标志位。0-读取/计算数据正常; 1-读取/计算设备失败
uint32_t HT[2]; // 湿度、温度 原始传感器的值,20Bit
float RH; // 湿度,转换单位后的实际值,标准单位%
float Temp; // 温度,转换单位后的实际值,标准单位°C
};
uint8_t AHT20_Init(void);
uint8_t AHT20_ReadHT(uint32_t *HT);
uint8_t StandardUnitCon(struct m_AHT20* aht);
#endif
AHT20.c
#include "AHT20.h"
/** * @brief 读AHT20 设备状态字 * @param void * @retval uint8_t 设备状态字 */
static uint8_t AHT20_ReadStatusCmd(void)
{
uint8_t tmp[1];
Soft_I2C_Read(ATH20_SLAVE_ADDRESS, AHT20_STATUS_REG, 1, tmp);
return tmp[0];
}
/** * @brief 读AHT20 设备状态字 中的Bit3: 校准使能位 * @param void * @retval uint8_t 校准使能位:1 - 已校准; 0 - 未校准 */
static uint8_t AHT20_ReadCalEnableCmd(void)
{
uint8_t tmp;
tmp = AHT20_ReadStatusCmd();
return (tmp>>3)&0x01;
}
/** * @brief 读AHT20 设备状态字 中的Bit7: 忙标志 * @param void * @retval uint8_t 忙标志:1 - 设备忙; 0 - 设备空闲 */
static uint8_t AHT20_ReadBusyCmd(void)
{
uint8_t tmp;
tmp = AHT20_ReadStatusCmd();
return (tmp>>7)&0x01;
}
/** * @brief AHT20 芯片初始化命令 * @param void * @retval void */
static void AHT20_IcInitCmd(void)
{
uint8_t tmp[2];
tmp[0] = 0x08;
tmp[1] = 0x00;
Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_INIT_REG, 2, tmp);
}
/** * @brief AHT20 触发测量命令 * @param void * @retval void */
static void AHT20_TrigMeasureCmd(void)
{
uint8_t tmp[2];
tmp[0] = 0x33;
tmp[1] = 0x00;
Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_TrigMeasure_REG, 2, tmp);
}
/** * @brief AHT20 软复位命令 * @param void * @retval void */
static void AHT20_SoftResetCmd(void)
{
uint8_t tmp[1];
Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_SoftReset, 0, tmp);
}
/** * @brief AHT20 设备初始化 * @param void * @retval uint8_t:0 - 初始化AHT20设备成功; 1 - 初始化AHT20失败,可能设备不存在或器件已损坏 */
uint8_t AHT20_Init(void)
{
uint8_t rcnt = 2+1;//软复位命令 重试次数,2次
uint8_t icnt = 2+1;//初始化命令 重试次数,2次
while(--rcnt)
{
icnt = 2+1;
delay_ms(40);//上电后要等待40ms
// 读取温湿度之前,首先检查[校准使能位]是否为1
while((!AHT20_ReadCalEnableCmd()) && (--icnt))// 2次重试机会
{
delay_ms(10);
// 如果不为1,要发送初始化命令
AHT20_IcInitCmd();
delay_ms(200);//这个时间不确定,手册没讲
}
if(icnt)//[校准使能位]为1,校准正常
{
break;//退出rcnt循环
}
else//[校准使能位]为0,校准错误
{
AHT20_SoftResetCmd();//软复位AHT20器件,重试
delay_ms(200);//这个时间不确定,手册没讲
}
}
if(rcnt)
{
delay_ms(200);//这个时间不确定,手册没讲
return 0;// AHT20设备初始化正常
}
else
{
return 1;// AHT20设备初始化失败
}
}
/** * @brief AHT20 设备读取 相对湿度和温度(原始数据20Bit) * @param uint32_t *HT:存储20Bit原始数据的uint32数组 * @retval uint8_t:0-读取数据正常; 1-读取设备失败,设备一直处于忙状态,不能获取数据 */
uint8_t AHT20_ReadHT(uint32_t *HT)
{
uint8_t cnt=3+1;//忙标志 重试次数,3次
uint8_t tmp[6];
uint32_t RetuData = 0;
// 发送触发测量命令
AHT20_TrigMeasureCmd();
do{
delay_ms(75);//等待75ms待测量完成,忙标志Bit7为0
}while(AHT20_ReadBusyCmd() && (--cnt));//重试3次
if(cnt)//设备闲,可以读温湿度数据
{
delay_ms(5);
// 读温湿度数据
Soft_I2C_Read(ATH20_SLAVE_ADDRESS, AHT20_STATUS_REG, 6, tmp);
// 计算相对湿度RH。原始值,未计算为标准单位%。
RetuData = 0;
RetuData = (RetuData|tmp[1]) << 8;
RetuData = (RetuData|tmp[2]) << 8;
RetuData = (RetuData|tmp[3]);
RetuData = RetuData >> 4;
HT[0] = RetuData;
// 计算温度T。原始值,未计算为标准单位°C。
RetuData = 0;
RetuData = (RetuData|tmp[3]) << 8;
RetuData = (RetuData|tmp[4]) << 8;
RetuData = (RetuData|tmp[5]);
RetuData = RetuData&0xfffff;
HT[1] = RetuData;
return 0;
}
else//设备忙,返回读取失败
{
return 1;
}
}
/** * @brief AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C) * @param struct m_AHT20* aht:存储AHT20传感器信息的结构体 * @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围 */
uint8_t StandardUnitCon(struct m_AHT20* aht)
{
aht->RH = (double)aht->HT[0] *100 / 1048576;//2^20=1048576 //原式:(double)aht->HT[0] / 1048576 *100,为了浮点精度改为现在的
aht->Temp = (double)aht->HT[1] *200 / 1048576 -50;
printf("Humidity:%.1f%%\r\n",aht->RH);
printf("Temperature:%.1f\r\n",aht->Temp);
printf("\r\n");
//限幅,RH=0~100%; Temp=-40~85°C
if((aht->RH >=0)&&(aht->RH <=100) && (aht->Temp >=-40)&&(aht->Temp <=85))
{
aht->flag = 0;
return 0;//测量数据正常
}
else
{
aht->flag = 1;
return 1;//测量数据超出范围,错误
}
}
3. 总结
- 代码中间调试出问题是在初始发送地址的地方出错了,地址是0x38,发送的时候是高7位是地址,低地址位是读写位读是1,写是0。
- 这份代码看起来比较好,封装的比较好。
- 测试过另一份代码,问题是出在获取数据的时候,主机(单片机)需要发送应答位是1,而函数IIC_wait_ack()函数返回值,如果是接受成功,会返回ack是0,误以为ack是1,导致后面没有发送应答位
- 总之,调试的过程中,看着文档,单步调试,细心就能够找到问题。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22734.html