【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();    
#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

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();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

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);}
}

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

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

(三)接收结果

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTPS是什么?原理是什么?用公钥加密为什么不能用公钥解密?

HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是HTTP的安全版本&#xff0c;它通过在HTTP协议之上加入SSL/TLS协议来实现数据加密传输&#xff0c;确保数据在客户端和服务器之间的传输过程中不会被窃取或篡改。 HTTPS 的工作原理 客户端发起HTTPS请求&…

C++进阶 | [4.3] 红黑树

摘要&#xff1a;什么是红黑树&#xff0c;模拟实现红黑树 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red 或 Black 。 通过对 任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树…

【RT摩拳擦掌】基于RT106L/S语音识别的百度云控制系统

【RT摩拳擦掌】基于RT106L/S语音识别的百度云控制系统 一 文档简介二 平台构建2.1 使用平台2.2 百度智能云2.2.1 物联网核心套件2.2.2 在线语音合成 2.3 playback语音数据准备与烧录2.4 开机语音准备与添加2.5 唤醒词识别词命令准备与添加 三 代码准备3.1 sln-local/2-iot 代码…

cube-studio开源一站式机器学习平台,在线ide,jupyter,vscode,matlab,rstudio,ssh远程连接,tensorboard

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; 一站式云原生机器学习平台 前言 开源地址&#xff1a;https://github.com/tencentmusic/cube-studio cube studio 腾讯开源的国内最热门的一站式机器学习mlops/大模型训练平台&#xff0c;支持多租户&…

什么是原始权益人?

摘要&#xff1a;每天学习一点金融小知识 原始权益人&#xff0c;在资产证券化&#xff08;ABS&#xff09;和公募REITs等金融产品中&#xff0c;指的是证券化基础资产的原始所有者&#xff0c;即金融产品的真正融资方。他们是按照相关规定及约定向资产支持专项计划转移其合法拥…

Mysql面试合集

概念 是一个开源的关系型数据库。 数据库事务及其特性 事务&#xff1a;是一系列的数据库操作&#xff0c;是数据库应用的基本逻辑单位。 事务特性&#xff1a; &#xff08;1&#xff09;原子性&#xff1a;即不可分割性&#xff0c;事务要么全部被执行&#xff0c;要么就…

基于决策树的旋转机械故障诊断(Python)

前置文章&#xff1a; 将一维机械振动信号构造为训练集和测试集&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/DTKjBo6_WAQ7bUPZEdB1TA 旋转机械振动信号特征提取&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/VwvzTzE-pacxqb9rs8hEVw import…

数据库定义语言(DDL)

数据库定义语言&#xff08;DDL&#xff09; 一、数据库操作 1、 查询所有的数据库 SHOW DATABASES;效果截图&#xff1a; 2、使用指定的数据库 use 2403 2403javaee;效果截图&#xff1a; 3、创建数据库 CREATE DATABASE 2404javaee;效果截图&#xff1a; 4、删除数据…

Web端登录页和注册页源码

前言&#xff1a;登录页面是前端开发中最常见的页面&#xff0c;下面是登录页面效果图和源代码&#xff0c;CV大法直接拿走。 1、登录页面 源代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>登录</ti…

springboot汽车租赁管理系统08754

目 录 摘 要 第 1 章 引 言 1.1 选题背景和意义 1.2 国内外研究现状 1.3 论文结构安排 第 2 章 系统的需求分析 2.1 系统可行性分析 2.1.1 技术方面可行性分析 2.1.2 经济方面可行性分析 2.1.3 法律方面可行性分析 2.1.4 操作方面可行性分析 2.2 系统功能需求分析…

视频监控EasyCVR视频汇聚/智能边缘网关:EasySearch无法探测到服务器如何处理?

安防监控EasyCVR智能边缘网关/视频汇聚网关/视频网关属于软硬一体的边缘计算硬件&#xff0c;可提供多协议&#xff08;RTSP/RTMP/国标GB28181/GAT1400/海康Ehome/大华/海康/宇视等SDK&#xff09;的设备接入、音视频采集、视频转码、处理、分发等服务&#xff0c;系统具备实时…

华为防火墙在广电出口安全方案中的应用(方案设计、配置、总结)

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 你们好&#xff0c;我的网工朋友。 不知道你有没有想过&#xff0c;我们每天看电视、上网追剧的广电网络&#xff0c;它的背后是如何确保安全稳定…

RANSAC空间圆拟合实现

由初中的几何知识我们可以知道&#xff0c;确定一个三角形至少需要三个不共线的点&#xff0c;因此确定一个三角形的外接圆至少可用三个点。我们不妨假设三个点坐标为P1(x1,y1,z1),P2(x2,y2,z2),P3(x3,y3,z3)。 圆方程的标准形式为&#xff1a; (xi-x)2(yi-y)2R2 &#xff08;1…

黑马点评下订单-小程序下单没问题但是Postman发送请求失败了,返回401

经过多方探索&#xff0c;这个✓8错误就是由于黑马点评使用了拦截器&#xff0c;我们直接发送请求是会被拦截器拦截下来的&#xff0c;我给出的解决方案是通过配置Postman解决&#xff0c;方法很简单&#xff01; 解决方案 右边的value写上Redis里面登录所用token值就可以了…

MSPG3507——蓝牙接收数据显示在OLED,滴答定时器延时500MS

#include "ti_msp_dl_config.h" #include "OLED.h" #include "stdio.h"volatile unsigned int delay_times 0;//搭配滴答定时器实现的精确ms延时 void delay_ms(unsigned int ms) {delay_times ms;while( delay_times ! 0 ); } int a0; …

昇思25天学习打卡营第10天|FCN图像语义分割

一、简介&#xff1a; 本篇博客是昇思大模型打卡营应用实践部分的第一次分享&#xff0c;主题是计算机视觉&#xff08;CV&#xff09;领域的FCN图像语义分割&#xff0c;接下来几天还会陆续分享其他CV领域的知识&#xff08;doge&#xff09;。 全卷积网络&#xff08;Fully…

微信小程序-插槽slot

一.插槽slot 在页面使用自定义组件的时候&#xff0c;如果在自定义组件里面写子组件&#xff0c;子组件的内容无法显示。 <custom01> <text slotslot-top>你好&#xff0c;上方组件</text> 你好&#xff0c;组件 <text slotslot-bottom>你好&#xf…

【从0实现React18】 (五) 初探react mount流程 完成核心递归流程

更新流程的目的&#xff1a; 生成wip fiberNode树标记副作用flags 更新流程的步骤&#xff1a; 递&#xff1a;beginWork归&#xff1a;completeWork 在 上一节 &#xff0c;我们探讨了 React 应用在首次渲染或后续更新时的整体更新流程。在 Reconciler 工作流程中&#xff…

Nginx 配置文件

Nginx的配置文件的组成部分&#xff1a; 主配置文件&#xff1a;nginx.conf子配置文件&#xff1a;include conf.d/*.conf 全局配置 nginx 有多种模块 核心模块&#xff1a;是 Nginx 服务器正常运行必不可少的模块&#xff0c;提供错误日志记录 、配置文件解析 、事件驱动机…

32.哀家要长脑子了!

1.299. 猜数字游戏 - 力扣&#xff08;LeetCode&#xff09; 公牛还是挺好数的&#xff0c;奶牛。。。妈呀&#xff0c;一朝打回解放前 抓本质抓本质&#xff0c;有多少位非公牛数可以通过重新排列转换公牛数字&#xff0c;意思就是&#xff0c;当这个数不是公牛数字时&#x…