基于FPGA的DS18B20温度测量以及数码管显示
基于FPGA的DS18B20温度测量以及数码管显示FPGA与各器件的连接如图所示:
dq为DS18B20的单总线
dtube_cs_n为数码管的4位
dtube_data为数码管的8段
ext_clk_25m为时钟输入
ext_rst_n为复位输入
顶层文件:
module DS18B20(
input ext_clk_25m, //外部输入25MHz时钟信号
input ext_rst_n, //外部输入复位信号,低电平有效
inout dq, //DS18B20的单总线接口
output dtube_cs_n, //7段数码管位选信号
output dtube_data //7段数码管段选信号(包括小数点为8段)
);
wire CLK_1MHz;
wire sys_rst_n;
pll_controller pll_controller_inst (
.areset ( !ext_rst_n ),
.inclk0 ( ext_clk_25m),
.c0 (CLK_1MHz),
.locked ( sys_rst_n )
);
wire num_temp;
ds18b20_demo uut_ds18b20_demo (
.clk(CLK_1MHz),
.rst_n(sys_rst_n),
.pin_ds18b20(dq),
.temp(num_temp)
);
wire temperature;
temperature_calculation uut_temperature_calculation(
.clk(ext_clk_25m),
.rst_n(sys_rst_n),
.two_byte_temp(num_temp),
.temperature(temperature)
);
digital_tube_display uut_digital_tube_display(
.clk(ext_clk_25m),
.rst_n(sys_rst_n),
.display_num(temperature),
.dtube_cs_n(dtube_cs_n),
.dtube_data(dtube_data)
);
endmodule
其次是DS18B20的控制代码:
module ds18b20_demo(
input clk,
input rst_n,
inout pin_ds18b20,
output temp
);
//*************************************************************
//DS18B20状态机各个阶段
parameter STATE_1 = 4'd1,//等待initen_cnt计数到10(即10us)才使能初始化
STATE_2 = 4'd2,//主机把总线电平拉低500us,等待DS18B20回应
STATE_3 = 4'd3,//DS18B20作出回应阶段
STATE_4 = 4'd4,//向DS18B20写0X44CCH跳过ROM操作和进行温度转换
STATE_5 = 4'd5,//等待2ms,等DS18B20把温度转换完成
STATE_6 = 4'd6,//回到STATE_2~STATE_3,再来一遍初始化
STATE_7 = 4'd7,//向DS18B20写0XBECCH跳过ROM操作和读取温度数据
STATE_8 = 4'd8,//读取DS18B20的两个字节温度数据
STATE_9 = 4'd9;//等待1S,重新开始上述过程
//*************************************************************
//1S计数器
reg one_second_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
one_second_cnt <= 20'd0;
else if(DS18b20_state == STATE_9)
one_second_cnt <= one_second_cnt + 1'b1;
else
one_second_cnt <= 20'd0;
end
//*************************************************************
//初始化计数器,计数到10(即10us)才使能初始化过程
reg initen_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
initen_cnt <= 10'd0;
else if(DS18b20_state == STATE_1)//只在第一阶段自递增
initen_cnt <= initen_cnt + 1'b1;
else
initen_cnt <= 10'd0;
end
//*************************************************************
//用来控制主机发出的初始化信号长度
reg master_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
master_cnt <= 10'd0;
else if(DS18b20_state == STATE_2)//在第二阶段自递增
master_cnt <= master_cnt + 1'd1;
else
master_cnt <= 10'd0;
end
//*************************************************************
//用来控制何时获得从机的应答信号
reg slave_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
slave_cnt <= 10'd0;
else if(DS18b20_state == STATE_3)//只在STATE_3自递增,即主机把总线拉低500us之后
slave_cnt <= slave_cnt + 1'd1;
else
slave_cnt <= 10'd0;
end
//*************************************************************
//写一个比特周期计数器,每个写周期62us,60us写数据+2us高电平间隔
reg write_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
write_cnt <= 7'd0;
else if((DS18b20_state == STATE_4) || (DS18b20_state == STATE_7))
write_cnt <= write_cnt + 1'd1;
else if(write_cnt > 7'd62)
write_cnt <= 7'd0;
else
write_cnt <= 7'd0;
end
//*************************************************************
//读一个比特周期计数器,每个读周期62us,60us读数据+2us高电平间隔
reg read_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
read_cnt <= 6'b0;
else if(DS18b20_state == STATE_8)
read_cnt <= read_cnt + 1'b1;
else if(read_cnt > 6'd62)
read_cnt <= 6'b0;
else
read_cnt <= 6'b0;
end
//*************************************************************
reg wait_cnt;//等待温度转换完成
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
wait_cnt <= 24'b0;
else if(DS18b20_state == STATE_5)
wait_cnt <= wait_cnt + 1'b1;
else
wait_cnt <= 24'b0;
end
//*************************************************************
//DS18b20_state,DS18b20_next_state赋值,后面的初始化状态机的状态判断要用到
reg DS18b20_state,DS18b20_next_state;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
DS18b20_state <= STATE_1;
else
DS18b20_state <= DS18b20_next_state;
end
//*************************************************************
//两个字节的数据一起写进DS18B20
reg hex_write;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
hex_write <= 16'h0000;
else if(DS18b20_state == STATE_4)
hex_write <= 16'h44cc;
else if(DS18b20_state == STATE_7)
hex_write <= 16'hbecc;
else
hex_write <= 16'h0000;
end
//*************************************************************
//选择写入字节中的第几位
reg write_bit_num;//对当前写的位进行计数,一个字节8位
reg write_over;//一个字节写完标志位
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
write_bit_num <= 5'd0;
write_over <= 1'b0;
end
else if(write_cnt == 7'd60)
write_bit_num <= write_bit_num + 1'd1;
else if(write_bit_num == 5'd16)
begin
write_bit_num <= 5'd0;
write_over <= 1'b1;
end
else if(DS18b20_state != STATE_4 || DS18b20_state != STATE_7)
write_over <= 1'b0;
else;
end
//*************************************************************
reg bit_write; //当前需要写入的一个比特数据
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
bit_write <= 1'b0;
else if(write_cnt <= 7'd2)
bit_write <= 1'b0;//每次写1bit拉低总线>1us
else if(write_cnt > 7'd3 && write_cnt < 7'd60)//传输当前bit
begin
if(write_bit_num == 5'd0) bit_write <= hex_write;
else if(write_bit_num == 5'd1) bit_write <= hex_write;
else if(write_bit_num == 5'd2) bit_write <= hex_write;
else if(write_bit_num == 5'd3) bit_write <= hex_write;
else if(write_bit_num == 5'd4) bit_write <= hex_write;
else if(write_bit_num == 5'd5) bit_write <= hex_write;
else if(write_bit_num == 5'd6) bit_write <= hex_write;
else if(write_bit_num == 5'd7) bit_write <= hex_write;
else if(write_bit_num == 5'd8) bit_write <= hex_write;
else if(write_bit_num == 5'd9) bit_write <= hex_write;
else if(write_bit_num == 5'd10) bit_write <= hex_write;
else if(write_bit_num == 5'd11) bit_write <= hex_write;
else if(write_bit_num == 5'd12) bit_write <= hex_write;
else if(write_bit_num == 5'd13) bit_write <= hex_write;
else if(write_bit_num == 5'd14) bit_write <= hex_write;
else if(write_bit_num == 5'd15) bit_write <= hex_write;
end
else if(write_cnt >= 7'd60 && write_cnt < 7'd62)
bit_write <= 1'b1;//写1bit末都需要把总线拉高>1us
else;
end
//*************************************************************
//对当前读的位进行计数,一个字节8位,两个一起读16位
reg read_bit_num;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
read_bit_num <= 5'd0;
else if(read_cnt == 6'd60 && DS18b20_state == STATE_8)
read_bit_num <= read_bit_num + 5'd1;
else if(DS18b20_state != STATE_8)
read_bit_num <= 5'd0;
else;
end
//*************************************************************
//读DS18B20的两个字节数据,一起读
reg read_two_byte;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
read_two_byte <= 16'd0;
else if(read_cnt == 6'd12 && read_bit_num <= 5'd15)
begin
read_two_byte <= {1'b0, read_two_byte};
read_two_byte <= pin_ds18b20;
end
else;
end
assign temp = read_two_byte;
//*************************************************************
//读两个字节完成标志
reg read_over;//两个字节读完标志位
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
read_over <= 1'b0;
else if(read_bit_num == 5'd16)
begin
read_over <= 1'b1;
end
else
read_over <= 1'b0;
end
//*************************************************************
//DS18B20初始化状态机,完成整个初始化过程的调度
reg rece_dat;
reg re_init_en;
//reg test;//测试用,与之相关的代码行可以忽略
always @ (DS18b20_state or DS18b20_next_state or master_cnt or slave_cnt or initen_cnt or wait_cnt or write_over or read_over or one_second_cnt or rece_dat or re_init_en or pin_ds18b20)
begin
case(DS18b20_state)
STATE_1:
if(initen_cnt == 10'd100)
DS18b20_next_state <= STATE_2;
else
DS18b20_next_state <= STATE_1;
STATE_2:
if(master_cnt == 10'd702)//主机把总线电平拉低480~960us,这里是700us
DS18b20_next_state <= STATE_3;
else
DS18b20_next_state <= STATE_2;
STATE_3:
if(slave_cnt == 10'd100)//接收DS18B20的低电平应答
rece_dat <= pin_ds18b20;
else if(slave_cnt == 10'd480 && rece_dat == 1'b1)
begin
DS18b20_next_state <= STATE_1;
//test <= 16'hFAFA;
end
else if(slave_cnt == 10'd480 && rece_dat == 1'b0 && re_init_en == 1'b0)
begin
DS18b20_next_state <= STATE_4;
//test <= 16'hD0D0;
end
else if(slave_cnt == 10'd480 && rece_dat == 1'b0 && re_init_en == 1'b1)
DS18b20_next_state <= STATE_7;
else
DS18b20_next_state <= STATE_3;
STATE_4:
if(write_over == 1'b1)
DS18b20_next_state <= STATE_5;
else
DS18b20_next_state <= STATE_4;
STATE_5:
if(wait_cnt == 24'd3000)
DS18b20_next_state <= STATE_6;
else
DS18b20_next_state <= STATE_5;
STATE_6:
begin
re_init_en <= 1'b1;
DS18b20_next_state <= STATE_1;
end
STATE_7:
if(write_over == 1'b1)
DS18b20_next_state <= STATE_8;
else
begin
DS18b20_next_state <= STATE_7;
re_init_en <= 1'b0;
end
STATE_8:
if(read_over == 1'b1)
DS18b20_next_state <= STATE_9;
else
DS18b20_next_state <= STATE_8;
STATE_9:
if(one_second_cnt == 20'd30_000)
DS18b20_next_state <= STATE_1;
else
DS18b20_next_state <= STATE_9;
default:
DS18b20_next_state <= STATE_1;
endcase
end
//assign temp = test;
//*************************************************************
//DS18B20的单总线信号方向以及读写控制
reg dq;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
dq <= 1'b1;
else if(master_cnt >= 10'd2 && master_cnt <= 10'd702)//把总线拉低700us,初始化DS18B20
dq <= 1'b0;
else if(slave_cnt >= 10'd15 && slave_cnt <= 10'd320)//接收DS18B20时设为高阻态
dq <= 1'bz;
else if (DS18b20_state == STATE_4 || DS18b20_state == STATE_7)//向DS18B20写数据
dq <= bit_write;
else if(DS18b20_state == STATE_8 && read_cnt <= 2)//读周期一开始做为主机先把总线拉低1微秒表示读周期开始
dq <= 1'b0;
else if(read_cnt > 2 && read_cnt <= 60)//60us的窗口内保持高阻态
dq <= 1'bz;
else
dq <= 1'b1;
end
assign pin_ds18b20 = dq;
endmodule
数据处理代码:
module temperature_calculation(
input clk,
input rst_n,
input two_byte_temp,
output temperature
);
wire result_sig;
mul mul_inst (
.clock ( clk ),
.dataa ( two_byte_temp),
.datab ( 10'd625 ),
.result ( result_sig )
);
wire one_decimal,remain_sig;
div_14bit div_14bit_inst_one (
.clock ( clk ),
.denom ( 14'd1000 ),
.numer ( result_sig ),
.quotient ( one_decimal ),
.remain ( remain_sig )
);
wire two_decimal;
div_14bit div_14bit_inst_two (
.clock ( clk ),
.denom ( 14'd100 ),
.numer ( remain_sig ),
.quotient ( two_decimal ),
.remain ( remain_sig_two )
);
wire ten_quotint,ten_fractional;
div_8bit div_8bit_inst (
.clock ( clk ),
.denom ( 8'd10),
.numer ({1'b0,two_byte_temp}),
.quotient ( ten_quotint ),
.remain ( ten_fractional )
);
assign temperature = {ten_quotint,ten_fractional,one_decimal,two_decimal};
endmodule
然后是温度的数码管显示代码:
module digital_tube_display(
input clk,
input rst_n,
input display_num,
output reg dtube_cs_n,//7段数码管位选信号
output reg dtube_data//7段数码管段选信号
);
//-------------------------------
//参数定义
//数码管显示0~F对应段选输出
parameter NUM0 = 8'h3f,
NUM1 = 8'h06,
NUM2 = 8'h5b,
NUM3 = 8'h4f,
NUM4 = 8'h66,
NUM5 = 8'h6d,
NUM6 = 8'h7d,
NUM7 = 8'h07,
NUM8 = 8'h7f,
NUM9 = 8'h6f,
POINT_NUM0 = 8'hbf,
POINT_NUM1 = 8'h86,
POINT_NUM2 = 8'hdb,
POINT_NUM3 = 8'hcf,
POINT_NUM4 = 8'he6,
POINT_NUM5 = 8'hed,
POINT_NUM6 = 8'hfd,
POINT_NUM7 = 8'h87,
POINT_NUM8 = 8'hff,
POINT_NUM9 = 8'hef;
//数码管位选0~3输出
parameter CSN = 4'B1111,
CS0 = 4'b1110,
CS1 = 4'b1101,
CS2 = 4'b1011,
CS3 = 4'b0111;
//-----------------------------------
//分时显示数据控制单元
reg current_display_num;//当前显示数据
reg div_cnt;//分时计数器
always @ (posedge clk or negedge rst_n)
if(!rst_n)
div_cnt <= 8'd0;
else
div_cnt <= div_cnt + 1'b1;
//显示数据
always @ (posedge clk or negedge rst_n)
if(!rst_n)
current_display_num <= 4'b0;
else
begin
case(div_cnt)
8'hff : current_display_num <= display_num;
8'h3f : current_display_num <= display_num;
8'h7f : current_display_num <= display_num;
8'hbf : current_display_num <= display_num;
default : ;
endcase
end
//段选数据译码
always @ (posedge clk or negedge rst_n)
if(!rst_n)
dtube_data <= NUM0;
else if(dtube_cs_n == CS2)
begin
case(current_display_num) //小数点显示位
4'h0 : dtube_data <= POINT_NUM0;
4'h1 : dtube_data <= POINT_NUM1;
4'h2 : dtube_data <= POINT_NUM2;
4'h3 : dtube_data <= POINT_NUM3;
4'h4 : dtube_data <= POINT_NUM4;
4'h5 : dtube_data <= POINT_NUM5;
4'h6 : dtube_data <= POINT_NUM6;
4'h7 : dtube_data <= POINT_NUM7;
4'h8 : dtube_data <= POINT_NUM8;
4'h9 : dtube_data <= POINT_NUM9;
default : ;
endcase
end
else if(dtube_cs_n != CS2)
begin
case(current_display_num)
4'h0 : dtube_data <= NUM0;
4'h1 : dtube_data <= NUM1;
4'h2 : dtube_data <= NUM2;
4'h3 : dtube_data <= NUM3;
4'h4 : dtube_data <= NUM4;
4'h5 : dtube_data <= NUM5;
4'h6 : dtube_data <= NUM6;
4'h7 : dtube_data <= NUM7;
4'h8 : dtube_data <= NUM8;
4'h9 : dtube_data <= NUM9;
default : ;
endcase
end
//位选译码
always @ (posedge clk or negedge rst_n)
if(!rst_n)
dtube_cs_n <= CSN;
else
begin
case(div_cnt)
2'b00 : dtube_cs_n <= CS0;
2'b01 : dtube_cs_n <= CS1;
2'b10 : dtube_cs_n <= CS2;
2'b11 : dtube_cs_n <= CS3;
default : dtube_cs_n <= CSN;
endcase
end
endmodule
---------------------
作者:墨晕纸
来源:CSDN
原文:https://blog.csdn.net/wangyiyunyinyue/article/details/88055724
版权声明:本文为博主原创文章,转载请附上博文链接! 基于FPGA的DS18B20温度测量以及数码管显示 基于FPGA的DS18B20温度测量以及数码管显示
页:
[1]