文章目录
一、I2C总线通信协议
1.I2C协议
I2C(Inter-Integrated Circuit),集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。
2.I2C物理层
I2C总线分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
常见的 I2C 通讯系统
2.I2C协议层
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的设备地址。通常的我们将CPU模块作为主设备,而挂接在总线上的其他设备作为从设备。I2C总线上的主设备与从设备之间以8字节为单位进行双向数据传输,并且每个单位后还须跟着一位ACK位。其中数据在SCL处于低电平时被放到SDA数据线上,在SCL处于高电平时进行数据的采样。
I2C总线数据传输协议时序图
由图可知,I2C总线的传输时序包括:开始条件
、地址帧
、数据帧
、停止条件
、重复开始条件
。
开始条件、停止条件:当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。当 SCL 是高电平时 SDA线由低电平向高电平切换,表示通讯的停止。开始和停止条件一般由主机产生。
起始和停止信号
地址帧:地址帧总是在一次通信的最开始出现,通常包括7位的设备地址(MSB)和最后1位的读写控制位(1表示读,0表示写),接下来是1位的NACK/ACK,当这8位地址发送完成后,Slave设备获得SDA的控制权,此时Slave设备应该在第9个时钟脉冲之前回复一个ACK(将SDA拉低)以表示数据接收正常,否则表示数据接受失败,控制权交由Master设备处理。
数据帧:每个数据帧8位,数据帧的数量可以是任意的,直到产生停止条件。每一个8位数据传输完成之后,接收方就需要回复一个ACK/NACK。
重复开始条件:有时Master设备需要在一次通信中进行多次消息交换(例如切换读写操作等),并且不希望其他Master设备干扰,这时可以使用重复开始条件,最后产生一个停止条件结束整个通信过程。
I2C也是支持10位地址空间的,对于10位地址的传输时序,需要2个地址帧完成地址的传输,其他和8位的传输协议相同。
10位地址传输时序图
I2C总线的上拉电阻的阻值要精心考虑,如果上拉电阻的阻值太大,则由于I2C设备输入端的输入电容的存在,会造成信号上升沿和下降沿变缓,以至于不能满足I2C设备的建立时间和保持时间,造成通信的错误发生;如果上拉电阻的阻值过小,则会造成较大的功率损耗。因此I2C通信的上拉电阻的阻值要满足设备上升沿和下降沿要求的同时尽量选择较大的阻值,以降低消耗的功耗问题。
3.软件I2C和硬件I2C
软件I2C:按照信号的时序要求,用软件直接控制 STM32的两个 GPIO 引脚(分别用作 SCL及 SDA管脚)状态以模拟I2C通信。由于直接控制 GPIO 引脚电平产生通讯时序时,需要由 CPU 控制每个时刻的引脚状态,称为软件I2C。
硬件IIC:STM32 的 I2C 片上外设专门负责实现 I2C 通讯协议,直接调用内部寄存器进行配置,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来, CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。
硬件I2C减轻了 CPU 的工作,其效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。
二、基于STM32和AHT20温湿度传感器的数据采集
1.任务
每隔2秒钟采集一次温湿度数据,并将采集的温度、湿度值通并通过串口发送到上位机(win10)。
2.主要代码
直接读取AHT20的温度和湿度数据
void AHT20_Read_CTdata(u32 *ct)
{
volatile u8 Byte_1th=0,Byte_2th=0,Byte_3th=0;
volatile u8 Byte_4th=0,Byte_5th=0,Byte_6th=0;
u32 RetuData = 0;
u16 cnt = 0,flag;
AHT20_SendAC();//向AHT20发送AC命令
delay_ms(80);//大约延时80ms
while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,
{
delay_ms(1);
if(cnt++>=100) break;
}
IIC_Start();
IIC_Send_Byte(0x71);
flag=IIC_Wait_Ack();
Byte_1th = IIC_Read_Byte(flag);//状态字
Byte_2th = IIC_Read_Byte(flag);//湿度,发送ACK(继续发送)
Byte_3th = IIC_Read_Byte(flag);//湿度
Byte_4th = IIC_Read_Byte(flag);//湿度/温度
Byte_5th = IIC_Read_Byte(flag);//温度
Byte_6th = IIC_Read_Byte(!flag);//温度,发送NAK(停止发送)
IIC_Stop();
//保存得到的数据到RetuData中
RetuData = (RetuData|Byte_2th)<<8;
RetuData = (RetuData|Byte_3th)<<8;
RetuData = (RetuData|Byte_4th);
RetuData =RetuData >>4;
ct[0] = RetuData;//湿度
RetuData = 0;
RetuData = (RetuData|Byte_4th)<<8;
RetuData = (RetuData|Byte_5th)<<8;
RetuData = (RetuData|Byte_6th);
RetuData = RetuData&0x0fffff;
ct[1] =RetuData; //温度
}
主函数
#include "led.h"
#include "delay.h"
#include "temhum.h"
#include "sys.h"
#include "usart.h"
int main(void)
{
u32 CT_data[2]={0};
volatile float hum=0,tem=0;
delay_init();//延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200);//串口初始化为115200
LED_Init(); //LED端口初始化
temphum_init();//ATH20初始化
while(1)
{
AHT20_Read_CTdata(CT_data);//不经过CRC校验,直接读取AHT20的温度和湿度数据
hum = CT_data[0]*100*10/1024/1024;//计算得到湿度值(放大了10倍)
tem = CT_data[1]*200*10/1024/1024-500;//计算得到温度值(放大了10倍)
printf("湿度:%.1f%%\r\n",(hum/10));
printf("温度:%.1f度\r\n",(tem/10));
printf("\r\n");
//延时2s,LED闪烁提示串口发送状态
LED=0;
delay_ms(1000);
LED=1;
delay_ms(1000);
}
}
可以参考AHT20的官方手册和本工程完整代码作更深一步的学习,链接放在参考资料里。
3.管脚连接
AHT20
AHT20 | STM32 |
---|---|
SCL | PB6 |
SDA | PB7 |
VCC | 3V3 |
GND | GND |
串口
STM32 | USB转TTL |
---|---|
PA9 | TXD |
PA10 | RXD |
3V3 | 3V3 |
GND | GND |
4.操作效果
可以看到每隔2秒钟采集一次温湿度数据,通过串口输出,用手摸一下AHT20芯片后温度、湿度值有明显变化。
三、总结
在了解了I2C协议基础上完成本次实验后,突然觉得身边的家电也不是什么难以理解的东西了,I2C作为串行通信总线解决了主板、嵌入式系统或手机与周边设备组件的通信问题。I2C总线是一种简单双向二进制同步串行总线,其只需要两根双向I/O线即可以实现连接在总线上的器件之间的信息传递。
四、参考资料
stm32通过I2C接口实现温湿度(AHT20)的采集
完整代码链接
提取码:03zq
奥松AHT20传感器厂商资料
提取码:95dx