DS18B20
module ds18b20(
input sys_clk,
input sys_rst_n,
inout dq,
output wire [7:0] cur_temp
);
//------------<参数定义>----------------------------------------------
//状态机状态定义
localparam INIT1 = 6'b000001 ,
WR_CMD = 6'b000010 ,
WAIT = 6'b000100 ,
INIT2 = 6'b001000 ,
RD_CMD = 6'b010000 ,
RD_DATA = 6'b100000 ;
//时间参数定义
localparam T_INIT = 1000 , //初始化最大时间,单位us
T_WAIT = 780_000 ; //转换等待延时,单位us
//命令定义
localparam WR_CMD_DATA = 16'h44cc, //跳过 ROM 及温度转换命令,低位在前
RD_CMD_DATA = 16'hbecc; //跳过 ROM 及读取温度命令,低位在前
//------------<reg定义>----------------------------------------------
reg [5:0] cur_state ; //现态
reg [5:0] next_state ; //次态
reg [4:0] cnt ; //50分频计数器,1Mhz(1us)
reg dq_out ; //双向总线输出
reg dq_en ; //双向总线输出使能,1则输出,0则高阻态
reg flag_ack ; //从机响应标志信号
reg sys_clk_us ; //us时钟
reg [19:0] cnt_us ; //us计数器,最大可表示1048ms
reg [3:0] bit_cnt ; //接收数据计数器
reg [15:0] data_temp ; //读取的温度数据寄存
reg [15:0] data ; //未处理的原始温度数据
reg [19:0] temp ;
reg sign ;
//------------<wire定义>----------------------------------------------
wire dq_in ; //双向总线输入
//==================================================================
//===========================<main code>===========================
//==================================================================
//-----------------------------------------------------------------------
//--双向端口使用方式
//-----------------------------------------------------------------------
assign dq_in = dq; //高阻态的话,则把总线上的数据赋给dq_in
assign dq = dq_en ? dq_out : 1'bz; //使能1则输出,0则高阻态
//-----------------------------------------------------------------------
//--us时钟生成,因为时序都是以us为单位,所以生成一个1us的时钟会比较方便
//-----------------------------------------------------------------------
//50分频计数
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 5'd0;
else if(cnt == 5'd24) //每25个时钟500ns清零
cnt <= 5'd0;
else
cnt <= cnt + 1'd1;
end
//生成1us时钟
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
sys_clk_us <= 1'b0;
else if(cnt == 5'd24) //每500ns
sys_clk_us <= ~sys_clk_us; //时钟反转
else
sys_clk_us <= sys_clk_us;
end
//-----------------------------------------------------------------------
//--三段式状态机
//-----------------------------------------------------------------------
//状态机第一段:同步时序描述状态转移
always @(posedge sys_clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)
cur_state <= INIT1;
else
cur_state <= next_state;
end
//状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
always @(*)begin
next_state = INIT1;
case(cur_state)
INIT1 :begin
if(cnt_us == T_INIT && flag_ack) //满足初始化时间且接收到了从机的响应信号
next_state = WR_CMD; //跳转到写状态
else
next_state = INIT1; //不满足则保持原有状态
end
WR_CMD :begin
if(bit_cnt == 4'd15 && cnt_us == 20'd62) //写完了16个数据,写跳过ROM和写温度转换命令
next_state = WAIT; //跳转到等待状态,等待温度转换完成
else
next_state = WR_CMD; //不满足则保持原有状态
end
WAIT :begin
if(cnt_us == T_WAIT) //等待时间结束
next_state = INIT2;
else
next_state = WAIT;
end
INIT2 :begin
if(cnt_us == T_INIT && flag_ack) //再进行初始化,时序同INIT1
next_state = RD_CMD;
else
next_state = INIT2;
end
RD_CMD :begin
if(bit_cnt == 4'd15 && cnt_us == 20'd62) //写完了16个数据,写跳过ROM和写读取温度转换命令
next_state = RD_DATA; //跳转到读取温度数据状态
else
next_state = RD_CMD;
end
RD_DATA :begin
if(bit_cnt == 4'd15 && cnt_us == 20'd62) //读取完了16个数据
next_state = INIT1; //跳转到初始化状态,开始新一轮温度采集
else
next_state = RD_DATA;
end
default:next_state = INIT1; //默认初始化状态
endcase
end
//状态机第三段:时序逻辑描述输出
always @(posedge sys_clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)begin //默认输出
dq_en <= 1'b0;
dq_out <= 1'b0;
flag_ack <= 1'b0;
cnt_us <= 20'd0;
bit_cnt <= 4'd0;
end
else begin
case(cur_state)
INIT1 :begin
if(cnt_us == T_INIT)begin //时间计数到最大值(初始化时间)
cnt_us <= 20'd0; //计数器清零
flag_ack <= 1'b0; //从机响应标志信号拉低
end
else begin //没有计数到最大值
cnt_us <= cnt_us + 1'd1; //计数器计数
if(cnt_us <= 20'd499)begin //小于500us时
dq_en <= 1'b1; //控制总线
dq_out <= 1'b0; //输出0,即拉低总线
end
else begin //在500us处
dq_en <= 1'b0; //释放总线,等待从机响应
if (cnt_us == 20'd570 && !dq_in) //在570us处采集总线电平,如果为0则说明从机响应了
flag_ack <= 1'b1; //拉高从机响应标志信号
end
end
end
WR_CMD :begin
if(cnt_us == 20'd62)begin //一个写时隙周期63us,满足计时条件则
cnt_us <= 20'd0; //清空计数器
dq_en <= 1'b0; //释放总线
if(bit_cnt == 4'd15) //如果数据已经写了15个
bit_cnt <= 4'd0; //则清空
else //没写15个
bit_cnt <= bit_cnt + 1'd1; //则数据计数器+1,代表写入了一个数据
end
else begin //一个写时隙周期63us未完成
cnt_us <= cnt_us + 1'd1; //计数器一直计数
if(cnt_us <= 20'd1)begin //0~1us(每两个写数据之间需要间隔2us)
dq_en <= 1'b1; //拉低总线
dq_out <= 1'b0;
end
else begin
if (WR_CMD_DATA[bit_cnt] == 1'b0)begin //需要写入的数据为0
dq_en <= 1'b1; //拉低总线
dq_out <= 1'b0; //
end
else if(WR_CMD_DATA[bit_cnt] == 1'b1)begin
dq_en <= 1'b0; //需要写入的数据为1
dq_out <= 1'b0; //释放总线
end
end
end
end
WAIT :begin //等待温度转换完成
dq_en <= 1'b1; //拉低总线兼容寄生电源模式
dq_out <= 1'b1;
if(cnt_us == T_WAIT) //计数完成
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'd1;
end
INIT2 :begin //第二次初始化,时序同INIT1
if(cnt_us == T_INIT)begin
cnt_us <= 20'd0;
flag_ack <= 1'b0;
end
else begin
cnt_us <= cnt_us + 1'd1;
if(cnt_us <= 20'd499)begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else begin
dq_en <= 1'b0;
if (cnt_us == 20'd570 && !dq_in)
flag_ack <= 1'b1;
end
end
end
RD_CMD :begin //写16个数据,时序同WR_CMD
if(cnt_us == 20'd62)begin
cnt_us <= 20'd0;
dq_en <= 1'b0;
if(bit_cnt == 4'd15)
bit_cnt <= 4'd0;
else
bit_cnt <= bit_cnt + 1'd1;
end
else begin
cnt_us <= cnt_us + 1'd1;
if(cnt_us <= 20'd1)begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else begin
if (RD_CMD_DATA[bit_cnt] == 1'b0)begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else if(RD_CMD_DATA[bit_cnt] == 1'b1)begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
end
end
RD_DATA :begin //读16位温度数据
if(cnt_us == 20'd62)begin //一个读时隙周期63us,满足计时条件则
cnt_us <= 20'd0; //清空计数器
dq_en <= 1'b0; //释放总线
if(bit_cnt == 4'd15)begin //如果数据已经读取了15个
bit_cnt <= 4'd0; //则清空
data <= data_temp; //临时的数据赋值给data
end
else begin //如果数据没有读取15个
bit_cnt <= bit_cnt + 1'd1; //则数据计数器+1,意味着读取了一个数据
data <= data;
end
end
else begin //一个读时隙周期还没结束
cnt_us <= cnt_us + 1'd1; //计数器累加
if(cnt_us <= 20'd1)begin //0~1us(每两个读数据之间需要间隔2us)
dq_en <= 1'b1; //拉低总线
dq_out <= 1'b0;
end
else begin //2us后
dq_en <= 1'b0; //释放总掉线
if (cnt_us == 20'd10) //在10us处读取总线电平
data_temp <= {dq,data_temp[15:1]}; //读取总线电平
end
end
end
default:;
endcase
end
end
//-----------------------------------------------------------------------
//--12位温度数据处理
//-----------------------------------------------------------------------
always @(posedge sys_clk_us or negedge sys_rst_n)begin
if(!sys_rst_n)begin //初始状态
temp <= 20'd0;
sign <= 1'b0;
end
else begin
if(!data[15])begin //最高位为0则温度为正
sign <= 1'b0; //标志位为正
temp <= data[10:0] * 11'd625 /14'd10000; //12位温度数据处理
end
else if(data[15])begin //最高位为1则温度为负
sign <= 1'b1; //标志位为负
temp <= (~data[10:0] + 1'b1)* 11'd625 /14'd10000; //12位温度数据处理
end
end
end
assign cur_temp = {sign, temp[6:0]};
endmodule
温度控制
module temp_control(
input wire sys_clk,
input wire sys_rst_n,
input wire [7:0] set_temp,
input wire [7:0] cur_temp,
output reg en_heater,
output reg en_cooler
);
// 提取符号位
wire set_sign = set_temp[7];
wire cur_sign = cur_temp[7];
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
en_cooler <= 1'b0;
en_heater <= 1'b0;
end
else begin
// 符号位不同的情况
if(set_sign != cur_sign) begin
if(set_sign == 1'b0 && cur_sign == 1'b1) begin
en_cooler <= 1'b0;
en_heater <= 1'b1;
end
else begin
en_cooler <= 1'b1;
en_heater <= 1'b0;
end
end
// 符号位相同的情况(同正或同负)
else begin
// 同正或同负时,转换为无符号数比较(补码特性)
if(set_sign == 1'b0) begin // 同正
if(set_temp[6:0] > cur_temp[6:0]) begin
en_cooler <= 1'b0;
en_heater <= 1'b1;
end
else if(set_temp[6:0] < cur_temp[6:0]) begin
en_cooler <= 1'b1;
en_heater <= 1'b0;
end
else begin
en_cooler <= 1'b0;
en_heater <= 1'b0;
end
end
else begin // 同负(补码比较:数值越大,实际值越小)
if(set_temp[6:0] < cur_temp[6:0]) begin // 补码数值小的实际值更大
en_cooler <= 1'b0;
en_heater <= 1'b1;
end
else if(set_temp[6:0] > cur_temp[6:0]) begin
en_cooler <= 1'b1;
en_heater <= 1'b0;
end
else begin
en_cooler <= 1'b0;
en_heater <= 1'b0;
end
end
end
end
end
endmodule
步进电机
module motor(
input wire sys_clk,
input wire sys_rst_n,
input wire [15:0] set_freq,
output reg [3:0] out_motor, // 步进电机控制引脚
output reg [15:0] cur_freq
);
reg [31:0] CNT_MAX;
reg [19:0] counter; // 计数器,用于控制步进电机的速度
reg [2:0] seq_index; // 序列索引
parameter SEQUENCE = {4'b0001, 4'b0011, 4'b0010, 4'b0110, 4'b0100, 4'b1100, 4'b1000, 4'b1001}; // 四相八拍控制序列
// 频率允许范围
localparam FREQ_MIN = 16'd15;
localparam FREQ_MAX = 16'd20;
// 50M主频
localparam CLK_FREQ = 32'd50_000_000;
always @(*) begin
// 限制set_freq在允许范围
if (!sys_rst_n || set_freq < FREQ_MIN || set_freq > FREQ_MAX)
CNT_MAX = 32'hffff_ffff;
else
CNT_MAX = (CLK_FREQ * 120) / (set_freq * 4096); // 一圈8拍
end
always @(*) begin
if (!sys_rst_n || set_freq < FREQ_MIN || set_freq > FREQ_MAX)
cur_freq = 16'd0;
else if (CNT_MAX != 0)
cur_freq = (CLK_FREQ * 120) / (CNT_MAX * 4096); // 实际输出频率
else
cur_freq = 16'd0;
end
/*always @(*) begin
if (!sys_rst_n || set_freq == 16'd0)
cur_freq = 16'd0;
else if(CNT_MAX <='d999_99 && CNT_MAX >='d699_99)
cur_freq = set_freq;
else if(CNT_MAX > 'd999_99)
cur_freq = 16'd0;
else if(CNT_MAX < 'd699_99)
cur_freq = 16'd0;
end
always @(*) begin
if (!sys_rst_n || set_freq == 8'd0)
CNT_MAX = 32'hffff_ffff;
else
CNT_MAX = 50_000_000 * 120 / 4096 / set_freq;
end*/
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n || set_freq == 8'd0) begin
counter <= 20'd0;
seq_index <= 3'd0;
out_motor <= 4'b0000;
end else begin
counter <= counter + 1;
if (counter == CNT_MAX) begin
counter <= 20'd0;
seq_index <= seq_index + 1;
if (seq_index == 3'd7) begin
seq_index <= 3'd0;
end
out_motor <= SEQUENCE[(seq_index * 4) +: 4];
end
end
end
endmodule
uart_rx
module uart_rx
#(
parameter UART_BPS = 'd115200, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output reg [7:0] po_data , //串转并后的8bit数据
output reg po_flag //串转并后的数据有效标志信号
);
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
reg start_nedge ;
reg work_en ;
reg [12:0] baud_cnt ;
reg bit_flag ;
reg [3:0] bit_cnt ;
reg [7:0] rx_data ;
reg rx_flag ;
//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到5207
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
bit_cnt <= 4'b0;
else if(bit_flag ==1'b1)
bit_cnt <= bit_cnt + 1'b1;
//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'b0;
else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
rx_data <= {rx_reg3, rx_data[7:1]};
//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 8'b0;
else if(rx_flag == 1'b1)
po_data <= rx_data;
//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;
endmodule
帧处理
module frame_processor(
input wire sys_clk,
input wire sys_rst_n,
input wire po_flag,
input wire [7:0] po_data,
output reg send_flag,
output reg [15:0] set_freq,
output reg [7:0] set_temp
);
localparam IDLE = 4'd0;
localparam HEAD_AA = 4'd1;
localparam HEAD_66 = 4'd2;
localparam CMD = 4'd3;
localparam TEMP = 4'd4;
localparam FREQ_L = 4'd5;
localparam FREQ_H = 4'd6;
localparam FRAME_CNT_L = 4'd7;
localparam FRAME_CNT_H = 4'd8;
localparam CHK_SUM = 4'd9;
localparam TAIL = 4'd10;
reg [3:0] state, next_state;
reg [7:0] cal_chk;
reg [15:0] frame_cnt;
reg data_val;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
state <= IDLE;
set_freq <= 16'd0;
set_temp <= 8'd0;
frame_cnt <= 16'd0;
cal_chk <= 8'd0;
send_flag <= 1'b0;
data_val <= 1'b0;
next_state <= IDLE;
end else if(send_flag)begin
send_flag <= 1'b0;
data_val <= 1'b0;
end else if(po_flag) begin
case(state)
IDLE: begin
if(po_data == 8'hAA) state <= HEAD_AA;
else state <= IDLE;
cal_chk <= 8'd0;
end
HEAD_AA: begin
if(po_data == 8'h66) state <= HEAD_66;
else state <= IDLE;
end
HEAD_66: begin
state <= CMD;
cal_chk <= po_data; //cmd
if(po_data==8'hA0) send_flag <= 1'b1;
else if(po_data==8'hA1)begin
send_flag <= 1'b0;
data_val <= 1'b1;
end
end
CMD: begin
state <= TEMP;
cal_chk <= cal_chk + po_data; //temp
if(data_val) set_temp <= po_data;
end
TEMP: begin
state <= FREQ_H;
if(data_val) set_freq[15:8] <= po_data;
end
FREQ_H: begin
state <= FREQ_L;
if(data_val) set_freq[7:0] <= po_data;
cal_chk <= cal_chk + po_data;
end
FREQ_L: begin
state <= FRAME_CNT_H;
frame_cnt[15:7] <= po_data;
end
FRAME_CNT_H: begin
frame_cnt[7:0] <= po_data;
cal_chk <= cal_chk + po_data;
state <= FRAME_CNT_L;
end
FRAME_CNT_L: begin
state <= CHK_SUM;
if(cal_chk == po_data)
next_state <= TAIL;
else next_state <= IDLE;
end
CHK_SUM: begin
state <= next_state;
end
TAIL: begin
if(po_data == 8'hAA) state <= HEAD_AA;
else begin
state <= IDLE;
cal_chk <= 8'd0;
end
end
default: state <= IDLE;
endcase
end
end
endmodule
帧组装
module frame_assembler#(
parameter UART_BPS = 115200,
parameter CLK_FREQ = 50_000_000
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire send_flag,
input wire [15:0] cur_freq,
input wire [7:0] cur_temp,
output reg [7:0] pi_data,
output reg pi_flag
);
reg [3:0] state, next_state, pre_state;
reg [7:0] cal_chk;
reg [15:0] frame_cnt;
reg [15:0] wait_cnt;
localparam WAIT_CNT_MAX = (CLK_FREQ/UART_BPS)*10;
localparam IDLE = 4'd0;
localparam HEAD_AA = 4'd1;
localparam HEAD_99 = 4'd2;
localparam TEMP = 4'd3;
localparam cur_freq_H = 4'd4;
localparam cur_freq_L = 4'd5;
localparam FRAME_CNT_H = 4'd6;
localparam FRAME_CNT_L = 4'd7;
localparam CHK_SUM = 4'd8;
localparam TAIL = 4'd9;
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
pre_state <= IDLE;
state <= IDLE;
end
else begin
pre_state <= state;
state <= next_state;
end
end
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
wait_cnt <= 1'd0;
else if(state == IDLE)
wait_cnt <= 1'd0;
else if(wait_cnt == WAIT_CNT_MAX-1)
wait_cnt <= 1'd0;
else
wait_cnt <= wait_cnt + 1'd1;
end
always @(*)begin
case(state)
IDLE:
next_state = send_flag ? HEAD_AA : IDLE;
HEAD_AA:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? HEAD_99 : HEAD_AA;
HEAD_99:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? TEMP : HEAD_99;
TEMP:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? cur_freq_H : TEMP;
cur_freq_H:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? cur_freq_L : cur_freq_H;
cur_freq_L:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? FRAME_CNT_H : cur_freq_L;
FRAME_CNT_H:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? FRAME_CNT_L : FRAME_CNT_H;
FRAME_CNT_L:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? CHK_SUM : FRAME_CNT_L;
CHK_SUM:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? TAIL : CHK_SUM;
TAIL:
next_state = (wait_cnt == WAIT_CNT_MAX-1) ? IDLE : TAIL;
default: next_state = IDLE;
endcase
end
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
pi_data <= 8'd0;
pi_flag <= 1'b0;
cal_chk <= 8'd0;
frame_cnt <= 16'd0;
end
else begin
case(state)
HEAD_AA: begin
pi_data <= 8'hAA;
if (pre_state != HEAD_AA)
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
end
HEAD_99: begin
pi_data <= 8'h99;
if (pre_state != HEAD_99)
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
end
TEMP: begin
pi_data <= cur_temp;
if (pre_state != TEMP)begin
pi_flag <= 1'b1;
cal_chk <= cal_chk + cur_temp;
end
else
pi_flag <= 1'b0;
end
cur_freq_H: begin
pi_data <= cur_freq[15:8];
if (pre_state != cur_freq_H)
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
end
cur_freq_L: begin
pi_data <= cur_freq[7:0];
if (pre_state != cur_freq_L)begin
pi_flag <= 1'b1;
cal_chk <= cal_chk + cur_freq[7:0];
end
else
pi_flag <= 1'b0;
end
FRAME_CNT_H: begin
pi_data <= 8'h18;
pi_data <= frame_cnt[15:8];
if (pre_state != FRAME_CNT_H)
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
end
FRAME_CNT_L: begin
pi_data <= frame_cnt[7:0];
if (pre_state != FRAME_CNT_L)begin
pi_flag <= 1'b1;
cal_chk <= cal_chk + frame_cnt[7:0];
end
else
pi_flag <= 1'b0;
end
CHK_SUM: begin
pi_data <= cal_chk;
if (pre_state != CHK_SUM)
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
end
TAIL: begin
pi_data <= 8'h68;
cal_chk <= 8'd0;
if (pre_state != TAIL)begin
pi_flag <= 1'b1;
frame_cnt <= frame_cnt + 16'd1;
end
else
pi_flag <= 1'b0;
end
default: begin
pi_data <= 8'h00;
pi_flag <= 1'b0;
cal_chk <= 8'd0;
end
endcase
end
end
endmodule
UART_TX
module uart_tx
#(
parameter UART_BPS = 'd115200,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [7:0] pi_data ,
input wire pi_flag ,
output reg tx
);
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt ;
reg work_en ;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(pi_flag == 1'b1)
work_en <= 1'b1;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
work_en <= 1'b0;
end
//baud_cnt:波特率计数器计数
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
end
//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
end
//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
end
//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
tx <= 1'b1; //空闲状态时为高电平
else if(bit_flag == 1'b1)
case(bit_cnt)
0 : tx <= 1'b0;
1 : tx <= pi_data[0];
2 : tx <= pi_data[1];
3 : tx <= pi_data[2];
4 : tx <= pi_data[3];
5 : tx <= pi_data[4];
6 : tx <= pi_data[5];
7 : tx <= pi_data[6];
8 : tx <= pi_data[7];
9 : tx <= 1'b1;
default : tx <= 1'b1;
endcase
end
endmodule
顶层模块
module top_system(
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output wire tx,
output wire en_cooler,
output wire en_heater,
output wire [3:0] out_motor
);
wire [7:0] po_data;
wire po_flag;
wire [7:0] pi_data;
wire pi_flag;
wire send_flag;
wire [7:0] set_temp;
wire [7:0] cur_temp;
wire [15:0] set_freq;
wire [15:0] cur_freq;
//-------------------<温度控制>--------------------------------------------
ds18b20 u_ds18b20(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.dq(),
.cur_temp(cur_temp) //
);
temp_control u_temp_control(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.set_temp(set_temp),
.cur_temp(cur_temp),//
.en_heater(en_heater),
.en_cooler(en_cooler)
);
//--------------------------------<步进电机>--------------------------------------------
motor u_motor(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.set_freq(set_freq),
.out_motor(out_motor),
.cur_freq(cur_freq)
);
//-------------------------------------<串口通信>----------------------------
uart_rx #(
.UART_BPS(115200),
.CLK_FREQ(50_000_000)
)
u_uart_rx
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.rx(rx),
.po_data(po_data),
.po_flag(po_flag)
);
frame_processor u_frame_processor(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.po_flag(po_flag),
.po_data(po_data),
.send_flag(send_flag),
.set_freq(set_freq),
.set_temp(set_temp)
);
frame_assembler u_frame_assembler(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.send_flag(send_flag),
.cur_freq(cur_freq),
.cur_temp(cur_temp),
.pi_data(pi_data),
.pi_flag(pi_flag)
);
uart_tx #(
.UART_BPS(115200),
.CLK_FREQ(50_000_000)
)
u_uart_tx(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.pi_data(pi_data),
.pi_flag(pi_flag),
.tx(tx)
);
endmodule