锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

基于stm32与AHT20温湿度传感器的软件模拟I2C通信

时间:2023-05-29 10:37:00 cnt温度传感器

基于stm32与AHT20温湿度传感器软件模拟I2C通信

  • 一、I2C通信协议
  • 二、硬件与软件模拟I2C的区别
  • 三、AHT20温湿度传感器连接stm32的软件I2C
    • 1、实作内容
    • 2、实验代码
  • 四、效果

一、I2C通信协议

I2C总线是由Philips公司开发的一种简单的双向二线系统同步串行总线。它只需要两根线就可以在连接到总线的设备之间传输信息。
主要设备用于启动总线传输数据,并生成时钟打开传输的设备。此时,任何被搜索的设备都被视为从设备。在总线上,主、从、发、收的关系不是恒定的,而是取决于此时数据传输的方向。如果主机想向设备发送数据,主机首先从设备找到地址,然后主动向设备发送数据,最后由主机终止数据传输;如果主机想从设备接收数据,主机首先从设备找到地址。然后主机接收从设备发送的数据,最后主机终止接收过程。在这种情况下,主机负责生成定时钟和终止数据传输。

1、工作原理

连接到总线的节点设备有两个角色:主机模式和从机模式。同时,主机模式只能有一个节点,其他节点处于从机模式。主机发起了总线上数据的传输。I2C总线没有片选信号线,所以要通过协议找到相应的操作芯片。主要设备用于启动总线传输数据,并生成时钟打开传输的设备。此时,任何被搜索的设备都被认为是从设备开始的。主、从、发、手在总线上的关系不稳定,这取决于数据传输的方向。如果主机想向设备发送数据,主机首先从设备中找到地址,最后由主机终止数据传输;如果主机想从设备中接收数据,主机首先从设备中找到地址,然后从设备中接收数据,最后由主机终止接收过程。在这种情况下,主机负责生成时钟和终止数据传输。

  • I2C数据传输的基本过程:
    1.主机首先开始发送信号
    2.主机随后发送从机地址信息(一个字节),字节信息的最低位置是读写控制码:1读,0写。从机设备的设备地址高7位
    3.从机后发出确认信息
    4.主机开始发送信号数据。每当发送字节数据时,从机器设备将确认信号发送给主机
    5.主机最终发送停止信号。
    START开始信号:在SCL当时钟线为高电平时,SDA数据线由高到低,产生开始信号
    STOP 停止信号:在SCL当时钟线为高电平时,SDA数据线由低变高,产生停止信号
    ACK确认信号: 当主机编写从机设备时,每次编写一个字节。如果数据正确,从机设备将在下一个时钟周期降低数据线,以通知主机有效运行。
    当主机读从机设备时,每次正确读完一个字节后,主机将在下一个时钟周期同样也要讲数据线拉低,发出确认信号,来通知从机所发数据以收到
    总之,SCL信号必须由主机发送
    注:读取从机设备时,当主机接收最后一个字节数据时,不发送确认信号,直接发送停止信号。在任何时候SCL当时钟线为高电平时,SDA数据上的电平变化被认为是起始信号和停止信号,因此在时钟为低电时必须改变数据的变化
    在这里插入图片描述

二、硬件与软件模拟I2C的区别

原理:硬件I2C(提供特殊的SDA,SCL口)时钟由系统产生,通常由晶体振动分频产生。I2C一般通过编程I/O模拟时钟线和数据线
控制:硬件I2C各种操作都是通过硬件中断实现的。I2C没有中断的概念,通过IO接口电位置高低,实现写入和读取
性能上:硬件模式更高效更稳定硬件I2C比软件I2C速度快很多,占用的时间也少,硬件I2C使用简单,只需将数据发送到指定的寄存器,除上述基本模式(标准模式下串行8位双向数据传输位率可达100Kbit/s)外,快速模式下可达400Kbit/s,高速模式下可达3,4Mbit/s。这两种模式在硬件电路和软件协议上都有变化

三、AHT20温湿度传感器连接stm32的软件I2C

1、实作内容

使用i2c通信协议完成温湿度采集,通过串口发送到上位机
硬件选用野火的stm32f103指南
开发板,AHT20温度传感器

AHT20数据手册i2c通信相关内容



2、实验代码

可见AHT20官网下载相关i2c参考例程

打开stm32空闲工程在工程中添加以下文件。

以下是需要使用的代码文件:

main.c

#include "delay.h" #include "usart.h" #include "bsp_i2c.h"   int main(void) { 
           delay_init();     //延迟初始化   uart_init(115200);  //串口波特率设置为115200  IIC_Init();   while(1)
	{ 
        
		printf("¿ªÊ¼²âÁ¿£¬ÇëÉԵȣº");
		read_AHT20_once();
		delay_ms(2000);
  }
}

AHT20_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;  //Humility
uint32_t  T1=0;  //Temperature

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;
 
}
//产生IIC起始信号
void IIC_Start(void)
{ 
        
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//住I2C总线,准备发送或接收数据
}	  
//²úÉúIICÍ£Ö¹ÐźÅ
void IIC_Stop(void)
{ 
        
	SDA_OUT();//sdaÏßÊä³ö
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
	delay_us(4);							   	
}
//µÈ´ýÓ¦´ðÐźŵ½À´
//·µ»ØÖµ£º1£¬½ÓÊÕÓ¦´ðʧ°Ü
// 0£¬½ÓÊÕÓ¦´ð³É¹¦
u8 IIC_Wait_Ack(void)
{ 
        
	u8 ucErrTime=0;
	SDA_IN();      //SDAÉèÖÃΪÊäÈë 
	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;//ʱÖÓÊä³ö0 
	return 0;  
} 
//²úÉúACKÓ¦´ð
void IIC_Ack(void)
{ 
        
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//²»²úÉúACKÓ¦´ð 
void IIC_NAck(void)
{ 
        
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				     
//IIC·¢ËÍÒ»¸ö×Ö½Ú
//·µ»Ø´Ó»úÓÐÎÞÓ¦´ð
//1£¬ÓÐÓ¦´ð
//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);   //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    
//¶Á1¸ö×Ö½Ú£¬ack=1ʱ£¬·¢ËÍACK£¬ack=0£¬·¢ËÍnACK 
u8 IIC_Read_Byte(unsigned char ack)
{ 
        
	unsigned char i,receive=0;
	SDA_IN();//SDAÉèÖÃΪÊäÈë
  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();//·¢ËÍnACK
	else
			IIC_Ack(); //·¢ËÍACK 
	return receive;
}
 
void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{ 
        
	IIC_Start();  
	
	if(device_addr==0xA0) //eepromµØÖ·´óÓÚ1×Ö½Ú
		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)//LM75ζÈÊý¾ÝΪ11bit
		{ 
        
			data=IIC_Read_Byte(0);
		}
		else
			{ 
        
				data=IIC_Read_Byte(1);
				data=(data<<8)+IIC_Read_Byte(0);
			}
		IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ 
		return data;
}


/********** *ÉÏÃæ²¿·ÖΪIO¿ÚÄ£¿éI2CÅäÖà * *´ÓÕâÒÔÏ¿ªÊ¼ÎªAHT20µÄÅäÖÃI2C *º¯ÊýÃûÓÐIICºÍI2CµÄÇø±ð£¬Çë×¢Ò⣡£¡£¡£¡£¡ * *2020/2/23×îºóÐÞ¸ÄÈÕÆÚ * ***********/
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) ;
	else printf("1-n-");
	I2C_WriteByte(0xBA);
	ack_status = Receive_ACK();
		if(ack_status) ;
	else printf("2-n-");
	I2C_Stop();

	/* AHT20_OutData[0] = 0; AHT20_OutData[1] = 0; AHT20_OutData[2] = 0; AHT20_OutData[3] = 0; */
}



void  init_AHT20(void)
{ 
        
	I2C_Start();

	I2C_WriteByte(0x70);
	ack_status = Receive_ACK();
	if(ack_status) ;
	else printf("3-n-");	
	I2C_WriteByte(0xE1);
	ack_status = Receive_ACK();
	if(ack_status) ;
	else printf("4-n-");
	I2C_WriteByte(0x08);
	ack_status = Receive_ACK();
	if(ack_status) ;
	else printf("5-n-");
	I2C_WriteByte(0x00);
	ack_status = Receive_ACK();
	if(ack_status) ;
	else printf("6-n-");
	I2C_Stop();
}



void  startMeasure_AHT20(void)
{ 
        
	//------------
	I2C_Start();

	I2C_WriteByte(0x70);
	ack_status = Receive_ACK();
	if(ack_status);
	else printf("7-n-");
	I2C_WriteByte(0xAC);
	ack_status = Receive_ACK();
	if(ack_status) ;
	else printf("8-n-");
	I2C_WriteByte(0x33);
	ack_status = Receive_ACK();
	if(ack_status);
	else printf("9-n-");
	I2C_WriteByte(0x00);
	ack_status = Receive_ACK();
	if(ack_status) ;
	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();
	//Send_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",T1/10,T1%10);
	printf("ʪ¶È:%d.%d",H1/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<
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章