AHT20温湿度传感器与LED屏显示

1,I2C协议介绍

I2C介绍可以看这位博主写的,https://blog.csdn.net/cjhz2333/article/details/128000429
这里就不再多说原理

测试准备

做这个实验需要项目模板,野火是有这一类项目模板的,但我没找到,自己搭建了一个,也不是很难,需要的可以去哔哩哔哩搜教程。搭建项目完后,我们需要用到厂商提供的AHT20的代码,这个不知道为什么会有差异,我后面做实验一直失败就是这个AHT20的代码不一样,所以可能需要注意一下,他的编译是不会报错的,但是他的运行是没用的。
然后新建一个group
添加我们需要的串口传输的函数和延时函数

#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;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint32_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}


uint32_t Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}


void Serial_SendFloat(float Num, uint8_t d_len, uint8_t f_len)
{
	uint8_t Len = d_len+f_len;	
	char arr[Len+2];			
	uint8_t i,j;				
	uint32_t temp;				
	
	i=0;
	if(Num>=0)
	{
		arr[i]=43;
	}else
	{
		arr[i]=45;
		Num=-Num;
	}
	i++;
	
	temp=(uint32_t)(Num*Pow(10,f_len));
	
	j=0;
	while(j<d_len)
	{
		arr[i]=temp/Pow(10,Len-j-1)%10+'0';
		j++;
		i++;
	}
	
	arr[i] = 46;
	i++;
	
	while(j<Len)
	{
		arr[i]=temp/Pow(10,Len-j-1)%10+'0';
		j++;
		i++;
	}
	Serial_SendString(arr);

}


void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}

void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Serial_RxData = USART_ReceiveData(USART1);
		Serial_RxFlag = 1;
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}


#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 


及各自的头文件`

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);

#endif


#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif


然后最后就是这样在这里插入图片描述
如果是自建模板,记得添加项目路径,而且要加一些命令,不然可能会报错
在这里插入图片描述
还要勾那个C99,除此之外,keil是不支持ARM compiler 5和6兼容的,所以需要下一个ARM compiler 5,这个也很麻烦,因为官网是不让你单独下的所以需要你去知乎搜一下,上面有解决办法。不下的话,这个写到最后编译也会报错。然后是对AHT20的那个文件进行修改。按下面改
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
然后因为我们这里是需要检验的·所以把提供的主函数要修改一下,并把给的那一段删掉。
主函数就是如下

#include "stm32f10x.h"
#include "AHT20-21_DEMO_V1_3.h"
#include "Serial.h"
#include "stdio.h"
#include "Delay.h"

int main(void)
{
		Serial_Init();//串口
		Init_I2C_Sensor_Port();//初始化SDA,SCL的IO口的函数
    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的温度和湿度数据 
		
			while(CT_data[0]==0x00&&CT_data[1]==0x00)
			{
				AHT20_Read_CTdata_crc(CT_data);
			}
			c1 = CT_data[0]*100*10/1024/1024;  //计算得到湿度值c1(放大了10倍)
			t1 = CT_data[1]*200*10/1024/1024-500;//计算得到温度值t1(放大了10倍)
			
			下一步客户处理显示数据,我们这里用两个字符串来表示计算得到的值
			char str1[5];
			char str2[5];
			sprintf(str1,"%3.1f",c1/10.0);
			sprintf(str2,"%3.1f",t1/10.0);
			Delay_1ms(2000);
			Serial_SendString("湿度");
			Serial_SendString(str1);
			Serial_SendString("% ");
			Serial_SendString("温度");
			
			Serial_SendString(str2);
			Serial_SendString("℃");
			Serial_SendString("\r\n");
		}

 }	


然后连线在这里插入图片描述
B1接管脚2,B0接管脚4
然后烧录,我这里运行的时候一开始中文是乱码,问了朋友,要把主函数文件用记事本打开后转为ANSI,在编译一次就好了。
在这里插入图片描述
总结:学习了自建模板的过程与消除一些错误的方法,了解了AHt20的工作原理与实验测试温湿度传感器。
然后OlED屏显示我也是用IIC协议做的,用的是四针脚。
在上面的工程中添加OLED的文件
在这里插入图片描述
然后是用显示屏,先生成字模,按如下设置在这里插入图片描述
在这里插入图片描述
并把生成的字模复制粘贴到下面的文件中
在这里插入图片描述
然后需要去定义我们的字模,因为原函数是不支持的

/**
  * @brief  OLED初始化
  * @param  Line 起始行位置
  * @param  Column 起始列位置
  * @retval 无
  */
void OLED_ShowCHINESE(uint8_t Line, uint8_t Column, uint8_t Num)
{
	
	uint8_t i;
	uint8_t wide = 20;//字宽
	
	OLED_SetCursor(( Line - 1 ) * 2, ( Column - 1 )* wide);		//参数1:把光标设置在第几页. 参数2:把光标设置在第几列
	for (i = 0; i < wide; i++)
	{
		OLED_WriteData(OLED_F10x16[Num][i]);			//显示上半部分内容
	}
	
	OLED_SetCursor(( Line - 1 ) * 2 + 1,( Column - 1) * wide);		
	for (i = 0; i < wide ; i++)
	{ 
		OLED_WriteData(OLED_F10x16[Num][i+wide]);		//显示下半部分内容
	}

}

要实现滚动效果,添加如下代码

				OLED_WriteCommand(0x2E); //关闭滚动
				OLED_WriteCommand(0x26); //向右滚动,27则向左
				OLED_WriteCommand(0x00); //虚拟字节
				OLED_WriteCommand(0x00); //起始页 这里为0
				OLED_WriteCommand(0x07); //滚动速度
				OLED_WriteCommand(0x03); //终止页 这里为3,也就是之后的姓名,学号
				OLED_WriteCommand(0x00); //虚拟字节
				OLED_WriteCommand(0xFF); //虚拟字节
				OLED_WriteCommand(0x2F); //开启滚动

然后是主函数代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AHT20-21_DEMO_V1_3.h"
#include <stdio.h>


int main(void)
{
	
		Init_I2C_Sensor_Port();//初始化SDA,SCL的IO口的函数
		uint32_t CT_data[2];
		volatile int  c1,t1;
		Delay_1ms(500);
		OLED_Init();//初始化OLED
		if((AHT20_Read_Status()&0x18)!=0x18)
		{
			AHT20_Start_Init(); //重新初始化寄存器
			Delay_1ms(10);
		}


		OLED_ShowCHINESE(1,1,0); //第1行第1列调用字模库第0个字 
		OLED_ShowCHINESE(1,2,1); //第1行第2列调用字模库第1个字 
		OLED_ShowString(2,1,"632007060523"); //第二行第一列显示字符串
		OLED_ShowCHINESE(3,1,3);//第3行第1列调用字模库第3个字 湿
		OLED_ShowCHINESE(3,2,4);//第3行第2列调用字模库第4个字 度
		OLED_ShowString(3,6,":"); 
		OLED_ShowCHINESE(4,1,2);//第4行第2列调用字模库第2个字 温
		OLED_ShowCHINESE(4,2,4);//第3行第2列调用字模库第4个字 度
		OLED_ShowString(4,6,":"); 
		while(1)
		{
				OLED_WriteCommand(0x2E); //关闭滚动
				OLED_WriteCommand(0x26); //向右滚动,27则向左
				OLED_WriteCommand(0x00); //虚拟字节
				OLED_WriteCommand(0x00); //起始页 这里为0
				OLED_WriteCommand(0x07); //滚动速度
				OLED_WriteCommand(0x03); //终止页 这里为3,也就是之后的姓名,学号
				OLED_WriteCommand(0x00); //虚拟字节
				OLED_WriteCommand(0xFF); //虚拟字节
				OLED_WriteCommand(0x2F); //开启滚动
	
				//AHT20_Read_CTdata(CT_data);       
				AHT20_Read_CTdata_crc(CT_data);   //CRC校验
		
				while(CT_data[0]==0x00&&CT_data[1]==0x00) 
				{
					AHT20_Read_CTdata_crc(CT_data);//CRC校验后,读取数据
				}
				c1 = CT_data[0]*100*10/1024/1024;  
				t1 = CT_data[1]*200*10/1024/1024-500;
				
				下一步客户处理数据,我们这里用两个字符串来表示计算得到的值
				char str1[5];
				char str2[5];
				sprintf(str1,"%.2f",c1/10.0);
				sprintf(str2,"%.2f",t1/10.0);
				OLED_ShowString(3,7,str1);//把浮点数转为字符串显示在屏上
				OLED_ShowString(4,7,str2);
				Delay_1ms(2000);

	}

}


然后编译运行通过开始烧录,最终效果如下,我这里字模计算有点问题,显示错位了,但我也没搞清楚什么原因,大致能看出来就行。

VID_20221127_002610


总结,了解了AHT20模块工作的原理,以及如和利用IIC协议,如何自建一个模板,还学习了如何插入汉字实现滚动在OLED屏上的方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1482581259

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值