差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
数字温湿度计设计 [2018/10/23 16:55]
anran [实验目的]
数字温湿度计设计 [2018/10/23 17:27] (当前版本)
anran [实验原理]
行 16: 行 16:
 ====设计框图==== ====设计框图====
  
 +根据前面的实验解析我们可以得知,该设计可以拆分成两个功能模块实现,
 +  * SHT20_Driver:温湿度传感器SHT-20芯片I2C总线通信驱动模块。
 +  * Calculate:完成温湿度码值到数码管显示之间的运算、转码和显示控制。
 +  * bin_to_bcd:将二进制数据转换成BCD码的方法。。
 +  * Segment_scan:通过驱动扫描式数码管将温湿度数据显示出来。
  
 +{{:​10-Top-Down层次设计.png?​500|Top-Down层次设计}} {{:​10-模块结构设计.png?​500|模块结构设计}}
 ====实验原理==== ====实验原理====
 +
 ===SHT-20模块介绍=== ===SHT-20模块介绍===
 +
 +SHT-20是一款集成温度和湿度感测于一体的传感器芯片,采用3mm x 3mm贴片DFN封装,数字I2C总线接口,管脚功能描述如下:
 +
 +{{:​10-管脚功能描述.png?​500|管脚功能描述}}
 +
 +SHT-20芯片典型电路连接如下:
 +
 +{{:​10-典型电路连接.png?​500|典型电路连接}}
 +
 +SHT-20芯片可以配置不同的分辨率模式,User Register中的bit0和bit7控制分辨率模式选择,默认状态温度T和湿度RH分别采用14bit和12bit模式
 +
 +{{:​10-分辨率模式配置.png?​500|分辨率模式配置}}
 +
 +不同的分辨率模式下,温度和湿度分辨率不同,默认状态温度和湿度分辨率分别为0.01℃和0.04%RH。
 +
 +{{:​10-温度和湿度分辨率.png?​800|温度和湿度分辨率}}
 +
 +不同的分辨率模式下,温度和湿度的转换时间也是不同的,默认状态温度和湿度最大转换时间分别为85ms和29ms。
 +
 +{{:​10-温度和湿度转换时间.png?​500|温度和湿度转换时间}}
 +
 +温度和湿度测量范围如下:
 +
 +{{:​10-温度和湿度测量范围.png?​500|温度和湿度测量范围}}
 +
 ===SHT-20模块连接=== ===SHT-20模块连接===
 +
 +STEP BaseBoard V3.0底板上的温湿度传感器SHT-20模块电路图如下(上拉电阻未显示):
 +
 +{{:​10-SHT-20模块电路.png?​600|SHT-20模块电路}}
 +
 +上图为温湿度传感器SHT-20模块电路,与FPGA硬件接口有I2C总线(SCL、SDA),SHT2x 传感器包含电容式湿度传感器、带隙温度传感器和专用的模拟和数字集成电路-全部放在单 CMOSens®芯片上。这在精度和稳定性方面,​ 以及功耗最小的情况下,​ 都能产生无与伦比的传感器性能, SHT20的分辨率可以通过命令 (RH/T 的8/12 位到12/14 位) 进行更改,​ 并且校验和有助于提高通信的可靠性。
 +
 ===SHT-20模块驱动设计=== ===SHT-20模块驱动设计===
 +
 +智能接近系统设计实验中我们已经讲述学习过I2C总线驱动的设计,本实验可以上原来的基础上调整,首先来了解SHT-20时序中的参数要点。
 +
 +{{:​10-SHT-20时序图.png?​500|SHT-20时序图}}
 +
 +{{:​10-SHT-20时序参数.png?​500|SHT-20时序参数}}
 +
 +通过SHT-20时序参数了解,SHT-20支持I2C通信400KHz快速模式同时兼容100KHz的标准模式,还有两种模式下时序中的各种时间参数,所以通信速度不需要调整。
 +  * 普通列表项目分频得到400KHz的时钟,程序实现同智能接近系统设计实验。
 +
 +I2C时序基本单元(启动、停止、发送、接收、发应答、读应答)协议里统一的,所以所以基本单元状态的设计也是不需要调整的。
 +  * 启动时序状态设计程序实现同智能接近系统设计实验。
 +  * 发送单元和读应答单元合并,时序状态设计程序实现同智能接近系统设计实验。
 +  * 接收单元和写应答单元合并,时序状态设计程序实现同智能接近系统设计实验。
 +  * 停止时序状态设计程序实现同智能接近系统设计实验。
 +
 +SHT-20驱动的流程,手册上看到SHT-20芯片有很多指令,指令列表如下:
 +
 +{{:​10-SHT-20基础指令.png?​500|SHT-20基础指令}}
 +
 +本实验涉及软件复位、温度测量和湿度测量三个操作分别查看其时序流程。
 +
 +**<wrap hi>​软件复位</​wrap>​**
 +
 +软件复位操作时序流程如下:
 +
 +{{:​10-软件复位操作.png?​600|软件复位操作}}
 +
 +我们将这种操作设计成一个一个状态,程序实现如下:
 +
 +<code verilog>
 +MODE1:begin //​单次写操作
 +        if(cnt_mode1 >= 4'd4) cnt_mode1 <= 1'​b0; ​   //​对START中的子状态执行控制cnt_start
 +        else cnt_mode1 <= cnt_mode1 + 1'b1;
 +        state_back <= MODE1;
 +        case(cnt_mode1)
 +            4'​d0: ​  begin state <= START; end   //​I2C通信时序中的START
 +            4'​d1: ​  begin data_wr <= dev_addr<<​1;​ state <= WRITE; end   //​设备地址
 +            4'​d2: ​  begin data_wr <= reg_addr; state <= WRITE; end  //​寄存器地址
 +            4'​d3: ​  begin state <= STOP; end    //​I2C通信时序中的STOP
 +            4'​d4: ​  begin state <= MAIN; end    //​返回MAIN
 +            default: state <= IDLE; //​如果程序失控,进入IDLE自复位状态
 +        endcase
 +    end
 +</​code>​
 +
 +**<wrap hi>​温湿度测量</​wrap>​**
 +
 +温度测量分为两种模式:hold master和no hold master,两种模式都可用但时序不同,本实验我们使用no hold master,湿度测量流程同温度测量流程,只是指令不一样。其操作时序流程如下:
 +
 +{{:​10-温湿度采样操作.png?​600|温湿度采样操作}}
 +
 +根据问湿度测量的时序流程,我们分为两部分,写指令部分和读数据部分,写指令部分比复位操作时序流程多了20us的等待,且20us等待不是必须的,可以直接使用MODE1状态完成,读数据部分如果没有测量完成寻址时就会不应答,如果测量完成时序流程程序实现如下:
 +
 +<code verilog>
 +MODE2:begin //​两次读操作
 +        if(cnt_mode2 >= 4'd7) cnt_mode2 <= 4'​d0; ​   //​对START中的子状态执行控制cnt_start
 +        else cnt_mode2 <= cnt_mode2 + 1'b1;
 +        state_back <= MODE2;
 +        case(cnt_mode2)
 +            4'​d0: ​  begin state <= START; end   //​I2C通信时序中的START
 +            4'​d1: ​  begin data_wr <= (dev_addr<<​1)|8'​h01;​ state <= WRITE; end//​设备地址
 +            4'​d2: ​  begin ack <= ACK; state <= READ; end    //​读寄存器数据
 +            4'​d3: ​  begin dat_h <= data_r; end
 +            4'​d4: ​  begin ack <= NACK; state <= READ; end   //​读寄存器数据
 +            4'​d5: ​  begin dat_l <= data_r; end
 +            4'​d6: ​  begin state <= STOP; end    //​I2C通信时序中的STOP
 +            4'​d7: ​  begin state <= MAIN; end    //​返回MAIN
 +            default: state <= IDLE; //​如果程序失控,进入IDLE自复位状态
 +        endcase
 +    end
 +</​code>​
 +
 +最后我们编程控制状态机按照驱动例程代码中流程运行,程序实现如下:
 +
 +<code verilog>
 +MAIN:begin
 +        if(cnt_main >= 4'd9) cnt_main <= 4'​d2; ​     //​写完控制指令后循环读数据
 +        else cnt_main <= cnt_main + 1'​b1; ​  
 +        case(cnt_main)
 +            //​软件复位
 +            4'​d0: ​  begin dev_addr <= 7'h40; reg_addr <= 8'hfe; state <= MODE1; end 
 +            4'​d1: ​  begin num_delay <= 24'​d6000;​ state <= DELAY; end //​复位时间,15ms
 +            //​测量温度
 +            4'​d2: ​  begin dev_addr <= 7'h40; reg_addr <= 8'hf3; state <= MODE1; end 
 +            4'​d3: ​  begin num_delay <= 24'​d34000;​ state <= DELAY; end //​温度转换,85ms ​
 +            4'​d4: ​  begin dev_addr <= 7'h40; state <= MODE2; end    //​读取配置
 +            4'​d5: ​  begin T_code <= {dat_h,​dat_l};​ end  //​读取数据
 +            //​测量湿度
 +            4'​d6: ​  begin dev_addr <= 7'h40; reg_addr <= 8'hf5; state <= MODE1; end 
 +            4'​d7: ​  begin num_delay <= 24'​d12000;​ state <= DELAY; end //​湿度转换,30ms
 +            4'​d8: ​  begin dev_addr <= 7'h40; state <= MODE2; end    //​读取配置
 +            4'​d9: ​  begin H_code <= {dat_h,​dat_l};​ end  //​读取数据
 +            default: state <= IDLE; //​如果程序失控,进入IDLE自复位状态
 +        endcase
 +    end
 +</​code>​
 +
 ===系统总体实现=== ===系统总体实现===
  
 +SHT-20驱动模块得到的是温度和湿度的编码值,想要得到℃和%RH的温度和湿度的数据还需要运算,运算后的数据是二进制数,想要显示在数码管上还需要BCD转码。先考虑运算:
 +
 +{{:​10-温度运算.png?​200|温度运算}} {{:​10-湿度运算.png?​200|湿度运算}}
 +
 +这里我们以温度的运算为例,FPGA不擅长小数的运算,我们可以将小数运算转换成整数运算处理,如下:
 +
 +T = -46.85 + 175.72 * T_code / 2^16 = (-4685 + 17572 * T_code / 2^16) / 100
 +
 +程序实现如下:
 +
 +<code verilog>
 +wire [31:0] a = T_code * 16'​d17572;​
 +wire [31:0] b = a >> 16; //​除以2^16取商
 +wire [31:0] c = (b>​=32'​d4685)?​(b - 32'​d4685):​(32'​d4685 - b);//​绝对值
 +wire [15:0] T_data_bin = c[15:0];
 +</​code>​
 +
 +上面程序中没有除以100的运算,没有集成专用除法器的FPGA实现除法运算非常麻烦,需要大量的逻辑资源且性能不佳,通常我们不在FPGA中直接做除法运算,上面程序中两个除法。
 +
 +⑴除以2^16可以通过右移16位方式解决。
 + 
 +⑵除以100在二进制数中不好解决,而在BCD码的十进制数据很好处理,相当于小数点左移两位(十进制位),所以等完成BCD码后再来处理。
 +
 +BCD转码在前面电压器实验中介绍过,这里直接例化,程序实现如下:
 +
 +<code verilog>
 +//​进行BCD转码处理
 +//​小数点在BCD码基础上左移2位,完成除以100的操作
 +//​移位后T_data_bcd[19:​16]百位,​[15:​12]十位,​[11:​8]个位,​[7:​0]两个小数位
 +wire [19:0] T_data_bcd;
 +bin_to_bcd u1
 +(
 +.rst_n ​             (rst_n ​     ),  //​系统复位,低有效
 +.bin_code ​          ​(T_data_bin ),  //​需要进行BCD转码的二进制数据
 +.bcd_code ​          ​(T_data_bcd )   //​转码后的BCD码型数据输出
 +);
 +
 +//​4位数码管用于温度显示,​保留1位小数
 +//​若温度为负,将T_data_bcd[19:​16]百位数据用数字A替换,同时把数码管A的字库显示负号
 +assign T_data = (b>​=32'​d4685)?​ T_data_bcd[19:​4]:​{4'​ha,​T_data_bcd[15:​4]};​
 +assign dot_en[7:4] = 4'​b0010; ​ //​小数点显示使能
 +</​code>​
 +
 +设计到这里,将4个BCD码显示在4个数码管上,就可以实现温度的显示了,另外还可以增加高位消零的设计,让数码管显示更加符合人的习惯
 +
 +<code verilog>
 +//​数据显示使能,高位消零
 +assign dat_en[7] = |T_data[15:​12];​ //自或
 +assign dat_en[6] = (b>​=32'​d4685)?​(|T_data[15:​8]):​(|T_data[11:​8]);​
 +assign dat_en[5:4] = 2'b11;
 +</​code>​
 +
 +综合后的设计框图如下:
 +
 +{{:​10-RTL设计框图.png?​800|RTL设计框图}} ​
  
 ====实验步骤==== ====实验步骤====
行 36: 行 228:
  
 ====实验现象==== ====实验现象====
 +
 +将程序加载到FPGA,观察数码管显示,左边4位数码管显示温度,右边4位数码管显示湿度,用手接触温湿度传感器,观察显示变化。
 +
 +{{:​10-实验现象.png?​400|实验现象}}