使用Vitis iic模块在FPGA上进行DHT20/AHT20温湿度传感器数据读取
目前网上大部分DHT20/AHT20温湿度传感器的读取都是基于stm32等单片机的,本篇文章讲一讲如何借助vivado和vitis在FPGA上进行DHT20温湿度传感器数据的读取。
目前网上大部分DHT20/AHT20温湿度传感器的读取都是基于stm32等单片机的,本篇文章讲一讲如何借助vivado和vitis在FPGA上进行DHT20温湿度传感器数据的读取。
Vivado部分
在Vivado中需完成软核的搭建,软核有很多种,自行搜索一个自己板子支持的就好。我的板子是NexysA7,搭建的软核是MicroBlaze。

MicroBlaze软核的搭建我是直接跟着B站上视频来的:
第一期 简介与搭建 基于ARTY A7的MicroBlaze系统搭建与应用_哔哩哔哩_bilibili
注意:视频中的部分步骤需要根据自己的板子实际情况来设置;更改波特率那部分需要自己进入设备管理器查看自己电脑上USB端口的波特率;另外,视频比较老了,里面提到的SDK现在是Vitis。
下一步需要导入AXI IIC的ip核,如下图所示,这是实现iic通信协议的关键。


为iic ip核的 sci 和sda分配FPGA上的引脚,两个pmod端口

之后生成比特流,导出.xsa硬件平台文件,再在Vitis导入生成的.xsa文件。
Vitis部分
vitis内部对iic模块封装好了对应的通信函数,我主要使用了xiic_l.h中声明的XIic_Send()和XIic_Recv()进行数据通信,使用这两个函数前需要导入xiic_l.h这个头文件。

XIic_Send()四个参数分别为:
- BaseAddress : 所用 iic接口的基地址
在vitis中可以在这里查看iic的基地址,我这里为0x4080 0000
- Address : iic从机的地址,DHT20从机地址固定为0x38
- BufferPtr : 向从机发送的数据指针
- ByteCount : 发送的数据字节数
- Option : 发送完数据后释放总线还是保持(有两个选择—— XIIC_STOP = 以STOP结束,即释放总线 ;XIIC_REPEATED_START = 不以STOP结束,保持总线)
XIic_Recv()函数的参数同理,注意使用这两个函数内部包含了iic协议开始通信的信号,在使用这两个函数前不需要额外发送开始通信信号,函数调用结束后是否释放数据总线需要自行设定Option参数进行设置。
DHT20官方手册:DHT20_(广州奥松)DHT20中文资料_价格_PDF手册-立创电子商城 (szlcsc.com))
在上面可以了解到DHT20数据读取的流程:

依照此流程编写代码:
1.上电后等待不少于100ms,发送0x71,之后需要获取状态字,故使用XIic_Send()函数发送1字节数据,然后保持总线不释放,接着使用XIic_Recv()函数接受1字节数据,接受完后释放总线。
u8 init = 0x71;
u8 data;
XIic_Send(Iic.BaseAddress,0x38,&init,1,XIIC_REPEATED_START);
XIic_Recv(Iic.BaseAddress,0x38,&data,1,XIIC_STOP);
函数的第三个参数要求数据指针,于是我提前定义了两个变量init和data分别保存要发送的数据和接受的数据。
2.判断接收到的数据是否等于0x18,若不等则进行寄存器初始化,初始化的流程较复杂这里没给出解释,我后面对着官方的例程代码复现了一遍,这里先不讨论,就假装他等于0x18继续进行。
3.等待10ms发送0xAC命令出发测量,接着再发送两个命令参数0x33和0x00。看上面第二张图片,在发送第二张图片前需要先发送一字节IIC address+write数据,此处为0x70,为什么呢?
这里iic的地址位为7位,前面说过DHT20的从机地址为0x38七位地址的前三位表示“3”的低三位即0011中取011,后四位为“8”即1000,同时“0”表示“write”,“1”表示“读”,所以七位从机地址在加上一位写组合起来就是 01110000,换成十六进制就是0x70。
综上所述,这一步要发送四个字节的数据,依次为0x70,0xAC, 0x33,0x00
先定义一个数组
u8 start_measure_signal[4] = {0x70,0xAC,0x33,0x00};
之后使用XIic_Send()函数一次性发送四字节的数据,发送完毕后释放总线:
XIic_Send(Iic.BaseAddress,0x38,start_measure_signal,4,XIIC_STOP);
C语言中, 数组名表示的就是首元素地址,所以这里不需要加取地址符&
4.接着发送xiic address+read表示开始读取,与上面同理这里要发送的是0x71,接着可直接读取七字节的数据,理论上说应该先读取第一个字节的数据判断一下是否测量完成的,我这里嫌麻烦就没判断。
u8 rec_data[7];//0-1 地址和状态;2、3、4.5湿度;4.5,5,6温度;7:CRC校验
u8 read_signal = 0x71;
XIic_Send(Iic.BaseAddress,0x38,&read_signal,1,XIIC_REPEATED_START);
XIic_Recv(Iic.BaseAddress,0x38,rec_data,7,XIIC_STOP);
5.接着就可根据以下公式进行数据处理,得到温度和湿度的十进制表示:


//数据处理
humid = (humid|rec_data[1])<<8;
humid = (humid|rec_data[2])<<8;
humid = (humid|rec_data[3]);
humid =humid >>4;
temper = (temper|rec_data[3])<<8;
temper = (temper|rec_data[4])<<8;
temper = (temper|rec_data[5]);
temper = temper&0xfffff;
int temp;int hum;
temp = temper*200*10/1024/1024 -500;
hum = humid*100*10/1024/1024;
在读取到温湿度后,便可进行串口输入至电脑,或者编写数码管展示模块:

其他:
- 上面提到的延时我适用vitis中封装的sleep函数实现,需要导入sleep.h头文件。
sleep()以秒为单位延时,usleep以微妙为单位延时,想延时80毫秒用usleep(80000)即可
- 下面是当第一步状态字不等于0x18时初始化寄存器的代码
//判断状态字 if((data&0x18)!=0x18) { AHT20_Start_Init(Iic); //usleep(10000); } //需要提前定义的函数 void JH_Reset_REG(u8 addr,XIic Iic) { u8 data = 0x71; u8 message[4] = {0x70,0x00,0x00,0x00}; message[1] = addr; u8 recv[3]; XIic_Send(Iic.BaseAddress,0x38,message,4,XIIC_STOP); usleep(5000); XIic_Send(Iic.BaseAddress,0x38,&data,1,XIIC_REPEATED_START); XIic_Recv(Iic.BaseAddress,0x38,recv,3,XIIC_STOP); usleep(10000); message[0] = 0x70;message[1] = (0xB0|addr); message[2] = recv[1];message[3] = recv[2]; XIic_Send(Iic.BaseAddress,0x38,message,4,XIIC_STOP); recv[1] = 0x00; recv[2] = 0x00; } void AHT20_Start_Init(XIic Iic) { JH_Reset_REG(0x1b,Iic); JH_Reset_REG(0x1c,Iic); JH_Reset_REG(0x1e,Iic); }
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)