基于stm32与AHT20温湿度传感器的软件模拟I2C通信
时间:2023-05-29 10:37:00
基于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<