简单时序图:
状态机转移图:
ds18b20_ctrl.v
/*================================================
Filename : ds18b20_ctrl.v
Author : xq
Description : ds18b20温度传感器控制驱动模块
Date : 2023-8-18 15:07:03
Email : 1617784441@qq.com
Company : 重庆交通大学
================================================*/
module ds18b20_ctrl(
input sys_clk , //时钟信号 50MHz
input sys_rst_n , //复位信号,低有效
output [13:0] temp_data_r ,//温度数据十进制
output reg temp_sign ,//温度正负符号
output reg temp_over ,
inout dq //总线
);
//参数定义
parameter TIME_1US = 5'd24 ;
parameter TIME_750MS = 20'd749_999 ;
parameter IDLE = 4'd0 ;
parameter RESET_PULSES = 4'd1 ;
parameter PRESENCE_PULSES = 4'd2 ;
parameter WR_RCC_CMD = 4'd3 ;
parameter WAIT_750MS = 4'd4 ;
parameter RESET_PULSES_2 = 4'd5 ;
parameter PRESENCE_PULSES_2 = 4'd6 ;
parameter WR_RCC_CMD_2 = 4'd7 ;
parameter RD_TEMP = 4'd8 ;
parameter CC44 = 16'b0100010011001100;
parameter CCBE = 16'b1011111011001100;
//信号定义
reg [4:0 ] cnt_1us ;
reg [19:0] cnt_us ;
reg dq_out,dq_en ;
wire dq_in ;
wire end_cnt_us ;
assign dq=dq_en?dq_out:1'bz ;
assign dq_in=dq ;
reg clk_us ;
reg [3:0 ] state_c ;
reg [3:0 ] state_n ;
reg [3:0 ] bit_num ;
reg start_flag ;
reg [15:0] data ;
reg [15:0] data_r ;
reg [20:0] temp_data ;//温度数据
//逻辑组成
assign temp_data_r=temp_data/100;
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
cnt_1us <= 5'd0;
end
else if(cnt_1us==TIME_1US)begin
cnt_1us <= 5'd0;
end
else begin
cnt_1us <= cnt_1us + 1'd1;
end
end
//微秒计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
clk_us <= 1'd0;
end
else if(cnt_1us==TIME_1US)begin
clk_us <= ~clk_us;
end
else begin
clk_us <= clk_us;
end
end
//微秒时钟
always @(posedge clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)begin
cnt_us <= 20'd0;
end
else if(end_cnt_us)begin
cnt_us <= 20'd0;
end
else begin
cnt_us <= cnt_us + 1'd1;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
temp_over <= 1'b0;
end
else if(state_c==RD_TEMP&&cnt_us==64&&bit_num==15)begin
temp_over <= 1'b1;
end
else begin
temp_over <= 1'b0;
end
end
assign end_cnt_us=(cnt_us==499&&(state_c==RESET_PULSES||state_c==RESET_PULSES_2||state_c==PRESENCE_PULSES||state_c==PRESENCE_PULSES_2))||(state_c==RD_TEMP&&cnt_us==64)||(cnt_us==74&&(state_c==WR_RCC_CMD||state_c==WR_RCC_CMD_2))||state_c==IDLE||(state_c==WAIT_750MS&&cnt_us==TIME_750MS);
//一段状态机
always @(posedge clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//取下降沿为开始信号
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)begin
start_flag <= 1'b0;
end
else if(state_c==PRESENCE_PULSES||PRESENCE_PULSES_2)begin
if(cnt_us==70&&dq_in==0)begin
start_flag <= 1'b1;
end
else begin
start_flag <= start_flag;
end
end
else begin
start_flag <= 1'b0;
end
end
//bit计数器
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)begin
bit_num <= 4'd0;
end
else if(state_c==WR_RCC_CMD||WR_RCC_CMD_2||RD_TEMP)begin
if((state_c==WR_RCC_CMD&&cnt_us==74)||(state_c==WR_RCC_CMD_2&&cnt_us==74)||(state_c==RD_TEMP&&cnt_us==64))begin
bit_num <= bit_num + 1'd1;
end
else begin
bit_num <= bit_num;
end
end
else begin
bit_num <= 4'd0;
end
end
//二段状态机
always @(*)begin
case (state_c)
IDLE :begin
state_n = RESET_PULSES;
end
RESET_PULSES :begin
if(cnt_us==499)begin
state_n = PRESENCE_PULSES;
end
else begin
state_n = RESET_PULSES;
end
end
PRESENCE_PULSES :begin
if(start_flag==1 &&cnt_us==499)begin
state_n = WR_RCC_CMD;
end
else if(start_flag==0&&cnt_us==499)begin
state_n = IDLE;
end
else begin
state_n = PRESENCE_PULSES;
end
end
WR_RCC_CMD :begin
if(cnt_us==74&&bit_num==15)begin
state_n = WAIT_750MS;
end
else begin
state_n = WR_RCC_CMD;
end
end
WAIT_750MS :begin
if(cnt_us==TIME_750MS)begin
state_n = RESET_PULSES_2;
end
else begin
state_n = WAIT_750MS;
end
end
RESET_PULSES_2 :begin
if(cnt_us==499)begin
state_n = PRESENCE_PULSES_2;
end
else begin
state_n = RESET_PULSES_2;
end
end
PRESENCE_PULSES_2:begin
if(start_flag==1&&cnt_us==499)begin
state_n = WR_RCC_CMD_2;
end
else if(start_flag==0&&cnt_us==499)begin
state_n = IDLE;
end
else begin
state_n = PRESENCE_PULSES_2;
end
end
WR_RCC_CMD_2 :begin
if(cnt_us==74&&bit_num==15)begin
state_n = RD_TEMP;
end
else begin
state_n = WR_RCC_CMD_2;
end
end
RD_TEMP :begin
if(cnt_us==64&&bit_num==15)begin
state_n = IDLE;
end
else begin
state_n = RD_TEMP;
end
end
default: state_n = IDLE;
endcase
end
//三段状态机
always @(*) begin
if(!sys_rst_n)begin
dq_out=1'b0;
dq_en =1'b0;
end
case (state_c)
IDLE :begin
dq_out=1'b0;
dq_en =1'b0;
end
RESET_PULSES :begin
dq_out=1'b0;
dq_en =1'b1;
end
PRESENCE_PULSES :begin
dq_out=1'b0;
dq_en =1'b0;
end
WR_RCC_CMD :begin
if(cnt_us>62)begin
dq_out=1'b0;
dq_en =1'b0;
end
else if(cnt_us<=1)begin
dq_out=1'b0;
dq_en =1'b1;
end
else if(CC44[bit_num]==0)begin
dq_out=1'b0;
dq_en =1'b1;
end
else if(CC44[bit_num]==1)begin
dq_out=1'b0;
dq_en =1'b0;
end
end
WAIT_750MS :begin
dq_out=1'b1;
dq_en =1'b1;
end
RESET_PULSES_2 :begin
dq_out=1'b0;
dq_en =1'b1;
end
PRESENCE_PULSES_2:begin
dq_out=1'b0;
dq_en =1'b0;
end
WR_RCC_CMD_2 :begin
if(cnt_us>62)begin
dq_out=1'b0;
dq_en =1'b0;
end
else if(cnt_us<=1)begin
dq_out=1'b0;
dq_en =1'b1;
end
else if(CCBE[bit_num]==0)begin
dq_out=1'b0;
dq_en =1'b1;
end
else if(CCBE[bit_num]==1)begin
dq_out=1'b0;
dq_en =1'b0;
end
end
RD_TEMP :begin
if(cnt_us<=2)begin
dq_out=1'b0;
dq_en =1'b1;
end
else begin
dq_out=1'b0;
dq_en =1'b0;
end
end
default: begin
dq_out=1'b0;
dq_en =1'b0;
end
endcase
end
//获取输入dq
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)begin
data <= 16'd0;
end
else if(state_c==RD_TEMP)begin
if(cnt_us==14)begin
data[bit_num] <= dq_in;
end
else begin
data <= data;
end
end
else begin
data <= 16'd0;
end
end
//将补码转换为原码
always @(posedge clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)begin
data_r <= 16'd0;
end
else if(state_c==IDLE)begin
data_r <= 16'd0;
end
else if((data[15]==1)&&state_c==RD_TEMP&&cnt_us==20&&bit_num==15)begin
data_r <= ~data + 1;
end
else if((data[15]==0)&&state_c==RD_TEMP&&cnt_us==20&&bit_num==15)begin
data_r <= data;
end
else begin
data_r <= data_r;
end
end
//获取温度值
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)begin
temp_data <= 21'd0;
end
else if(state_c==RD_TEMP&&cnt_us==63&&bit_num==15)begin
temp_data <= data_r[0]*625+data_r[1]*1250+data_r[2]*2500+data_r[3]*5000+data_r[4]*10000+data_r[5]*20000+data_r[6]*40000+data_r[7]*80000+data_r[8]*160000+data_r[9]*320000+data_r[10]*640000;
end
else begin
temp_data <= temp_data ;
end
end
//获取符号位
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
temp_sign <= 1'b0;
end
else if(state_c==RD_TEMP&&cnt_us==63&&bit_num==15)begin
temp_sign <= data[15];
end
else begin
temp_sign <= temp_sign ;
end
end
endmodule
ds18b20_top.v
/*================================================
Filename :
Author : xq
Description :
Date : yy/mm/dd
Email : 1617784441@qq.com
Company :
================================================*/
module ds18b20_top(
input sys_clk , //时钟信号 50MHz
input sys_rst_n , //复位信号,低有效
output [05:00] dig_sel , //
output [07:00] dig_seg , //
output tx ,
inout dq //总线
);
wire [13:0] temp_data_r ;
wire temp_sign ;
reg [ 7:0 ] data ;
wire rdreq ;
wire wrreq ;
wire empty ;
wire full ;
wire [ 7:0 ] data_in ;
reg send_flag ;
reg flag ;
reg [ 3:0 ] cnt_byte ;
wire temp_over ;
wire [19:0] temp ;
reg [25:00] cnt ;
wire add_cnt ;
wire end_cnt ;
assign temp[3:0] =temp_data_r%10;
assign temp[7:4] =temp_data_r/10%10;
assign temp[11:8] =temp_data_r/100%10;
assign temp[15:12] =temp_data_r/1000%10;
assign temp[19:16] =temp_data_r/10000%10;
parameter TIME_1S = 26'd49999999;
ds18b20_ctrl u_ds18b20_ctrl(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.temp_data_r (temp_data_r ),
.temp_sign (temp_sign ),
.temp_over (temp_over ),
.dq (dq )
);
seg_driver u_seg_driver(
.Clk (sys_clk ),
.Rst_n (sys_rst_n ),
.point (6'b111011 ),
.data_in(temp_data_r),
.sign (temp_sign ),
.dig_sel(dig_sel),
.dig_seg(dig_seg)
);
uart_tx u_uart_tx(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.start_flag_x(rdreq ),
.baud_rate (115200 ),
.data (data_in ),
.over_flag (over_flag ),
.tx (tx )
);
tx_fifo tx_fifo_inst (
.aclr ( ~sys_rst_n ),
.clock ( sys_clk),
.data ( data ),
.rdreq ( rdreq ),
.wrreq ( wrreq ),
.empty ( empty ),
.full ( full ),
.q ( data_in ),
.usedw ( usedw_sig )
);
assign rdreq = over_flag && ~empty;
assign wrreq = ~full && send_flag && flag;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
send_flag <= 0;
end
else if(cnt_byte==11)begin
send_flag <= 0;
end
else if(cnt_byte==0&&end_cnt)begin
send_flag <= ~send_flag;
end
else begin
send_flag <= send_flag;
end
end
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
end
assign add_cnt = 1;
assign end_cnt = add_cnt && cnt == TIME_1S ;
//数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt_byte <= 0;
end
else if(cnt_byte == 11) begin
cnt_byte <= 0;
end
else if(send_flag==0)begin
cnt_byte <= 0;
end
else if(send_flag) begin
cnt_byte <= cnt_byte + 1;
end
end
always @(*) begin
if(!sys_rst_n) begin
flag = 0;
end
else if(!send_flag) begin
flag = 0;
end
else if(cnt_byte<5) begin
flag = 1;
end
else if(cnt_byte==5&&temp_sign==1)begin
flag = 1;
end
else if(cnt_byte==6&&data>48)begin
flag = 1;
end
else if(cnt_byte>6)begin
flag = 1;
end
else begin
flag = 0;
end
end
always @(*) begin
if(!sys_rst_n) begin
data =0;
end
else if(send_flag) begin
case (cnt_byte)
0 : data = 116;//t
1 : data = 101;//e
2 : data = 109;//m
3 : data = 112;//p
4 : data = 58 ;//:
5 : data = 45 ;//-
6 : data = temp[19:16] + 48 ;
7 : data = temp[15:12] + 48 ;
8 : data = temp[11:8] + 48 ;
9 : data = 46 ;//.
10: data = temp[7:4] + 48 ;
11: data = temp[3:0] + 48 ;
default: data =0;
endcase
end
end
endmodule
uart_tx.v
/*================================================
Filename : uart_tx
Author : xq
Description : 串口通信的发送模块
Date : 2023-8-12 10:41:41
Email : 1617784441@qq.com
Company :
================================================*/
module uart_tx(
input wire sys_clk , //时钟信号 50MHz
input wire sys_rst_n , //复位信号,低有效
input wire start_flag_x , //数据有效使能信号
input wire [16:0] baud_rate ,
input wire [7 :0] data , //数据
output over_flag ,
output reg tx
);
//参数定义
parameter TIME_1S = 26'd5000_0000;
parameter START = 2'b01 ,
SEND = 2'b10 ;
//信号定义
wire [12:0] bit_time ;
wire [10:0] rx_data;
reg [1:0] state_c ;
reg [1:0] state_n ;
reg [12:0] cnt_bit ;
reg [3:0] bit_num ;
reg parity_bit;
//逻辑组成
assign bit_time=(TIME_1S/baud_rate)-1; // 计算每个位的时间
assign rx_data = {1'b1,parity_bit,data, 1'b0}; // 添加校验位
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
state_c <= START; // 复位时将当前状态设为START
end
else begin
state_c <= state_n; // 正常工作状态下,当前状态更新为下一个状态
end
end
always @(*) begin
case (state_c)
START:begin
if(start_flag_x==1)begin
state_n = SEND; // 当前状态为START时,如果收到start_flag_x信号,则下一个状态为SEND
end
else begin
state_n = START; // 如果未收到start_flag_x信号,则保持当前状态为START
end
end
SEND :begin
if(cnt_bit==bit_time&&bit_num==10)begin
state_n = START; // 当前状态为SEND时,如果达到指定的bit_time并且bit_num为9,则下一个状态为START
end
else begin
state_n = SEND; // 其他情况下,下一个状态为SEND
end
end
default: state_n = START; // 默认情况下,下一个状态为START
endcase
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
parity_bit <= 1'b0; // 复位时将校验位parity_bit设置为逻辑低电平
end
else begin
case (state_c)
START: parity_bit <= 1'b0; // 当前状态为START时,校验位parity_bit设置为逻辑低电平
SEND: begin
if (cnt_bit == bit_time && bit_num == 8) begin
if (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]) begin
parity_bit <= 1'b0; // 奇校验
end
else begin
parity_bit <= 1'b1; // 偶校验
end
end
else begin
parity_bit <= parity_bit;
end
end
default: parity_bit <= 1'b0; // 默认情况下,校验位parity_bit设置为逻辑低电平
endcase
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
cnt_bit <= 13'b0; // 复位时将计数器cnt_bit清零
end
else if(cnt_bit == bit_time&&state_c==SEND)begin
cnt_bit <= 13'b0; // 当前状态为SEND时,如果计数器达到bit_time,则将计数器cnt_bit清零
end
else if(state_c==SEND)begin
cnt_bit <= cnt_bit + 1'b1; // 当前状态为SEND时,计数器cnt_bit递增
end
else begin
cnt_bit <= 13'b0; // 其他情况下,计数器cnt_bit清零
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
bit_num <= 1'b0; // 复位时将位号bit_num清零
end
else if(state_c==SEND)begin
if(cnt_bit==bit_time)begin
if(bit_num==10)begin
bit_num <= 1'b0; // 当前状态为SEND时,如果计数器cnt_bit达到bit_time,并且位号bit_num为9,则将位号bit_num清零
end
else begin
bit_num <= bit_num + 1'b1; // 其他情况下,位号bit_num递增
end
end
else begin
bit_num <= bit_num; // 其他情况下,保持位号bit_num不变
end
end
else begin
bit_num <= 1'b0; // 其他情况下,位号bit_num清零
end
end
always @(*) begin
if(!sys_rst_n)begin
tx = 1'b1; // 复位时将输出信号tx设置为逻辑高电平
end
else begin
case (state_c)
START:tx = 1'b1; // 当前状态为START时,输出信号tx设置为逻辑高电平
SEND :tx = rx_data[bit_num]; // 当前状态为SEND时,输出信号tx根据位号bit_num从tx_data中获取信号
default:tx = 1'b1; // 默认情况下,输出信号tx设置为逻辑高电平
endcase
end
end
reg flag_send_data;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
flag_send_data <= 0;
end
else if(start_flag_x) begin
flag_send_data <= 1;
end
else if(cnt_bit==bit_time&&bit_num==10) begin
flag_send_data <= 0;
end
else begin
flag_send_data <= flag_send_data;
end
end
assign over_flag = ~flag_send_data ;
endmodule
seg_drive.v
module seg_driver(
input Clk , //system clock 50MHz
input Rst_n , //reset, low valid
input [05:00] point , //决定小数点是否点亮,低有效
input [23:00] data_in , //默认以十进制数据输入
input sign ,
output reg [05:00] dig_sel , //
output reg [07:00] dig_seg //
);
//Parameter Declarations
parameter MAX_1MS = 50_000;
localparam //段码显示参数
SYB_0 = 8'b1100_0000,
SYB_1 = 8'b1111_1001,
SYB_2 = 8'b1010_0100,
SYB_3 = 8'b1011_0000,
SYB_4 = 8'b1001_1001,
SYB_5 = 8'b1001_0010,
SYB_6 = 8'b1000_0010,
SYB_7 = 8'b1111_1000,
SYB_8 = 8'b1000_0000,
SYB_9 = 8'b1001_0000,
SYB_A = 8'b1000_1000,
SYB_B = 8'b1000_0011,
SYB_C = 8'b1100_0110,
SYB_D = 8'b1010_0001,
SYB_E = 8'b1000_0110,
SYB_F = 8'b1000_1110;
//Internal wire/reg declarations
reg [15:00] cnt_1ms ; //Counter 控制位选切换定时器
wire add_cnt_1ms ; //Counter Enable
wire end_cnt_1ms ; //Counter Reset
reg [03:00] data_tmp ; //
reg dot ; //小数点
//Logic Description
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_1ms <= 'd0;
end
else if(add_cnt_1ms)begin
if(end_cnt_1ms)begin
cnt_1ms <= 'd0;
end
else begin
cnt_1ms <= cnt_1ms + 1'b1;
end
end
else begin
cnt_1ms <= 'd0;
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms >= MAX_1MS - 1;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
dig_sel <= 6'b011_111;
end
else if(end_cnt_1ms)begin
dig_sel <= {dig_sel[0],dig_sel[5:1]}; //切换位选信号
end
else begin
dig_sel <= dig_sel;
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
data_tmp <= 4'd0;
dot <= 1'b1;
end
else begin
case(dig_sel)
6'b011_111:begin data_tmp <= data_in % 10 ;dot <= point[0] ;end //个位
6'b101_111:begin data_tmp <= data_in / 10 % 10 ;dot <= point[1] ;end //十位
6'b110_111:begin data_tmp <= data_in / 100 % 10 ;dot <= point[2] ;end //百位
6'b111_011:begin data_tmp <= data_in / 1000 % 10 ;dot <= point[3] ;end //千位
6'b111_101:begin data_tmp <= data_in / 10000 % 10 ;dot <= point[4] ;end //万位
6'b111_110:begin
if(sign==1)begin
dot <= point[5] ;//十万
data_tmp <= 10;
end
else begin
dot <= point[5] ; //十万
data_tmp <= 11;
end
end
default: ;
endcase
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
dig_seg <= SYB_0;
end
else begin
case(data_tmp)
0:dig_seg <= {dot,SYB_0[6:0]};
1:dig_seg <= {dot,SYB_1[6:0]};
2:dig_seg <= {dot,SYB_2[6:0]};
3:dig_seg <= {dot,SYB_3[6:0]};
4:dig_seg <= {dot,SYB_4[6:0]};
5:dig_seg <= {dot,SYB_5[6:0]};
6:dig_seg <= {dot,SYB_6[6:0]};
7:dig_seg <= {dot,SYB_7[6:0]};
8:dig_seg <= {dot,SYB_8[6:0]};
9:dig_seg <= {dot,SYB_9[6:0]};
10:dig_seg <= {dot,7'b0111111};
11:dig_seg <= {dot,7'b1111111};
default: ;
endcase
end
end //always end
endmodule