文章目录
一、任务目标
学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。具体任务:
1)解释什么是“软件I2C”和“硬件I2C”? (阅读野火配套教材的第23章“I2C–读写EEPROM”原理章节)
2)阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win10)。
二、材料准备
硬件:
- STM32F103C8T6最小板
- CH340模块
- AHT20温湿度传感器
- 面包板
- 杜邦线
软件:
- Keil 5
- Flymcu
- 串口助手
三、I2C介绍
1.I2C通信
- I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线
- 两根通信线:SCL(Serial Clock)、SDA(Serial Data)
- 同步,半双工
- 带数据应答
- 支持总线挂载多设备(一主多从、多主多从)
2.硬件电路
- 所有I2C设备的SCL连在一起,SDA连在一起
- 设备的SCL和SDA均要配置成开漏输出模式
- SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
3.I2C时序基本单元
起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
4.I2C时序
指定地址写
对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
当前地址读
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
指定地址读
对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
5.硬件I2C与软件I2C
-
硬件I2C是直接利用 STM32 芯片中的硬件 I2C 外设,在初始化好 I2C 外设后,只需要把某寄存器位置 1,此时外设就会控制对应的 SCL 及 SDA 线自动产生 I2C 起始信号,不需要内核直接控制引脚的电平。
-
软件I2C直接使用 CPU 内核按照 I2C 协议的要求控制 GPIO 输出高低电平,从而模拟I2C。
-
区别:硬件I2C速度快,而软件I2C更灵活。
四、温湿度传感器模块
1.官方教程:
链接: AHT20 产品手册
2.建立工程及代码:
部分配置代码在这里下载,找到这个东西下载。
首先我们翻它的教程,找到下面这一页,这个可以便于我们理解它给的代码。
我们打开AHT20-21_DEMO_V1_3.c这个c程序,翻到最下面可以看到官方给的主函数的代码,对照着上面的图片看,我们就能知道每个函数大概是用来干什么的了。
int32_t main(void)
{
uint32_t CT_data[2];
volatile int c1,t1;
/***********************************************************************************/
/**///①刚上电,产品芯片内部就绪需要时间,延时100~500ms,建议500ms
/***********************************************************************************/
Delay_1ms(500);
/***********************************************************************************/
/**///②上电第一次发0x71读取状态字,判断状态字是否为0x18,如果不是0x18,进行寄存器初始化
/***********************************************************************************/
if((AHT20_Read_Status()&0x18)!=0x18)
{
AHT20_Start_Init(); //重新初始化寄存器
Delay_1ms(10);
}
/***********************************************************************************/
/**///③根据客户自己需求发测量命令读取温湿度数据,当前while(1)循环发测量命令读取温湿度数据,仅供参考
/***********************************************************************************/
while(1)
{
AHT20_Read_CTdata(CT_data); //不经过CRC校验,直接读取AHT20的温度和湿度数据 推荐每隔大于1S读一次
//AHT20_Read_CTdata_crc(CT_data); //crc校验后,读取AHT20的温度和湿度数据
c1 = CT_data[0]*100*10/1024/1024; //计算得到湿度值c1(放大了10倍)
t1 = CT_data[1]*200*10/1024/1024-500;//计算得到温度值t1(放大了10倍)
下一步客户处理显示数据,
}
}
但官方给的代码并不能完成我们的任务,我们还要自己添加一些东西,比如把拿到的数据通过串口传输给我们的电脑,这里给出代码:
#include "stm32f10x.h" // Serial.c
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU