基于FPGA的恒温控制系统

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值