马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
媒介
DS18B20是DALLAS半导体公司生产的单总线数字温度传感器,其输出的是数字信号,具有体积小,功耗低,抗干扰能力强,精度高的特点。
温度范围-55摄氏度至+125摄氏度,在-10摄氏度至+85摄氏度可以到达不超过 0.5摄氏度的误差。单端口节省FPGA接口资源。传感器内部含EEPROM内部存储温度阈值,测量分辨率,体系掉电保护数据。
正文
一、基于DS18B20的温度检测
1.项目需求
实行目标:基于ds18b20数据温度传感器,完成基于FPGA的温度计设计。(数码管显示)
2.技能介绍
每个DS18B20的片内ROM都存有一个独一无二的64位编码。在该ROM编码的低8位生存有DS18B20的分类编码:28h;中间的48位是独一无二的序列号;最高8位是前面56位的CRC循环冗余校验码 (CRC=X8+X5+X4+1)。
由于每个DS18B20的序列号都不一样,以是一条总线上可以控制多个DS18B20。
温度测量方法:DS18B20中的温度传感器可完成对温度的测量,他的温度转换精度用户可自定义为9、10、11、12位,精度分别为0.5℃、0.25℃、0.125℃、0.0625℃分辨率。
符号标记位(S)(5位)表示温度的正负极性:若S=0,则为正数;若S=1,则为负数。
温度数据正数源码输出,负数补码输出(计算温度时求补码)输出二进制数*温度精度=当前温度
高速缓冲器中第5个字节即为配置寄存器,通过修改R1,R2的值来配置DS18B20的分辨率。TM(0,工作模式,1测试模式),默认12位宽。
DS18B20实现温度转换
主机控制DS18B20完成温度转换必须经过三个步骤:每一次读写之前都要对DS18B20进行 初始化操作,初始化乐成后发送一条ROM下令,末了发送RAM下令,这样才能对DS18B20进行预定的操作。
1.初始化:单总线上的全部操作都必须以初始化为开始。初始化序列由总线上的主装备发出的复位脉冲以及紧跟着从装备回应的存在脉冲构成。该存在脉冲是让总线主装备知道DS18B20在总线上并准备好运行。
2.ROM下令:搜索ROM[F0h](识别从机)、读ROM[33h](数据总线存在一个从机)、匹配ROM[55h](多从机选定从机工作)、跳过ROM[CCh]、警报搜索ROM[ECh]。
3.RAM下令:温度转换[44h](单次温度转换)、写入暂存器[4Eh](向传感器写入温度阈值与分辨率)、读取高速缓存器[BEh]、复制高速缓存器[48H1]、召回EEPROM[B8h]、读取供电模式[B4h]。(0寄存电容,1外部供电)
数据传输过程:与DS18B20全部的通信都是由初始化开始的,初始化由主装备发出的复位脉冲及从装备响应的存在脉冲构成。主装备发出480-960us的低电平脉冲,之后释放总线,紧接着主装备进行480us的总线检测。总线有低电平出现表示总线上的器件应答。从装备进行480-960us的应答检测,检测到后进行数据输出到数据总线。
写时序:主装备通过写时序将下令写入DS18B20中,写时序模式有1,0两种模式。数据总线由高电平拉至低电平常进入写时序。
读时序:发送读取供电模式[B4h]或读高速缓存区[BEh]下令时,实时生成读时序在读时隙从装备才可以向主装备传输数据。
这里利用状态机,简便实行代码。
3.顶层架构
4.端口描述
clk | 时钟(50Mhz) | rst_n | 复位信号(低电平有效) | dp | 数据总线 | [2:0]sel | 位选信号 | [7:0]seg | 段选信号 | 二、代码验证
数据处理模块
- module ds18b20_data(
- input clk ,
- input rst_n ,
- inout dp ,//数据总线
-
- output wire[19:0] data_out ,//读取到的数据
- output reg data_flag //符号位
- );
- //0011_0011;跳过ROM命令 CCh
- //0010_0010;温度转换命令 44h
- //1111_0010;写入暂存器命令 4Eh
- //0111_1101;读温度命令 BEh
- parameter date = 3'd1,//初始化
- wier = 3'd2,//写命令
- dend = 3'd3,//等待转换
- datt = 3'd4,//再次初始化
- romx = 3'd5,//Rom功能命令
- duqu = 3'd6;//数据读取
- parameter cch = 16'h44cc,
- beh = 16'hbecc;
-
-
- reg [4:0]cnt_1ns;//1ns计数器
- reg clk_1ns;//1ns时钟
- reg [19:0]cnt_us;//us计数器
- reg flag_us;//存在脉冲有效信号
- reg[2:0]stater;//状态机状态
- reg[3:0]bit_cnt;//bit计数器
- reg[15:0]data_temp;//存储接收的温度数据
- reg[19:0]data_temp_t;//温度数据进行正负判断,小数点位统一,((数据*625(精度)/10000)=摄氏度)*1000=数码管数据,反码源码转换
- reg dp_en;//输出为1,输入为0
- reg dp_out;//输入0,输出为操作命令
- assign dp = (dp_en ==1'b1)? dp_out:1'bz;
- always@(posedge clk_1ns,negedge rst_n) //符号位
- begin
- if(rst_n == 0)
- data_flag <= 1'b0;
- else
- if((stater == duqu)&&(bit_cnt == 4'd15)&&(cnt_us == 20'd60)&&(data_temp[15]== 1'b0))
- data_flag <= 1'b0;
- else
- if((stater == duqu)&&(bit_cnt == 4'd15)&&(cnt_us == 20'd60)&&(data_temp[15]== 1'b1))
- data_flag <= 1'b1;
- else
- data_flag <= data_flag;
- end
- always@(posedge clk,negedge rst_n)//1ns计数器使能模块
- begin
- if(rst_n == 0)
- cnt_1ns <= 5'd0;
- else
- if(cnt_1ns == 5'd24)
- cnt_1ns <= 5'd0;
- else
- cnt_1ns <= cnt_1ns + 5'd1;
- end
- always@(posedge clk,negedge rst_n)//1ns时钟
- begin
- if(rst_n == 0)
- clk_1ns <= 1'b0;
- else
- if(cnt_1ns == 5'd24)
- clk_1ns <= ~clk_1ns;
- else
- clk_1ns <= clk_1ns;
- end
- always@(posedge clk_1ns,negedge rst_n)//us计数器使能
- begin
- if(rst_n == 0)
- cnt_us <= 20'd0;
- else
- if((((stater == date)||(stater == datt))&&(cnt_us == 20'd999))||(((stater == wier)||(stater == romx)||(stater == duqu))&&(cnt_us == 20'd64))||((stater == dend)&&(cnt_us == 20'd750_000)))
- cnt_us <= 20'd0;
- else
- cnt_us <= cnt_us + 20'd1;
- end
-
- always@(posedge clk_1ns,negedge rst_n)//存在脉冲有效
- begin
- if(rst_n == 0)
- flag_us <= 1'b0;
- else
- if((((stater == date)||(stater == datt))&&(cnt_us == 20'd570)&&(dp == 1'b0)))
- flag_us <= 1'b1;
- else
- if(((stater == date)||(stater == datt))&&(cnt_us == 20'd999))
- flag_us <= 1'b0;
- else
- flag_us <= flag_us;
- end
- always@(posedge clk_1ns,negedge rst_n)//bit计数器使能
- begin
- if(rst_n == 0)
- bit_cnt <= 4'd0;
- else
- if(((stater == wier)||(stater == romx)||(stater == duqu))&&(bit_cnt == 4'd15)&&(cnt_us == 20'd64))
- bit_cnt <= 4'd0;
- else
- if(((stater == wier)||(stater == romx)||(stater == duqu))&&(cnt_us == 20'd64))
- bit_cnt <= bit_cnt + 4'd1;
- else
- bit_cnt <= bit_cnt;
- end
- always@(posedge clk_1ns,negedge rst_n)//存储接收的温度数据
- begin
- if(rst_n == 0)
- data_temp <= 16'd0;
- else
- if((stater == duqu)&&(cnt_us == 20'd13))
- data_temp <= {dp,data_temp[15:1]};
- else
- data_temp <= data_temp;
- end
- always@(posedge clk_1ns,negedge rst_n)//温度数据进行正负判断,小数点位统一,((数据*625(精度)/10000)=摄氏度)*1000=数码管数据,反码源码转换
- begin
- if(rst_n == 0)
- data_temp_t <= 20'd0;
- else
- if((stater == duqu)&&(bit_cnt == 4'd15)&&(cnt_us == 20'd60)&&(data_temp[15]== 1'b0))
- data_temp_t <= data_temp[11:0];
- else
- if(((stater == duqu)&&(bit_cnt == 4'd15)&&(cnt_us == 20'd60)&&(data_temp[15]== 1'b0)))
- data_temp_t <= ~data_temp[11:0] + 1'b1;
- else
- data_temp_t <= data_temp_t;
- end
-
- assign data_out = (data_temp_t * 625) /10;
-
- always@(posedge clk_1ns,negedge rst_n)//状态机状态跳转条件
- begin
- if(rst_n == 0)
- stater <= date;
- else
- case(stater)
- date : if((cnt_us == 20'd999) && (flag_us == 1'b1))
- stater <= wier;
- else
- stater <= date;
- wier : if((bit_cnt == 4'd15) &&(cnt_us == 20'd64))
- stater <= dend;
- else
- stater <= wier;
- dend : if(cnt_us == 20'd750_000)
- stater <= datt;
- else
- stater <= dend;
- datt : if((cnt_us == 20'd999) && (flag_us == 1'b1))
- stater <= romx;
- else
- stater <= datt;
- romx : if((bit_cnt == 4'd15) &&(cnt_us == 20'd64))
- stater <= duqu;
- else
- stater <= romx;
- duqu : if((bit_cnt == 4'd15) &&(cnt_us == 20'd64))
- stater <= date;
- else
- stater <= duqu;
- default :stater <= date;
- endcase
- end
-
- always@(posedge clk_1ns,negedge rst_n)//输出为1,输入为0
- begin //输入0,输出为操作命令
- if(rst_n == 0)
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- else
- case(stater)
- date : if(cnt_us <499)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- wier : if(cnt_us >62)
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- else
- if(cnt_us <= 1)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- if(beh[bit_cnt] == 1'b0)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- if(beh[bit_cnt] == 1'b1)
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- dend : begin
- dp_en <= 1'b1;
- dp_out <= 1'b1;
- end
- datt : if(cnt_us <499)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- romx : if(cnt_us >62)
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- else
- if(cnt_us <= 1)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- if(cch[bit_cnt] == 1'b0)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- if(cch[bit_cnt] == 1'b1)
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- duqu : if(cnt_us <= 1)
- begin
- dp_en <= 1'b1;
- dp_out <= 1'b0;
- end
- else
- begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- default : begin
- dp_en <= 1'b0;
- dp_out <= 1'b0;
- end
- endcase
- end
-
- endmodule
复制代码 数码管显示模块
- module shu_ma_g_MAX(
- input clk ,
- input rst_n ,
- input [19:0] data ,//数据10进制
- input [ 5:0] point ,//小数点位
- input signe ,//正负号位
- input seg_en ,//数码管使能
-
- output reg[2:0] sel ,
- output reg[7:0] seg
- );
- parameter cnt_1ms_max = 16'd49999;
- wire[3:0] data1 ;//数码管数据
- wire[3:0] data2 ;//数码管数据
- wire[3:0] data3 ;//数码管数据
- wire[3:0] data4 ;//数码管数据
- wire[3:0] data5 ;//数码管数据
- wire[3:0] data6 ;//数码管数据
- reg[23:0]data_reg ;//寄存显示数据
- reg[15:0]cnt_1ms ;//1ms计数器
- reg cnt_1ms_flag ;
- reg[2:0] cnt_sel ;//扫描周期计数器
- reg[3:0] data_zhan ;//数码管显示暂存数据
- reg point_flag ;//小数点使能信号
- reg[2:0] sel_reg ;//暂存输出
- always@(posedge clk,negedge rst_n)//判断符号位
- begin
- if(rst_n == 0)
- data_reg <= 24'b0;
- else
- if((data6)||(point[5]))
- data_reg <= {data6,data5,data4,data3,data2,data1};
- else
- if(((data5)||(point[4]))&&(signe == 1'b1))//最高位为符号位011-111
- data_reg <= {4'd10,data5,data4,data3,data2,data1};
- else
- if(((data5)||(point[4]))&&(signe == 1'b0))
- data_reg <= {4'd11,data5,data4,data3,data2,data1};
- else
-
- if(((data4)||(point[3]))&&(signe == 1'b1))//次高位为符号位001-111
- data_reg <= {4'd11,4'd10,data4,data3,data2,data1};
- else
- if(((data4)||(point[3]))&&(signe == 1'b0))
- data_reg <= {4'd11,4'd11,data4,data3,data2,data1};
- else
-
- if(((data3)||(point[2]))&&(signe == 1'b1))//次次高位为符号位000-111
- data_reg <= {4'd11,4'd11,4'd10,data3,data2,data1};
- else
- if(((data3)||(point[2]))&&(signe == 1'b0))
- data_reg <= {4'd11,4'd11,4'd11,data3,data2,data1};
- else
-
- if(((data2)||(point[1]))&&(signe == 1'b1))//次次次高位为符号位000-011
- data_reg <= {4'd11,4'd11,4'd11,4'd10,data2,data1};
- else
- if(((data2)||(point[1]))&&(signe == 1'b0))
- data_reg <= {4'd11,4'd11,4'd11,4'd11,data2,data1};
- else
-
- if(((data1)||(point[0]))&&(signe == 1'b1))//次次次次高位为符号位000-001
- data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,data1};
- else
- data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,data1};
-
- end
- always@(posedge clk,negedge rst_n) //计数器驱动模块
- begin
- if(rst_n == 0)
- cnt_1ms <= 16'd0;
- else
- if(cnt_1ms == cnt_1ms_max)
- cnt_1ms <= 16'd0;
- else
- cnt_1ms <= cnt_1ms + 16'd1;
-
- end
- always@(posedge clk,negedge rst_n)//1ms标志信号
- begin
- if(rst_n == 0)
- cnt_1ms_flag <= 1'b0;
- else
- if(cnt_1ms == cnt_1ms_max)
- cnt_1ms_flag <= 1'b1;
- else
- cnt_1ms_flag <= 1'b0;
- end
- always@(posedge clk,negedge rst_n)//扫描周期计数器使能
- begin
- if(rst_n == 0)
- cnt_sel <= 3'd0;
- else
- if((cnt_sel == 3'd5)&&(cnt_1ms_flag <= 1'b1))
- cnt_sel <= 3'd0;
- else
- if(cnt_1ms_flag <= 1'b1)
- cnt_sel <= cnt_sel + 3'd1;
- else
- cnt_sel <= cnt_sel;
- end
-
- always@(posedge clk,negedge rst_n)//暂存输出
- begin
- if(rst_n == 0)
- sel_reg <= 3'd0;
- else
- if((cnt_sel == 3'd0)&&(cnt_1ms_flag <= 1'b1))
- sel_reg <= 3'd0;
- else
- if(cnt_1ms_flag <= 1'b1)
- sel_reg <= sel_reg + 1'd1;
- else
- sel_reg <= sel_reg;
- end
- always@(posedge clk,negedge rst_n)//段码数据传递
- begin
- if(rst_n == 0)
- data_zhan <= 4'd0;
- else
- if((seg_en == 1'b1)&&(cnt_1ms_flag <= 1'b1))
- case(cnt_sel)
- 3'd0 : data_zhan <= data_reg[3:0];
- 3'd1 : data_zhan <= data_reg[7:4];
- 3'd2 : data_zhan <= data_reg[11:8];
- 3'd3 : data_zhan <= data_reg[15:12];
- 3'd4 : data_zhan <= data_reg[19:16];
- 3'd5 : data_zhan <= data_reg[23:20];
- default : data_zhan <= 4'd0;
- endcase
- else
- data_zhan <= data_zhan;
- end
- always@(posedge clk,negedge rst_n)//小数点点亮
- begin
- if(rst_n == 0)
- point_flag <= 1'b0;
- else
- if(cnt_1ms_flag <= 1'b1)
- point_flag <= ~point[cnt_sel];
- else
- point_flag <= point_flag;
- end
-
- always@(posedge clk,negedge rst_n)//段码数值判断并输出
- begin
- if(rst_n == 0)
- seg <= 8'b1111_1111;//0
- else
- case(data_zhan)
- 4'd0 : seg <= {point_flag,7'd100_0000};//0
- 4'd1 : seg <= {point_flag,7'd100_0000};//1
- 4'd2 : seg <= {point_flag,7'd100_0000};//2
- 4'd3 : seg <= {point_flag,7'd100_0000};//3
- 4'd4 : seg <= {point_flag,7'd100_0000};//4
- 4'd5 : seg <= {point_flag,7'd100_0000};//5
- 4'd6 : seg <= {point_flag,7'd100_0000};//6
- 4'd7 : seg <= {point_flag,7'd100_0000};//7
- 4'd8 : seg <= {point_flag,7'd100_0000};//8
- 4'd9 : seg <= {point_flag,7'd100_0000};//9
-
- 4'd10: seg <= 8'b1011_1111;//-
- 4'd11: seg <= 8'b1111_1111;//熄灭
- /*
- 4'd10: seg <= {point_flag,7'd100_0000};//A
- 4'd11: seg <= {point_flag,7'd100_0000};//b
- 4'd12 : seg <= {point_flag,7'd100_0000};//C
- 4'd13 : seg <= {point_flag,7'd100_0000};//d
- 4'd14 : seg <= {point_flag,7'd100_0000};//E
- 4'd15 : seg <= {point_flag,7'd100_0000};//F
- */
- default : seg <= 8'd1100_0000;
- endcase
- end
- always@(posedge clk,negedge rst_n)
- begin
- if(rst_n == 0)
- sel <= 3'd0;//0
- else
- sel <= sel_reg;
- end
- er_bcd er_bcd_inst(
- .clk (clk ),
- .rst_n(rst_n),
- .data (data ),//数据10进制
-
- .data1(data1),
- .data2(data2),
- .data3(data3),
- .data4(data4),
- .data5(data5),
- .data6(data6)
- );
-
- endmodule
复制代码 数码管辅助模块
- module er_bcd(
- input clk ,
- input rst_n ,
- input [19:0] data ,//数据10进制
-
- output reg[3:0] data1 ,//bcd码
- output reg[3:0] data2 ,//bcd码
- output reg[3:0] data3 ,//bcd码
- output reg[3:0] data4 ,//bcd码
- output reg[3:0] data5 ,//bcd码
- output reg[3:0] data6 //bcd码
- );
- reg [4 :0]cnt_shift ;
- reg [43:0]data_shift ;//暂存转换后的BCD码
- reg shift_flag ;
- always@(posedge clk, negedge rst_n)//记时钟21次后清零,大约20ns*20=400ns进行一次数据转码并输出
- begin
- if(rst_n == 0)
- cnt_shift <= 5'd0;
- else
- if((cnt_shift == 5'd21)&&(shift_flag == 1'b1))//计数清零
- cnt_shift <= 5'd0;
- else
- if(shift_flag == 1'b1)
- cnt_shift <= cnt_shift + 5'd1;
- else
- cnt_shift <= cnt_shift;
- end
- always@(posedge clk, negedge rst_n)
- begin
- if(rst_n == 0)
- data_shift <= 43'd0;
- else
- if(cnt_shift == 5'd0)
- data_shift <= {24'd0,data};
- else
- if((cnt_shift <= 20)&&(shift_flag == 1'b0))
- begin
- data_shift[23:20] <= (data_shift[23:20] > 4)?(data_shift[23:20] + 2'd3):(data_shift[23:20]);//大四加三
- data_shift[27:24] <= (data_shift[27:24] > 4)?(data_shift[27:24] + 2'd3):(data_shift[27:24]);//大四加三
- data_shift[31:28] <= (data_shift[31:28] > 4)?(data_shift[31:28] + 2'd3):(data_shift[31:28]);//大四加三
- data_shift[35:32] <= (data_shift[35:32] > 4)?(data_shift[35:32] + 2'd3):(data_shift[35:32]);//大四加三
- data_shift[39:36] <= (data_shift[39:36] > 4)?(data_shift[39:36] + 2'd3):(data_shift[39:36]);//大四加三
- data_shift[43:40] <= (data_shift[43:40] > 4)?(data_shift[43:40] + 2'd3):(data_shift[43:40]);//大四加三
- end
- else
- if((cnt_shift <= 20)&&(shift_flag == 1'b1))
- data_shift <= data_shift << 1;
- else
- data_shift <= data_shift;
- end
- always@(posedge clk, negedge rst_n)//相对于时钟信号,0时数据计算,1时进行数据移位
- begin
- if(rst_n == 0)
- shift_flag <= 1'b0;
- else
- shift_flag = ~shift_flag;
- end
- always@(posedge clk, negedge rst_n)
- begin
- if(rst_n == 0)
- begin
- data1 <= 4'b0;
- data2 <= 4'b0;
- data3 <= 4'b0;
- data4 <= 4'b0;
- data5 <= 4'b0;
- data6 <= 4'b0;
- end
- else if(cnt_shift == 5'd21)
- begin
- data1 <= data_shift[23:20];//分段传递
- data2 <= data_shift[27:24];//分段传递
- data3 <= data_shift[31:28];//分段传递
- data4 <= data_shift[35:32];//分段传递
- data5 <= data_shift[39:36];//分段传递
- data6 <= data_shift[43:40];//分段传递
- end
- end
- endmodule
复制代码 顶层连线
- module ds18b20_ctrl(
- input clk ,
- input rst_n ,
- inout dp ,
-
- output [2:0] sel ,
- output [7:0] seg
- );
- wire data_flag;
- wire [19:0]data;
- ds18b20_data ds18b20_data(
- .clk (clk ),
- .rst_n (rst_n ),
- .dp (dp ),
-
- .data_out (data ),
- .data_flag (data_flag )
- );
- shu_ma_g_MAX shu_ma_g_MAX(
- .clk (clk ) ,
- .rst_n (rst_n ) ,
- .data (data ) ,//数据10进制
- .point (6'b001000 ) ,//小数点位
- .signe (data_flag ) ,//正负号位
- .seg_en (1'b1 ) ,//数码管使能
-
- .sel (sel ) ,
- .seg (seg )
- );
- endmodule
复制代码 三、仿真验证
这里进行初始化,写下令跳过ROM下令,状态跳转到等待状态
经过480us后存在脉冲有效信号拉高,证实识别到传感器
数据开始从总线上读入
这里可以看到,有数据输出,实行乐成
参考资料
DS18B20
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |