基于stm32的温度采集并且显示

news2025/2/26 15:18:53

目录

一、I2C总线通信协议

(一)I2C简介

(二)I2C物理层

(三)I2C协议层

1、I2C基本读写过程

2、通信的起始和停止信号

3、数据的有效性

4、地址及数据方向

5、响应

(四)软件I2C和硬件I2C

1、硬件I2C

2、软件I2C

软件实现

3、二者差异

二、STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

(一)AHT20介绍

1、简介:

2、接口定义

(二)实验内容及其操作

1、题目要求:

2、代码编写

3、效果展示

三、总结


一、I2C总线通信协议

(一)I2C简介

        STM32的I2C(Inter-Integrated Circuit)协议是一种用于短距离串行数据交换的通信协议。它允许STM32微控制器与其他设备(如传感器、存储器等)进行有效的通信。通过两根线(串行数据线SDA和串行时钟线SCL),STM32可以作为主设备控制多个从设备,实现数据的传输和交换。该协议支持多种通信速率,并通过起始和停止条件来管理数据传输。

(二)I2C物理层

注:所有I2C设备的SCL连在一起,SDA连在一起,设备的SCL和SDA均要配置成开漏输出模式 ,SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

对I2物理层简单介绍:

1、信号线

  • SDA(Serial Data Line):双向串行数据线,用于实际数据传输。
  • SCL(Serial Clock Line):时钟线,由主设备控制,用于同步数据传输的时钟信号。

2、电气特性

  • 电压级别:通常为3.3V或5V,取决于具体的设备和应用场景。
  • 上拉电阻:连接到SDA和SCL线,以确保在无信号状态下保持高电平,通常为4.7kΩ。

总线空闲状态:当所有设备空闲时,SDA和SCL线被上拉电阻拉成高电平。

3、地址分配和多设备支持

  • 每个设备在总线上都有唯一的7位地址,用于标识设备。
  • 支持多个主机(控制器)和多个从机(外设),主机通过地址选择器件进行通信。

4、仲裁机制

  • 多主机情况下,使用仲裁机制决定哪个主机可以访问总线,防止数据冲突。
  • 仲裁是通过在每个数据位之后的ACK(应答位)或NACK(非应答位)来实现的。

5、传输速率

  • 标准模 式:传输速率为100kbit/s。
  • 快速模式:传输速率为400kbit/s。
  • 高速模式:最高可达3.4Mbit/s,但支持此模式的设备相对较少,因此常用传输速率为400kbit/s。

6、物理连接限制

  • 总线的最大电容为400pF,这限制了连接到总线的设备数量,最多支持挂载127个从机。

7、总结上述介绍文字

  • I2C物理层提供了一种简单而灵活的方式,让多个设备通过两条线路进行数据通信。
  • 通过地址分配、仲裁机制和多种传输速率选择,I2C允许在单一总线上实现复杂的设备互联,适用于各种嵌入式系统和传感器网络中的数据交换需求。

(三)I2C协议层

I2C 的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

对I2C协议层简单介绍:

1、I2C基本读写过程

(1)接发:

  • 发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

  • 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

  • 发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

  • 接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

(2)读写:

  • 指定地址写:对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

  • 当前地址读:对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)

  • 指定地址读:对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

2、通信的起始和停止信号

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平

3、数据的有效性

  • I2C使用SDA信号线来传输数据,使用SCL信号线进行数据同步。 SDA数据线在SCL的每个时钟周期传输一位数据。
  • SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。
  • 当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备

4、地址及数据方向

        每个I2C设备有独立地址,主机通过SDA线发送设备地址(SLAVE_ADDRESS)以寻找从机。协议允许设备地址为7位或10位,但实际应用中7位地址更为普遍。地址后紧跟一个数据方向位(R/W),位于第8位或第11位。R/W为“1”表示主机读取从机数据,为“0”表示主机向从机写入数据。

        读数据方向时,主机会释放对 SDA 信号线的控制,由从机控制 SDA 信号线,主机接收信号,写数据方向时,SDA由主机控制,从机接收信号。        

5、响应

        I2C的数据和地址传输都有响应,包括“ACK”(应答)和“NACK”(非应答)信号。作为接收端,接收到一个字节数据或地址后,若要继续接收数据,需发送“ACK”信号;若要结束数据传输,需发送“NACK”信号,发送方收到后会停止数据传输。

        传输时主机产生时钟,在第 9 个时钟时,数据发送端会释放 SDA 的控制权,由数据接收端控制 SDA,若 SDA 为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。        

(四)软件I2C和硬件I2C

I2C的两种方式——硬件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线上的电平变化来处理错误,如超时、无应答等情况。

3、二者差异

        硬件 I2C 直接使用外设来控制引脚,可以减轻 CPU 的负担。不过使用硬件I2C 时必须使用某些固定的引脚作为 SCL 和 SDA,软件模拟 I2C 则可以使用任意 GPIO 引脚,相对比较灵活。对于硬件I2C用法比较复杂,软件I2C的流程更清楚一些。如果要详细了解I2C的协议,使用软件I2C可能更好的理解这个过程。在使用I2C过程,硬件I2C可能通信更加快,更加稳定。

二、STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

(一)AHT20介绍

1、简介

        DHT20 是 DHT11 的全新升级产品,配置了专用的 ASIC 传感器芯片、高性能的半导体硅基电容式湿度传感器和一个标准的片上温度传感器,并使用了标准 I²C 数据输出信号格式。其性能已经大大提升,并且超过了前一代传感器( DHT11 )的可靠性水平。新一代升级产品,经过改进使其在高温高湿环境下的性能更稳定;同时,产品的精度、响应时间、测量范围都得到了大幅的提升。每一个传感器的出厂都经过严格的校准和测试,保障并满足客户的大规模应用

2、接口定义

(1)电源引脚 VDD GND :

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

(2)串行时钟 SCL:

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

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

应用电路接线图:

(二)实验内容及其操作

1、题目要求

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

2、代码编写

        此处在固件库版的空白工程上进行添加代码,并实现以下功能:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机

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

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

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 header


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

将上述代码和main.c文件放在User中如下图所示:

3、效果展示

三、总结

        通过本次学习我进一步掌握了I2C协议的内容,以及使用使得我能够通过I2C协议与多种外设进行融合。

参考博客:AHT20温度采集_uart是什么意思啊-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常说的云VR是什么意思?与传统vr的区别

虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;是一种利用计算机技术模拟产生一个三维空间的虚拟世界&#xff0c;让用户通过视觉、听觉、触觉等感官&#xff0c;获得与现实世界类似或超越的体验。VR技术发展历程可追溯至上世纪&#xff0c;经历概念提出、…

方差分析【单/双因素方差分析】

文章目录 方差分析一、单因素方差分析&#xff08;Analysis of Variance&#xff09;1.方差分析在做什么&#xff1f;2.方差分析的思路&#xff1a;3.方差分析中的计算&#xff1a;4.构造F统计量&#xff1a; 二、双因素方差分析(Two-way ANOVA)1.双因素方差分析在做什么&#…

HCIA 18 结束 企业总部-分支综合实验(上)

1.实验介绍及拓扑 &#xff08;1&#xff09;总部和分支机构都可以上互联网访问8.8.8.8&#xff1b; &#xff08;2&#xff09;总部和分支机构使用广域网专线互访作为主线&#xff0c;并且通过互联网建立GRE隧道互访作为备线&#xff1b; &#xff08;3&#xff09;总部内为…

【database3】oracle:数据交换/存储/收集

文章目录 1.oracle安装&#xff1a;swap&#xff0c;dd1.1 创建swap交换区&#xff1a;grep MemTotal /proc/meminfo &#xff08;安装Oracle物理内存要求1024MB以上&#xff09;&#xff0c;grep SwapTotal /proc/meminfo1.2 安装依赖包及改系统核心参数&#xff1a;关闭一些系…

机器学习算法(二):1 逻辑回归的从零实现(普通实现+多项式特征实现非线性分类+正则化实现三个版本)

文章目录 前言一、普通实现1 数据集准备2 逻辑回归模型3 损失函数4 计算损失函数的梯度5 梯度下降算法6 训练模型二、多项式特征实现非线性分类1 数据准备与多项式特征构造2 逻辑回归模型三、逻辑回归 --- 正则化实现1 数据准备2 逻辑回归模型3 正则化损失函数4 计算损失函数的…

Cyber Weekly #12

赛博新闻 1、Anthropic发布Claude 3.5 Sonnet 本周五&#xff08;6月21日&#xff09;凌晨&#xff0c;Anthropic宣布推出其最新的语言模型Claude 3.5 Sonnet&#xff0c;距离上次发布Claude3才过去3个月。Claude3.5拥有20万token的长上下文窗口&#xff0c;目前已经在Claude…

企业中订单超时关闭是怎么做的?我说用延迟消息,面试官让我回去等消息?

文章目录 背景时序图方案对比方案一 被动关闭方案二 定时关闭方案三 Rocket MQ延迟消息 总结 背景 订单超时未支付是电商中的一个核心场景&#xff0c;当用户创建订单后&#xff0c;超过一定时间没有支付&#xff0c;平台需要及时将该订单关闭。需要关闭的主要原因有以下几个&…

初中英语优秀作文分析-005How to Plan Our Life Wisely-如何明智地规划我们的生活

PDF格式公众号回复关键字:SHCZYF005 记忆树 1 The “double reduction policy” reduces the burden on students and offers us more spare time than before, but how to plan our life wisely? 翻译 “双减政策”减轻了学生的负担&#xff0c;给了我们比以前更多的业余…

预备资金有5000-6000买什么电脑比较好?大学生电脑选购指南

小新pro14 2024 处理器&#xff1a;采用了英特尔酷睿Ultra5 125H或Ultra9 185H两种处理器可选&#xff0c;这是英特尔最新的高性能低功耗处理器&#xff0c;具有18个线程&#xff0c;最高可达4.5GHz的加速频率&#xff0c;支持PCIe 4.0接口&#xff0c;内置了强大的ARC核芯显卡…

Windows Update Blocker 完全禁用或启用Windows系统上的自动更新,一键阻止,无需额外操作!

你是否曾因为突如其来的系统更新而感到手忙脚乱&#xff1f;Windows Update Blocker v1.8让你只需一键&#xff0c;即可完全禁用或启用Windows系统上的自动更新&#xff0c;不需要任何的额外操作&#xff0c;只需要打开软件&#xff0c;点击应用即可关闭Windows系统上的自动更新…

DVWA-CSRF-samesite分析

拿DVWA的CSRF为例子 接DVWA的分析&#xff0c;发现其实Impossible的PHPSESSID是设置的samesite1. 参数的意思参考Set-Cookie SameSite:控制 cookie 是否随跨站请求一起发送&#xff0c;这样可以在一定程度上防范跨站请求伪造攻击&#xff08;CSRF&#xff09;。 下面用DVWA CS…

[案例]国家数据局:首批“数据要素×”典型案例深度解析系列之五

“ 通过示范引领&#xff0c;激励多方主体积极参与&#xff0c;释放数据要素价值。” 本文为“数据要素”典型案例深度解析系列的第五篇&#xff0c;前四篇请见 [案例]国家数据局&#xff1a;首批“数据要素”典型案例深度解析系列之一 [案例]国家数据局&#xff1a;首批“数…

微信小程序入门2

微信开发者工具的安装方法 1.打开微信开发者工具下载页面 在微信小程序管理后台的左侧边栏中选择“开发工具”&#xff0c;然后选择“开发者工具”&#xff0c;即可找到微信开发者工具的下载页面。 2.打开微信开发者工具的下载链接页面 单击“下载” 按钮下载&#xff0c;即…

【网络安全的神秘世界】已解决burpsuite报错Failed to start proxy service on 127.0.0.1:8080

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 解决burpsuite无法在 127.0.0.1&#xff1a;8080 上启动代理服务端口被占用以及抓不到本地包的问题 Burpsuite无法启动proxy…

深度学习 --- stanford cs231学习笔记五(训练神经网络的几个重要组成部分之二,数据的预处理)

数据的预处理(Data Preprocessing) 2 Data Preprocessing数据的预处理 数据预处理的几种方法 2&#xff0c;1 数据的零点中心化 数据的零点中心化的目的就是为了把数据的整体分布拉回到原点附近&#xff0c;也就是让数据的整体均值变为0。 ​ 2&#xff0c;2 数据的标准化 数据…

VS Code Arduino编程

①Arduino Arduino是一款便捷灵活、方便上手的开源电子原型平台。包含硬件&#xff08;各种型号的Arduino板&#xff09;和软件&#xff08;Arduino IDE)。 ②VS Code&#xff08;全称 Visual Studio Code&#xff09; 是由微软开发的一款开源、轻量级的跨平台现代代码编辑器…

PADS学习笔记

1.PADS设计PCB流程 封装库&#xff08;layout&#xff09;&#xff0c;原理图库&#xff08;logic&#xff09;的准备原件封装的匹配&#xff08;logic&#xff09;原理图的绘制&#xff08;logic&#xff09;导网表操作&#xff08;logic&#xff09;导入结构&#xff08;lay…

一文掌握提升 Python 代码质量的最佳伴侣工具:black、isort、flake8 和 mypy

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在 Python 项目开发中&#xff0c;为了保持代码质量和提高开发效率&#xff0c;我们常需借助一些工具。今天&#xff0c;我将为大家介绍四个 Python 代码工程的得力助手&#xff1a;black、isort、flak…

风险评估概念

渗透服务只是风险评估的一种内容 风险评估的概念 是识别&#xff0c;控制&#xff0c;降低&#xff0c;或者消除可能影响到信息系统的安全风险过程。 风险评估的定义&#xff1a; 就是量化测评一种事情带来的影响&#xff0c;整个量化的过程是偏主观化(客户觉得) 风险的特…

AI 开发平台(Coze)搭建小游戏《挑战花光10亿》

前言 本文讲解如何从零开始&#xff0c;使用扣子平台去搭建一个小游戏 这是成品链接&#xff1a;挑战花光10亿 - 扣子 AI Bot (coze.cn) 欢迎大家去体验一下 效果 正文 什么是coze平台&#xff1f; 扣子&#xff08;Coze&#xff09;是字节跳动推出的一站式 AI 开发平台&am…