UART例程

以下代码可实现基于UART串口通信协议的数据收发,包含top模块,UART_RX,UART_TX三个模块。具体的功能实现请查看代码注释 

TOP模块:输入输出端口包含基本的时钟信号与复位信号,以及用于UART的RXD与TXD,收发信号有LED灯展现

module top
(
	input		wire  		clk             ,
	input  	    wire		rst             ,
	output	    wire		tx              ,
	input		wire		rx   	        , 
	output      reg  [7:0]	led		
);


wire [7:0] 		tx_data          	;//发送的数据
wire			done   				;//使能信号

//UART_TX主要包含三个变量:tx_data发送的数据;ready:完成标志;tx_data_vld:使能信号
uart_tx inst_tx( 
    .clk					(clk)		,
    .rst					(rst)		,
    .tx_data                (tx_data)	,
    .tx_data_vld		    (done)		,
    .ready     		        (1'b1)		,
    .tx                     (tx)
);
//UART_RX主要包含两个变量:rx_data接收的数据;tx_data_vld:完成标志
uart_rx inst_rx( 
    .clk					(clk)       ,
    .rst					(rst)       ,
    .rx					    (rx)        ,
    .rx_data_vld		    (done)      ,
    .rx_data                (tx_data)
);

always @(posedge clk or posedge rst) begin
	if(rst) begin
		led <= 8'b1111_1111;
	end else begin	
		if(done)
			led <= tx_data;
		else
			led <= led;
	end
end

endmodule

UART_RX模块:用于接收数据 

module uart_rx( 
    input				clk,
    input				rst,
    input               rx,
    output           rx_data_vld,
    output   [7:0]	 rx_data            
);								 


parameter   MAX_BPS = 115200;
parameter   CLOCK = 50_000_000;
parameter   MAX_1bit = CLOCK/MAX_BPS;
parameter   CHECK_BIT = "None";//无校验位

//定义状态机
localparam  IDLE   = 'b0001,
            START  = 'b0010,
            DATA   = 'b0100,
            CHECK  = 'b1000;

reg 	[3:0]	cstate     	;
reg	    [3:0]	nstate     	;
//状态转换标志    
wire			IDLE_START;
wire    		START_DATA;
wire    		DATA_IDLE;
wire    		DATA_CHECK;
wire    		CHECK_IDLE;
//波特率计数器 
reg	[8:0]	    cnt_baud	   	;
wire			add_cnt_baud	;
wire			end_cnt_baud	;
//比特位计数器 
reg	[2:0]	    cnt_bit	   	;
wire			add_cnt_bit	;
wire			end_cnt_bit	;
    
reg	[3:0]	bit_max;
 
reg	[7:0]	rx_temp;
reg			rx_check;
wire		check_val; 
//打两拍 
reg			rx_r1;
reg			rx_r2;
wire		rx_nege;
 
//下降沿检测
always @(posedge clk or posedge rst) begin
	if (rst) begin
		rx_r1 <= 1;
		rx_r2 <= 1;
		end
	else begin
		rx_r1 <= rx;
		rx_r2 <= rx_r1;
		end
	end
 
assign rx_nege = ~rx_r1 && rx_r2;
 
//
always @(posedge clk or posedge rst)begin 
	if(rst)begin
		cnt_baud <= 'd0;
		end 
	else if(add_cnt_baud)begin 
		if(end_cnt_baud)begin 
			cnt_baud <= 'd0;
			end
		else begin 
			cnt_baud <= cnt_baud + 1'd1;
			end 
		end
	end 
    
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
    
//
always @(posedge clk or posedge rst)begin 
	if(rst)begin
		cnt_bit <= 'd0;
		end 
	else if(add_cnt_bit)begin 
		if(end_cnt_bit)begin 
			cnt_bit <= 'd0;
			end
		else begin 
			cnt_bit <= cnt_bit + 1'd1;
			end 
		end
	end 
    
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
    
//定义每个状态字节数,根据UART串口通信协议
always @(*)begin 
	case (cstate)
		IDLE :bit_max = 'd0;
		START:bit_max = 'd1;
		DATA :bit_max = 'd8;
		CHECK:bit_max = 'd1;
		default: bit_max = 'd0;
	endcase
end
//定义状态转换标志
assign IDLE_START = (cstate == IDLE) && rx_nege;
assign START_DATA = (cstate == START) && end_cnt_bit;
assign DATA_IDLE = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";
assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;
assign CHECK_IDLE = (cstate == CHECK) && end_cnt_bit;

//
always @(posedge clk or posedge rst)begin 
	if(rst)begin
		cstate <= IDLE;
		end 
	else begin 
		cstate <= nstate;
		end 
	end
    
//
always @(*) begin
	case(cstate)
		IDLE  :begin
			if (IDLE_START) begin
				nstate = START;
				end
			else begin
				nstate = cstate;
				end
			end
		START :begin
			if (START_DATA) begin
				nstate = DATA;
				end
			else begin
				nstate = cstate;
				end
			end
		DATA  :begin
			if (DATA_IDLE) begin
				nstate = IDLE;
				end
			else if (DATA_CHECK) begin
				nstate = CHECK;
				end
			else begin
				nstate = cstate;
				end
			end
		CHECK:begin
			if (CHECK_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end
		default : nstate = IDLE;
	endcase
end

//校验位处理
always @(posedge clk or posedge rst) begin
	if (rst) begin
		rx_check <= 0;
		end
	else if (cstate == CHECK && cnt_baud == MAX_1bit >>1) begin
		rx_check <= rx_r1;
		end
	end

assign check_val = (CHECK_BIT == "Odd") ? ~^rx_temp : ^rx_temp;
//数据储存
always @(posedge clk or posedge rst) begin
	if (rst) begin
		rx_temp <= 0;
		end
	else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin
		rx_temp[cnt_bit] <= rx_r1;
	end else begin
		rx_temp <= rx_temp;
	end
end
assign rx_data = rx_temp;
assign rx_data_vld  = (CHECK_BIT == "None") ? DATA_IDLE
                          :(CHECK_IDLE && (check_val == rx_check)) ? 1
                          : 0;
    
endmodule


module uart_tx( 
    input					clk			,
    input					rst			,
    input       [7:0]   	tx_data 	,
    input               	tx_data_vld	,
    output  wire        	ready   	,
    output  reg         	tx              
);								 

parameter   MAX_BPS = 115200;//波特率
parameter   CLOCK = 50_000_000;//时钟频率
parameter   MAX_1bit = CLOCK/MAX_BPS;// 计算每一位传输所需的时钟周期数
parameter   CHECK_BIT = "None";//校验位mode
//定义状态机
localparam  IDLE   = 'b00001,
            START  = 'b00010,
            DATA   = 'b00100,
            CHECK  = 'b01000,
            STOP   = 'b10000;
				
reg 	[4:0]		cstate     		;
reg		[4:0]		nstate     		;
//状态机跳转标志    
wire				IDLE_START;
wire 				START_DATA;
wire 				DATA_CHECK;
wire 				CHECK_STOP;
wire				STOP_IDLE;

reg	[8:0]			cnt_baud	   	;
wire				add_cnt_baud	;
wire				end_cnt_baud	;

reg	[2:0]		    cnt_bit	   		;
wire				add_cnt_bit		;
wire				end_cnt_bit		;
 
reg 	[3:0]   	bit_max			;
reg  	[7:0]   	tx_data_r		;
    
wire				check_val		;
    
//波特率计数器
always @(posedge clk or posedge rst)begin 
	if(rst)begin
		cnt_baud <= 'd0;
		end 
   else if(add_cnt_baud)begin 
      if(end_cnt_baud)begin 
			cnt_baud <= 'd0;
         end
      else begin 
         cnt_baud <= cnt_baud + 1'd1;
         end 
      end
   end 
    
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
    
//数据位计数器
always @(posedge clk or posedge rst)begin 
   if(rst)begin
		cnt_bit <= 'd0;
		end 
	else if(add_cnt_bit)begin 
		if(end_cnt_bit)begin 
			cnt_bit <= 'd0;
			end
		else begin 
			cnt_bit <= cnt_bit + 1'd1;
			end 
		end
	end 
    
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
    
//数据位定义
always @(*)begin 
	case (cstate)
		IDLE :bit_max = 'd0;
		START:bit_max = 'd1;
		DATA :bit_max = 'd8;
		CHECK:bit_max = 'd1;
		STOP :bit_max = 'd1;
		default: bit_max = 'd0;
	endcase
end
//状态跳转条件
assign IDLE_START = (cstate == IDLE) && tx_data_vld;
assign START_DATA = (cstate == START) && end_cnt_bit;
assign DATA_STOP = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";
assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;
assign CHECK_STOP = (cstate ==CHECK) && end_cnt_bit;
assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;

//状态机转换
always @(posedge clk or posedge rst)begin 
   if(rst)begin
		cstate <= IDLE;
		end 
   else begin 
		cstate <= nstate;
	end 
end
    
//FSM
always @(*) begin
	case(cstate)
		IDLE  :begin
			if (IDLE_START) begin
				nstate = START;
				end
			else begin
				nstate = cstate;
				end
			end
		START :begin
			if (START_DATA) begin
				nstate = DATA;
				end
			else begin
				nstate = cstate;
				end
			end
		DATA  :begin
			if (DATA_CHECK) begin
				nstate = CHECK;
					end
			else if (DATA_STOP) begin
				nstate = STOP;
				end
			else begin
				nstate = cstate;
				end
		end
		CHECK :begin
			if (CHECK_STOP) begin
				nstate = STOP;
				end
			else begin
				nstate = cstate;
				end
			end
		STOP  :begin
			if (STOP_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end
		default : nstate = cstate;
	endcase
end

//数据位寄存
always @(posedge clk or posedge rst) begin
	if (rst) begin
		tx_data_r <= 'd0;
		end
	else if (tx_data_vld) begin
		tx_data_r <= tx_data;
		end
	else begin
		tx_data_r <= tx_data_r;
		end
end
//校验位奇偶校验    
assign check_val = (CHECK_BIT == "Odd") ? ~^tx_data_r : ^tx_data_r;
    
//发送数据
always @(*)begin 
	case (cstate)
		IDLE : tx = 1'b1;
		START: tx = 1'b0;
		DATA : tx = tx_data_r[cnt_bit];
		CHECK: tx = check_val;
		STOP : tx = 1'b1;
	default: tx = 1'b1;
	endcase
end            

//空闲状态
assign ready = cstate == IDLE;
     
endmodule

TIPS:波特率为115200,数据收发过程中需要用到串口助手。

UART协议基本介绍:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值