前言
环境
KEIL:5.0
FIyMcu:V0.993
开发板:STM32F103C8T6
器件
AHT-20 温湿度传感器
0.96英寸OLED屏幕
任务1内容
学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。具体任务:
1)解释什么是“软件I2C”和“硬件I2C”?
2)阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win10)。
任务2内容
理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:
-
显示自己的学号和姓名;
-
显示AHT20的温度和湿度;
-
上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(使用硬件刷屏模式)。
环境
MDK-KEIL 5
FIyMcu:V0.993
开发板:STM32F103C8T6
任务1
I2C通讯
- I2C通讯协议(Inter-Integrated Circuit)引脚少,硬件实现简单,可扩展性强,不需要USART、CAN等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯
- 实现I2C需要两根信号线完成信息交换,SCL(Serial Clock)时钟信号线,SDA(Serial Data)数据输入/输出线。它属于同步通信,由于输入输出数据均使用一根线,因此通信方向为半双工。
- I2C最少只需要两根线,和异步串口类似,但可以支持多个slave设备。一个I2C理论上最多可挂载127个设备,但除去保留地址,最多可挂载112个设备。
- ·多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
- 和SPI不同的是,I2C可以支持multi-master系统,允许有多个master并且每个master都可以与所有的slaves通信(master之间不可通过I2C通信,并且每个master只能轮流使用I2C总线)。
- I2C的数据传输速率位于串口和SPI之间,大部分I2C设备支持100KHz和400KHz模式。
硬件I2C
下图中是一组多从模型中协议的规定:
- 左边的CPU是单片机,作为总线的主机。主机能够对SCL线的完全控制。在空闲状态下,主机可以主动发起对SDA的控制。只有在从机发送数据和从机应答的时候,主机才会转交SDA控制权给从机。
- 挂在在SCL线上的被控设备就是挂在在I2C总线上的从机。这些从机可以是姿态传感器、OLED、存储器、时钟模块等。
- 从机的权利比较小,对于SCL时钟线,在任何时候都只能被动的读取,不被允许控制SCL线。对于SDA数据线,从机不允许主动发起对SDA的控制,只有在主机发送读取从机命令后或者从机应答的时候,从机才能短暂地取得SDA的控制权

硬件电路:
- 所有I2C设备的SCL线连在一起,SDA连在一起。
- 所有I2C设备的SCL和SDA均要配置成开漏输出模式。这是为了防止两个引脚同时处于输出状态。导致电源短路。所以I2C禁止所有设备输出强上拉的高电平,采用外置弱上拉电阻的电路结构如上图。在SDA和SCL上各添加一个上拉电阻,阻值一般为4.7k欧左右。
- 每一个设备(从机和从机)的引脚内部结构如下图,左边部分为SCL(即图中SCLK)的结构,右边部分为SDA(即图中DATA)结构,都采用了开漏输出的方式。开漏输出时,输出低电平时导通,是强下拉;输出高电平时下管断开,但是没有上管,此时引脚处于浮空状态。

软件I2C
I2C时序基本单元
在了解几个时序基本单元之前需要了解一下几点:
- 在I2C总线处于空闲状态时,SCL和SDA都是处于高电平状态
起始条件和终止条件
一个完整的数据帧都是以起始条件开始、终止条件结束。且起始条件和终止条件都是由主机产生的。在一主多从模型中,从机不允许产生起始条件和终止条件,所以在总线空闲状态时,从机不可以改变总线状态。
起始条件是指:SCL高电平期间,SDA从高电平切换到低电平。当主机捕获到SDA下降沿和SCL高电平状态时,会在SDA变为低电平后将SCL高电平转化为低电平。(这也保证了除起始条件和终止条件之外,每个时序单元的SCL都是以低电平开始低电平结束)

终止条件是指:SCL高电平期间,SDA从低电平切换到高电平。这个过程中SCL会先恢复到高电平,之后SDA在恢复到高电平产生的上升沿过程就是终止条件。(终止条件后SDA和SCL都是高电平,最终回到初始的空闲状态)

发送一个字节时序单元
发送一个字节:
SCL低电平期间,主机将数据位依次放到SDA线上(高位先行,串口是地位先行),然后释放SCL,从主机将SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程八次即可发送一个字节。
注意:
1、在SCL低电平期间SDA的数据是可以改变的。
2、如果主机想发送1,那么将SDA置为高电平;如果想发送0,那么将SDA置为低电平。
3、在SCL为高电平期间,就是从机读取数据的时候,此时SDA的状态不能够改变。
4、一般在上升沿过程中从机就已经完成了数据读取,因为从机不能判断下降沿,只能尽快读取。
5、主机需要在SCL下降沿之后(即SCL处于低电平的时候),下一个上升沿来临之前尽快把下一位数据放到SDA上准备好下一次传输。
6、若发生中断,SCL的时序会不断拉长,直到中断处理完成之后再回来继续进行处理。
7、该过程中,SDA和SCL全程都由主机掌控,从机只能被动读取。

接收一个字节
接收一个字节:在SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)。
1、图中SDA为虚线表示从机在控制SDA
2、SCL还是由主机控制

发送应答和接收应答
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
:若主机没有接收到数据,从机还是需要交出对SDA的控制权

接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接受之前需要释放SDA)

数据的发送结构

- 图中S表示上文提到的起始条件
- SLAVE ADDRESS 与R/W共同构成第一个字节,前七位是SLAVE ADDRESS(从机设备地址),用于寻找从机。最后一位是R/W位表示读或者写操作。
1、从机设备地址在I2C标准协议中分为7位地址和10位地址。本文讲解的是7位地址的模式。七位地址相对比较简单,且应用范围广。、
2、每个设备在出厂时,厂商都会为它分配一个7位地址,这个地址具体是什么应该在相应的设备手册中查找。
3、一般同一厂家生产的同一设备的设备地址相同。如AHT20温湿度传感器的设备地址是0111000。
4、如果有相同的设备挂载在同一总线时,就需要使用地址中可变部分了。一般器件地址的最后几位是可以在电路中改变的,通过改变器件上的引脚接入可以改变器件地址的最后几位,在不接任何地址引脚的情况下HT20温湿度传感器器件地址就是0111000。
- 图中A表示上文提到的接收应答。
- DATA表示按照上文发送一个字节或者接收一个字节方式进行数据的传输。
- P表示终止条件。
stm32通过I2C接口实现温湿度(AHT20)的采集
创建标准库
因为现有资源所提供的AHT20项目必须在标准库中进行,所以需要先创建一个标准库。
标准库的创建参考:江科大stm32新建工程
引入AHT20的资源文件
DHT20温湿度采集资源文件:点击下载
提取码:8888
将资源文件中的AHT20-21_DEMO_V1_3.h和AHT20-21_DEMO_V1_3.c两个文件复制到工程下的User目录下

注意:一定要根据创建标准库流程将User文件夹添加到资源文件路径中,否则引入的资源不可用
点击打开AHT20-21_DEMO_V1_3.h文件可以看到一些对AHT20进行操作的函数及函数说明。
void Delay_N10us(uint32_t t);//延时函数
void SensorDelay_us(uint32_t t);//延时函数
void Delay_4us(void); //延时函数
void Delay_5us(void); //延时函数
void Delay_1ms(uint32_t t);
void AHT20_Clock_Init(void); //延时函数
void SDA_Pin_Output_High(void) ; //将PB15配置为输出 , 并设置为高电平, PB15作为I2C的SDA
void SDA_Pin_Output_Low(void); //将P15配置为输出 并设置为低电平
void SDA_Pin_IN_FLOATING(void); //SDA配置为浮空输入
void SCL_Pin_Output_High(void); //SCL输出高电平,P14作为I2C的SCL
void SCL_Pin_Output_Low(void); //SCL输出低电平
void Init_I2C_Sensor_Port(void); //初始化I2C接口,输出为高电平
void I2C_Start(void); //I2C主机发送START信号
void AHT20_WR_Byte(uint8_t Byte); //往AHT20写一个字节
uint8_t AHT20_RD_Byte(void);//从AHT20读取一个字节
uint8_t Receive_ACK(void); //看AHT20是否有回复ACK
void Send_ACK(void) ; //主机回复ACK信号
void Send_NOT_ACK(void); //主机不回复ACK
void Stop_I2C(void); //一条协议结束
uint8_t AHT20_Read_Status(void);//读取AHT20的状态寄存器
void AHT20_SendAC(void); //向AHT20发送AC命令
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num);
void AHT20_Read_CTdata(uint32_t *ct); //没有CRC校验,直接读取AHT20的温度和湿度数据
void AHT20_Read_CTdata_crc(uint32_t *ct); //CRC校验后,读取AHT20的温度和湿度数据
void JH_Reset_REG(uint8_t addr);///重置寄存器
void AHT20_Start_Init(void);///上电初始化进入正常测量状态
编写程序
需要注意AHT20芯片的使用过程如下:
void read_AHT20_once(void)
{
delay_ms(10);
reset_AHT20();//重置AHT20芯片
delay_ms(10);
init_AHT20();//初始化AHT20芯片
delay_ms(10);
startMeasure_AHT20();//开始测试AHT20芯片
delay_ms(80);
read_AHT20();//读取AHT20采集的到的数据
delay_ms(5);
}
其中read_AHT20()代码如下
void read_AHT20(void)
{
uint8_t i;
for(i=0; i<6; i++)
{
readByte[i]=0;
}
I2C_Start();//I2C启动
I2C_WriteByte(0x71);//I2C写数据
ack_status = Receive_ACK();//收到的应答信息
readByte[0]= I2C_ReadByte();//I2C读取数据
Send_ACK();//发送应答信息
readByte[1]= I2C_ReadByte();
Send_ACK();
readByte[2]= I2C_ReadByte();
Send_ACK();
readByte[3]= I2C_ReadByte();
Send_ACK();
readByte[4]= I2C_ReadByte();
Send_ACK();
readByte[5]= I2C_ReadByte();
SendNot_Ack();
//Send_ACK();
I2C_Stop();//I2C停止函数
//判断读取到的第一个字节是不是0x08,0x08是该芯片读取流程中规定的,如果读取过程没有问题,就对读到的数据进行相应的处理
if( (readByte[0] & 0x68) == 0x08 )
{
H1 = readByte[1];
H1 = (H1<<8) | readByte[2];
H1 = (H1<<8) | readByte[3];
H1 = H1>>4;
H1 = (H1*1000)/1024/1024;
T1 = readByte[3];
T1 = T1 & 0x0000000F;
T1 = (T1<<8) | readByte[4];
T1 = (T1<<8) | readByte[5];
T1 = (T1*2000)/1024/1024 - 500;
AHT20_OutData[0] = (H1>>8) & 0x000000FF;
AHT20_OutData[1] = H1 & 0x000000FF;
AHT20_OutData[2] = (T1>>8) & 0x000000FF;
AHT20_OutData[3] = T1 & 0x000000FF;
}
else
{
AHT20_OutData[0] = 0xFF;
AHT20_OutData[1] = 0xFF;
AHT20_OutData[2] = 0xFF;
AHT20_OutData[3

本文详细介绍了如何使用STM32F103C8T6通过I2C协议与AHT20温湿度传感器交互,采集数据并经串口输出。同时,利用SPI接口实现OLED屏幕显示学号、姓名以及AHT20的温湿度数据。内容涵盖了I2C和SPI通信协议的基本概念、硬件I2C与软件I2C的区别、OLED屏幕的工作原理及显示方法。通过示例代码展示了数据采集和显示的完整流程。
最低0.47元/天 解锁文章
31万+

被折叠的 条评论
为什么被折叠?



