STM32 温湿度采集与OLED显示

2024-06-23 18:52

本文主要是介绍STM32 温湿度采集与OLED显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、I2C总线通信协议 

1、I2C介绍

2、软件I2C和硬件I2C

(1)硬件I2C

(2)软件I2C

差异

二、AHT20温湿度传感器 

接口原理介绍

1. 温度测量原理

2. 湿度测量原理

实物引脚

 传感器性能

电气特性  

三、任务实现

具体要求

代码示例

结果展示

总结


学习目标:

学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。

一、I2C总线通信协议 

1、I2C介绍

       对于I2C的介绍,可前往往期博客阅读学习(博客地址:基于I2C协议的OLED显示(利用U82G库)_u8g2-CSDN博客)除了关于I2C的基本内容外,本期博客再介绍软硬件I2C。

2、软件I2C和硬件I2C

(1)硬件I2C

直接利用 STM32 芯片中的硬件 I2C 外设

       硬件实现通常依赖于专门的硬件模块(如I2C控制器),这些控制器内置了I2C协议的主要功能,包括起始条件、数据传输、时序控制和停止条件的生成。硬件I2C的优点包括:

  • 初始化:配置I2C控制器的参数,包括通信速率、模式(主机或从机)、设备地址等。
  • 发送起始条件:主机通过I2C控制器生成起始条件,即将SDA从高电平切换到低电平,同时保持SCL线为高电平。
  • 发送设备地址和操作位:主机发送目标设备的地址和读写操作位(R/W位)通过SDA线。
  • 数据传输:根据需要,主机通过I2C控制器发送或接收数据,确保时序符合I2C协议要求。
  • 接收ACK/NACK:每发送一个数据字节后,主机等待接收方的应答信号(ACK或NACK),由I2C控制器解析处理。
  • 重复传输:根据通信需求,主机可以继续发送或接收数据,并发送相应的ACK或NACK信号。
  • 发送停止条件:传输结束后,主机通过I2C控制器发送停止条件,即将SDA从低电平切换到高电平,同时保持SCL线为高电平。
  • 错误处理:I2C控制器监测和处理通信中的错误条件,如总线忙、设备未响应等情况,以确保通信的可靠性。

(2)软件I2C

直接使用 CPU 内核按照 I2C 协议的要求控制 GPIO 输出高低电平,从而模拟I2C。

在某些硬件资源受限的情况下,可以通过软件实现I2C通信,这种方法被称为Bit-Banging。软件控制每个时钟周期上的数据线变化,以模拟I2C协议。具体步骤包括:

  • 初始化:配置两个GPIO引脚作为SDA(数据线)和SCL(时钟线),并设置它们的初始状态和方向(输入或输出)。
  • 发送起始条件:将SDA从高电平切换到低电平,同时保持SCL为高电平,以生成起始条件。
  • 发送设备地址和操作位:通过控制SDA线的电平变化,发送目标设备的地址和读写操作位(R/W位)。
  • 数据传输:根据读写操作位的指示,发送方(主机或从机)通过控制SDA线上的电平变化来发送或接收数据。
  • 接收ACK/NACK:每发送一个数据字节后,发送方等待接收方的应答信号(ACK或NACK)。这通过控制SDA线上的电平变化来模拟。
  • 重复传输:根据通信需求,继续发送或接收数据,并根据接收方的应答发送相应的ACK或NACK信号。
  • 发送停止条件:传输完成后,将SDA从低电平切换到高电平,同时保持SCL线为高电平,以发送停止条件。
  • 错误处理:在通信过程中,通过检测SDA线和SCL线上的电平变化来处理错误,如超时、无应答等情况。

差异

       当使用硬件 I2C,系统直接使用外设来控制引脚,有效减轻了 CPU 的负担。但是,硬件 I2C 必须使用特定的引脚作为 SCL 和 SDA,这种约束限制了其灵活性。相比之下,软件模拟 I2C 可以利用任意 GPIO 引脚,因此更加灵活。尽管硬件 I2C 提供了更高效的通信和稳定性,但其配置和使用相对复杂。相反,软件 I2C 的工作流程通常更直观和清晰,因此对于初学者理解 I2C 协议可能更为有利。总体而言,在实际应用中,硬件 I2C 往往能够提供更快速和更稳定的通信。

二、AHT20温湿度传感器 

        AHT20是国内奥松生成的I2C接口的MEMS温湿度传感器,ADC位数为20Bit,具有体积小、精度高、成本低等优点。相较于AHT10,最显著的变化是体积更小,缩小到 3*3*1.0mm。相对湿度精度 RH=±2%,温度精度 T=±0.3°C。相对湿度测量范围 RH=0~100%,温度测量范围 T=-40~85°C。AHT10/15/20只是供电电压不同,其他参数没有什么不同,其中AHT15具有聚四氟乙烯防水防尘膜,允许传感器在恶劣环境条件下使用。

接口原理介绍

上图为AHT20封装图。 

 

  • 1. 温度测量原理

       AHT20 传感器使用了一个集成的温度传感器来测量环境的温度。主要原理基于温度对半导体材料电阻值的影响。通常采用的是微电阻(RTD)或热敏电阻(PTC/NTC)原理。AHT20 内部的温度传感器通过测量温度对电阻值的影响,将其转换为数字信号输出,从而得到环境的温度数据。

  • 2. 湿度测量原理

       AHT20 传感器的湿度测量采用了电容湿度传感器的原理。电容湿度传感器利用介电常数与空气中水分含量之间的关系来测量湿度。具体来说,AHT20 使用一对电容传感器电极,当介电常数随环境湿度变化时,传感器的电容值也相应变化。通过测量这种电容值的变化,AHT20 可以准确地计算出环境的相对湿度(RH)。

实物引脚

对我们手上拿到的实物,引脚功能如下(孔面朝前):

  • 电源引脚 VDD GND :

        DHT20的供电范围为 2.2-5.5 V ,VDD 接电压输入,GND 接地

  • 串行时钟 SCL:

        SCL 用于微处理器与 DHT20 之间的通讯同步。由于接口包含了完全静态逻辑,因而不存在最小 SCL 频率

  • 串行数据 SDA:

        SDA 引脚用于传感器的数据输入和输出。当向传感器发送命令时,SDA 在串行时钟( SCL )的上升沿有效,且当 SCL 为高电平时,SDA 必须保持稳定。在 SCL 下降沿之后,SDA 值可被改变。为确保通信安全,SDA 的有效时间在 SCL 上升沿之前和下降沿之后应该分别延长至 TSU and THO 。当从传感器读取数据时,SDA 在 SCL 变低以后有效( TV ),且维持到下一个 SCL 的下降沿。

 连接如下:

 传感器性能

电气特性  

三、任务实现

具体要求

        阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件。

代码示例

usart.c

#include "sys.h"
#include "usart.h"#if SYSTEM_SUPPORT_UCOS
#include "includes.h"				
#endif#if 1
#pragma import(__use_no_semihosting)             struct __FILE 
{ int handle; }; FILE __stdout;       void _sys_exit(int x) 
{ x = x; 
} 
//Öض¨Òåfputcº¯Êý 
int fputc(int ch, FILE *f)
{      while((USART1->SR&0X40)==0);USART1->DR = (u8) ch;      return ch;
}
#endif #if EN_USART1_RX   u8 USART_RX_BUF[USART_REC_LEN];    u16 USART_RX_STA=0;       void uart_init(u32 bound){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//ʹÄÜUSART1£¬GPIOAʱÖÓGPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			NVIC_Init(&NVIC_InitStructure);	USART_InitStructure.USART_BaudRate = bound;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_Cmd(USART1, ENABLE);                    }void USART1_IRQHandler(void)                {u8 Res;
#ifdef OS_TICKS_PER_SEC	 	OSIntEnter();    
#endifif(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  {Res =USART_ReceiveData(USART1);if((USART_RX_STA&0x8000)==0){if(USART_RX_STA&0x4000){if(Res!=0x0a)USART_RX_STA=0;else USART_RX_STA|=0x8000;	}else {	if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;}		 }}   		 } 
#ifdef OS_TICKS_PER_SEC	 	OSIntExit();  											 
#endif
} 
#endif	

usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" #define USART_REC_LEN  			200  	
#define EN_USART1_RX 			1		    extern u8  USART_RX_BUF[USART_REC_LEN];
extern u16 USART_RX_STA;         		void uart_init(u32 bound);
#endif

bsp_i2c.c

#include "bsp_i2c.h"
#include "delay.h"uint8_t   ack_status=0;
uint8_t   readByte[6];
uint8_t   AHT20_status=0;uint32_t  H1=0;  
uint32_t  T1=0;  uint8_t  AHT20_OutData[4];
uint8_t  AHT20sendOutData[10] = {0xFA, 0x06, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};void IIC_Init(void)
{					     GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	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);IIC_SCL=1;IIC_SDA=1;}void IIC_Start(void)
{SDA_OUT();    IIC_SDA=1;	  	  IIC_SCL=1;delay_us(4);IIC_SDA=0;delay_us(4);IIC_SCL=0;
}	  void IIC_Stop(void)
{SDA_OUT();IIC_SCL=0;IIC_SDA=0;delay_us(4);IIC_SCL=1; IIC_SDA=1;delay_us(4);							   	
}u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();     IIC_SDA=1;delay_us(1);	   IIC_SCL=1;delay_us(1);	 while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;   return 0;  
} void IIC_Ack(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}void IIC_NAck(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=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);   IIC_SCL=1;delay_us(2); IIC_SCL=0;	delay_us(2);}	 
} 	    u8 IIC_Read_Byte(unsigned char ack)
{unsigned char i,receive=0;SDA_IN();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();elseIIC_Ack();   return receive;
}void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{IIC_Start();  if(device_addr==0xA0) IIC_Send_Byte(0xA0 + ((addr/256)<<1));elseIIC_Send_Byte(device_addr);	    IIC_Wait_Ack(); IIC_Send_Byte(addr&0xFF);  IIC_Wait_Ack(); IIC_Send_Byte(data);     					   IIC_Wait_Ack();  		    	   IIC_Stop();if(device_addr==0xA0) //delay_ms(10);elsedelay_us(2);
}uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead) 
{	uint16_t data;IIC_Start();  if(device_addr==0xA0)IIC_Send_Byte(0xA0 + ((addr/256)<<1));elseIIC_Send_Byte(device_addr);	IIC_Wait_Ack();IIC_Send_Byte(addr&0xFF);  IIC_Wait_Ack(); IIC_Start();  	IIC_Send_Byte(device_addr+1);	    IIC_Wait_Ack();if(ByteNumToRead == 1){data=IIC_Read_Byte(0);}else{data=IIC_Read_Byte(1);data=(data<<8)+IIC_Read_Byte(0);}IIC_Stop();   return data;
}void  read_AHT20_once(void)
{delay_ms(10);reset_AHT20();delay_ms(10);init_AHT20();delay_ms(10);startMeasure_AHT20();delay_ms(80);read_AHT20();delay_ms(5);
}void  reset_AHT20(void)
{I2C_Start();I2C_WriteByte(0x70);ack_status = Receive_ACK();if(ack_status) printf("1");else printf("1-n-");I2C_WriteByte(0xBA);ack_status = Receive_ACK();if(ack_status) printf("2");else printf("2-n-");I2C_Stop();}void  init_AHT20(void)
{I2C_Start();I2C_WriteByte(0x70);ack_status = Receive_ACK();if(ack_status) printf("3");else printf("3-n-");	I2C_WriteByte(0xE1);ack_status = Receive_ACK();if(ack_status) printf("4");else printf("4-n-");I2C_WriteByte(0x08);ack_status = Receive_ACK();if(ack_status) printf("5");else printf("5-n-");I2C_WriteByte(0x00);ack_status = Receive_ACK();if(ack_status) printf("6");else printf("6-n-");I2C_Stop();
}void  startMeasure_AHT20(void)
{//------------I2C_Start();I2C_WriteByte(0x70);ack_status = Receive_ACK();if(ack_status) printf("7");else printf("7-n-");I2C_WriteByte(0xAC);ack_status = Receive_ACK();if(ack_status) printf("8");else printf("8-n-");I2C_WriteByte(0x33);ack_status = Receive_ACK();if(ack_status) printf("9");else printf("9-n-");I2C_WriteByte(0x00);ack_status = Receive_ACK();if(ack_status) printf("10");else printf("10-n-");I2C_Stop();
}void read_AHT20(void)
{uint8_t   i;for(i=0; i<6; i++){readByte[i]=0;}//-------------I2C_Start();I2C_WriteByte(0x71);ack_status = Receive_ACK();readByte[0]= I2C_ReadByte();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();I2C_Stop();//--------------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] = 0xFF;printf("ʧ°ÜÁË");}printf("\r\n");printf("ζÈ:%d%d.%d",T1/100,(T1/10)%10,T1%10);printf("ʪ¶È:%d%d.%d",H1/100,(H1/10)%10,H1%10);printf("\r\n");
}uint8_t  Receive_ACK(void)
{uint8_t result=0;uint8_t cnt=0;IIC_SCL = 0;SDA_IN(); delay_us(4);IIC_SCL = 1;delay_us(4);while(READ_SDA && (cnt<100)){cnt++;}IIC_SCL = 0;delay_us(4);if(cnt<100){result=1;}return result;
}void  Send_ACK(void)
{SDA_OUT();IIC_SCL = 0;delay_us(4);IIC_SDA = 0;delay_us(4);IIC_SCL = 1;delay_us(4);IIC_SCL = 0;delay_us(4);SDA_IN();
}void  SendNot_Ack(void)
{SDA_OUT();IIC_SCL = 0;delay_us(4);IIC_SDA = 1;delay_us(4);IIC_SCL = 1;delay_us(4);IIC_SCL = 0;delay_us(4);IIC_SDA = 0;delay_us(4);
}void I2C_WriteByte(uint8_t  input)
{uint8_t  i;SDA_OUT();for(i=0; i<8; i++){IIC_SCL = 0;delay_ms(5);if(input & 0x80){IIC_SDA = 1;}else{IIC_SDA = 0;}IIC_SCL = 1;delay_ms(5);input = (input<<1);}IIC_SCL = 0;delay_us(4);SDA_IN();delay_us(4);
}	uint8_t I2C_ReadByte(void)
{uint8_t  resultByte=0;uint8_t  i=0, a=0;IIC_SCL = 0;SDA_IN();delay_ms(4);for(i=0; i<8; i++){IIC_SCL = 1;delay_ms(3);a=0;if(READ_SDA){a=1;}else{a=0;}resultByte = (resultByte << 1) | a;IIC_SCL = 0;delay_ms(3);}SDA_IN();delay_ms(10);return   resultByte;
}void  set_AHT20sendOutData(void)
{AHT20sendOutData[3] = AHT20_OutData[0];AHT20sendOutData[4] = AHT20_OutData[1];AHT20sendOutData[5] = AHT20_OutData[2];AHT20sendOutData[6] = AHT20_OutData[3];}void  I2C_Start(void)
{SDA_OUT();IIC_SCL = 1;delay_ms(4);IIC_SDA = 1;delay_ms(4);IIC_SDA = 0;delay_ms(4);IIC_SCL = 0;delay_ms(4);
}void  I2C_Stop(void)
{SDA_OUT();IIC_SDA = 0;delay_ms(4);IIC_SCL = 1;delay_ms(4);IIC_SDA = 1;delay_ms(4);
}

bsp_i2c.h

#ifndef __BSP_I2C_H
#define __BSP_I2C_H#include "sys.h"
#include "delay.h"
#include "usart.h"
//ʹÓÃIIC1 ¹ÒÔØM24C02,OLED,LM75AD,HT1382    PB6,PB7#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}//IO²Ù×÷º¯Êý	 
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA	 
#define READ_SDA   PBin(7)  //ÊäÈëSDA //IICËùÓвÙ×÷º¯Êý
void IIC_Init(void);                //³õʼ»¯IICµÄIO¿Ú				 
void IIC_Start(void);				//·¢ËÍIIC¿ªÊ¼ÐźÅ
void IIC_Stop(void);	  			//·¢ËÍIICÍ£Ö¹ÐźÅ
void IIC_Send_Byte(u8 txd);			//IIC·¢ËÍÒ»¸ö×Ö½Ú
u8 IIC_Read_Byte(unsigned char ack);//IIC¶ÁÈ¡Ò»¸ö×Ö½Ú
u8 IIC_Wait_Ack(void); 				//IICµÈ´ýACKÐźÅ
void IIC_Ack(void);					//IIC·¢ËÍACKÐźÅ
void IIC_NAck(void);				//IIC²»·¢ËÍACKÐźÅvoid IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr);
uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead);//¼Ä´æÆ÷µØÖ·£¬Æ÷¼þµØÖ·£¬Òª¶ÁµÄ×Ö½ÚÊý  void  read_AHT20_once(void);
void  reset_AHT20(void);
void  init_AHT20(void);	
void  startMeasure_AHT20(void);
void  read_AHT20(void);
uint8_t  Receive_ACK(void);
void  Send_ACK(void);
void  SendNot_Ack(void);
void I2C_WriteByte(uint8_t  input);
uint8_t I2C_ReadByte(void);	
void  set_AHT20sendOutData(void);
void  I2C_Start(void);
void  I2C_Stop(void);
#endif

sys.c

#ifndef __BSP_I2C_H
#define __BSP_I2C_H#include "sys.h"
#include "delay.h"
#include "usart.h"#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}//IO²Ù×÷º¯Êý	 
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA	 
#define READ_SDA   PBin(7)  //ÊäÈëSDA //IICËùÓвÙ×÷º¯Êý
void IIC_Init(void);                //³õʼ»¯IICµÄIO¿Ú				 
void IIC_Start(void);				//·¢ËÍIIC¿ªÊ¼ÐźÅ
void IIC_Stop(void);	  			//·¢ËÍIICÍ£Ö¹ÐźÅ
void IIC_Send_Byte(u8 txd);			//IIC·¢ËÍÒ»¸ö×Ö½Ú
u8 IIC_Read_Byte(unsigned char ack);//IIC¶ÁÈ¡Ò»¸ö×Ö½Ú
u8 IIC_Wait_Ack(void); 				//IICµÈ´ýACKÐźÅ
void IIC_Ack(void);					//IIC·¢ËÍACKÐźÅ
void IIC_NAck(void);				//IIC²»·¢ËÍACKÐźÅvoid IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr);
uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead);void  read_AHT20_once(void);
void  reset_AHT20(void);
void  init_AHT20(void);	
void  startMeasure_AHT20(void);
void  read_AHT20(void);
uint8_t  Receive_ACK(void);
void  Send_ACK(void);
void  SendNot_Ack(void);
void I2C_WriteByte(uint8_t  input);
uint8_t I2C_ReadByte(void);	
void  set_AHT20sendOutData(void);
void  I2C_Start(void);
void  I2C_Stop(void);
#endif

sys.h

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"
//	 //STM32F103ºËÐÄ°åÀý³Ì
//¿âº¯Êý°æ±¾Àý³Ì
/********** mcudev.taobao.com ³öÆ·  ********/// 	 //0,²»Ö§³Öucos
//1,Ö§³Öucos
#define SYSTEM_SUPPORT_UCOS		0		//¶¨ÒåϵͳÎļþ¼ÐÊÇ·ñÖ§³ÖUCOS//λ´ø²Ù×÷,ʵÏÖ51ÀàËƵÄGPIO¿ØÖƹ¦ÄÜ
//¾ßÌåʵÏÖ˼Ïë,²Î¿¼<<CM3ȨÍþÖ¸ÄÏ>>µÚÎåÕÂ(87Ò³~92Ò³).
//IO¿Ú²Ù×÷ºê¶¨Òå
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO¿ÚµØÖ·Ó³Éä
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    #define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 //IO¿Ú²Ù×÷,Ö»¶Ôµ¥Ò»µÄIO¿Ú!
//È·±£nµÄֵСÓÚ16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //Êä³ö 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //ÊäÈë #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //Êä³ö 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //ÊäÈë #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //Êä³ö 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //ÊäÈë #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //Êä³ö 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //ÊäÈë #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //Êä³ö 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //ÊäÈë#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //Êä³ö 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //ÊäÈë#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //Êä³ö 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //ÊäÈëvoid NVIC_Configuration(void);#endif

main.c 

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"
#include "stm32f10x.h"                  // Device headerint main(void)
{	delay_init();     //ÑÓʱº¯Êý³õʼ»¯	  uart_init(115200);	 //´®¿Ú³õʼ»¯Îª115200IIC_Init();while(1){printf("¿ªÊ¼²âÁ¿£¬ÇëÉԵȣº");read_AHT20_once();delay_ms(1500);}
}

 在keil的文件栏的User下添加上述文件,然后尝试烧录运行,查看实现结果。

结果展示

 

总结

       在学习STM32单片机及其应用的过程中,完成了使用I2C协议与AHT20温湿度传感器进行数据采集,并通过串口输出的任务。我学习了I2C总线通信协议的两种实现方式:硬件I2C和软件I2C。硬件I2C利用单片机内部的硬件模块直接控制I2C总线,具有高效稳定的特点,适用于对时序要求严格的应用场景;而软件I2C则通过软件编码模拟I2C通信协议,灵活性更强,适用于特定设计需求。理解并实现了这两种方式为后续的项目实施奠定了基础。深入阅读AHT20传感器的数据手册后,我了解了其基于电容式湿度测量和温度传感器的工作原理,并学习了如何在STM32单片机上配置和操作该传感器。最终,我成功实现了每隔2秒钟从AHT20传感器采集一次温度和湿度数据,并将这些数据实时显示在连接的OLED屏幕上,同时通过串口发送到上位机的串口助手软件。这一过程不仅提升了我的嵌入式系统设计和开发能力,还加深了我对理论知识与实际应用结合的认识。

这篇关于STM32 温湿度采集与OLED显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087987

相关文章

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

据阿谱尔APO Research调研显示,2023年全球髓内钉市场销售额约为4.7亿美元

根据阿谱尔 (APO Research)的统计及预测,2023年全球髓内钉市场销售额约为4.7亿美元,预计在2024-2030年预测期内将以超过3.82%的CAGR(年复合增长率)增长。 髓内钉市场是指涉及髓内钉制造、分销和销售的行业。髓内钉是一种用于整形外科手术的医疗器械,用于稳定长骨骨折,特别是股骨、胫骨和肱骨。髓内钉通常由不銹钢或钛等材料制成,并插入骨的髓管中,以在愈合过程中提供结构支

vue+elementUI下拉框联动显示

<el-row><el-col :span="12"><el-form-item label="主账号:" prop="partyAccountId" :rules="[ { required: true, message: '主账号不能为空'}]"><el-select v-model="detailForm.partyAccountId" filterable placeholder="

WordPress网创自动采集并发布插件

网创教程:WordPress插件网创自动采集并发布 阅读更新:随机添加文章的阅读数量,购买数量,喜欢数量。 使用插件注意事项 如果遇到404错误,请先检查并调整网站的伪静态设置,这是最常见的问题。需要定制化服务,请随时联系我。 本次更新内容 我们进行了多项更新和优化,主要包括: 界面设置:用户现在可以更便捷地设置文章分类和发布金额。代码优化:改进了采集和发布代码,提高了插件的稳定

小红书商家电话采集软件使用指南

使用小红书商家电话采集软件可以提高商家电话的采集效率,以下是使用指南及附带代码。 步骤一:安装Python和相关库 首先,确保你的电脑已经安装了Python运行环境(建议安装Python3版本)。安装完成后,同样需要安装一些相关的库,如requests、beautifulsoup4等。在命令行窗口中输入以下命令进行安装: pip install requestspip install bea

温湿度采集及OLED显示

目录 软件I2C和硬件I2C每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件 软件I2C和硬件I2C "I2C"代表Inter-Integrated Circuit,是一种用于在数字电路之间进行通信的串行通信协议。软件I2C和硬件I2C是两种实现这种协议的方式。 软件I2C是通过软件来模拟I2C通信协议的实现方式。在这种情况下,微控制

Linux之时间显示

在linux中使用使用date的方式来显示时间,但是如果想按照自己想要的格式展示,那就需要加上一点参数了 显示当前时间 date 2024年 06月 23日 星期日 23:21:42 CST 显示当前年份 date +%Y 2024 显示当前月份 date +%m 6 显示当前日期 date +%d 23 自定义显示格式 date "+%Y-%m-%d

STM32单片机PWR电源控制详解

文章目录 1. PWR概述 2. 电源结构框图 3. 上电复位和掉电复位 4. 可编程电压监测器 5. 低功耗模式 6. 模式选择 6.1 睡眠模式 6.2 停止模式 6.3 待机模式 7. 代码示例 1. PWR概述 PWR(Power Control)电源控制,负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能。 可编程电压监测器

【QML】用 Image(QQuickPaintedItem) 显示图片

大体功能: 频繁地往界面推送图片,帧率达到视频效果。捕获画布上的鼠标事件和键盘事件。 代码如下: // DrawImageInQQuickPaintedItem.pro 代码如下:QT += quick# You can make your code fail to compile if it uses deprecated APIs.# In order to do so, uncom