赞
踩
目录
DSS全称为“直接数字式频率合成”,通过逻辑高低电平的相加合成数字信号,在将数信信号转换,生成模拟信号。
DSS信号发生器的实现主要分为三个步骤:
调用ROM,首先需要生成一个ROM。步骤如下:
1. PROJECT MANAGER -- IP Catalog;
2. 在IP Catalog界面搜索ROM,选择RAMs & ROMs & BRAM -- Block Memory Generator;
3. 选择所需要的Memory Type ,这里我们选择Single Port ROM;
4. 设定Memory Size,根据所需要的Width 与 Depth,这里我们由于所用的波形数据为256个采样点,故设定Width = 8;Depth = 256;
5. 设定波形文件,在Memory Initialization中勾选 Load Init File,然后在Coe File一栏选择对于的文件,随后点击OK,这样ROM就生成完毕了。
调用端口如下:
- rom_name rom_name(
- .clka( ),
- //input ck
- .addra( ),
- //input address
- .douta( )
- //output data
- );
需要注意,rom的地址从0开始,依次向上加1。如0地址的下一位地址为1。
波形数据生成较为简单,MATLAB代码如下:
- clc;
- clear all;
- N=2^8;
- A=2^8;%振幅
- f=1;9
- F1=0;%相位
- F2=256;
- n=[0:N-1];
- s1=round((A/2)*sin(2*pi*n/N+pi*F1)+F2/2);%256/2为0
- fild=fopen('wave_dds_sin.coe','wt');
- fprintf(fild,'memory_initialization_radix=10;\n');
- fprintf(fild,'memory_initialization_vector=\n');
- for i=1:N
- if(s1(i)==256)
- s1(i)=255;
- end
- fprintf(fild,'%d,\n',s1(i));
- end
- fclose(fild);
- plot(s1)
通过程序生成单周期有256个数据点的正弦波,A为峰峰值。
需要注意最小值为0,而最大值并非256,而是255,因为ROM所设置的Width为8,仅能储存八位二进制数,而256为“ 'b100000000 ” 。若最大值为256,则会在ROM选择信号源文件时报错。
假设系统时钟频率为50MHz,一个周期输出一个数据点,则输出波形频率为
Fout = 50M/256 Hz = 195312.5Hz
若想要改变输出波形的频率,可以生成一个相位累加器,俗称加法器,同时设置一个频率控制字Fword来控制加法器累加的速度。
虽然在固定的时钟频率下加法器每次累加的速度是一样的,但是可以调整每次累加的步长来控制其达到最大值的速度。
频率控制字、加法器长度(位数)N、时钟频率以及输出波形频率关系如下:
Fword * clk = Fout * 2 ^ N
加法器控制程序如下:
- always@(posedge dac_clk or negedge rst )//计数器,越界归零, frequency = 50 MHz
- begin
- if(rst) begin//当 rst = 1
- Fcnt <= 32'd0;
- end
- else//当rst等于0时
- Fcnt <= Fcnt + Fword;
- end
需要注意的是,由于程序中使用的频率控制字并不一定为整数,故在计算时会产生一定误差,但此误差基本可忽略不计。
由于所用的ROM地址为8位二进制数,在一个周期内需要从0变化到255 即 11111111 一次,而累加器同样需要变到 1111 1111……一次,故可以使用累加器的前八位作为调用ROM的地址。
assign rom_addr = Fcnt[31:24] + Pword;
- module DDS_CHEN(
- input clk, //fpga clock
- input rst,//rst is 0 if no act
- input swi,
- input [3:0]bot,//按下时为高电平,逻辑1,控制频率以及幅度
- output dac_clk,
- output [7:0]sin_out,
- output [4:0] led
- );
- reg [31:0] Fword;
- wire [31:0] Pword;
- assign Pword = 8'b0;
- wire clk50;//标准时钟
- wire clk10;//没啥用
-
- wire [7:0] wave_data_sin;//读取数据
- wire [7:0] wave_data_sq;
-
- reg [7:0] wave_data_r;//赋值数据;
- reg [31:0] Fcnt;//计数器
- wire [7:0] rom_addr;//地址
-
- reg [4:0]led_r;//测试用
-
- //实际时钟
- assign dac_clk = clk50; //输出时钟
- //仿真时钟
- //assign dac_clk = clk;
-
- //控频
- //50M clk 858993-10k 8589933-100k 429497-5k 85899-1k 4295-50 相位累加器步长误差最大为7.6E-6
- //Fword = fout*(2^n)/fclk n = 32 fclk = 50MHz
- always@( posedge clk50)
- begin
- casex(bot)
- 4'b11xx: Fword = 4295;//50
- 4'b10xx: Fword = 85899;//1k
- 4'b01xx: Fword = 429497;//5k
- 4'b00xx: Fword = 858993;//10k
- default :Fword = 858993;
- endcase
- end
-
- //地址控制
- always@(posedge dac_clk or negedge rst )//计数器,越界归零, frequency = 50 MHz
- begin
- if(rst) begin//当 rst = 1
- Fcnt <= 32'd0;
- end
- else//当rst等于0时
- Fcnt <= Fcnt + Fword;
- end
- assign rom_addr = Fcnt[31:24] + Pword;//the first 8 bit as the address
-
- //指示灯
- always@(posedge dac_clk)
- begin
- if(!rst&&!bot)
- led_r <= 5'b1;
- else if(!rst&&bot[0])
- led_r <= 5'b00010;
- else if(!rst&&bot[1])
- led_r <= 5'b00100;
- else if(!rst&&bot[2])
- led_r <= 5'b01000;
- else if(!rst&&bot[3])
- led_r <= 5'b10000;
- else
- led_r <=0;
- end
-
- //赋值与控幅,控幅还可以通过外部电路改变电压来实现
- always@(posedge dac_clk)
- begin
- case(swi)
- 1'b0:
- casex(bot)
- 4'bxx00 : wave_data_r <= wave_data_sin / 4;
- 4'bxx01 : wave_data_r <= wave_data_sin / 2;
- 4'bxx10 : wave_data_r <= (wave_data_sin / 4)*3 ;
- 4'bxx11 : wave_data_r <= wave_data_sin ;
- endcase
- 1'b1:
- casex(bot)
- 4'bxx00 : wave_data_r <= wave_data_sq / 4;
- 4'bxx01 : wave_data_r <= wave_data_sq / 2;
- 4'bxx10 : wave_data_r <= (wave_data_sq / 4)*3 ;
- 4'bxx11 : wave_data_r <= wave_data_sq;
- default: wave_data_r <= 114;
- endcase
- endcase
- end
- assign sin_out = wave_data_r;
- assign led = led_r;
-
- blk_mem_gen_0 blk_mem_gen_0 (
- //实际
- .clka(clk50), // input clka
- //仿真
- //.clka(clk),
- .addra(rom_addr), // input [8 : 0] addra
- .douta(wave_data_sin) // output [7 : 0] douta
- );
-
- blk_mem_gen_1 sq(
- //仿真
- //.clka(clk),
- //实际
- .clka(clk50),
- .addra(rom_addr),
- .douta(wave_data_sq)
- );
- clk_wiz_0 clk_wiz_0 (
- .clk_in1(clk),
- .resetn(1'b1),
- .clk_out50M(clk50),
- .clk_out10M(clk10),
- .locked()
- );
- endmodule
一般而言,数码管可以分为共阴、共阳两种。
共阴为数码管的八个二极管共用一个阴极,此时控制不同二极管阳极的电平就可以控制其显示状态,当阳极与阴极形成一定电压差时,二极管导通发光,即高电平发光。一般而言,共极低电平表示数码管工作。
共阳为数码管的八个二极管共用一个阳极。一般当共阳极为高电平时二极管工作,相应二极管阴极为低电平时发光。即低电平发光。
共阳、共阴极的数码管真值表正好完全相反。
本次实验所使用的是四位共阳数码管SM410564。当正视显示面时,其管脚约束如下:
s1~s4为四个共阳极,控制四个显示数位,可以同时为高电平,由于共极管脚分别独立,故电平高低与否与其他管脚无关。
a~g为显示数字的七个发光二极管的阴极管脚,dp为小数点位置发光二极管的阴极管脚。
整个模块共由4*8共32个发光二极管组成,显然控制发光二极管的8个阴极管脚不足以同时显示四个不同的符号,但可以同时显示相同的符号。故采用交替显示的方式进行输出。
交替显示通过对于每一时钟周期,仅让一个共极为高电平,并将相应真值赋值,在下一个周期相邻共极变为高电平,当前共极变为低电平,并重新进行赋值,如此循环。假设时钟周期为50M赫兹,则整个显示模块的刷新率即为50Mhz, 而对于单一的显示位,刷新率为50M/4 = 12.5MHz远大于人眼25Hz或是80Hz的基本要求。
完整代码如下:(刷新了为1lHz,输出仅为6.6.6.6.)
- `timescale 1ns / 1ps
-
- module SMG(
- input clk,
- input rst,
- output [3:0] numo,
- output [6:0] datao,
- output pointo
- );
- wire clk50;
- reg [3:0]numr;
- wire [3:0]numw;
- reg [6:0]datar;
- wire[6:0]dataw;
- reg clk_s;
- reg [32:0] cnt;//微妙时钟计数器
- reg pointr;
-
- assign pointo = pointr;
- assign numo = numr;
- assign datao = datar;
-
- always@(posedge clk_s)//0.001s
- begin
- datar = 7'b0000_010;//6
- pointr = 1'b0;
- if(rst)
- numr = 4'b0001;
- else if(numr ==4'b1000)
- numr = 4'b0001;//从s4向s1刷新;
- else if(numr !=4'b1000)
- numr = numr << 1;
- end
- //时钟
- always@(posedge clk50 or negedge rst)
- begin//一个周期为25时钟周期,0.02*25*10^6=0.5us,一个周期0.5us
- if(rst)
- cnt <= 32'd0;
- else if(cnt == 32'd24_999)//毫秒计数器
- cnt <= 32'd0;
- else
- cnt <= cnt + 1'b1;
- end
- //微秒时钟2,由cnt控制
- always@(posedge clk50 or negedge rst)
- begin
- if(rst)
- clk_s <= 1'b0;
- else if(cnt== 32'd24_999)//将cnt-us换为cnt,此时0.5us翻转一次,clk-us一个周期为0.001s
- clk_s <= ~ clk_s;
- else
- clk_s <= clk_s;
- end
- clk_wiz_0 clk_wiz_0(
- .reset(1'b0),
- .clk_in1(clk),
详情参考技术手册。
采用单线双向串口通信,一次性传输四十个字节的二进制数据,高位先输出。数据每八位分为一组,第一组为温度整数;第二组为温度小数;第三组为湿度整数;第四组为湿度小数;第五组为校验码,在正常情况下第五组应为前四组数据之和。
但对于简单的温湿度测量来说,实际上有用的只有前24位,即前三组。因为在不拓展的情况下,湿度小数的部分输出数据一直为0,即8'b 0000_0000。
DHT11的通信串口需要并联一个5K欧姆左右的上拉电阻使其在非工作状态保持高电平,其控制主要分为6部分:
对于数据采集中0或1的判断,通过每个字节高电平的时间来判断。每个字节由恒定的50us低电平开始,若高电平持续时间为20~28us,则为0;若高电平持续时间为70us,则为1。
在此时需要注意两个问题:
对于整个程序,将其分为三个模块进行。
此外,额外设置一个按钮flag_key来控制温湿度的切换显示。
此模块较为简单,有四个输入:时钟clk、复位rst、整数部分输入int_in、小数部分输入dec_in;四个输出:int_out1,2和dec_out1,2,分别对应整数、小数的十位与个位。
十位分离过程直接通过对10('b1010)整除即可以实现;个位分离过程通过原数据减去十倍的十位部分即可得到。
代码如下:
- `timescale 1ns / 1ps
- module BTD(
- input clk50,
- input [7:0] int_in,
- input [7:0] dec_in,
- output [3:0] int_out1,
- output [3:0] int_out2,
- output [3:0] dec_out1,
- output [3:0] dec_out2,
- input rst
- );
- //定义
- reg [7:0]intbr;
- reg [3:0]in1;
- reg [3:0]in2;
-
- reg [3:0]de1;
- reg [3:0]de2;
- reg [7:0]decbr;
- //整数位
- always@(posedge clk50)begin
- intbr = int_in;
- in1 = intbr/4'b1010;
- in2 = intbr-in1*4'b1010;
- end
- //小数位
- always@(posedge clk50)begin
- decbr = dec_in;
- de1 = decbr/4'b1010;
- de2 = decbr-de1*4'b1010;
- end
- //赋值
- assign int_out1 = in1;
- assign int_out2 = in2;
- assign dec_out1 = de1;
- assign dec_out2 = de2;
- endmodule
数据转换模块结构简单,主体部分即为四个数据选择器。
需要注意的仅有共阳数码管为低电平发光以及数据赋值的顺序为从右往左为从低到高。
代码如下:
- `timescale 1ns / 1ps
- module SMG(
- input clk50,
- input rst,
- input data_flag,//0-hu 1-te//没有用
- input [3:0] int_in1,//D
- input [3:0] dec_in1,//D
- input [3:0] int_in2,//D
- input [3:0] dec_in2,//D
- output [6:0] data_out1,
- output [6:0] data_out2,
- output [6:0] data_out3,
- output [6:0] data_out4
- );
- //定义
- reg [3:0]numr;
- reg [6:0]datar1;
- reg [6:0]datar2;
- reg [6:0]datar3;
- reg [6:0]datar4;
- reg [31:0]cnt;
- reg [3:0]temp_data_1;
- reg [3:0]temp_data_2;
- reg [3:0]temp_data_3;
- reg [3:0]temp_data_4;
-
- reg int1;
- reg int2;
- reg dec1;
- reg dec2;
- //输出赋值
- assign data_out1 = datar1;
- assign data_out2 = datar2;
- assign data_out3 = datar3;
- assign data_out4 = datar4;
- //数据选择器
- //小数点显示位数选择 转换数据选择
- always@(posedge clk50)//0.02us 一次
- begin
- temp_data_1 = int_in1;
- temp_data_2 = int_in2;
- temp_data_3 = dec_in1;
- temp_data_4 = dec_in2;
- end
- //数据选择器 数据转换
- always@(posedge clk50)
- begin
- case(temp_data_1)//gfedcba
- 4'b0000:datar1 = 7'b1000000;//0
- 4'b0001:datar1 = 7'b1111001;
- 4'b0010:datar1 = 7'b0100100;
- 4'b0011:datar1 = 7'b0110000;
- 4'b0100:datar1 = 7'b0011001;
- 4'b0101:datar1 = 7'b0010010;
- 4'b0110:datar1 = 7'b0000010;
- 4'b0111:datar1 = 7'b1111000;
- 4'b1000:datar1 = 7'b0000000;
- 4'b1001:datar1 = 7'b0010000;
- endcase
- end
- always@(posedge clk50)
- begin
- case(temp_data_2)//gfedcba
- 4'b0000:datar2 = 7'b1000000;//0
- 4'b0001:datar2 = 7'b1111001;
- 4'b0010:datar2 = 7'b0100100;
- 4'b0011:datar2 = 7'b0110000;
- 4'b0100:datar2 = 7'b0011001;
- 4'b0101:datar2 = 7'b0010010;
- 4'b0110:datar2 = 7'b0000010;
- 4'b0111:datar2 = 7'b1111000;
- 4'b1000:datar2 = 7'b0000000;
- 4'b1001:datar2 = 7'b0011000;
- endcase
- end
- always@(posedge clk50)
- begin
- case(temp_data_3)//gfedcba
- 4'b0000:datar3 = 7'b1000000;//0
- 4'b0001:datar3 = 7'b1111001;
- 4'b0010:datar3 = 7'b0100100;
- 4'b0011:datar3 = 7'b0110000;
- 4'b0100:datar3 = 7'b0011001;
- 4'b0101:datar3 = 7'b0010010;
- 4'b0110:datar3 = 7'b0000010;
- 4'b0111:datar3 = 7'b1111000;
- 4'b1000:datar3 = 7'b0000000;
- 4'b1001:datar3 = 7'b0011000;
- endcase
- end
- always@(posedge clk50)
- begin
- case(temp_data_4)//gfedcba
- 4'b0000:datar4 = 7'b1000000;//0
- 4'b0001:datar4 = 7'b1111001;
- 4'b0010:datar4 = 7'b0100100;
- 4'b0011:datar4 = 7'b0110000;
- 4'b0100:datar4 = 7'b0011001;
- 4'b0101:datar4 = 7'b0010010;
- 4'b0110:datar4 = 7'b0000010;
- 4'b0111:datar4 = 7'b1111000;
- 4'b1000:datar4 = 7'b0000000;
- 4'b1001:datar4 = 7'b0011000;
- endcase
- end
- endmodule
DHT11的控制主要有四个重点:
通过两个指示信号来实现,代码如下:
- //通过dht11的上升下降沿来控制步进次数,确保在输入一个字节是bitcnt等累加器只会加一次,同时控制判别器在电平下降时才进行判断
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)//复位是两个都是1
- begin
- dht11_reg1 <= 1'b1;
- dht11_reg2 <= 1'b1;
- end
- else
- begin
- dht11_reg1 <= dht11;//读入数据,非上升下降沿时,二者相等,pos、neg均为0,
- //上升沿:reg1 = 1,reg2 = 0,pos = 1,neg = 0;
- //下降沿:reg1 = 0,reg2 = 1,pos = 0,neg = 1;
- dht11_reg2 <= dht11_reg1;//reg2 = reg1
- end
- end
- assign dht11_pos = (dht11_reg1) & (~dht11_reg2);//posedge,时钟上升沿
- assign dht11_neg = (~dht11_reg1) & (dht11_reg2);//negedge,时钟下降沿
主机仅在前两个阶段生成开始指示信号是控制端口,其他阶段仅作为接收端。
IO状态的控制可以通过对dht11进行赋值来实现,当主机输出时dht11为具体值,当辅机输出时dht11为未知量1'bz。
代码如下:
- //数值判定 IO状态 与 输出值
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)begin
- dht11_en <= 1'b0;
- dht11_out <= 1'b1;
- end
- else if(state == WAIT_1S)//等待系统稳定
- begin
- dht11_en <= 1'b1;
- dht11_out <= 1'b1;
- end
- else if(state == START)//wait 1s or start
- begin
- dht11_en <= 1'b1;
- dht11_out <= 1'b0;
- if(cnt_us == LOW_18MS_MAX)
- dht11_out <= 1'b1;
- end
- else //其他状态
- begin
- dht11_en <= 1'b0;
- dht11_out <=1'b0;
- end
- end
- //赋值
- assign dht11 = dht11_en ? dht11_out : 1'bz;
状态判断主要通过两个计数器进行,一个记录高电平以及非工作时间、一个记录低电平时间。状态转换的判定通过上升、下降沿,计数器取值来进行,每当状态进行转换,计数器清零一次。
计数器控制代码:
- //DHT11状态变量控制
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)//复位
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- else
- begin
- case(state)
- WAIT_1S:begin//初始状态,
- if(cnt_us == WAIT_1S_MAX)//若满足时间1s
- cnt_us = 20'd0;
- else //not 到1s时,每1us cnt us+1,要加1E6次
- cnt_us = cnt_us + 1'b1;
- end
- START :begin//主机拉低频率18ms
- if(cnt_us == LOW_18MS_MAX)//在清零后cnt us 重新开始计数,直到到达18ms
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- DLY_1 :begin//等待从机发出信号,延时30us后 cntus清零
- if(cnt_us == 20'd29)
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- REPLY :begin//从机发射响应信号
- if(dht11_pos == 1'b1 && (cnt_low > 80))//从机相应80us后,清零、进入下一状态
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- else if(dht11 == 1'b0)//DATA为低电平,但为满足状态,持续计数
- begin
- cnt_low = cnt_low + 1'b1;//低电平时间计数
- cnt_us = cnt_us + 1'b1;//时间计数
- end
- else if(cnt_us > 1000)//若超过1ms,归零,重新开始
- begin
- cnt_low <= 20'd0;
- cnt_us <= 20'd0;
- end
- else //系统不稳定,计时但是不记录低电平时间
- begin
- cnt_low = cnt_low;
- cnt_us = cnt_us + 1'b1;
- end
- end
- DLY_2 :begin//等待
- if(dht11_neg == 1'b1 && (cnt_us > 80))//拉高80us响应后,进入读取阶段
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- RD_DATA:begin//传输信号数据
- if(dht11_neg == 1'b1 || dht11_pos == 1'b1)//df与dr均为1时归零(电平变化时)
- begin
- cnt_us = 1'b0;
- end
- else
- cnt_us = cnt_us + 1'b1;//计时
- end
- default://其他情况归零
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- endcase
- end
- end
状态控制代码:
- //状态控制,控制变量在后续模块
- always@(posedge clk_us or negedge sys_rst)//微妙时钟或复位
- begin
- if(sys_rst)//rst = 0
- state <= WAIT_1S; //等待1s,初始状态为state = wait 1s
- else
- begin
- case(state)
- WAIT_1S:begin
- if(cnt_us == WAIT_1S_MAX)//1s后,state = start,同时cnt us清零
- state = START;
- else
- state = WAIT_1S;
- end
- START :begin//主机发出开始信号
- if(cnt_us == LOW_18MS_MAX)//到达18ms后cnt us清零,进入等待1状态
- state = DLY_1;
- else
- state = START;
- end
- DLY_1 :begin//拉高30us表示结束
- if(cnt_us == 20'd30)//10us后进入从机相应状态
- state = REPLY;
- else
- state = DLY_1;
- end
- REPLY :begin//从机回应
- if(dht11_pos == 1'b1 && (cnt_low > 80))//低电平计数80us以上,进入等待2状态,等待传感器数据
- state = DLY_2;
- else if(cnt_us > 1000)//表示等待了1MS,重新开始
- state = START;
- else
- state = REPLY;
- end
- DLY_2 :begin//拉高80us后进入数据读取
- if(dht11_neg == 1'b1 && cnt_us >80)
- state = RD_DATA;
- else
- state = DLY_2;
- end
- RD_DATA:begin
- if(bit_cnt == 40 && dht11_pos == 1'b1)//读取完40bit数据后重新开始
- state = START;//读完后立刻返回开始
- else//否则持续进行
- state = RD_DATA;
- end
- default:state = WAIT_1S;
- endcase
- end
- end
代码如下:
- //依次对data——temp写入信号数据,输出data-temp
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)
- data_temp <= 40'd0;
- else if(state == RD_DATA && dht11_neg == 1'b1 && cnt_us< 50 ) //下降沿是出发,确保高点平占时完全被记录
- data_temp[39 - bit_cnt] <= 1'b0; //DHT11先输出高位,因此从高位向低位依次赋值
- else if(state == RD_DATA && dht11_neg == 1'b1 && cnt_us > 50)
- data_temp[39 - bit_cnt] <= 1'b1;//小于50us当成0,大于50us当成1
- else
- data_temp <= data_temp;
- end
-
- //数据校验和赋值,输出data
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)
- data <= 32'd0;
- else if(data_temp[7:0] == data_temp[39:32] + data_temp[31:24] + data_temp[23:16] + data_temp[15:8])
- data <= data_temp[39:8];//校验位无误时将数据赋值给data
- else
- data <= data;
- end
第一组:
- `timescale 1ns / 1ps
- //
- // Company:
- // Engineer:
- //
- // Create Date: 2023/06/11 15:49:57
- // Design Name:
- // Module Name: dht11_ctrl
- // Project Name:
- // Target Devices:
- // Tool Versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- //
-
-
- module dht11_ctrl(sys_clk,sys_rst,data_flag,dht11,data_out, test_leds);
-
- input sys_clk;//clk-50Mhz
- input sys_rst;//rst,触发为1
- input data_flag;//控制输出温度还是湿度
- inout dht11;//既可输入又可输出,即为DATA线
- output [15:0] data_out;//输出16位信号
- output [3:0] test_leds;
-
- //状态定义
- parameter WAIT_1S = 6'b000_001,//上电等待1s状态
- START = 6'b000_010,//主机拉低20ms,发送开始信号状态
- DLY_1 = 6'b000_100,//等待从机答应
- REPLY = 6'b001_000,//从机对主机发出发送信号
- DLY_2 = 6'b010_000,//等待主机回应
- RD_DATA = 6'b100_000;//开始传输数据
-
- parameter WAIT_1S_MAX = 32'd999_999,
- LOW_18MS_MAX = 20'd19_999;
-
- wire dht11_pos;
- wire dht11_neg;
-
- reg clk_us;
- reg [4:0] cnt;//微妙时钟计数器
- reg [5:0] state;
- reg [19:0] cnt_us;//微秒计时器
- reg [19:0] cnt_low;//低电平计时器
- reg dht11_reg1;//时钟沿计数器
- reg dht11_reg2;//时钟沿计数器
- reg [5:0] bit_cnt;//数据写入计数器
- reg [39:0] data_temp;//全部数据
- reg [31:0] data;//校验后数据
- reg dht11_en;
- reg dht11_out;
- reg [3:0] led;
- //微秒时钟1,一个周期0.5us
- always@(posedge sys_clk or negedge sys_rst)
- begin//一个周期为25时钟周期,0.02*25=0.5us,一个周期0.5us
- if(sys_rst)
- cnt <= 5'd0;
- else if(cnt == 5'd24)//微秒计数器
- cnt <= 5'd0;
- else
- cnt <= cnt + 1'b1;
- end
- //微秒时钟2,由cnt控制
- always@(posedge sys_clk or negedge sys_rst)
- begin
- if(sys_rst)
- clk_us <= 1'b0;
- else if(cnt== 5'd24)//将cnt-us换为cnt,此时一个没0.5us翻转一次,clk-us一个周期为1us
- clk_us <= ~ clk_us;
- else
- clk_us <= clk_us;
- end
-
- //状态控制,控制变量在后续模块
- always@(posedge clk_us or negedge sys_rst)//微妙时钟或复位
- begin
- if(sys_rst)//rst = 0
- state <= WAIT_1S; //等待1s,初始状态为state = wait 1s
- else
- begin
- case(state)
- WAIT_1S:begin
- if(cnt_us == WAIT_1S_MAX)//1s后,state = start,同时cnt us清零
- state = START;
- else
- state = WAIT_1S;
- end
- START :begin//主机发出开始信号
- if(cnt_us == LOW_18MS_MAX)//到达18ms后cnt us清零,进入等待1状态
- state = DLY_1;
- else
- state = START;
- end
- DLY_1 :begin//拉高30us表示结束
- if(cnt_us == 20'd30)//10us后进入从机相应状态
- state = REPLY;
- else
- state = DLY_1;
- end
- REPLY :begin//从机回应
- if(dht11_pos == 1'b1 && (cnt_low > 80))//低电平计数80us以上,进入等待2状态,等待传感器数据
- state = DLY_2;
- else if(cnt_us > 1000)//表示等待了1MS,重新开始
- state = START;
- else
- state = REPLY;
- end
- DLY_2 :begin//拉高80us后进入数据读取
- if(dht11_neg == 1'b1 && cnt_us >80)
- state = RD_DATA;
- else
- state = DLY_2;
- end
- RD_DATA:begin
- if(bit_cnt == 40 && dht11_pos == 1'b1)//读取完40bit数据后重新开始
- state = START;//读完后立刻返回开始
- else//否则持续进行
- state = RD_DATA;
- end
- default:state = WAIT_1S;
- endcase
- end
- end
-
- //DHT11状态变量控制
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)//复位
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- else
- begin
- case(state)
- WAIT_1S:begin//初始状态,
- if(cnt_us == WAIT_1S_MAX)//若满足时间1s
- cnt_us = 20'd0;
- else //not 到1s时,每1us cnt us+1,要加1E6次
- cnt_us = cnt_us + 1'b1;
- end
- START :begin//主机拉低频率18ms
- if(cnt_us == LOW_18MS_MAX)//在清零后cnt us 重新开始计数,直到到达18ms
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- DLY_1 :begin//等待从机发出信号,延时30us后 cntus清零
- if(cnt_us == 20'd29)
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- REPLY :begin//从机发射响应信号
- if(dht11_pos == 1'b1 && (cnt_low > 80))//从机相应80us后,清零、进入下一状态
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- else if(dht11 == 1'b0)//DATA为低电平,但为满足状态,持续计数
- begin
- cnt_low = cnt_low + 1'b1;//低电平时间计数
- cnt_us = cnt_us + 1'b1;//时间计数
- end
- else if(cnt_us > 1000)//若超过1ms,归零,重新开始
- begin
- cnt_low <= 20'd0;
- cnt_us <= 20'd0;
- end
- else //系统不稳定,计时但是不记录低电平时间
- begin
- cnt_low = cnt_low;
- cnt_us = cnt_us + 1'b1;
- end
- end
- DLY_2 :begin//等待
- if(dht11_neg == 1'b1 && (cnt_us > 80))//拉高80us响应后,进入读取阶段
- cnt_us = 20'd0;
- else
- cnt_us = cnt_us + 1'b1;
- end
- RD_DATA:begin//传输信号数据
- if(dht11_neg == 1'b1 || dht11_pos == 1'b1)//df与dr均为1时归零(电平变化时)
- begin
- cnt_us = 1'b0;
- end
- else
- cnt_us = cnt_us + 1'b1;//计时
- end
- default://其他情况归零
- begin
- cnt_low = 20'd0;
- cnt_us = 20'd0;
- end
- endcase
- end
- end
-
- reg ct;
- always@(posedge clk_us)
- begin
- if(cnt_us == 20'b1000)
- ct = 1;
- if(ct == 1)
- led[0] = 1;
- else if(ct == 0)
- led[0] = 0;
- end
- //通过dht11的上升下降沿来控制步进次数,确保在输入一个字节是bitcnt等累加器只会加一次,同时控制判别器在电平下降时才进行判断
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)//复位是两个都是1
- begin
- dht11_reg1 <= 1'b1;
- dht11_reg2 <= 1'b1;
- end
- else
- begin
- dht11_reg1 <= dht11;//读入数据,非上升下降沿时,二者相等,pos、neg均为0,
- //上升沿:reg1 = 1,reg2 = 0,pos = 1,neg = 0;
- //下降沿:reg1 = 0,reg2 = 1,pos = 0,neg = 1;
- dht11_reg2 <= dht11_reg1;//reg2 = reg1
- end
- end
- assign dht11_pos = (dht11_reg1) & (~dht11_reg2);//posedge,时钟上升沿
- assign dht11_neg = (~dht11_reg1) & (dht11_reg2);//negedge,时钟下降沿
-
- //数据位数控制,输出bit-cnt
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)
- bit_cnt <= 6'd0;
- else if(bit_cnt == 40 && dht11_pos == 1'b1)
- bit_cnt <= 6'd0;
- else if((state == RD_DATA) && (dht11_neg == 1'b1))
- bit_cnt <= bit_cnt + 1'b1;//当状态为写入且dht11-neg = 1时,bit—cnt依次变化
- else
- bit_cnt <= bit_cnt;
- end
-
- //依次对data——temp写入信号数据,输出data-temp
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)
- data_temp <= 40'd0;
- else if(state == RD_DATA && dht11_neg == 1'b1 && cnt_us< 50 ) //下降沿是出发,确保高点平占时完全被记录
- data_temp[39 - bit_cnt] <= 1'b0; //DHT11先输出高位,因此从高位向低位依次赋值
- else if(state == RD_DATA && dht11_neg == 1'b1 && cnt_us > 50)
- data_temp[39 - bit_cnt] <= 1'b1;//小于50us当成0,大于50us当成1
- else
- data_temp <= data_temp;
- end
- always@(posedge clk_us)
- begin
- if(data_temp == 0)
- led[1] = 1;
- end
- //数据校验和赋值,输出data
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)
- data <= 32'd0;
- else if(data_temp[7:0] == data_temp[39:32] + data_temp[31:24] + data_temp[23:16] + data_temp[15:8])
- data <= data_temp[39:8];//校验位无误时将数据赋值给data
- else
- data <= data;
- end
-
- //IO控制
- always@(posedge clk_us or negedge sys_rst)
- begin
- if(sys_rst)begin
- dht11_en <= 1'b0;
- dht11_out <= 1'b1;
- end
- else if(state == WAIT_1S)//等待系统稳定
- begin
- dht11_en <= 1'b1;
- dht11_out <= 1'b1;
- end
- else if(state == START)//wait 1s or start
- begin
- dht11_en <= 1'b1;
- dht11_out <= 1'b0;
- if(cnt_us == LOW_18MS_MAX)
- dht11_out <= 1'b1;
- end
- else //其他状态
- begin
- dht11_en <= 1'b0;
- dht11_out <=1'b0;
- end
- end
-
- assign dht11 = dht11_en ? dht11_out : 1'bz;
- //当dht11en = 1时,dht11 = dht11 out,当en = 0 时,dht11 = 未知
- //start时dht11 受主机控制,等于0--低电平
- //其他时候,dht11为未知量,由辅机控制
- reg [15:0] datar;
- always@(posedge clk_us or negedge sys_rst)//温湿度选择器,输出data-out
- begin
- if(sys_rst)
- datar <= 16'd0;//十六位
- else if(data_flag == 1'b0)//data为32位 整温-小温-整湿-小湿
- datar <= data[31:16];//湿度数据
- else if(data_flag == 1'b1)
- datar <= data[15:0];//湿度数据
- else
- datar <= data_out;
- end
- assign data_out = datar;
- always@(posedge clk_us)
- begin
- if(data == 0 /*&& data_temp != 0*/)
- led[2] = 1;
- else if(datar == 0)
- led[3] = 1;
- end
-
- endmodule
第二组:
- `timescale 1ns / 1ps
-
- module dht11_2(
- input sys_clk , //system clock
- input sys_rst_n , //system reset negedge
- inout dht11_data , //dht11 inout port
- output reg [39:0] t_h_data
- );
- //tate code
- parameter WAIT = 6'b000_001,//wait state 2s
- START = 6'b000_010,//make bus low 20ms
- WAIT_RES = 6'b000_100,//wait respond
- RES_LOW = 6'b001_000,//respond low
- RES_HIGH = 6'b010_000,//respong high
- REC_DATA = 6'b100_000;//receive datas
- //time parameter
- parameter CNT_2S_MAX = 100_000_000 ,
- CNT_20MS_MAX = 1_000_000 ,
- CNT_1US_MAX = 50 ;
- //state define
- reg [5:0] state_cur;//current state
- reg [5:0] state_nex;//next state
- //lag define
- wire end_2s ; //wait 2s end
- wire end_20ms ; //wait 20ms end
- wire res_ok ; //respond ok
- wire res_no ; //no respond
- wire end_res_low ; //wait respond low end 83us
- wire end_res_high; //wait respond high end 87us
- wire end_rec ; //data receive end 40bits
- //dht11
- reg dht11_data_r1;
- reg dht11_data_r2;
- wire dht11_posedge;
- wire dht11_negedge;
- reg data;
- reg output_en;
- wire check;//校验
- reg [39:0] t_h_data_temp;//温湿度数据
- //计数器
- reg [26:0] cnt_2s;
- reg [19:0] cnt_20ms;
- reg [6:0] cnt_nus;
- reg [5:0] cnt_1us;
- reg cnt_us_rst;
- reg [5:0] cnt_bit;
-
- //条件判断
- assign end_2s = (state_cur == WAIT && cnt_2s == CNT_2S_MAX - 1'b1) ? 1'b1 : 1'b0;
- assign end_20ms = (state_cur == START && cnt_20ms == CNT_20MS_MAX - 1'b1) ? 1'b1 : 1'b0;
- assign res_ok = (state_cur == WAIT_RES && cnt_nus < 20 && dht11_negedge) ? 1'b1 : 1'b0;
- assign res_no = (state_cur == WAIT_RES && cnt_nus > 20) ? 1'b1 : 1'b0;
- assign end_res_low = (state_cur == RES_LOW && cnt_nus > 70 && dht11_posedge) ? 1'b1 : 1'b0;
- assign end_res_high = (state_cur == RES_HIGH && cnt_nus > 70 && dht11_negedge) ? 1'b1 : 1'b0;
- assign end_rec = (state_cur == REC_DATA && cnt_bit >= 40) ? 1'b1 : 1'b0;
-
- //dht11传输上升、下降延判断
- assign dht11_posedge = dht11_data_r1 & ~dht11_data_r2;
- assign dht11_negedge = ~dht11_data_r1 & dht11_data_r2;
- //生成
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- dht11_data_r1 <= 1'b0;
- dht11_data_r2 <= 1'b0;
- end
- else begin
- dht11_data_r1 <= dht11_data;
- dht11_data_r2 <= dht11_data_r1;
- end
- end
- //信息校验
- assign check = (t_h_data_temp[39:32]+t_h_data_temp[31:24]+
- t_h_data_temp[23:16]+t_h_data_temp[15:8] == t_h_data_temp[7:0])
- ? 1'b1 : 1'b0;
- //计数器群
- always@(*)begin
- case(state_cur)
- WAIT : cnt_us_rst = 1'b1;
- START : cnt_us_rst = 1'b1;
- WAIT_RES : begin
- if(res_ok)
- cnt_us_rst = 1'b1;
- else
- cnt_us_rst = 1'b0;
- end
- RES_LOW : begin
- if(end_res_low)
- cnt_us_rst = 1'b1;
- else
- cnt_us_rst = 1'b0;
- end
- RES_HIGH : begin
- if(end_res_high)
- cnt_us_rst = 1'b1;
- else
- cnt_us_rst = 1'b0;
- end
- REC_DATA : begin
- if(dht11_posedge || dht11_negedge)
- cnt_us_rst = 1'b1;
- else
- cnt_us_rst = 1'b0;
- end
- default :cnt_us_rst = 1'b1;
- endcase
- end
- //cnt_2s
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- cnt_2s <= 27'd0;
- end
- else begin
- if(state_cur == WAIT)begin
- if(cnt_2s <= CNT_2S_MAX - 1'b1)
- cnt_2s <= cnt_2s + 1'b1;
- else
- cnt_2s <= cnt_2s;
- end
- else if(state_cur == REC_DATA)begin
- cnt_2s <= 27'd0;
- end
- else begin
- cnt_2s <= cnt_2s;
- end
- end
- end
- //cnt_20ms
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- cnt_20ms <= 20'd0;
- end
- else begin
- if(state_cur == START)begin
- if(cnt_20ms <= CNT_20MS_MAX - 1'b1)
- cnt_20ms <= cnt_20ms + 1'b1;
- else
- cnt_20ms <= cnt_20ms;
- end
- else if(state_cur == REC_DATA)begin
- cnt_20ms <= 20'd0;
- end
- else begin
- cnt_20ms <= cnt_20ms;
- end
- end
- end
- //cnt_1us
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- cnt_1us <= 6'd0;
- end
- else begin
- if(cnt_1us == CNT_1US_MAX - 1'b1)
- cnt_1us <= 6'd0;
- else if(cnt_us_rst)
- cnt_1us <= 6'd0;
- else
- cnt_1us <= cnt_1us + 1'b1;
- end
- end
- //cnt_nus
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- cnt_nus <= 7'd0;
- end
- else begin
- if(cnt_us_rst)
- cnt_nus <= 7'd0;
- else if(cnt_1us == CNT_1US_MAX - 1'b1)
- cnt_nus <= cnt_nus + 1'b1;
- else
- cnt_nus <= cnt_nus;
- end
- end
- //信号位数控制
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- cnt_bit <= 6'd0;
- end
- else begin
- if(state_cur == REC_DATA)begin
- if(dht11_negedge)
- cnt_bit <= cnt_bit + 1'b1;
- else
- cnt_bit <= cnt_bit;
- end
- else begin
- cnt_bit <= 6'd0;
- end
- end
- end
-
- //状态控制1
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)
- state_cur <= WAIT;
- else
- state_cur <= state_nex;
- end
- //状态控制2
- always@(*)begin
- case(state_cur)
- WAIT :begin
- if(end_2s)
- state_nex = START; //count 2s finish
- else
- state_nex = WAIT;
- end
- START :begin
- if(end_20ms)
- state_nex = WAIT_RES;//count 20ms finish
- else
- state_nex = START;
- end
- WAIT_RES:begin
- if(res_ok) //respond
- state_nex = RES_LOW;
- else if(res_no) //no respond
- state_nex = WAIT;
- else
- state_nex = WAIT_RES;
- end
- RES_LOW :begin
- if(end_res_low)
- state_nex = RES_HIGH;
- else
- state_nex = RES_LOW;
- end
- RES_HIGH:begin
- if(end_res_high)
- state_nex = REC_DATA;
- else
- state_nex = RES_HIGH;
- end
- REC_DATA:begin
- if(end_rec)
- state_nex = WAIT;
- else
- state_nex = REC_DATA;
- end
- default :begin
- state_nex = WAIT;
- end
- endcase
- end
- //IO控制
- assign dht11_data = output_en ? data : 1'bz;
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- output_en <= 1'b0;
- data <= 1'b0;
- end
- else begin
- case(state_cur)
- WAIT :begin
- output_en <= 1'b1;//output
- data <= 1'b1;
- end
- START :begin
- output_en <= 1'b1;//output
- data <= 1'b0;
- if(end_20ms)
- data <= 1'b1;
- end
- WAIT_RES :begin
- output_en <= 1'b0;//input
- data <= 1'b0;
- end
- RES_LOW :begin
- output_en <= 1'b0;//input
- data <= 1'b0;
- end
- RES_HIGH :begin
- output_en <= 1'b0;//input
- data <= 1'b0;
- end
- REC_DATA :begin
- output_en <= 1'b0;//input
- data <= 1'b0;
- end
- default :begin
- output_en <= 1'b0;//input
- data <= 1'b0;
- end
- endcase
- end
- end
- //写入1
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- t_h_data_temp <= 40'd0;
- end
- else begin
- if(state_cur == REC_DATA)begin
- if(cnt_nus > 50 && dht11_negedge)
- t_h_data_temp[39 - cnt_bit] <= 1'b1;
- else if(cnt_nus < 50 && dht11_negedge)
- t_h_data_temp[39 - cnt_bit] <= 1'b0;
- else
- t_h_data_temp <= t_h_data_temp;
- end
- else begin
- t_h_data_temp <= t_h_data_temp;
- end
- end
- end
- //写入2
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(~sys_rst_n)begin
- t_h_data <= 40'd0;
- end
- else begin
- if(state_cur == REC_DATA)begin
- if(end_rec && check)
- t_h_data <= t_h_data_temp;
- else
- t_h_data <= t_h_data;
- end
- else begin
- t_h_data <= t_h_data;
- end
- end
- end
- endmodule
顶层模块需要注意两点:
1、若数据只是“经过”顶层模块或是作为赋值对象而不对其改变,则需要用wire型变量,否则将会报错;
2、最好保持输出位置与输出数据的控制时序相同,千万不要让输出数据的改变快于输出位置的改变,否则数码管最终会显示非理想的输出。而非理想输出的原因可能在于:数据转换模块有问题;DHT11控制模块有问题;数码管模块有问题。本人就因此将所有代码从头到尾检查了一遍。
代码如下:
- `timescale 1ns / 1ps
- //
- // Company:
- // Engineer:
- //
- // Create Date: 2023/06/11 14:45:14
- // Design Name:
- // Module Name: DHT_TOP
- // Project Name:
- // Target Devices:
- // Tool Versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- //
-
-
- module DHT_TOP(
- input sys_clk,
- input sys_rst,//触发为1 D20
- input tap8421,
- input key, //D19
- inout dht11, //V17 AR8
- output point, //AR7
- output [3:0]num, //A0-5
- output [6:0]abcdefg, //AR0-6
- output [3:0]leds
- );
-
- reg data_flag;
- //显示切换 1--温度 0--湿度
- wire [15:0] data_ctrl;
- wire [39:0] thdata;
- //不同模块之间传输而不在顶层改变的变量用wire型
- //应用时钟 自用 输出给dht11——ctrl 输出给——SMG
- wire clk50;
- //数据选择器所用变量
- reg [7:0] data_hu_int;//十位湿度整数
- reg [7:0] data_te_int;//十位温度整数
- reg [7:0] data_hu_dec;//十位湿度小数
- reg [7:0] data_te_dec;//十位温度小数
- //SMG 4个数据信号
- //BTD 小数点内设,不需要输入
- reg [7:0] data_smg_int;
- reg [7:0] data_smg_dec;
- //SMG的输入 BTD的输出
- wire [3:0] int_d1;//四位十进制
- wire [3:0] int_d2;//四位十进制
- wire [3:0] dec_d1;//四位十进制
- wire [3:0] dec_d2;//四位十进制
- reg [3:0] numr;
- reg pointr;
- //test
- wire [6:0] a1;
- wire [6:0] a2;
- wire [6:0] a3;
- wire [6:0] a4;
- reg [6:0] ar;
-
- assign abcdefg = ar;
- assign num = numr;
- assign point = pointr;
- //dht11控制程序
- /*
- dht11_ctrl dht11_ctrl
- (
- .sys_clk(clk50), //input
- .sys_rst(sys_rst),//input
- .data_flag(data_flag), //input 温湿度选择
- .dht11(dht11), //DHT11数据 input
- .data_out(data_ctrl),//输出数据 output
- .test_leds(leds)
- );
- */
- //输出控制 8421BCD TO ABCDEFG
- dht11_2 dht11_2
- (
- .sys_clk(clk50),
- .sys_rst_n(!sys_rst),
- .dht11_data(dht11),
- .t_h_data(thdata)
- );
- assign leds = int_d1;
- //assign leds = dec_d1;
- SMG SMG
- (
- .clk50(clk50),//in
- .rst(sys_rst),//in normal = 0
- .data_flag(data_flag),//in 0h 1t
- .int_in1(int_d1),//in d
- .dec_in1(dec_d1),//in d
- .int_in2(int_d2),//in d
- .dec_in2(dec_d2),//in d
- .data_out1(a1),
- .data_out2(a2),
- .data_out3(a3),
- .data_out4(a4)
- //out 8421bcd to abcdefg
- );
- //BTD SMG TO 4 8421 BCD
- BTD BTD
- (
- .clk50(clk50),
- .int_in(data_smg_int[7:0]),
- .dec_in(data_smg_dec[7:0]),
- //.int_in('b01010100),//
- //.dec_in('b00010101),//
- //DHT11有效测试范围不过100,因此仅前7位信号有效
- .int_out1(int_d1),
- .dec_out1(dec_d1),
- .int_out2(int_d2),
- .dec_out2(dec_d2),
- .rst(sys_rst)
- );
- //温湿度切换
- //通过按键的key信号,转换data_out输出的是湿度还是温度,没按一次按钮,转换一次
- always@(posedge clk50 or negedge sys_rst)
- begin
- if(sys_rst)
- data_flag <= 1'b0;
- else if(key == 1'b1)
- data_flag <= ~data_flag;
- else
- data_flag <= data_flag;
- end
- //温湿度选择器,输出data-out
- always@(posedge clk50 or negedge sys_rst)
- begin
- if(sys_rst)
- begin
- end
- else if(data_flag == 1'b0)//data为32位 整温-小温-整湿-小湿
- //data_flag为0时data_crtl为湿度数据
- begin
- data_hu_int <= thdata[39:32];//湿度数据
- data_hu_dec <= thdata[31:24];//湿度数据
- end
- else if(data_flag == 1'b1)//te
- begin
- data_te_int <= thdata[23:16];//温度数据
- data_te_dec <= thdata[15:8];//温度数据
-
- end
- end
- //数据选择器1
- always@(posedge clk50)
- begin
- if(sys_rst)begin
- numr = 4'b1111;
- end
- else if(numr == 4'b1000)
- numr = 4'b0001;
- else
- numr = numr <<1;
- end
- always@(posedge clk50)
- begin
- case(numr)
- 4'b0001:begin ar = a1;
- end
- 4'b0010:begin ar = a2;
- end
- 4'b0100:begin ar = a3;
- end
- 4'b1000:begin ar = a4;
- end
- 4'b1111:begin ar = 7'b0111111;
- end
- endcase
- end
- always@(posedge clk50)
- begin
- if(numr == 4'b0010)
- pointr = 1'b0;
- else
- pointr = 1'b1;
- end
-
- //smg赋值
- always@(posedge clk50 or negedge sys_rst)
- begin
- if(sys_rst)
- begin
- data_smg_int <= 8'b0000_0000;
- data_smg_dec <= 8'b0000_0000;
- end
- else if (tap8421)
- begin
- data_smg_int <= 8'b0101_0100;//84
- data_smg_dec <= 8'b0001_0101;//21
- end
- else if(data_flag == 1'b1 && !tap8421)//温度
- begin
- data_smg_int <= data_te_int;
- data_smg_dec <= data_te_dec;
- end
- else if(data_flag == 1'b0 && !tap8421)//湿度
- begin
- data_smg_int <= data_hu_int;
- data_smg_dec <= data_hu_dec;
- end
- end
-
- //时钟
- clk_wiz_0 clk0(
- .reset(1'b0),
- .clk_in1(sys_clk),
- .clk50(clk50)
- );
-
- endmodule
-
湿度:37%
温度:28.09
城市参考值:
可以看到实际数据与城市参考值基本上差不多,同时证明在旁边放一桶水确实能够提高空气湿度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。