摘要:通过学习软件IIC来进行实操AHT21B采集温湿度。
前期准备:
- 软件:Keil 5.28,FlyMcu v0.188(烧录软件),XCOM v2.6(串口通信软件)
- 硬件:stm32F103C8,AHT21B(温湿度采集模块),USB转TTL模块
以下工程案例基于正点原子,请各位注意。
IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。百度百科-IIC
IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
在I2C总线传输过程中,将两种特定的情况定义为开始和停止条件:
开始和停止条件均由主控制器产生。使用硬件接口可以很容易地检测到开始和停止条件,没有这种接口的微机必须以每时钟周期至少两次对SDA取样,以检测这种变化。百度百科-IIC
具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式。
目前有两种实现IIC的方式:(1)软件IIC(2)硬件IIC
软件IIC一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的
AHT21B数字温湿度模块是一款经过校准数字信号输出的温湿度复合传感器。它以专用的数字模块采集技术和温湿度传感技术,确保产品具有非常高的可靠性与卓越的长期稳定性。该产品具有品质卓越、响应迅速、抗干扰能力强、性价比高等优点。每个传感器都在专业的湿度校验室中进行校准,使产品达到更高的精度标准。标准I²C接口,使系统集成变得简易快捷。产品体积小、功耗低使其成为各类应用甚至最为苛刻的应用场合的最佳选择。奥松电子官网
• 完全标定
• 数字输出,I²C接口
• 优异的长期稳定性
• 响应迅速
• 抗干扰能力强
• 多种配件可供选择
• 量身定制应用方案
参数 | 说明 |
---|---|
供电电压 | DC:2-5.5V |
测量范围 | 温度:-40~+80°C; 湿度:0~100%RH |
测量精度 | 温度:±0.3℃; 湿度:±2%RH(25℃) |
分辨率 | 温度:0.01℃ 湿度:0.024%RH |
输出信号 | I²C信号 |
包装 | 吸塑盘 |
名称 | 描述 |
---|---|
VCC | 供电电压 |
SDA | 串行数据,双向口 |
GND | 电源地 |
SCL | 串行时钟,双向口 |
电源引脚( VDD GND)
AHT21B的供电范围为2.0-5.5V,推荐电压为3.3V,并且在VCC和GND之间必须加上去耦电容10uF,起到滤波作用。
串行时钟SCL
SCL用于微处理器与AHT21B之间的通讯同步。由于接口包含了完全静态逻辑,因而不存在最小SCL频率。
串行数据SDA
SDA引脚用于传感器的数据输入和输出。当向传感器发送命令时,SDA在串行时钟SCL的上升沿有效,且当SCL为高电平时,SDA必须保持稳定。在SCL下降沿之后,SDA值可被改变。为确保通信安全,SDA的有效时间在SCL上升沿之前,和下降沿之后应该分别延长至 TSU AND THO,当从传感器读取数据时,SDA在SCL变低以后有效(TV),且维持到下一个SCL的下降沿
1.采集温湿度并进行串口输出显示
int main(void)
{
u32 CT_data[2]={0};
volatile float c1=0,t1=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
temphum_init();
delay_ms(40);//刚上电,延时40ms才可以读取状态
if(!((AHT20_Read_Status()&0x08)==0x08))//首先发0x71读取状态字bit[3],如果=1,为校准输出,无须初始化!!! 正常情况下读回来的状态是0x1C或者是0x18,读回来是0x80表示忙状态;
{
AHT20_Init(); //初始化AHT20
}
while(1)
{
//DisableIrq(); //由于是模拟I2C,为读取数据更准确 ,读取之前禁止中断;
delay_ms(1000);
AHT20_Read_CTdata(CT_data); //不经过CRC校验,直接读取AHT20的温度和湿度数据 推荐每隔大于1S读一次
//AHT20_Read_CTdata_crc(CT_data); //crc校验后,读取AHT20的温度和湿度数据
c1 = CT_data[0]*100*10/1024/1024; //计算得到湿度值(放大了10倍)
t1 = CT_data[1]*200*10/1024/1024-500;//计算得到温度值(放大了10倍)
//printf("%d %d\r\n",*CT_data,*(CT_data+1));
LED=0;
delay_ms(500);
LED=1;
printf("湿度:%.1f%%\r\n",(c1/10));
printf("温度:%.1f℃\r\n",(t1/10));
printf("\r\n");
delay_ms(500);
}
}
#include "myiic.h"
#include "delay.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//IIC驱动 代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/9
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 输出高
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
等待应答信号到来
返回值:1,接收应答成功
0,接收应答失败
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 0;
}
}
IIC_SCL=0;//时钟输出0
return 1;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
#include "temhum.h"
//读取AHT20的状态寄存器
u8 AHT20_Read_Status(void)
{
u8 Byte_first,flag;
IIC_Start();
IIC_Send_Byte(0x71);
flag=IIC_Wait_Ack();
Byte_first = IIC_Read_Byte(flag);
IIC_NAck();
IIC_Stop();
return Byte_first;
}
void AHT20_SendAC(void) //向AHT20发送AC命令
{
IIC_Start();
IIC_Send_Byte(0x70);
IIC_Wait_Ack();
IIC_Send_Byte(0xac);//0xAC采集命令
IIC_Wait_Ack();
IIC_Send_Byte(0x33);
IIC_Wait_Ack();
IIC_Send_Byte(0x00);
IIC_Wait_Ack();
IIC_Stop();
}
void AHT20_Init(void) //初始化AHT20
{
IIC_Init();
IIC_Start();
IIC_Send_Byte(0x70);
IIC_Wait_Ack();
IIC_Send_Byte(0xa8);//0xA8进入NOR工作模式
IIC_Wait_Ack();
IIC_Send_Byte(0x00);
IIC_Wait_Ack();
IIC_Send_Byte(0x00);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(10);//延时10ms左右
IIC_Start();
IIC_Send_Byte(0x70);
IIC_Wait_Ack();
IIC_Send_Byte(0xbe);//0xBE初始化命令,AHT20的初始化命令是0xBE, AHT10的初始化命令是0xE1
IIC_Wait_Ack();
IIC_Send_Byte(0x08);//相关寄存器bit[3]置1,为校准输出
IIC_Wait_Ack();
IIC_Send_Byte(0x00);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(10);//延时10ms左右
}
void temphum_init()
{
delay_ms(40);//刚上电,延时40ms才可以读取状态
//首先发0x71读取状态字bit[3],如果=1,为校准输出,无须初始化!!!正常情况下读回来的状态是0x1C或者是0x18,读回来是0x80表示忙状态;
if(!((AHT20_Read_Status()&0x08)==0x08))
{
AHT20_Init(); //初始化AHT20
}
}
void AHT20_Read_CTdata(u32 *ct) //没有CRC校验,直接读取AHT20的温度和湿度数据
{
volatile u8 Byte_1th=0;
volatile u8 Byte_2th=0;
volatile u8 Byte_3th=0;
volatile u8 Byte_4th=0;
volatile u8 Byte_5th=0;
volatile u8 Byte_6th=0;
u32 RetuData = 0;
u16 cnt = 0,flag;
AHT20_SendAC();//向AHT20发送AC命令
delay_ms(80); //大约延时80ms
cnt = 0;
while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态
{
delay_ms(1);
if(cnt++>=100) break;
}
IIC_Start();
IIC_Send_Byte(0x71);
flag=IIC_Wait_Ack();
Byte_1th = IIC_Read_Byte(flag);//状态字
//IIC_Ack();
Byte_2th = IIC_Read_Byte(flag);//湿度
//IIC_Ack();
Byte_3th = IIC_Read_Byte(flag);//湿度
//IIC_Ack();
Byte_4th = IIC_Read_Byte(flag);//湿度/温度
//IIC_Ack();
Byte_5th = IIC_Read_Byte(flag);//温度
//IIC_Ack();
Byte_6th = IIC_Read_Byte(!flag);//温度
//IIC_NAck();
IIC_Stop();
RetuData = (RetuData|Byte_2th)<<8;
RetuData = (RetuData|Byte_3th)<<8;
RetuData = (RetuData|Byte_4th);
RetuData =RetuData >>4;
ct[0] = RetuData;//湿度
RetuData = 0;
RetuData = (RetuData|Byte_4th)<<8;
RetuData = (RetuData|Byte_5th)<<8;
RetuData = (RetuData|Byte_6th);
RetuData = RetuData&0xfffff;
ct[1] =RetuData; //温度
}
部分代码参考基于I2C通信协议的温湿度采集
1.USB转TTL连线
stm32核心板 | USB转串口 |
---|---|
PA9 (USART1-TX) | RXD |
PA10 (USART1-RX) | TXD |
3V3 | 3V3 |
GND | GND |
跳线BOOT0为1,BOOT1为0.
2.AHT21B与STM32F103C8
AHT20 | STM32F10X |
---|---|
SCL | PB6 |
SDA | PB7 |
VCC | 3V3 |
GND | GND |
通过实验结果可以看出,AHT21B可以正常采集温湿度进行串口显示。
通过此次学习,我初步了解了软件IIC与硬件IIC的基本知识。通过实操AHT21B采集温湿度,学习并掌握了软件IIC的代码编写以及工程调试。其中遇到了很多问题,特别感谢我的老师和不#曾&轻听博主对我的帮助。
1.奥松官网
2.AHT21B温湿度采集-GitHub
3.基于I2C通信协议的温湿度采集
4.硬件IIC和软件IIC区别