數(shù)字溫濕度計(jì)設(shè)計(jì)
實(shí)驗(yàn)任務(wù)
實(shí)驗(yàn)?zāi)康?/h4>前面的章節(jié)中我們學(xué)習(xí)了掃描式數(shù)碼管模塊和BCD轉(zhuǎn)碼模塊的工作原理及驅(qū)動(dòng)方法,也對(duì)I2C總線協(xié)議及相關(guān)知識(shí),本實(shí)驗(yàn)主要對(duì)I2C總線驅(qū)動(dòng)方法加以練習(xí),同時(shí)熟悉FPGA設(shè)計(jì)中常用運(yùn)算方法,最終完成數(shù)字溫濕度計(jì)總體設(shè)計(jì)。
本文引用地址:http://m.butianyuan.cn/article/202312/453963.htm設(shè)計(jì)框圖
根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成兩個(gè)功能模塊實(shí)現(xiàn),
實(shí)驗(yàn)原理
SHT-20模塊介紹
SHT-20是一款集成溫度和濕度感測(cè)于一體的傳感器芯片,采用3mm x 3mm貼片DFN封裝,數(shù)字I2C總線接口,管腳功能描述如下:
SHT-20芯片典型電路連接如下:
SHT-20芯片可以配置不同的分辨率模式,User Register中的bit0和bit7控制分辨率模式選擇,默認(rèn)狀態(tài)溫度T和濕度RH分別采用14bit和12bit模式
不同的分辨率模式下,溫度和濕度分辨率不同,默認(rèn)狀態(tài)溫度和濕度分辨率分別為0.01℃和0.04%RH。
不同的分辨率模式下,溫度和濕度的轉(zhuǎn)換時(shí)間也是不同的,默認(rèn)狀態(tài)溫度和濕度最大轉(zhuǎn)換時(shí)間分別為85ms和29ms。
溫度和濕度測(cè)量范圍如下:
SHT-20模塊連接
STEP BaseBoard V3.0底板上的溫濕度傳感器SHT-20模塊電路圖如下(上拉電阻未顯示):
上圖為溫濕度傳感器SHT-20模塊電路,與FPGA硬件接口有I2C總線(SCL、SDA),SHT2x 傳感器包含電容式濕度傳感器、帶隙溫度傳感器和專用的模擬和數(shù)字集成電路-全部放在單 CMOSens?芯片上。這在精度和穩(wěn)定性方面, 以及功耗最小的情況下, 都能產(chǎn)生無與倫比的傳感器性能, SHT20的分辨率可以通過命令 (RH/T 的8/12 位到12/14 位) 進(jìn)行更改, 并且校驗(yàn)和有助于提高通信的可靠性。
SHT-20模塊驅(qū)動(dòng)設(shè)計(jì)
智能接近系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)中我們已經(jīng)講述學(xué)習(xí)過I2C總線驅(qū)動(dòng)的設(shè)計(jì),本實(shí)驗(yàn)可以上原來的基礎(chǔ)上調(diào)整,首先來了解SHT-20時(shí)序中的參數(shù)要點(diǎn)。
通過SHT-20時(shí)序參數(shù)了解,SHT-20支持I2C通信400KHz快速模式同時(shí)兼容100KHz的標(biāo)準(zhǔn)模式,還有兩種模式下時(shí)序中的各種時(shí)間參數(shù),所以通信速度不需要調(diào)整。
I2C時(shí)序基本單元(啟動(dòng)、停止、發(fā)送、接收、發(fā)應(yīng)答、讀應(yīng)答)協(xié)議里統(tǒng)一的,所以所以基本單元狀態(tài)的設(shè)計(jì)也是不需要調(diào)整的。
SHT-20驅(qū)動(dòng)的流程,手冊(cè)上看到SHT-20芯片有很多指令,指令列表如下:
本實(shí)驗(yàn)涉及軟件復(fù)位、溫度測(cè)量和濕度測(cè)量三個(gè)操作分別查看其時(shí)序流程。
軟件復(fù)位
軟件復(fù)位操作時(shí)序流程如下:
我們將這種操作設(shè)計(jì)成一個(gè)一個(gè)狀態(tài),程序?qū)崿F(xiàn)如下:
MODE1:begin //單次寫操作
if(cnt_mode1 >= 4'd4) cnt_mode1 <= 1'b0; //對(duì)START中的子狀態(tài)執(zhí)行控制cnt_start
else cnt_mode1 <= cnt_mode1 + 1'b1;
state_back <= MODE1;
case(cnt_mode1)
4'd0: begin state <= START; end //I2C通信時(shí)序中的START
4'd1: begin data_wr <= dev_addr<<1; state <= WRITE; end //設(shè)備地址
4'd2: begin data_wr <= reg_addr; state <= WRITE; end //寄存器地址
4'd3: begin state <= STOP; end //I2C通信時(shí)序中的STOP
4'd4: begin state <= MAIN; end //返回MAIN
default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
endcase
end
溫濕度測(cè)量
溫度測(cè)量分為兩種模式:hold master和no hold master,兩種模式都可用但時(shí)序不同,本實(shí)驗(yàn)我們使用no hold master,濕度測(cè)量流程同溫度測(cè)量流程,只是指令不一樣。其操作時(shí)序流程如下:
根據(jù)問濕度測(cè)量的時(shí)序流程,我們分為兩部分,寫指令部分和讀數(shù)據(jù)部分,寫指令部分比復(fù)位操作時(shí)序流程多了20us的等待,且20us等待不是必須的,可以直接使用MODE1狀態(tài)完成,讀數(shù)據(jù)部分如果沒有測(cè)量完成尋址時(shí)就會(huì)不應(yīng)答,如果測(cè)量完成時(shí)序流程程序?qū)崿F(xiàn)如下:
MODE2:begin //兩次讀操作
if(cnt_mode2 >= 4'd7) cnt_mode2 <= 4'd0; //對(duì)START中的子狀態(tài)執(zhí)行控制cnt_start
else cnt_mode2 <= cnt_mode2 + 1'b1;
state_back <= MODE2;
case(cnt_mode2)
4'd0: begin state <= START; end //I2C通信時(shí)序中的START
4'd1: begin data_wr <= (dev_addr<<1)|8'h01; state <= WRITE; end//設(shè)備地址
4'd2: begin ack <= ACK; state <= READ; end //讀寄存器數(shù)據(jù)
4'd3: begin dat_h <= data_r; end
4'd4: begin ack <= NACK; state <= READ; end //讀寄存器數(shù)據(jù)
4'd5: begin dat_l <= data_r; end
4'd6: begin state <= STOP; end //I2C通信時(shí)序中的STOP
4'd7: begin state <= MAIN; end //返回MAIN
default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
endcase
end
最后我們編程控制狀態(tài)機(jī)按照驅(qū)動(dòng)例程代碼中流程運(yùn)行,程序?qū)崿F(xiàn)如下:
MAIN:begin
if(cnt_main >= 4'd9) cnt_main <= 4'd2; //寫完控制指令后循環(huán)讀數(shù)據(jù)
else cnt_main <= cnt_main + 1'b1;
case(cnt_main)
//軟件復(fù)位
4'd0: begin dev_addr <= 7'h40; reg_addr <= 8'hfe; state <= MODE1; end
4'd1: begin num_delay <= 24'd6000; state <= DELAY; end //復(fù)位時(shí)間,15ms
//測(cè)量溫度
4'd2: begin dev_addr <= 7'h40; reg_addr <= 8'hf3; state <= MODE1; end
4'd3: begin num_delay <= 24'd34000; state <= DELAY; end //溫度轉(zhuǎn)換,85ms
4'd4: begin dev_addr <= 7'h40; state <= MODE2; end //讀取配置
4'd5: begin T_code <= {dat_h,dat_l}; end //讀取數(shù)據(jù)
//測(cè)量濕度
4'd6: begin dev_addr <= 7'h40; reg_addr <= 8'hf5; state <= MODE1; end
4'd7: begin num_delay <= 24'd12000; state <= DELAY; end //濕度轉(zhuǎn)換,30ms
4'd8: begin dev_addr <= 7'h40; state <= MODE2; end //讀取配置
4'd9: begin H_code <= {dat_h,dat_l}; end //讀取數(shù)據(jù)
default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
endcase
end
系統(tǒng)總體實(shí)現(xiàn)
SHT-20驅(qū)動(dòng)模塊得到的是溫度和濕度的編碼值,想要得到℃和%RH的溫度和濕度的數(shù)據(jù)還需要運(yùn)算,運(yùn)算后的數(shù)據(jù)是二進(jìn)制數(shù),想要顯示在數(shù)碼管上還需要BCD轉(zhuǎn)碼。先考慮運(yùn)算:
這里我們以溫度的運(yùn)算為例,F(xiàn)PGA不擅長(zhǎng)小數(shù)的運(yùn)算,我們可以將小數(shù)運(yùn)算轉(zhuǎn)換成整數(shù)運(yùn)算處理,如下:
T = -46.85 + 175.72 * Tcode / 2^16 = (-4685 + 17572 * Tcode / 2^16) / 100
程序?qū)崿F(xiàn)如下:
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);//絕對(duì)值
wire [15:0] T_data_bin = c[15:0];
上面程序中沒有除以100的運(yùn)算,沒有集成專用除法器的FPGA實(shí)現(xiàn)除法運(yùn)算非常麻煩,需要大量的邏輯資源且性能不佳,通常我們不在FPGA中直接做除法運(yùn)算,上面程序中兩個(gè)除法。
⑴除以2^16可以通過右移16位方式解決。
⑵除以100在二進(jìn)制數(shù)中不好解決,而在BCD碼的十進(jìn)制數(shù)據(jù)很好處理,相當(dāng)于小數(shù)點(diǎn)左移兩位(十進(jìn)制位),所以等完成BCD碼后再來處理。
BCD轉(zhuǎn)碼在前面電壓器實(shí)驗(yàn)中介紹過,這里直接例化,程序?qū)崿F(xiàn)如下:
//進(jìn)行BCD轉(zhuǎn)碼處理
//小數(shù)點(diǎn)在BCD碼基礎(chǔ)上左移2位,完成除以100的操作
//移位后T_data_bcd[19:16]百位,[15:12]十位,[11:8]個(gè)位,[7:0]兩個(gè)小數(shù)位
wire [19:0] T_data_bcd;
bin_to_bcd u1
(
.rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效
.bin_code (T_data_bin ), //需要進(jìn)行BCD轉(zhuǎn)碼的二進(jìn)制數(shù)據(jù)
.bcd_code (T_data_bcd ) //轉(zhuǎn)碼后的BCD碼型數(shù)據(jù)輸出
);
//4位數(shù)碼管用于溫度顯示,保留1位小數(shù)//若溫度為負(fù),將T_data_bcd[19:16]百位數(shù)據(jù)用數(shù)字A替換,同時(shí)把數(shù)碼管A的字庫顯示負(fù)號(hào)
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; //小數(shù)點(diǎn)顯示使能
設(shè)計(jì)到這里,將4個(gè)BCD碼顯示在4個(gè)數(shù)碼管上,就可以實(shí)現(xiàn)溫度的顯示了,另外還可以增加高位消零的設(shè)計(jì),讓數(shù)碼管顯示更加符合人的習(xí)慣
//數(shù)據(jù)顯示使能,高位消零
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;
綜合后的設(shè)計(jì)框圖如下:
實(shí)驗(yàn)步驟
實(shí)驗(yàn)現(xiàn)象
將程序加載到FPGA,觀察數(shù)碼管顯示,左邊4位數(shù)碼管顯示溫度,右邊4位數(shù)碼管顯示濕度,用手接觸溫濕度傳感器,觀察顯示變化。
前面的章節(jié)中我們學(xué)習(xí)了掃描式數(shù)碼管模塊和BCD轉(zhuǎn)碼模塊的工作原理及驅(qū)動(dòng)方法,也對(duì)I2C總線協(xié)議及相關(guān)知識(shí),本實(shí)驗(yàn)主要對(duì)I2C總線驅(qū)動(dòng)方法加以練習(xí),同時(shí)熟悉FPGA設(shè)計(jì)中常用運(yùn)算方法,最終完成數(shù)字溫濕度計(jì)總體設(shè)計(jì)。
本文引用地址:http://m.butianyuan.cn/article/202312/453963.htm根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成兩個(gè)功能模塊實(shí)現(xiàn),
SHT-20是一款集成溫度和濕度感測(cè)于一體的傳感器芯片,采用3mm x 3mm貼片DFN封裝,數(shù)字I2C總線接口,管腳功能描述如下:
SHT-20芯片典型電路連接如下:
SHT-20芯片可以配置不同的分辨率模式,User Register中的bit0和bit7控制分辨率模式選擇,默認(rèn)狀態(tài)溫度T和濕度RH分別采用14bit和12bit模式
不同的分辨率模式下,溫度和濕度分辨率不同,默認(rèn)狀態(tài)溫度和濕度分辨率分別為0.01℃和0.04%RH。
不同的分辨率模式下,溫度和濕度的轉(zhuǎn)換時(shí)間也是不同的,默認(rèn)狀態(tài)溫度和濕度最大轉(zhuǎn)換時(shí)間分別為85ms和29ms。
溫度和濕度測(cè)量范圍如下:
STEP BaseBoard V3.0底板上的溫濕度傳感器SHT-20模塊電路圖如下(上拉電阻未顯示):
上圖為溫濕度傳感器SHT-20模塊電路,與FPGA硬件接口有I2C總線(SCL、SDA),SHT2x 傳感器包含電容式濕度傳感器、帶隙溫度傳感器和專用的模擬和數(shù)字集成電路-全部放在單 CMOSens?芯片上。這在精度和穩(wěn)定性方面, 以及功耗最小的情況下, 都能產(chǎn)生無與倫比的傳感器性能, SHT20的分辨率可以通過命令 (RH/T 的8/12 位到12/14 位) 進(jìn)行更改, 并且校驗(yàn)和有助于提高通信的可靠性。
智能接近系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)中我們已經(jīng)講述學(xué)習(xí)過I2C總線驅(qū)動(dòng)的設(shè)計(jì),本實(shí)驗(yàn)可以上原來的基礎(chǔ)上調(diào)整,首先來了解SHT-20時(shí)序中的參數(shù)要點(diǎn)。
通過SHT-20時(shí)序參數(shù)了解,SHT-20支持I2C通信400KHz快速模式同時(shí)兼容100KHz的標(biāo)準(zhǔn)模式,還有兩種模式下時(shí)序中的各種時(shí)間參數(shù),所以通信速度不需要調(diào)整。
I2C時(shí)序基本單元(啟動(dòng)、停止、發(fā)送、接收、發(fā)應(yīng)答、讀應(yīng)答)協(xié)議里統(tǒng)一的,所以所以基本單元狀態(tài)的設(shè)計(jì)也是不需要調(diào)整的。
SHT-20驅(qū)動(dòng)的流程,手冊(cè)上看到SHT-20芯片有很多指令,指令列表如下:
本實(shí)驗(yàn)涉及軟件復(fù)位、溫度測(cè)量和濕度測(cè)量三個(gè)操作分別查看其時(shí)序流程。
軟件復(fù)位
軟件復(fù)位操作時(shí)序流程如下:
我們將這種操作設(shè)計(jì)成一個(gè)一個(gè)狀態(tài),程序?qū)崿F(xiàn)如下:
MODE1:begin //單次寫操作 if(cnt_mode1 >= 4'd4) cnt_mode1 <= 1'b0; //對(duì)START中的子狀態(tài)執(zhí)行控制cnt_start else cnt_mode1 <= cnt_mode1 + 1'b1; state_back <= MODE1; case(cnt_mode1) 4'd0: begin state <= START; end //I2C通信時(shí)序中的START 4'd1: begin data_wr <= dev_addr<<1; state <= WRITE; end //設(shè)備地址 4'd2: begin data_wr <= reg_addr; state <= WRITE; end //寄存器地址 4'd3: begin state <= STOP; end //I2C通信時(shí)序中的STOP 4'd4: begin state <= MAIN; end //返回MAIN default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài) endcase end
溫濕度測(cè)量
溫度測(cè)量分為兩種模式:hold master和no hold master,兩種模式都可用但時(shí)序不同,本實(shí)驗(yàn)我們使用no hold master,濕度測(cè)量流程同溫度測(cè)量流程,只是指令不一樣。其操作時(shí)序流程如下:
根據(jù)問濕度測(cè)量的時(shí)序流程,我們分為兩部分,寫指令部分和讀數(shù)據(jù)部分,寫指令部分比復(fù)位操作時(shí)序流程多了20us的等待,且20us等待不是必須的,可以直接使用MODE1狀態(tài)完成,讀數(shù)據(jù)部分如果沒有測(cè)量完成尋址時(shí)就會(huì)不應(yīng)答,如果測(cè)量完成時(shí)序流程程序?qū)崿F(xiàn)如下:
MODE2:begin //兩次讀操作 if(cnt_mode2 >= 4'd7) cnt_mode2 <= 4'd0; //對(duì)START中的子狀態(tài)執(zhí)行控制cnt_start else cnt_mode2 <= cnt_mode2 + 1'b1; state_back <= MODE2; case(cnt_mode2) 4'd0: begin state <= START; end //I2C通信時(shí)序中的START 4'd1: begin data_wr <= (dev_addr<<1)|8'h01; state <= WRITE; end//設(shè)備地址 4'd2: begin ack <= ACK; state <= READ; end //讀寄存器數(shù)據(jù) 4'd3: begin dat_h <= data_r; end 4'd4: begin ack <= NACK; state <= READ; end //讀寄存器數(shù)據(jù) 4'd5: begin dat_l <= data_r; end 4'd6: begin state <= STOP; end //I2C通信時(shí)序中的STOP 4'd7: begin state <= MAIN; end //返回MAIN default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài) endcase end
最后我們編程控制狀態(tài)機(jī)按照驅(qū)動(dòng)例程代碼中流程運(yùn)行,程序?qū)崿F(xiàn)如下:
MAIN:begin if(cnt_main >= 4'd9) cnt_main <= 4'd2; //寫完控制指令后循環(huán)讀數(shù)據(jù) else cnt_main <= cnt_main + 1'b1; case(cnt_main) //軟件復(fù)位 4'd0: begin dev_addr <= 7'h40; reg_addr <= 8'hfe; state <= MODE1; end 4'd1: begin num_delay <= 24'd6000; state <= DELAY; end //復(fù)位時(shí)間,15ms //測(cè)量溫度 4'd2: begin dev_addr <= 7'h40; reg_addr <= 8'hf3; state <= MODE1; end 4'd3: begin num_delay <= 24'd34000; state <= DELAY; end //溫度轉(zhuǎn)換,85ms 4'd4: begin dev_addr <= 7'h40; state <= MODE2; end //讀取配置 4'd5: begin T_code <= {dat_h,dat_l}; end //讀取數(shù)據(jù) //測(cè)量濕度 4'd6: begin dev_addr <= 7'h40; reg_addr <= 8'hf5; state <= MODE1; end 4'd7: begin num_delay <= 24'd12000; state <= DELAY; end //濕度轉(zhuǎn)換,30ms 4'd8: begin dev_addr <= 7'h40; state <= MODE2; end //讀取配置 4'd9: begin H_code <= {dat_h,dat_l}; end //讀取數(shù)據(jù) default: state <= IDLE; //如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài) endcase end
SHT-20驅(qū)動(dòng)模塊得到的是溫度和濕度的編碼值,想要得到℃和%RH的溫度和濕度的數(shù)據(jù)還需要運(yùn)算,運(yùn)算后的數(shù)據(jù)是二進(jìn)制數(shù),想要顯示在數(shù)碼管上還需要BCD轉(zhuǎn)碼。先考慮運(yùn)算:
這里我們以溫度的運(yùn)算為例,F(xiàn)PGA不擅長(zhǎng)小數(shù)的運(yùn)算,我們可以將小數(shù)運(yùn)算轉(zhuǎn)換成整數(shù)運(yùn)算處理,如下:
T = -46.85 + 175.72 * Tcode / 2^16 = (-4685 + 17572 * Tcode / 2^16) / 100
程序?qū)崿F(xiàn)如下:
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);//絕對(duì)值 wire [15:0] T_data_bin = c[15:0];
上面程序中沒有除以100的運(yùn)算,沒有集成專用除法器的FPGA實(shí)現(xiàn)除法運(yùn)算非常麻煩,需要大量的邏輯資源且性能不佳,通常我們不在FPGA中直接做除法運(yùn)算,上面程序中兩個(gè)除法。
⑴除以2^16可以通過右移16位方式解決。
⑵除以100在二進(jìn)制數(shù)中不好解決,而在BCD碼的十進(jìn)制數(shù)據(jù)很好處理,相當(dāng)于小數(shù)點(diǎn)左移兩位(十進(jìn)制位),所以等完成BCD碼后再來處理。
BCD轉(zhuǎn)碼在前面電壓器實(shí)驗(yàn)中介紹過,這里直接例化,程序?qū)崿F(xiàn)如下:
//進(jìn)行BCD轉(zhuǎn)碼處理 //小數(shù)點(diǎn)在BCD碼基礎(chǔ)上左移2位,完成除以100的操作 //移位后T_data_bcd[19:16]百位,[15:12]十位,[11:8]個(gè)位,[7:0]兩個(gè)小數(shù)位 wire [19:0] T_data_bcd; bin_to_bcd u1 ( .rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效 .bin_code (T_data_bin ), //需要進(jìn)行BCD轉(zhuǎn)碼的二進(jìn)制數(shù)據(jù) .bcd_code (T_data_bcd ) //轉(zhuǎn)碼后的BCD碼型數(shù)據(jù)輸出 ); //4位數(shù)碼管用于溫度顯示,保留1位小數(shù)//若溫度為負(fù),將T_data_bcd[19:16]百位數(shù)據(jù)用數(shù)字A替換,同時(shí)把數(shù)碼管A的字庫顯示負(fù)號(hào) 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; //小數(shù)點(diǎn)顯示使能
設(shè)計(jì)到這里,將4個(gè)BCD碼顯示在4個(gè)數(shù)碼管上,就可以實(shí)現(xiàn)溫度的顯示了,另外還可以增加高位消零的設(shè)計(jì),讓數(shù)碼管顯示更加符合人的習(xí)慣
//數(shù)據(jù)顯示使能,高位消零 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;
綜合后的設(shè)計(jì)框圖如下:
將程序加載到FPGA,觀察數(shù)碼管顯示,左邊4位數(shù)碼管顯示溫度,右邊4位數(shù)碼管顯示濕度,用手接觸溫濕度傳感器,觀察顯示變化。
評(píng)論