文章目录

  • 一、I2C总线通讯协议
    • 1.I2C总线简介
    • 2.I2C 协议的物理层和协议层
      • 2.1物理层
      • 2.2协议层
    • 3.I2C的两种方式——硬件I2C和软件I2C
      • 3.1硬件I2C
      • 3.2软件I2C
      • 3.3两者区别
  • 二、AHT20温湿度传感器
    • 1.外观
    • 2.原理图
    • 3.引脚说明
    • 4.温湿度测量范围
    • 5.优点
  • 三、实现AHT20采集程序
    • 1.题目要求
    • 2.编写代码
    • 3.执行测试
    • 4.结果显示
  • 四、参考资料

一、I2C总线通讯协议

1.I2C总线简介

I2C是Inter-Integrated Circuit的简称,读作:I-squared-C。由飞利浦公司于1980年代提出,为了让主板、嵌入式系统或手机用以连接低速周边外部设备而发展。

I2C总线是一种双向的同步串行总线,它支持设备之间的短距离通信,经常用于处理器和一些外围设备之间的接口通信。I2C总线的标准通信速率是100Kbps,快速模式是400Kbps,高速模式支持3.4Mbps。I2C总线支持多设备的通信,而且各个设备之间的SCL和SDA线都是线与关系。I2C总线上扩展的器件的数量主要由电容负载来决定,其负载能力为400pF。I2C总线具有极低的电流消耗。

2.I2C 协议的物理层和协议层

2.1物理层

I2C总线物理层由两根线组成:串行时钟线SCL串行数据线SDA。由于这两根线都是开漏输出结构,因此必须都接上拉电阻到高电平,因此当总线处于空闲状态时,两根线都处于高电平状态。下图为I2C总线的物理层示意图。


I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。

I2C通信方式为半双工,只有一根SDA线,同一时间只可以单向通信,485也为半双工,SPI和uart为双工。

2.2协议层

I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的设备地址。通常的我们将CPU模块作为主设备,而挂接在总线上的其他设备作为从设备。I2C总线上的主设备与从设备之间以8字节为单位进行双向数据传输,并且每个单位后还须跟着一位ACK位。其中数据在SCL处于低电平时被放到SDA数据线上,在SCL处于高电平时进行数据的采样。下图是I2C总线的数据传输协议时序图。


由图可知,I2C总线的传输时序包括:开始条件地址帧数据帧停止条件重复开始条件

开始条件:标识传输正式开始,当SCL处于高电平时,SDA由高电平变为低电平。这样所有Slave设备都会知道传输已经开始。

地址帧:地址帧总是在一次通信的最开始出现,通常包括7位的设备地址(MSB)和最后1位的读写控制位(1表示读,0表示写)。接下来是1位的NACK/ACK,当这8位地址发送完成后,Slave设备获得SDA的控制权,此时Slave设备应该在第9个时钟脉冲之前回复一个**ACK(将SDA拉低)**以表示数据接收正常,否则表示数据接受失败,控制权交由Master设备处理。

数据帧:在地址帧发送之后,就可以开始传送数据了。每个数据帧8位,数据帧的数量可以是任意的,直到产生停止条件。每一个8位数据传输完成之后,接收方就需要回复一个ACK/NACK。

停止条件:当所有数据都发送完成时,当SCL处于高电平时,SDA由低电平变为高电平。除了开始条件和停止条件,在正常的数据传输过程中,当SCL处于高电平时,SDA上的值不能变化,否则会意外产生停止条件。

重复开始条件:有时Master设备需要在一次通信中进行多次消息交换(例如切换读写操作等),并且不希望其他Master设备干扰,这时可以使用重复开始条件。再一次通信中,Master设备可以产生多次开始条件来完成多次信息交换,最后在产生一个停止条件结束整个通信过程。

应答信号

主设备每发送完8bit数据后等待从设备的ACK,即在第9个clk,读取到SDA低电平为有效;主设备把clk拉低,并将sda换成输入模式(上拉电阻,默认高电平)读取第9位,clk再次拉高,读取从设备发来的ACK。这里又分两种情况:

1.写操作:主设备把clk拉高,等待读取ACK,从设备发现clk拉高后,就把sda拉低,告诉主设备,成功接收到8位数据。

2.读操作:主设备发送芯片地址和寄存器地址,这两个字节的ACK都是由从设备来拉低,同写操作;从设备开始向从设备发送数据,clk为低时,sda变化,主设备clk拉高时读取sda,ACK由主设备拉低;当从设备发送完一个字节后,主设备强制把ACK拉高,通知从设备不要需要再发了,从设备发现这个ACK没有被拉低,认为主设备接收错误,也就结束发送了,当然从设备自己也知道这是一个字节。

3.I2C的两种方式——硬件I2C和软件I2C

3.1硬件I2C

硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的I2C;一般也较为稳定,但是程序较为繁琐。硬件(固件)I2C是直接调用内部寄存器进行配置;而软件I2C是没有寄存器这个概念的。

硬件I2C的使用
只要配置好对应的寄存器,外设就会产生标准串口协议的时序。在初始化好 I2C 外设后,只需要把某寄存器位置 1,此时外设就会控制对应的 SCL 及 SDA 线自动产生 I2C 起始信号,不需要内核直接控制引脚的电平。

3.2软件I2C

软件I2C一般是使用GPIO管脚,用软件控制SCL,SDA线输出高低电平,模拟i2c协议的时序。

软件I2C的使用
需要在控制产生 I2C 的起始信号时,控制作为 SCL 线的 GPIO 引脚输出高电平,然后控制作为 SDA 线的 GPIO 引脚在此期间完成由高电平至低电平的切换,最后再控制SCL 线切换为低电平,这样就输出了一个标准的 I2C 起始信号。

3.3两者区别

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

二、AHT20温湿度传感器

1.外观

2.原理图

3.引脚说明

6根引脚,名称与功能如下;
NC 保持悬空
vdd 为外接供电电源输入端
GND 地线
SCL I2C通信模式时钟信号,双向
SDA I2C通信模式数据信号,双向
NC 保持悬空

4.温湿度测量范围

5.优点

  • 高精度,完全校准
  • 极高的可靠性与卓越的长期稳定性(较上一代aht10有极大的提升)
  • 抗干扰能力强
  • 性价比极高
  • 适用于恶劣的环境条件下

三、实现AHT20采集程序

1.题目要求

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

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

2)阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win10)。

2.编写代码

在野火提供的示例代码中,打开一个只包含固件库的空项目。向工程中添加相关代码:

主函数代码如下:
main.c

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"int main(void)
{   delay_init();     //延时函数  uart_init(115200);     //uart函数设置波特率问115200IIC_Init();while(1){printf("温度湿度显示");read_AHT20_once();delay_ms(2000);}
}

如图在main函数中调用了delay.h延时函数,usart.h通用同步/异步串行接收/发送函数,在主函数体中进行调用两个函数,在while循环体中循环输出“温度湿度显示”,然后读取AHT20传感器一次,接下来延时2000ms就是2s,所以这里关键点就是这个AHT20的内容,我们接下来会说明。

然后将如下函数放在main函数同一目录文件下:

usart.c

#include "sys.h"
#include "usart.h"//STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///
//è?1?ê1ó?ucos,?ò°üà¨????μ?í·???t?′?é.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h"                 //ucos ê1ó?
#endif
//
//STM32?a·¢°?
//′??ú13?ê??ˉ          //     //
//?óè?ò???′ú??,?§3?printfoˉêy,??2?Dèòa????use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//±ê×??aDèòaμ??§3?oˉêy
struct __FILE
{ int handle; }; FILE __stdout;
//?¨ò?_sys_exit()ò?±ü?aê1ó?°??÷?ú?£ê?
void _sys_exit(int x)
{ x = x;
}
//???¨ò?fputcoˉêy
int fputc(int ch, FILE *f)
{      while((USART1->SR&0X40)==0);//?-?··¢?í,?±μ?·¢?ííê±?   USART1->DR = (u8) ch;      return ch;
}
#endif /*ê1ó?microLibμ?·?·¨*//*
int fputc(int ch, FILE *f)
{USART_SendData(USART1, (uint8_t) ch);while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}  return ch;
}
int GetKey (void)  { while (!(USART1->SR & USART_FLAG_RXNE));return ((int)(USART1->DR & 0x1FF));
}
*/#if EN_USART1_RX   //è?1?ê1?üá??óê?
//′??ú1?D??·t??3ìDò
//×¢òa,?áè?USARTx->SR?ü±ü?a?a??????μ?′í?ó
u8 USART_RX_BUF[USART_REC_LEN];     //?óê??o3?,×?′óUSART_REC_LEN??×??ú.
//?óê?×′ì?
//bit15£?    ?óê?íê3é±ê??
//bit14£?    ?óê?μ?0x0d
//bit13~0£?  ?óê?μ?μ?óDD§×??úêy??
u16 USART_RX_STA=0;       //?óê?×′ì?±ê??     void uart_init(u32 bound){//GPIO???úéè??GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //ê1?üUSART1£?GPIOAê±?ó//USART1_TX   PA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //?′ó?í?íìê?3?GPIO_Init(GPIOA, &GPIO_InitStructure);//USART1_RX   PA.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//????ê?è?GPIO_Init(GPIOA, &GPIO_InitStructure);  //Usart1 NVIC ????NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//?à??ó??è??3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;     //×óó??è??3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQí¨μàê1?üNVIC_Init(&NVIC_InitStructure);    //?ù?Y???¨μ?2?êy3?ê??ˉVIC??′??÷//USART 3?ê??ˉéè??USART_InitStructure.USART_BaudRate = bound;//ò?°?éè???a9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×?3¤?a8??êy?Y??ê?USART_InitStructure.USART_StopBits = USART_StopBits_1;//ò???í£?1??USART_InitStructure.USART_Parity = USART_Parity_No;//?T????D£?é??USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//?Tó2?têy?Yá÷????USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  //ê?·¢?£ê?USART_Init(USART1, &USART_InitStructure); //3?ê??ˉ′??úUSART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//?a???D??USART_Cmd(USART1, ENABLE);                    //ê1?ü′??ú }void USART1_IRQHandler(void)                    //′??ú1?D??·t??3ìDò{u8 Res;
#ifdef OS_TICKS_PER_SEC     //è?1?ê±?ó?ú??êy?¨ò?á?,?μ?÷òaê1ó?ucosIIá?.OSIntEnter();
#endifif(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //?óê??D??(?óê?μ?μ?êy?Y±?D?ê?0x0d 0x0a?á?2){Res =USART_ReceiveData(USART1);//(USART1->DR);    //?áè??óê?μ?μ?êy?Yif((USART_RX_STA&0x8000)==0)//?óê??′íê3é{if(USART_RX_STA&0x4000)//?óê?μ?á?0x0d{if(Res!=0x0a)USART_RX_STA=0;//?óê?′í?ó,??D??aê?else USART_RX_STA|=0x8000; //?óê?íê3éá? }else //?1??ê?μ?0X0D{  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;//?óê?êy?Y′í?ó,??D??aê??óê?   }      }}          }
#ifdef OS_TICKS_PER_SEC     //è?1?ê±?ó?ú??êy?¨ò?á?,?μ?÷òaê1ó?ucosIIá?.OSIntExit();
#endif
}
#endif

我们看到这里调用了usart.h和sys.h文件,所以我们接下来还要编写这两个代码:

usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h" //STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///
//STM32?a·¢°?
//′??ú13?ê??ˉ          #define USART_REC_LEN            200     //?¨ò?×?′ó?óê?×??úêy 200
#define EN_USART1_RX            1           //ê1?ü£¨1£?/???1£¨0£?′??ú1?óê?extern u8  USART_RX_BUF[USART_REC_LEN]; //?óê??o3?,×?′óUSART_REC_LEN??×??ú.??×??ú?a??DD·?
extern u16 USART_RX_STA;                //?óê?×′ì?±ê??
//è?1???′??ú?D???óê?£???2?òa×¢êíò???oê?¨ò?
void uart_init(u32 bound);
#endif

sys.c

#include "sys.h"//STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///  //STM32?a·¢°?
//?μí3?D??·?×ééè???ˉ           //********************************************************************************
void NVIC_Configuration(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //éè??NVIC?D??·?×é2:2???à??ó??è??£?2???ìó|ó??è??}

sys.h

#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
//   //STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///      //0,2??§3?ucos
//1,?§3?ucos
#define SYSTEM_SUPPORT_UCOS     0       //?¨ò??μí3???t?Dê?·??§3?UCOS//??′?2ù×÷,êμ??51àà??μ?GPIO????1|?ü
//??ì?êμ??????,2???<<CM3è¨ít????>>μú????(87ò3~92ò3).
//IO?ú2ù×÷oê?¨ò?
#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?úμ??·ó3é?
#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?ú2ù×÷,????μ¥ò?μ?IO?ú!
//è·±£nμ??μD?óú16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //ê?3?
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //ê?è? #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //ê?3?
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //ê?è? #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //ê?3?
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //ê?è? #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //ê?3?
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //ê?è? #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //ê?3?
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //ê?è?#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //ê?3?
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //ê?è?#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //ê?3?
#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;  //Humility
uint32_t  T1=0;  //Temperatureuint8_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 ;   //í?íìê?3?GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);IIC_SCL=1;IIC_SDA=1;}
//2úéúIIC?eê?D?o?
void IIC_Start(void)
{SDA_OUT();     //sda??ê?3?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×ü??£?×?±?·¢?í?ò?óê?êy?Y
}
//2úéúIICí£?1D?o?
void IIC_Stop(void)
{SDA_OUT();//sda??ê?3?IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(4);IIC_SCL=1; IIC_SDA=1;//·¢?íI2C×ü???áê?D?o?delay_us(4);
}
//μè′yó|′eD?o?μ?à′
//·μ???μ£o1£??óê?ó|′e꧰ü
//        0£??óê?ó|′e3é1|
u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();      //SDAéè???aê?è?  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;//ê±?óê?3?0       return 0;
}
//2úéúACKó|′e
void IIC_Ack(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}
//2?2úéúACKó|′e
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·¢?íò???×??ú
//·μ??′ó?úóD?Tó|′e
//1£?óDó|′e
//0£??Tó|′e
void IIC_Send_Byte(u8 txd)
{                        u8 t;   SDA_OUT();         IIC_SCL=0;//à-μíê±?ó?aê?êy?Y′?ê?for(t=0;t<8;t++){              IIC_SDA=(txd&0x80)>>7;txd<<=1;    delay_us(2);   //??TEA5767?aèy???óê±??ê?±?D?μ?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éè???aê?è?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();//·¢?ínACKelseIIC_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));//·¢?í??μ??·elseIIC_Send_Byte(device_addr);     //·¢?÷?tμ??·IIC_Wait_Ack(); IIC_Send_Byte(addr&0xFF);   //·¢?íμíμ??·IIC_Wait_Ack(); IIC_Send_Byte(data);     //·¢?í×??ú                               IIC_Wait_Ack();                     IIC_Stop();//2úéúò???í£?1ì??t if(device_addr==0xA0) //delay_ms(10);elsedelay_us(2);
}uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead)  //?á??′??÷?ò?áêy?Y
{   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);      //·¢?÷?tμ??·IIC_Wait_Ack();if(ByteNumToRead == 1)//LM75???èêy?Y?a11bit{data=IIC_Read_Byte(0);}else{data=IIC_Read_Byte(1);data=(data<<8)+IIC_Read_Byte(0);}IIC_Stop();//2úéúò???í£?1ì??t       return data;
}/**********
*é???2?·??aIO?ú?£?éI2C????
*
*′ó?aò????aê??aAHT20μ?????I2C
*oˉêy??óDIICoíI2Cμ???±e£???×¢òa£?£?£?£?£?
*
*2020/2/23×?oóDT??è??ú
*
***********/
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();/*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) 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();//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("lyy");}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;//delaymm(10);}else{IIC_SDA = 0;//delaymm(10);}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 | a;resultByte = (resultByte << 1) | a;IIC_SCL = 0;delay_ms(3);}SDA_IN();delay_ms(10);return   resultByte;
}void  set_AHT20sendOutData(void)
{/* --------------------------* 0xFA 0x06 0x0A temperature(2 Bytes) humility(2Bytes) short Address(2 Bytes)* And Check (1 byte)* -------------------------*/AHT20sendOutData[3] = AHT20_OutData[0];AHT20sendOutData[4] = AHT20_OutData[1];AHT20sendOutData[5] = AHT20_OutData[2];AHT20sendOutData[6] = AHT20_OutData[3];//  AHT20sendOutData[7] = (drf1609.shortAddress >> 8) & 0x00FF;
//  AHT20sendOutData[8] = drf1609.shortAddress  & 0x00FF;//    AHT20sendOutData[9] = getXY(AHT20sendOutData,10);
}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"
//ê1ó?IIC1 1ò??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;}//IO2ù×÷oˉêy
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA
#define READ_SDA   PBin(7)  //ê?è?SDA //IIC?ùóD2ù×÷oˉêy
void IIC_Init(void);                //3?ê??ˉIICμ?IO?ú
void IIC_Start(void);               //·¢?íIIC?aê?D?o?
void IIC_Stop(void);                //·¢?íIICí£?1D?o?
void IIC_Send_Byte(u8 txd);         //IIC·¢?íò???×??ú
u8 IIC_Read_Byte(unsigned char ack);//IIC?áè?ò???×??ú
u8 IIC_Wait_Ack(void);              //IICμè′yACKD?o?
void IIC_Ack(void);                 //IIC·¢?íACKD?o?
void IIC_NAck(void);                //IIC2?·¢?íACKD?o?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);//??′??÷μ??·£??÷?tμ??·£?òa?áμ?×??úêy  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

延时函数:
delay.c

#include "delay.h"
#include "sys.h"//STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///
//è?1?ê1ó?ucos,?ò°üà¨????μ?í·???t?′?é.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h"                 //ucos ê1ó?
#endif
//   //STM32?a·¢°?
//ê1ó?SysTickμ???í¨??êy?£ê????ó3ù??DD1üàí
//°üà¨delay_us,delay_ms//
static u8  fac_us=0;//us?óê±±?3?êy
static u16 fac_ms=0;//ms?óê±±?3?êy
#ifdef OS_CRITICAL_METHOD   //è?1?OS_CRITICAL_METHOD?¨ò?á?,?μ?÷ê1ó?ucosIIá?.
//systick?D??·t??oˉêy,ê1ó?ucosê±ó?μ?
void SysTick_Handler(void)
{                  OSIntEnter();        //??è??D??OSTimeTick();       //μ÷ó?ucosμ?ê±?ó·t??3ìDò               OSIntExit();        //′¥·¢è????D??èí?D??
}
#endif//3?ê??ˉ?ó3ùoˉêy
//μ±ê1ó?ucosμ?ê±oò,′?oˉêy?á3?ê??ˉucosμ?ê±?ó?ú??
//SYSTICKμ?ê±?ó1ì?¨?aHCLKê±?óμ?1/8
//SYSCLK:?μí3ê±?ó
void delay_init()
{#ifdef OS_CRITICAL_METHOD  //è?1?OS_CRITICAL_METHOD?¨ò?á?,?μ?÷ê1ó?ucosIIá?.u32 reload;
#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //????ía2?ê±?ó  HCLK/8fac_us=SystemCoreClock/8000000;  //?a?μí3ê±?óμ?1/8  #ifdef OS_CRITICAL_METHOD    //è?1?OS_CRITICAL_METHOD?¨ò?á?,?μ?÷ê1ó?ucosIIá?.reload=SystemCoreClock/8000000;        //?????óμ???êy′?êy μ¥???aK      reload*=1000000/OS_TICKS_PER_SEC;//?ù?YOS_TICKS_PER_SECéè?¨ò?3?ê±??//reload?a24????′??÷,×?′ó?μ:16777216,?ú72M??,??o?1.86s×óóò   fac_ms=1000/OS_TICKS_PER_SEC;//′ú±íucos?éò??óê±μ?×?éùμ¥??      SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;     //?a??SYSTICK?D??SysTick->LOAD=reload;  //??1/OS_TICKS_PER_SEC???D??ò?′?    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;     //?a??SYSTICK
#elsefac_ms=(u16)fac_us*1000;//·?ucos??,′ú±í????msDèòaμ?systickê±?óêy
#endif
}                                   #ifdef OS_CRITICAL_METHOD   //ê1ó?á?ucos
//?óê±nus
//nus?aòa?óê±μ?usêy.
void delay_us(u32 nus)
{       u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD;   //LOADμ??μ           ticks=nus*fac_us;             //Dèòaμ??ú??êy           tcnt=0;told=SysTick->VAL;         //????è?ê±μ???êy?÷?μwhile(1){tnow=SysTick->VAL; if(tnow!=told){        if(tnow<told)tcnt+=told-tnow;//?aà?×¢òaò???SYSTICKê?ò???μY??μ???êy?÷?í?éò?á?.else tcnt+=reload-tnow+told;        told=tnow;if(tcnt>=ticks)break;//ê±??3?1y/μèóúòa?ó3ùμ?ê±??,?òí?3?.}  };
}
//?óê±nms
//nms:òa?óê±μ?msêy
void delay_ms(u16 nms)
{   if(OSRunning==TRUE)//è?1?osò??-?ú?üá?     {         if(nms>=fac_ms)//?óê±μ?ê±??′óóúucosμ?×?éùê±???ü?ú {OSTimeDly(nms/fac_ms);//ucos?óê±}nms%=fac_ms;             //ucosò??-?T·¨ìá1??a?′D?μ??óê±á?,2éó???í¨·?ê??óê±    }delay_us((u32)(nms*1000));    //??í¨·?ê??óê±,′?ê±ucos?T·¨???ˉμ÷?è.
}
#else//2?ó?ucosê±
//?óê±nus
//nus?aòa?óê±μ?usêy.
void delay_us(u32 nus)
{       u32 temp;            SysTick->LOAD=nus*fac_us; //ê±???ó??            SysTick->VAL=0x00;        //??????êy?÷SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //?aê?μ1êy  do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16)));//μè′yê±??μ?′?   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //1?±???êy?÷SysTick->VAL =0X00;       //??????êy?÷
}
//?óê±nms
//×¢òanmsμ?·??§
//SysTick->LOAD?a24????′??÷,?ùò?,×?′ó?óê±?a:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLKμ¥???aHz,nmsμ¥???ams
//??72Mì??t??,nms<=1864
void delay_ms(u16 nms)
{                 u32 temp;        SysTick->LOAD=(u32)nms*fac_ms;//ê±???ó??(SysTick->LOAD?a24bit)SysTick->VAL =0x00;           //??????êy?÷SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //?aê?μ1êy  do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16)));//μè′yê±??μ?′?   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //1?±???êy?÷SysTick->VAL =0X00;       //??????êy?÷
}
#endif

delay.h

#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
//   //STM32F103o?D?°?ày3ì
//?aoˉêy°?±?ày3ì
/********** mcudev.taobao.com 3??·  ********///ê1ó?SysTickμ???í¨??êy?£ê????ó3ù??DD1üàí
//°üà¨delay_us,delay_ms//
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);#endif

在bsp_i2c.c函数中包含对传感器内容的编写,主要有传感器的初始化和读写数据程序:
初始化:

void  read_AHT20_once(void)
{delay_ms(10);reset_AHT20();//重置AHT20芯片delay_ms(10);init_AHT20();//初始化AHT20芯片delay_ms(10);startMeasure_AHT20();//开始测试AHT20芯片delay_ms(80);read_AHT20();//读取AHT20采集的到的数据delay_ms(5);
}

读写数据:

void read_AHT20(void)
{uint8_t   i;for(i=0; i<6; i++){readByte[i]=0;}//-------------I2C_Start();//I2C启动I2C_WriteByte(0x71);//I2C写数据ack_status = Receive_ACK();//收到的应答信息readByte[0]= I2C_ReadByte();//I2C读取数据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();//I2C停止函数//--------------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("lyy");}printf("\r\n");//根据AHT20芯片中,温度和湿度的计算公式,得到最终的结果,通过串口显示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");
}

3.执行测试

首先将上面编写的代码加入到工程文件:

编译执行检查有没有错误:

4.结果显示


可以看到结果显示程序陆续读取到温湿度信息,当我们对着传感器呼出一口气会发现显示的温度上升两到三度,湿度上升幅度很大。

四、参考资料

https://blog.csdn.net/xx_0305401/article/details/81914528
https://blog.csdn.net/weixin_40774605/article/details/88399276
https://blog.csdn.net/weixin_40877615/article/details/94338850

STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集相关推荐

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

    文章目录 前言 一.I2C总线通信协议 1.I2C总线 2.工作原理 3.I2C特点 4.I2C模式选择 5.软件I2C和硬件I2C 二.串口输出温湿度传感器的数据 1.核心代码分析 2.硬件实操连接 ...

  2. STM32F103基于I2C协议的AHT20温湿度传感器的数据采集

    目录 一.I2C 1.I2C 协议简介 2.I2C 物理层 3.协议层 通讯的起始和停止信号 数据有效性 响应 4. 软件I2C"和"硬件I2C 二.实现AHT20采集程序 1.A ...

  3. 基于I2C协议的AHT20温湿度传感器的数据采集

    文章目录 一.I2C相关 1.I2C总线简介 工作原理 总线特征 2.I2C协议简介 软件I2C 硬件I2C 二者比较 二.基于I2C的AHT20温湿度采集实验 AHT20简介 1.实验要求 2.实验 ...

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

    目录 一.I2C总线协议 二.实现AHT20采集程序 三.总结 一.I2C总线协议 1.什么是I2C总线? I2C总线是由Philips公司开发的一种简单.双向二线制同步串行总线.它只需要两根线即可在 ...

  5. 用STM32F103达成基于I2C协议的AHT20温湿度传感器和OLED屏显示汉字

    目录 一 I2C协议简介 硬件I2C与软件I2C 二 代码和ATH20芯片实现温湿度的串口显示 三 用stm32f103芯片的SPI和IIC接口接上OLED屏显示中文姓名温湿度 1 先用文字字模生成器 ...

  6. 基于I2C硬件协议的AHT20温湿度传感器的数据采集

    基于I2C的温湿度采集 硬件I2C和软件I2C 温湿度采集 任务要求 硬件连接 添加代码 最终效果 硬件I2C和软件I2C 硬件I2C对应芯片上的baiI2C外设,有相应I2C驱动电路,其所使用的I2 ...

  7. 基于I2C的AHT20温湿度传感器的数据采集

    一.I2C简介 二.软件I2C和硬件I2C 三.AHT20简介 四.基于stm32的AHT20温湿度传感器的数据采集 五.总结 一.I2C简介 I2C(芯片间)总线接口连接微控制器和串行I2C总线.它 ...

  8. AHT20温湿度传感器的数据采集

    目录 一.AHT20温度传感器数据采集 1.目的 2.准备条件 3.1实现代码 3.2连接器件 3.3编译烧录 3.4运行结果 二.OLED屏显和汉字点阵编码 1.目的 使用STM32F103的SPI ...

  9. 基于I2C硬件协议的AH20温湿度传感器的数据采集

    目录 I2C 温湿度传感器数据采集 实验准备 实验步骤: 实验结果: I2C I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实 ...

最新文章

  1. 如何学好单片机编程?学好单片机的基础是什么?
  2. python界面设置-PYTHON图形化操作界面的编程七__创建菜单
  3. 牛客题霸 NC16 判断二叉树是否对称
  4. return和break的区别
  5. RTMP规范简单分析
  6. 复工后,汉堡薯条、奶茶“续命”又开始了
  7. python教程推荐-入门python有什么好的书籍推荐?
  8. ios标签控制器怎么用_带故事板的iOS标签栏控制器
  9. 全局变量 局部变量 静态变量
  10. 网页鼠标指针样式(cursor属性)
  11. 华为安装gsm框架_华为Mate30Pro怎么安装谷歌服务框架?谷歌服务GMS框架安装方法...
  12. excel按季度分类汇总_巧用excel进行分类汇总的五种方法
  13. 目前已完成linux适配的软件,WPS Linux版与国产统一操作系统UOS完成适配:体验追上Wintel...
  14. Entity Framework Core系列教程-2安装EF Core
  15. 用 MeGUI 压制 DVDrip 入门
  16. 小白网安学习日记(2) hacknet游戏(模拟黑客入侵的游戏)
  17. 硬件:Nand Flash、Nor Flash
  18. [内附完整源码和文档] 基于Java的个人通讯录管理系统
  19. luogu P2600 [ZJOI2008]瞭望塔
  20. TCP/IP协议,握手,挥手

热门文章

  1. Retrofit用Interceptor实现内外网接口自动切换访问(在内网IP访问失败的时候.访问外网接口)
  2. 乖宝宠物IPO过会:年营收25.75亿 KKR与君联是股东
  3. 新乡市各县市新冠病毒肺炎疫情专题地图
  4. 计算机毕业设计(附源码)python智慧校园防疫管理平台
  5. 这些免费插件,让你的 ChatGPT 效率爆炸
  6. iPhone XR隐藏逆天好用功能,别说你还不知道,手机翻倍好用
  7. 刺激战场国际服越来越卡,竟是腾讯为了让玩家重回和平精英?
  8. 快速理解Vue 使用 vm.$set 解决对象新增属性不能响应的问题
  9. 深度优先算法和广度优先算法
  10. 安装Phoenix连接Hase