【STM32】温湿度采集与OLED显示

一、任务要求

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

任务要求:

1)解释什么是“软件I2C”和“硬件I2C”?(阅读野火配套教材的第23章“I2C--读写EEPROM”原理章节)

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

二、了解I2C总线通信协议

(一)什么是I2C协议 

I2C总线协议是一种串行通信协议,由Philips公司(现在的NXP半导体)于1982年开发,用于微控制器与外部设备(如传感器、存储器等)之间的通信,没有严格的波特率要求,实现简单,可扩展性强。

2.设备角色
在I2C通信中,设备可以扮演两种角色:

(1)主设备(Master):控制总线上的所有通信,发起数据传输的设备。
(2)从设备(Slave):响应主设备的指令,接收或发送数据的设备。

3.数据传输
数据在I2C总线上传输时,一次传输包括以下步骤:

(1)起始条件(Start Condition):主设备发出一个特定的起始信号,标志着数据传输的开始。
(2)地址+读写位(Address + Read/Write Bit):主设备发送目标从设备的地址,同时指定是读取还是写入操作。
(3)数据传输(Data Transfer):根据主设备发送的读写位,数据可以从主设备传输到从设备,或者从从设备传输到主设备。
(4)应答(Acknowledge):每个数据字节传输后,接收设备都会发送应答信号,以确认数据的接收。
(5)停止条件(Stop Condition):主设备发出停止信号,表示传输结束。

4.时序特性
I2C通信的时序特性包括:

(1)时钟频率(Clock Frequency):确定数据传输的速率。
(2)数据位数(Data Bits):每个数据字节通常是8位。
(3)传输模式(Transmission Mode):可以是标准模式(100 kbit/s)、快速模式(400 kbit/s)、高速模式(3.4 Mbit/s)等不同速率。

(二)I2C协议的物理层和协议层 

物理层:
I2C总线由两根线构成:

(1)Serial Data Line (SDA):串行数据线,用于实际的数据传输。

          它可以由上拉电阻拉高,以及由任何连接在总线上的设备拉低,形成开漏或者三态输出。

(2)Serial Clock Line (SCL):串行时钟线,用于同步数据传输。

         ·时钟信号由主设备(通常是微控制器)生成,控制数据的传输速率。

         ·它也可以由上拉电阻拉高,以及由任何连接在总线上的设备拉低。

协议层: 

1.起始和停止条件:

起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。

SDA线受到SCL线影响,可以看到只有当SCL处于高电平时,SDA线传输的数据才有效

(1)SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据(开始)。

(2)SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据(结束)。

(3)每传送一个字节后,接收设备会发送一个应答位,以确认数据的接收(应答)。


2.地址和数据传输:

(1)每个I2C设备都有一个唯一的7位或10位地址。
(2)传输数据时,先发送设备地址和读/写位来选择目标设备。
(3)数据以8位字节的形式传输,每个字节后面跟随一个确认位。
3.时钟频率: 

(1)I2C支持多种时钟频率,包括:

      标准模式(100 kbit/s)、快速模式(400 kbit/s)、高速模式 (3.4 Mbit/s)
(2)时钟频率由主设备控制,在总线上设置以控制数据传输速率。
4.数据传输顺序:

数据传输是按照先发送地址,然后发送数据(或接收数据)的顺序进行的。

(三)硬件I2C和软件I2C 

硬件I2C和软件I2C各有其适用的场景和优劣势。硬件I2C提供了更高的性能和可靠性,适合需要快速数据传输和稳定操作的场合;而软件I2C则适合于资源受限、或者需要较低成本解决方案的应用,但通常牺牲了一些性能和实时性。选择合适的I2C实现方式取决于具体的应用需求和系统设计考量。

硬件I2C:

硬件I2C是指使用专门的硬件模块或者外设来实现I2C通信的方式。

1.硬件模块:

(1)微控制器或处理器内部集成了专用的硬件模块,用于生成和处理I2C总线的信号。
(2)这些硬件模块通常能够提供高精度的时钟信号、自动应答功能以及高速数据传输,因此在时间和资源敏感的应用中表现良好。
2.物理层实现:

使用硬件I2C时,物理层的连接通常简单可靠,通过连接SDA和SCL线到微控制器的专用引脚上。

软件I2C:

软件I2C是在没有硬件I2C模块的微控制器或者处理器上,通过编程实现的软件驱动方式。

1.GPIO控制:

(1)使用微控制器的通用输入输出(GPIO)引脚模拟实现I2C通信的时钟和数据线功能。

(2)通过编程控制GPIO引脚的状态变化,来模拟I2C总线上的信号传输。
2.实时性和精度:

(1)软件I2C通常比硬件I2C更,因为它依赖于处理器的时钟频率和软件实现的精度。

(2)实时性和时序控制较差,可能受到中断延迟、任务调度等因素的影响。
3.适用场景:

(1)在资源有限、或者需要在没有硬件支持的平台上实现I2C通信时使用。

(2)适合低速设备和不需要高频率通信的应用。

 三、AHT20温湿度传感器

了解AHT20芯片的相关信息,具体信息请到官方下载对应产品介绍文档
资料链接:

软件下载-温湿度传感器 温湿度芯片 温湿度变送器模块 气体传感器 流量传感器 广州奥松电子股份有限公司icon-default.png?t=N7T8http://www.aosong.com/class-36.htmlAHT20是一种数字式温湿度传感器,具有高精度和低功耗的特点,适合用于各种环境监测和控制应用。以下是关于AHT20温湿度传感器的一些主要特点和特性:

1.测量范围:

温度:-40°C+85°C

湿度:0% RH 到 100% RH
2.精度:

温度精度:±0.3°C(在0°C 到 60°C 范围内)

湿度精度:±2% RH
3.工作电压:8.1.8V 到 3.6V 的宽电压工作范围

4.接口:支持标准的I2C接口(数据传输速率最高可达400 kbit/s)

5.响应时间:

温度测量响应时间约为30 ms

湿度测量响应时间约为5.5 s

实物图如下:

 原理图如下:

 仿真电路图如下:

特性和应用

1.高精度:AHT20提供较高的温度和湿度测量精度,使其适用于对环境参数精度要求较高的应用,如气象观测、环境监测等。
2.低功耗:低功耗设计使得AHT20非常适合于需要长期运行和电池寿命长的无线传感器网络(WSN)应用。
3.快速响应:尽管湿度测量响应时间较长,但温度测量的快速响应时间适合于需要快速变化监测的应用。
4.易于集成通过标准的I2C接口和小型封装,AHT20可以方便地集成到各种电子设备和系统中,提供温湿度信息。

四、利用AHT20实现采集任务

(一)任务要求

阅读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();    
#endif
	if(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
 

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
 

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();
	else
			IIC_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));
	else
		IIC_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);
	else
		delay_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));
		else
			IIC_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
 

main.c: 

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

usart.c,bsp_i2c.c,delay.c,sys.c加到工程文件中,显示如下:

编译无误即可烧录,接受温湿度采集并显示

(三)接收结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/762527.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频号视频怎么下载保存到手机,视频号视频如何下载到电脑本地

在数字化浪潮的推动下&#xff0c;视频号成为了我们获取信息、分享生活的重要平台。但有时候&#xff0c;我们遇到一些精彩的内容&#xff0c;想要保存下来以便日后观看&#xff0c;却发现视频号并不提供直接的下载功能。下面我就来为大家详细介绍视频号视频下载的方法&#xf…

Datax快速使用之牛刀小试

前言 一次我发现业务他们在用 datax数据同步工具&#xff0c;我尤记得曾经 19 年使用过&#xff0c;并且基于当时的版本还修复了个 BUG并且做了数据同步管道的集成开发。没想到时间过的飞快&#xff0c;业务方基于海豚调度 2.0.6 的版本中有在使用&#xff0c;由于业务方还没有…

大促前夕即高点,综合电商平台的“稀缺”魔法正在消失?

新一期618大促早已结束良久了&#xff0c;但似乎其产生的余韵却仍旧未消散。 从最直观的资本市场走势来看&#xff0c;自这一波618大促陆续开展之后&#xff0c;包括京东、阿里巴巴、拼多多等港美股股价就一改此前的上行态势&#xff0c;持续下滑至今。 事实上&#xff0c;早…

【计算机网络期末复习】例题汇总(一)

重点例题选择填空简答题与传输媒体的接口的特性重点 计算机网络的性能指标计算机网络体系结构例题 选择

【Linux】线程id与互斥(线程三)

上一期我们进行了线程控制的了解与相关操作&#xff0c;但是仍旧有一些问题没有解决 本章第一阶段就是解决tid的问题&#xff0c;第二阶段是进行模拟一个简易线程库&#xff08;为了加深对于C库封装linux原生线程的理解&#xff09;&#xff0c;第三阶段就是互斥。 目录 线程id…

【解锁未来:深入了解机器学习的核心技术与实际应用】

解锁未来&#xff1a;深入了解机器学习的核心技术与实际应用 &#x1f48e;1.引言&#x1f48e;1.1 什么是机器学习&#xff1f; &#x1f48e;2 机器学习的分类&#x1f48e;3 常用的机器学习算法&#x1f48e;3.1 线性回归&#xff08;Linear Regression&#xff09;&#x1…

【PYG】Planetoid中边存储的格式,为什么打印前十条边用edge_index[:, :10]

edge_index 是 PyTorch Geometric 中常用的表示图边的张量。它通常是一个形状为 [2, num_edges] 的二维张量&#xff0c;其中 num_edges 表示图中边的数量。每一列表示一条边&#xff0c;包含两个节点的索引。 实际上这是COO存储格式&#xff0c;官方文档里也有写&#xff0c;…

爬虫逆向实战(41)-某巢登陆(AES、MD5、RSA、滑块验证码)

一、数据接口分析 主页地址&#xff1a;某巢 1、抓包 通过抓包可以发现在登录时&#xff0c;网站首先请求captcha/querySlideImage/来获取滑块验证码的图片&#xff0c;然后请求captcha/checkCode/接口来验证滑块验证码。滑块验证码校验成功后&#xff0c;请求noshiro/getPu…

高性能LDO电路设计,有配套文档

内容&#xff1a; 1、电路文件&#xff08;有仿真状态&#xff09;和PDK&#xff08;TSMC180&#xff09; 2、配套仿真结果文档讲解6页 3、参考资料三篇 指标&#xff1a; LDO 温度系数1.09ppm LDO 环路增益在 64.3dB&#xff0c;相位裕度在 66&#xff0c;系统稳定。 LDO 最大…

抛弃 Neofetch?众多优秀替代方案等你体验!

目录 抛弃 Neofetch&#xff1f;众多优秀替代方案等你体验Neofetch 的替代品FastfetchscreenFetchmacchina 抛弃 Neofetch&#xff1f;众多优秀替代方案等你体验 NeoFetch 是用 Bash 3.2 编写的命令行系统信息工具&#xff0c;该项目的主要开发人员已将 GitHub 存储库存档&…

【漏洞复现】和丰多媒体信息发布系统 QH.aspx 任意文件上传漏洞

0x01 产品简介 和丰多媒体信息发布系统也称数字标牌&#xff08;Digital Signage&#xff09;&#xff0c;是指通过大屏幕终端显示设备&#xff0c;发布商业、财经和娱乐信息的多媒体专业视听系统&#xff0c;常被称为除纸张媒体、电台、电视、互联网之外的“第五媒体”。该系…

民生银行收大额罚单:信用卡中心一同被罚,管理层如何施救?

民生银行的2024年&#xff0c;再添变故。 近日&#xff0c;国家金融监管总局宁波分局公布了数则行政处罚信息公开表。内容显示&#xff0c;民生银行&#xff08;SH:600016、HK:01988&#xff09;宁波分行、民生银行信用卡中心宁波分中心因多项违法违规事实&#xff0c;共计被处…

【Git 学习笔记】Ch1.1 Git 简介 + Ch1.2 Git 对象

还是绪个言吧 今天整理 GitHub 仓库&#xff0c;无意间翻到了几年前自学 Git 的笔记。要论知识的稳定性&#xff0c;Git 应该能挤进前三——只要仓库还在&#xff0c;理论上当时的所有开发细节都可以追溯出来。正好过段时间会用到 Git&#xff0c;现在整理出来就当温故知新了。…

Redis集群-主从复制、哨兵

●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。 主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。缺陷&#xff1a;故障 恢复无法自动化&#xff1b;写操作无法负载均…

HCIE实验这样玩太高级了吧?实现FRR+BFD+OSPF与BGP的联动

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 今天搞个HCIE实验玩玩&#xff0c;上回分享了个张总讲解的防火墙配置实验思路&#xff0c;后来还特地搞了个视…

STM32人体心电采集系统

资料下载地址&#xff1a;STM32人体心电采集系统 1、项目功能介绍 此项目主要实现了以STM32为核心的人体心电采集系统软硬件的设计。软件设计过程是在STM32上移植的uCGUI做图形界面&#xff0c;并如实显示采集到的心电波形信号&#xff0c;有SD卡存储和USB数据传输功能。 2、实…

Linux源码阅读笔记08-进程调度API系统调用案例分析

kthread_create_on_node kthread_create_on_node函数功能&#xff1a;指定存储节点创建新内核线程。源码如下&#xff1a; 操作实战 #include <linux/module.h> #include <linux/pid.h> #include <linux/sched.h> #include <linux/kthread.h> #inclu…

复制完若依后,idea没有maven窗口

右击项目 添加框架 添加maven框架就可以了

PV操作经典例题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文☀️☀️☀️三、总结&#x1f353;&#x1f353;&#x1f353; 一、前言&#x1f680;&#x1f680;&am…