100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 温湿度传感器 SHT3x-DIS 详解 FPGA驱动

温湿度传感器 SHT3x-DIS 详解 FPGA驱动

时间:2020-06-28 16:51:43

相关推荐

温湿度传感器 SHT3x-DIS 详解  FPGA驱动

芯片简介

SHT3x-DIS 是一款温湿度传感器,I2C 接口,通信速度最高可达 1MHz,测量精度 ±1.5%RH,±0.1∘C\pm 1.5\%\mathrm{RH},\ \pm 0.1^\circ C±1.5%RH,±0.1∘C 。数字输出经过校准和线性化,并进行了温度补偿。

SHT3x-DIS 内部结构及电路示意如上图,由于 SDA 与SCL 为开漏,因此须接上拉电阻。除此之外,SDA 与 SCL 应串联限流电阻。

引脚说明:

SDA

I2C 串行数据总线,双向,最高支持 1MHz1\rm MHz1MHz,大于 400kHz400\rm kHz400kHz 的通信需符合 I2C 快速模式标准。

SCL

I2C 串行时钟总线,双向,支持在 0∼1MHz0\sim1\mathrm{MHz}0∼1MHz 间自由选择。

nRESET

复位引脚,低电平有效,复位脉冲至少维持 1us 才能可靠地使芯片复位。若不使用建议悬空(芯片内部有 50kΩ50k\Omega50kΩ 的上拉电阻),或接 2kΩ2k\Omega2kΩ 以上的上拉电阻到 VDD。

ALERT

告警引脚,当温湿度超过设置的阈值时,该引脚给出高电平。若不使用,必须悬空。(datasheet 提到告警阈值是可编程的,但是没看到给出设置的方法)

ADDR

地址引脚,当该引脚接地时,设置 I2C 设备地址为 0x44,当该引脚拉高时,设置地址为 0x45。ADDR 引脚不可悬空,必须接地或接高电平。

VDD

供电引脚,2.15V 到 5.5V。

VSS

Ground。

R

Reserved,无电气作用,接地。

采样模式

SHT3x-DIS 支持 I2C 快速模式,最高 1MHz。向传感器发送命令后,至少 1ms 后才可发送下一条命令。

SH3x-DIS 的数据和命令都映射到 16bit 的地址空间,并使用 CRC 校验进行保护。16bit 命令已经包含了 3bit 的 CRC 校验和,同时传感器的每次数据接收与发送,均使用 8 位 CRC 校验。

当进行写操作时,必须提供 CRC 校验,SHT-3x-DIS 只接受具有正确校验和的数据;当进行读操作时,SHT3x-DIS 提供 8bit CRC 校验。

当芯片上电后,经过一段时间后(1ms@5V,1.5ms@2.4V)自动进入空闲状态,准备好接收指令。在未处在接收指令或测量状态时,芯片自动进入空闲状态,以实现节能。

测量通信序列由 7bit 设备地址,0 作为写入位,16bit 测量命令组成。传感器对每个字节的正确接收做出确认,在第 8 个 SCL 下降沿后给出 SDA=L 以示正确接收到了该字节。在接收完测量命令后,传感器开始测量湿度和温度。

单次采集模式

该模式下,传感器每接收到一次测量命令,进行一次温湿度测量,温度和湿度均使用 16bit 数字量表示。

单次采集模式的 16bit 指令如下表所示

可重复性(Repeatability)

可重复性影响采样的持续时间,重复性越高,测量时间越长(功耗越大),测量精度越高。三种可重复性下的测量时间以及对应的温湿度测量精度如下表

时钟拉伸(Clock Stretching)

在 disable Clock Stretching 时,若 Master 发出读取报头时传感器尚未完成数据采样,将回复不确认 NACK (SDA=H)。

当 enable Clock Stretching 时,传感器相应读报头,随后下拉 SCL ,直到测量完成。一旦数据测量完成,传感器将释放 SCL,并传输测量数据。

两种时钟拉伸状态下的传输时序如上图,白色部分由微控制器给出,灰色部分由传感器给出。

上分支所示是 Clock Stretching disabled 的情况,若数据尚未完成采样,传感器 NACK 读报头;当数据准备好之后,Mater 需再次发送读报文头,传感器 ACK 读报文头,并依次给出温度、湿度数据。

下分支对应 Clock Stretching enabled 的情况,Master 只需要发出一次读报文头,若传感器数据尚未准备好,将 NACK 读报文头,并强制拉低 SCL 以终止数据传输,在数据准备好后释放 SCL,并随着 SCL 依次给出温度、湿度数据。

16bit 数字量与实际物理量的对应关系如下

相对湿度

RH=SRH216−1×100%RH=\frac{S_{RH}}{2^{16}-1}\times100\% RH=216−1SRH​​×100%

温度

T(∘C)=−45+175⋅ST216−1T(^\circ C)=-45+175\cdot\frac{S_T}{2^{16}-1} T(∘C)=−45+175⋅216−1ST​​

周期采集模式

此模式下,一个测量命令将产生一个测量数据流,每个数据对由 16bit 温度和 16bit 湿度组成。

周期采集命令

周期采集模式的命令如下

表中 mps 表示每秒采集几次(measurement per second),有 0.5,1,2,4,10mps0.5,1,2,4,10\ mps0.5,1,2,4,10mps 共 5 种测量频率。周期采集模式下,没有 Clock Stretching。

周期采集模式还有一个 ART (accelerated response time) 模式,发出 ART 命令后,传感器将以 4Hz 的频率进行数据采集。

读取周期采集数据

要读取数据,使用如下的读取时序(注意Fetch Data Command 后没有停止信号 P,而是紧接着一个 restart 信号 S,随后给出读报文头)

若传感器内没有数据,I2C 读取头将回应 NACK,通信停止。若有数据,将回应 ACK,并给出温湿度数据,读取完成后将清空数据存储器

终止周期采集模式

采用如下指令终止周期采集模式,回到 Single Shot 模式。恢复为单次采集模式至少要 1ms。

复位 Reset

SHT3x-DIS 有如下几种复位方式:

Interface Reset

接口复位,保持 SDA=H,切换 SCL 9次以上。该复位仅重置接口,不清空采样数据存储器。

Soft Reset

软复位,通过发送命令进行复位,软复位将重置传感器,并重新加载校准数据。

Reset through General Call

通过 I2C 一般呼叫模式产生复位,功能上与通过 nRESET 复位相同。这种复位会使挂载在同一根 I2C 总线上的所有支持一般呼叫的设备重置。一般呼叫的 I2C 序列如下

Reset through the nReset Pin

拉低 nRESET 引脚至少 1us 可使 SHT3x-DIS 复位。

Hard Reset

硬复位,下电后重新上电。

加热器 Heater

SHT3x-DIS 内部有一个加热器,仅用于合理性验证(而不是为了什么保持传感器工作温度之类的),默认关闭。通过以下命令开关加热器。无法控制加热到多高温度,温度变化在几摄氏度(受环境影响)。

状态寄存器

状态寄存器(16bit)包含关于加热器的运行状态、警报模式以及最后一个命令和最后一个写入序列的执行状态等信息。

读取状态寄存器的命令如下

寄存器含义如下

通过如下命令清空状态寄存器

FPGA驱动实现

SHT3x-DIS 驱动代码

SHT3x_singleShot.v

/* * file: SHT3x_singleShot.v* author: 今朝无言* Lab: WHU-EIS-LMSWE* date: -03-20* version: v1.0* description: SHT3x-DISn单采集模式 (Single Shot Mode)* Copyright © WHU-EIS-LMSWE, All Rights Reserved.*/module SHT3x_singleShot(inputclk_1M,//4倍SCL,采用1MHz时钟,SCL_freq = 250kHzinputrst_n,inputsamp_en,//上升沿有效outputbusy,outputalert,outputreg[15:0]T,//温度,数字量outputreg[15:0]RH,//相对湿度,数字量inoutSCL,inoutSDA,inputALERT,outputnRESET);// 物理量 <- 数字量// T(℃)=-45+175*S_T/65535// RH=S_RH/65535*100%localparamADDR= 7'h44;//I2C设备地址localparamRW_W= 1'b0;localparamRW_R= 1'b1;localparamCMD_SINGLE_SHOT= 16'h2400;//Sigle Shot, High Repeatability, Clock Stretching Disabled//---------------------I2C Master State Define----------------------// I2C Master sub 状态定义localparamIDLE= 8'h01;//空闲,释放SCL/SDAlocalparamSTART= 8'h02;//起始,SCL=H,SDA=DlocalparamSEND_DATA= 8'h04;//发送数据localparamGET_DATA= 8'h08;//读取数据,释放SDAlocalparamCHECK_ACK= 8'h10;//检查SDA的ACK/NACK,释放SDAlocalparamACK= 8'h20;//发出ACK,SDA=LlocalparamNACK= 8'h40;//发出NACK,SDA=HlocalparamSTOP= 8'h80;//停止,SCL=H,SDA=R//------------------------SHT State Define-------------------------// ---Send Command---//IDLE,START,SEND_ADDR_W,CHECK_ACK1,SEND_COMMAND_MSB,CHECK_ACK2,SEND_COMMAND_LSB,CHECK_ACK3,STOPlocalparamC_IDLE= 8'h00;localparamC_START= 8'h01;localparamC_SEND_ADDR_W= 8'h02;localparamC_CHECK_ACK1= 8'h03;localparamC_SEND_COMMAND_MSB= 8'h04;localparamC_CHECK_ACK2= 8'h05;localparamC_SEND_COMMAND_LSB= 8'h06;localparamC_CHECK_ACK3= 8'h07;localparamC_STOP= 8'h08;// ---Get Data---//IDLE,START,SEND_ADDR_R,CHECK_ACK,GET_T_MSB,ACK1,GET_T_LSB,ACK2,GET_CRC1,ACK3,//GET_RH_MSB,ACK4,GET_RH_LSB,ACK5,GET_CRC2,ACKH6,STOPlocalparamD_IDLE= 8'h10;localparamD_START= 8'h11;localparamD_SEND_ADDR_R= 8'h12;localparamD_CHECK_ACK= 8'h13;localparamD_GET_T_MSB= 8'h14;localparamD_ACK1= 8'h15;localparamD_GET_T_LSB= 8'h16;localparamD_ACK2= 8'h17;localparamD_GET_CRC1= 8'h18;localparamD_ACK3= 8'h19;localparamD_GET_RH_MSB= 8'h1a;localparamD_ACK4= 8'h1b;localparamD_GET_RH_LSB= 8'h1c;localparamD_ACK5= 8'h1d;localparamD_GET_CRC2= 8'h1e;localparamD_ACK6= 8'h1f;localparamD_STOP= 8'h20;// ---SHT3x state---localparamSHT_IDLE= 8'h01;localparamSHT_COMMAND_START= 8'h02;// IDLE -> STARTlocalparamSHT_SEND_COMMAND= 8'h04;// I2C busy, Send CommandlocalparamSHT_SAMPLING= 8'h08;// wait 20mslocalparamSHT_DATA_START= 8'h10;// IDLE -> STARTlocalparamSHT_GET_DATA= 8'h20;// I2C busy, Get DatalocalparamSHT_STOP= 8'h40;// T <- T_tmp, RH <- RH_tmp//------------------------------------------------------------------reg[7:0]I2C_state= IDLE;//该state输入I2C_Master_subreg[7:0]SHT_state= SHT_IDLE;reg[7:0]SHT_next_state= SHT_IDLE;reg[7:0]C_state= C_IDLE;reg[7:0]C_next_state= C_IDLE;reg[7:0]D_state= D_IDLE;reg[7:0]D_next_state= D_IDLE;regstart_flag= 1'b0;regC_start_flag= 1'b0;regD_start_flag= 1'b0;reg[7:0]wrdat_buf= 8'd0;wire[7:0]rddat_tmp;wirecheck_ack;wirechange_state;reg[15:0]T_tmp= 16'd0;reg[15:0]RH_tmp= 16'd0;//--------------------------state trans------------------------------always @(posedge change_state or negedge rst_n) beginif(~rst_n) beginSHT_state<= SHT_IDLE;endelse beginSHT_state<= SHT_next_state;endendalways @(posedge change_state) begincase(SHT_state)SHT_COMMAND_START, SHT_SEND_COMMAND: beginC_state<= C_next_state;enddefault: beginC_state<= C_state;endendcaseendalways @(posedge change_state) begincase(SHT_state)SHT_DATA_START, SHT_GET_DATA: beginD_state<= D_next_state;enddefault: beginD_state<= D_state;endendcaseend//--------------------Send Command State Machine---------------------always @(*) begincase(C_state)C_IDLE: beginif(C_start_flag) beginC_next_state<= C_START;endelse beginC_next_state<= C_IDLE;endendC_START: beginC_next_state<= C_SEND_ADDR_W;endC_SEND_ADDR_W: beginC_next_state<= C_CHECK_ACK1;endC_CHECK_ACK1: beginC_next_state<= C_SEND_COMMAND_MSB;endC_SEND_COMMAND_MSB: beginC_next_state<= C_CHECK_ACK2;endC_CHECK_ACK2: beginC_next_state<= C_SEND_COMMAND_LSB;endC_SEND_COMMAND_LSB: beginC_next_state<= C_CHECK_ACK3;endC_CHECK_ACK3: beginC_next_state<= C_STOP;endC_STOP: beginC_next_state<= C_IDLE;enddefault: beginC_next_state<= C_IDLE;endendcaseend//----------------------Get Data State Machine-----------------------always @(*) begincase(D_state)D_IDLE: beginif(D_start_flag) beginD_next_state<= D_START;endelse beginD_next_state<= D_IDLE;endendD_START: beginD_next_state<= D_SEND_ADDR_R;endD_SEND_ADDR_R: beginD_next_state<= D_CHECK_ACK;endD_CHECK_ACK: beginD_next_state<= D_GET_T_MSB;endD_GET_T_MSB: beginD_next_state<= D_ACK1;endD_ACK1: beginD_next_state<= D_GET_T_LSB;endD_GET_T_LSB: beginD_next_state<= D_ACK2;endD_ACK2: beginD_next_state<= D_GET_CRC1;endD_GET_CRC1: beginD_next_state<= D_ACK3;endD_ACK3: beginD_next_state<= D_GET_RH_MSB;endD_GET_RH_MSB: beginD_next_state<= D_ACK4;endD_ACK4: beginD_next_state<= D_GET_RH_LSB;endD_GET_RH_LSB: beginD_next_state<= D_ACK5;endD_ACK5: beginD_next_state<= D_GET_CRC2;endD_GET_CRC2: beginD_next_state<= D_ACK6;endD_ACK6: beginD_next_state<= D_STOP;endD_STOP: beginD_next_state<= D_IDLE;enddefault: beginD_next_state<= D_IDLE;endendcaseend//----------------------I2C State Machine-----------------------always @(*) begincase({C_state,D_state}){C_IDLE, D_IDLE}: beginI2C_state<= IDLE;end//---Send Command---{C_START, D_IDLE}: beginI2C_state<= START;end{C_SEND_ADDR_W, D_IDLE}: beginI2C_state<= SEND_DATA;end{C_CHECK_ACK1, D_IDLE}: beginI2C_state<= CHECK_ACK;end{C_SEND_COMMAND_MSB, D_IDLE}: beginI2C_state<= SEND_DATA;end{C_CHECK_ACK2, D_IDLE}: beginI2C_state<= CHECK_ACK;end{C_SEND_COMMAND_LSB, D_IDLE}: beginI2C_state<= SEND_DATA;end{C_CHECK_ACK3, D_IDLE}: beginI2C_state<= CHECK_ACK;end{C_STOP, D_IDLE}: beginI2C_state<= STOP;end//---Get Data---{C_IDLE, D_START}: beginI2C_state<= START;end{C_IDLE, D_SEND_ADDR_R}: beginI2C_state<= SEND_DATA;end{C_IDLE, D_CHECK_ACK}: beginI2C_state<= CHECK_ACK;end{C_IDLE, D_GET_T_MSB}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK1}: beginI2C_state<= ACK;end{C_IDLE, D_GET_T_LSB}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK2}: beginI2C_state<= ACK;end{C_IDLE, D_GET_CRC1}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK3}: beginI2C_state<= ACK;end{C_IDLE, D_GET_RH_MSB}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK4}: beginI2C_state<= ACK;end{C_IDLE, D_GET_RH_LSB}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK5}: beginI2C_state<= ACK;end{C_IDLE, D_GET_CRC2}: beginI2C_state<= GET_DATA;end{C_IDLE, D_ACK6}: beginI2C_state<= ACK;end{C_IDLE, D_STOP}: beginI2C_state<= STOP;enddefault: beginI2C_state<= IDLE;endendcaseend//--------------------------SHT State Machine--------------------------always @(*) begincase(SHT_state)SHT_IDLE: beginif(start_flag) beginSHT_next_state<= SHT_COMMAND_START;endelse beginSHT_next_state<= SHT_IDLE;endendSHT_COMMAND_START: beginSHT_next_state<= SHT_SEND_COMMAND;endSHT_SEND_COMMAND: beginif(C_state==C_IDLE) beginSHT_next_state<= SHT_SAMPLING;endelse beginSHT_next_state<= SHT_SEND_COMMAND;endendSHT_SAMPLING: beginif(~delay_busy) beginSHT_next_state<= SHT_DATA_START;endelse beginSHT_next_state<= SHT_SAMPLING;endendSHT_DATA_START: beginSHT_next_state<= SHT_GET_DATA;endSHT_GET_DATA: beginif(D_state==D_IDLE) beginSHT_next_state<= SHT_STOP;endelse beginSHT_next_state<= SHT_GET_DATA;endendSHT_STOP: beginSHT_next_state<= SHT_IDLE;enddefault: beginSHT_next_state<= SHT_IDLE;endendcaseend//---------------------------I2C Master sub----------------------------I2C_Master_sub I2C_Master_sub_inst(.clk(clk_1M),.wrdat_buf(wrdat_buf),.rddat_tmp(rddat_tmp),.check_ack(check_ack),.SCL(SCL),.SDA(SDA),.change_state(change_state),.state(I2C_state));//---------------------------Delay----------------------------regdelay_en= 1'b0;wiredelay_busy;monostable_flipflop #(.Width(32))monostable_flipflop_inst(.clk(clk_1M),.rst_n(1'b1),.delay_N(32'd100_000),//delay 100ms.reset_N(1'b1),.in(delay_en),.out(delay_busy));//------------------------------Control-------------------------------// ---samp_en edge detect---regsamp_en_d0;regsamp_en_d1;wiresamp_en_pe;always @(posedge clk_1M) beginsamp_en_d0<= samp_en;samp_en_d1<= samp_en_d0;endassignsamp_en_pe= samp_en_d0 & (~samp_en_d1);// ---start flag---//启动samp进程always @(posedge clk_1M) beginif(samp_en_pe && ~busy) beginstart_flag<= 1'b1;endelse if(SHT_state == SHT_COMMAND_START) beginstart_flag<= 1'b0;endelse beginstart_flag<= start_flag;endend// ---busy---assignbusy = (SHT_state==SHT_IDLE)? 1'b0 : 1'b1;// ---Send Command start flag---always @(*) begincase(SHT_state)SHT_COMMAND_START: beginC_start_flag<= 1'b1;enddefault: beginC_start_flag<= 1'b0;endendcaseend// ---Get Data start flag---always @(*) begincase(SHT_state)SHT_DATA_START: beginD_start_flag<= 1'b1;enddefault: beginD_start_flag<= 1'b0;endendcaseend// ---delay_en---always @(*) beginif(C_state==C_STOP) begindelay_en<= 1'b1;endelse begindelay_en<= 1'b0;endend// ---T_tmp---always @(posedge clk_1M) begincase(D_state)D_START: beginT_tmp<= 16'd0;endD_ACK1: beginT_tmp[15:8]<= rddat_tmp;endD_ACK2: beginT_tmp[7:0]<= rddat_tmp;enddefault: beginT_tmp<= T_tmp;endendcaseend// ---RH_tmp---always @(posedge clk_1M) begincase(D_state)D_START: beginRH_tmp<= 16'd0;endD_ACK4: beginRH_tmp[15:8]<= rddat_tmp;endD_ACK5: beginRH_tmp[7:0]<= rddat_tmp;enddefault: beginRH_tmp<= RH_tmp;endendcaseend// ---wrdat_buf---always @(posedge clk_1M) begincase({C_state, D_state}){C_IDLE, D_IDLE}: beginwrdat_buf<= 8'd0;end{C_START, D_IDLE}: beginwrdat_buf<= {ADDR, RW_W};end{C_CHECK_ACK1, D_IDLE}: beginwrdat_buf<= CMD_SINGLE_SHOT[15:8];end{C_CHECK_ACK2, D_IDLE}: beginwrdat_buf<= CMD_SINGLE_SHOT[7:0];end{C_CHECK_ACK3, D_IDLE}: beginwrdat_buf<= 8'd0;end{C_IDLE, D_START}: beginwrdat_buf<= {ADDR, RW_R};end{C_IDLE, D_CHECK_ACK}: beginwrdat_buf<= 8'd0;enddefault: beginwrdat_buf<= wrdat_buf;endendcaseend// ---T/RH---always @(posedge clk_1M) begincase(SHT_state)SHT_STOP: beginT<= T_tmp;//缓存T/RH,给出稳定的输出结果RH<= RH_tmp;enddefault: beginT<= T;RH<= RH;endendcaseend//-------------------------alert & nReset----------------------------assignalert= ALERT;assignnRESET= 1'b1;endmodule

I2C_Master_sub.v

该模块是 I2C Master 的 SCL/SDA 状态输出控制模块,关于 I2C 如何使用 Verilog 实现详见我之前的博文

/* * file: I2C_Master_sub.v* author: 今朝无言* Lab: WHU-EIS-LMSWE* date: -03-19* version: v1.0* description: I2C master 的 SDA/SCL 控制模块(通过 state)*/module I2C_Master_sub(inputclk,//4倍SCLinput[7:0]wrdat_buf,outputreg[7:0]rddat_tmp,outputregcheck_ack,//检查Slave给出的ACK信号,若为NACK,输出一个高电平脉冲inoutSCL,inoutSDA,outputregchange_state,//上升沿时 top 模块应执行 state <- next_stateinput[7:0]state);localparamIDLE= 8'h01;//空闲,释放SCL/SDAlocalparamSTART= 8'h02;//起始,SCL=H,SDA=DlocalparamSEND_DATA= 8'h04;//发送数据localparamGET_DATA= 8'h08;//读取数据,释放SDAlocalparamCHECK_ACK= 8'h10;//检查SDA的ACK/NACK,释放SDAlocalparamACK= 8'h20;//发出ACK,SDA=LlocalparamNACK= 8'h40;//发出NACK,SDA=HlocalparamSTOP= 8'h80;//停止,SCL=H,SDA=RregSCL_link= 1'b0;regSDA_link= 1'b0;regSCL_buf= 1'b1;//o_bufregSDA_buf= 1'b1;wireSCL_ibuf;//i_bufwireSDA_ibuf;reg[3:0]bit_cnt= 4'd15;//----------------------IO_BUF-----------------------------//IOBUF for SCLIOBUF IOBUF_SCL(.O(SCL_ibuf),// Buffer的输出,接采集信号.IO(SCL),// connect directly to top-level port.I(SCL_buf),// Buffer的输入,接要输出到FPGA外的信号.T(~SCL_link)// =1时,O <- IO;=0时,IO <- I);//IOBUF for SDAIOBUF IOBUF_SDA(.O(SDA_ibuf),.IO(SDA),.I(SDA_buf),.T(~SDA_link));//---------------------clk div-----------------------------//将一个SCL周期划分为4份,便于逻辑实现reg [1:0]clk_cnt= 2'd0;always @(posedge clk) beginclk_cnt<= clk_cnt + 1'b1;end//---------------------SCL_link-----------------------------always @(posedge clk) begincase(state)IDLE: beginSCL_link<= 1'b0;endSTART, SEND_DATA, GET_DATA, CHECK_ACK, ACK, NACK, STOP: beginSCL_link<= 1'b1;enddefault: beginSCL_link<= 1'b0;endendcaseend//---------------------SDA_link-----------------------------always @(posedge clk) begincase(state)IDLE, GET_DATA, CHECK_ACK: beginSDA_link<= 1'b0;endSTART, SEND_DATA, ACK, NACK, STOP: beginSDA_link<= 1'b1;enddefault: beginSDA_link<= 1'b0;endendcaseend//---------------------SCL_buf-----------------------------always @(posedge clk) begincase(state)IDLE: begin//1111SCL_buf<= 1'b1;endSTART: begin//1110case(clk_cnt)2'd0, 2'd1, 2'd2: beginSCL_buf<= 1'b1;end2'd3: beginSCL_buf<= 1'b0;enddefault: ;endcaseendSTOP: begin//0111case(clk_cnt)2'd1, 2'd2, 2'd3: beginSCL_buf<= 1'b1;end2'd0: beginSCL_buf<= 1'b0;enddefault: ;endcaseendSEND_DATA, GET_DATA, CHECK_ACK, ACK, NACK: begin//0110case(clk_cnt)2'd1, 2'd2: beginSCL_buf<= 1'b1;end2'd0, 2'd3: beginSCL_buf<= 1'b0;enddefault: ;endcaseenddefault: begin//1111SCL_buf<= 1'b1;endendcaseend//---------------------bit_cnt-----------------------------always @(posedge clk) begincase(state)SEND_DATA, GET_DATA: begincase(clk_cnt)2'd2: beginbit_cnt<= bit_cnt - 1'b1;enddefault: ;endcaseendSTART, ACK, NACK, CHECK_ACK: beginbit_cnt<= 4'd7;enddefault: beginbit_cnt<= 4'd15;endendcaseend//--------------------rddat_tmp----------------------------always @(posedge clk) begincase(state)GET_DATA: begincase(clk_cnt)2'd1: beginrddat_tmp[bit_cnt]<= SDA_ibuf;enddefault: ;endcaseenddefault: beginrddat_tmp<= rddat_tmp;endendcaseend//--------------------check_ack----------------------------always @(posedge clk) begincase(state)CHECK_ACK: begincase(clk_cnt)2'd1: begincheck_ack<= SDA_ibuf;enddefault: begincheck_ack<= check_ack;endendcaseenddefault: begincheck_ack<= 0;endendcaseend//---------------------SDA_buf-----------------------------always @(posedge clk) begincase(state)IDLE: beginSDA_buf<= 1'b1;endSTART: begin//1100,从而在SCL=H时,产生SDA=Dcase(clk_cnt)2'd0, 2'd1: beginSDA_buf<= 1'b1;end2'd2, 2'd3: beginSDA_buf<= 1'b0;enddefault: ;endcaseendSEND_DATA: begin//在clk_cnt=0给出数据,从而在clk_cnt=1,2时(SCL=H)保持SDA的稳定case(clk_cnt)2'd0: beginSDA_buf<= wrdat_buf[bit_cnt];enddefault: ;endcaseendGET_DATA: beginSDA_buf<= 1'b1;endCHECK_ACK: beginSDA_buf<= 1'b0;endACK: beginSDA_buf<= 1'b0;endNACK: beginSDA_buf<= 1'b1;endSTOP: begin//0011,从而在SCL=H时,产生SDA=Rcase(clk_cnt)2'd0, 2'd1: beginSDA_buf<= 1'b0;end2'd2, 2'd3: beginSDA_buf<= 1'b1;enddefault: ;endcaseenddefault: beginSDA_buf<= 1'b1;endendcaseend//-------------------change_state---------------------------always @(posedge clk) begincase(state)IDLE, ACK, NACK, CHECK_ACK, STOP: begincase(clk_cnt)2'd3: beginchange_state<= 1'b1;enddefault: beginchange_state<= 1'b0;endendcaseendSEND_DATA, GET_DATA: begincase(bit_cnt)4'd15: begincase(clk_cnt)2'd3: beginchange_state<= 1'b1;enddefault: beginchange_state<= 1'b0;endendcaseenddefault: beginchange_state<= 1'b0;endendcaseenddefault: begincase(clk_cnt)2'd3: beginchange_state<= 1'b1;enddefault: beginchange_state<= 1'b0;endendcaseendendcaseendendmodule

monostable_flipflop.v

单稳态电路,用于实现延时。单采集模式下,Sampling 阶段会持续 20 ms 左右,期间 SHT3x-DIS 会 NACK 读请求头

/* * file: monostable_flipflop.v* author: 今朝无言* Lab: WHU-EIS-LMSWE* date: -03-19* version: v1.0* description: 单稳态触发器*/module monostable_flipflop(inputclk,inputrst_n,input[Width-1:0]delay_N,inputreset_N,inputin,inputout);parameter Width = 32;reg[Width-1:0]delay_N_buf= 1;reg[Width-1:0]cnt= 0;always @(posedge clk or posedge reset_N) beginif(reset_N) begindelay_N_buf<= delay_N;endelse begindelay_N_buf<= delay_N_buf;endendregin_d0;regin_d1;wirein_pe;assignin_pe= in_d0 & (~in_d1);always @(posedge clk) beginin_d0<= in;in_d1<= in_d0;endalways @(posedge clk or negedge rst_n) beginif(~rst_n) begincnt<= 0;endelse if(in_pe) begincnt<= delay_N_buf;endelse if(cnt > 0) begincnt<= cnt - 1'b1;endelse begincnt<= cnt;endendassignout= (|cnt)? 1 : 0;endmodule

实机测试结果

笔者的 SHT35-DIS 芯片湿度采集似乎有问题,一直在跳变,温度采集是很稳定的,大概在 30∘C30^\circ C30∘C ,这是由于传感器芯片靠近 FPGA 的缘故。后来外接 SHT30-DIS 型号的温湿度芯片,测试结果正常(53%,22.5∘C22.5^\circ C22.5∘C)。

参考文献

[1] Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。