基于IIC和SPI协议的温湿度采集与OLED显示

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

前言

环境

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接口实现以下功能:

  1. 显示自己的学号和姓名;

  2. 显示AHT20的温度和湿度;

  3. 上下或左右的滑动显示长字符,比如“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硬件电路模型——一主多从
硬件电路:

  • 所有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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值