基于FPGA的DS18B20温度测量以及数码管显示
这是我在CSDN的第一篇文章,如果文章排版不好或者存在其它的一些问题,希望大家海涵。
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[3:0] dtube_cs_n, //7段数码管位选信号
output[7:0] 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[15:0] num_temp;
ds18b20_demo uut_ds18b20_demo (
.clk(CLK_1MHz),
.rst_n(sys_rst_n),
.pin_ds18b20(dq),
.temp(num_temp)
);
wire[15:0] 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 [15:0] 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[19:0] 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[9:0] 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[9:0] 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[9:0] 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[6:0] 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[5:0] 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 [23:0] 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 [3:0] 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[15:0] 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[4:0] 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[0];
else if(write_bit_num == 5'd1) bit_write <= hex_write[1];
else if(write_bit_num == 5'd2) bit_write <= hex_write[2];
else if(write_bit_num == 5'd3) bit_write <= hex_write[3];
else if(write_bit_num == 5'd4) bit_write <= hex_write[4];
else if(write_bit_num == 5'd5) bit_write <= hex_write[5];
else if(write_bit_num == 5'd6) bit_write <= hex_write[6];
else if(write_bit_num == 5'd7) bit_write <= hex_write[7];
else if(write_bit_num == 5'd8) bit_write <= hex_write[8];
else if(write_bit_num == 5'd9) bit_write <= hex_write[9];
else if(write_bit_num == 5'd10) bit_write <= hex_write[10];
else if(write_bit_num == 5'd11) bit_write <= hex_write[11];
else if(write_bit_num == 5'd12) bit_write <= hex_write[12];
else if(write_bit_num == 5'd13) bit_write <= hex_write[13];
else if(write_bit_num == 5'd14) bit_write <= hex_write[14];
else if(write_bit_num == 5'd15) bit_write <= hex_write[15];
end
else if(write_cnt >= 7'd60 && write_cnt < 7'd62)
bit_write <= 1'b1;//写1bit末都需要把总线拉高>1us
else;
end
//*************************************************************
//对当前读的位进行计数,一个字节8位,两个一起读16位
reg[4:0] 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[15:0] 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[15:1]};
read_two_byte[15] <= pin_ds18b20;
end
else;
end
assign temp[15:0] = read_two_byte[15:0];
//*************************************************************
//读两个字节完成标志
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[15:0] 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[15:0] = test[15:0];
//*************************************************************
//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[15:0] two_byte_temp,
output[15:0] temperature
);
wire[13:0] result_sig;
mul mul_inst (
.clock ( clk ),
.dataa ( two_byte_temp[3:0]),
.datab ( 10'd625 ),
.result ( result_sig )
);
wire [13:0] 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 [13:0] two_decimal;
div_14bit div_14bit_inst_two (
.clock ( clk ),
.denom ( 14'd100 ),
.numer ( remain_sig ),
.quotient ( two_decimal ),
.remain ( remain_sig_two )
);
wire [7:0] ten_quotint,ten_fractional;
div_8bit div_8bit_inst (
.clock ( clk ),
.denom ( 8'd10),
.numer ({1'b0,two_byte_temp[10:4]}),
.quotient ( ten_quotint ),
.remain ( ten_fractional )
);
assign temperature = {ten_quotint[3:0],ten_fractional[3:0],one_decimal[3:0],two_decimal[3:0]};endmodule
然后是温度的数码管显示代码:
module digital_tube_display(
input clk,
input rst_n,
input [15:0] display_num,
output reg[3:0] dtube_cs_n,//7段数码管位选信号
output reg[7:0] 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[3:0] current_display_num;//当前显示数据
reg[7:0] 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[3:0];
8'h3f : current_display_num <= display_num[7:4];
8'h7f : current_display_num <= display_num[11:8];
8'hbf : current_display_num <= display_num[15:12];
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[7:6])
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
基于FPGA的DS18B20温度测量以及数码管显示相关推荐
- 基于FPGA的 DS18B20多功能温度显示
基于FPGA的 DS18B20多功能温度显示 实现功能: 1.实时温度显示在数码管上,更新速率1-2s一次 2.按下按键显示最近30s内的最高温和最低温 不包含板子, 3.按下按键可以存储当前温度,最 ...
- 74hc164驱动数码管c语言程序,基于51单片机的74HC164驱动数码管显示程序与仿真
基于51单片机的74HC164驱动数码管显示程序与仿真 基于51单片机的74HC164驱动一位数码管显示程序与仿真 #include #include #define uchar unsigned c ...
- 基于51单片机的8位数码管显示的可调时电子时钟
基于51单片机的8位数码管显示的可调时电子时钟 本人大二本科生,第一次发东西,功能比较简单,代码有点复杂,希望能有大神指正. 基于51单片机的不可调时间的时钟显示,晶振为11.0592MHZ,60H ...
- 51单片机DS18B20测温数码管显示例程(Proteus仿真+程序)
编号:19 51单片机DS18B20测温数码管显示例程 功能描述: 本设计由STM32单片机+DS18B20温度传感器+四段数码管显示模块组成. 1.主控制器是51单片机 2.DS18B20温度传感器 ...
- 单片机8位数码管时钟c语言汇编,基于8051单片机和DS12C8878位数码管显示的时钟.docx...
基于8051单片机和DS12C8878位数码管显示的时钟 #include #include #define sec XBYTE[0xed00]//秒寄存器地址 #define min XBYTE[0 ...
- 基于51单片机的温度控制系统数码管显示蜂鸣器报警proteus仿真原理图PCB
功能: 0.本系统采用STC89C52作为单片机 1.系统实时监测并显示当前温度,并通过四位数码管显示 2.超过设定阈值,蜂鸣器将报警,同时控制相应继电器实现降温或者加热 3.系统具备三个功能按键,可 ...
- 【Verilog】基于FPGA的五子棋小游戏(VGA显示、双人对战、胜负判别、附完整代码)
基于FPGA的五子棋小游戏 有一些说明: 1.本文是基于VGA的显示小游戏,主要为VGA显示的拓展应用: 2.为适应不同显示屏的分辨率,棋盘确定为10X10的黑线白底的方格: 3.下棋主要用棋格颜色变 ...
- 基于FPGA的ds18b20温度传感器使用
文章目录 一.传感器介绍 1.特点 2.内部结构 3.ds18b20管脚 4.ds18b20内部高速暂存存储器 5.ds18b20工作时序 6.ds18b20单线通信 二.FPGA代码实现 1.状态图 ...
- DS18B20测量温度数码管显示
DS18B20温度传感器简介 DS18B20是一种数字温度传感器.它输出的是数字信号,同时具有体积小,硬件资源耗费少,抗干扰能力强,精度高等特点. DS18B20温度传感器特点 1.单线接口:DS18 ...
最新文章
- python免费视频百度网盘-Python入门视频百度网盘看这些就够
- vue2.0中引入wangEditor2 步骤与坑
- 基于动态代码生成技术的动态对象工厂
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架
- 王盛:QUIC让B站在20%丢包时实现零卡顿
- 内推|百度2020春实习-计算机视觉算法研发工程师-北京
- 使用devops的团队_DevOps与兼职社区团队兼容吗?
- Guacamole 介绍以及架构
- salt把返回写入到mysql
- 【Oracle】DataGuard中 Switchover 主、备切换
- 远程sun服务器,向日葵远程控制(com.oray.sunlogin) - 11.1.0.39347 - 应用 - 酷安
- itextpdf字体编码研究
- 【业务】5个顶级案例教你实现最牛供应链管理
- 动易cms net版本拿shell
- sklearn_scaler
- 编写一递归函数求斐波纳契数列1,1,2,3,5,8,13,…的前40项。c语言
- Versal ACAP AI 引擎入门
- Python - yamail - 进阶之路 - Day08
- 双鱼座三:舞者与梦想家的一周
- ‘tensorflow.python.framework.ops.EagerTensor‘ object has no attribute ‘reshape‘