zl程序教程

您现在的位置是:首页 >  其他

当前栏目

verilog基础---uart_rx代码

基础代码 --- Verilog uart RX
2023-09-11 14:20:47 时间

1、功能概述

功能是接收串口,波特率是115200,时钟是148.5Mhz。

控制的参数:

顶层接口:

clk

148.5M

Rst_n

低电平复位

rx_data

串口接收的数据

rs232_rx

串口的tx引脚线

rx_dvalid

1表示rx_data数据有效

转载:https://blog.csdn.net/weixin_36590806/article/details/118441673

思路:

设计两个模块,一个模块是根据时钟控制读写的时间点。

另一个模块是接收串口的模块。

顶层模块的代码:

module my_uart_rx_top

(

input clk ,  //148.5M

input rst_n ,

input rs232_rx ,        

output rx_dvalid ,

output [7:0]rx_data

);

wire bps_start ;

wire clk_bps1 ;

speed_select speed_rx_inst

(        

.clk      ( clk       ),        //波特率选择模块

.rst_n    ( rst_n     ),

.bps_start( bps_start ),

.clk_bps  ( clk_bps1  )

);

my_uart_rx  my_uart_rx_inst

(                

.clk      ( clk       ),        //接收数据模块

.rst_n    ( rst_n     ),

.rs232_rx ( rs232_rx  ),

.rx_data  ( rx_data   ),

.rx_int   ( rx_dvalid ),

.clk_bps  ( clk_bps1  ),

.bps_start( bps_start )

);

endmodule

speed_select模块代码

module speed_select

(

clk      ,

rst_n    ,

bps_start,

clk_bps

);

input      clk      ;        // 148.5MHz主时钟

input      rst_n    ;        //低电平复位信号

input      bps_start; //接收到数据后,波特率时钟启动信号置位

output     clk_bps  ;        // clk_bps的高电平为接收或者发送数据位的中间采样点

parameter bps115200          = 1288 ;        //148.5MHZ 波特率为115200bps

parameter bps115200_2 = 644 ; 

reg[13:0] cnt      ;                            //分频计数

reg       clk_bps_r;                            //波特率时钟寄存器

//----------------------------------------------------------

always @ (posedge clk or negedge rst_n)

if(!rst_n)

cnt <= 14'd0;

else if((cnt >= bps115200) || !bps_start)

cnt <= 14'd0;          //波特率计数清零

else

cnt <= cnt+1'b1;//波特率时钟计数启动

always @ (posedge clk or negedge rst_n)

if(!rst_n)

clk_bps_r <= 1'b0;

else if(cnt == bps115200_2)

clk_bps_r <= 1'b1;

else                          

clk_bps_r <= 1'b0;

assign clk_bps = clk_bps_r;

endmodule

my_uart_rx模块的代码:

module my_uart_rx(

clk      ,

rst_n    ,

rs232_rx ,

rx_data  ,

rx_int   ,

clk_bps  ,

bps_start

);

input clk          ;        // 148.5MHz主时钟

input rst_n        ;        //低电平复位信号

input rs232_rx     ;        // RS232接收数据信号

input clk_bps      ;        // clk_bps的高电平为接收或者发送数据位的中间采样点

output bps_start   ;  //接收到数据后,波特率时钟启动信号置位

output[7:0] rx_data;        //接收数据寄存器,保存直至下一个数据来到

output rx_int      ;        //接收数据中断信号,接收到数据期间始终为高电平

//----------------------------------------------------------------

reg  rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3,rs232_rx4;        //接收数据寄存器,滤波用

wire neg_rs232_rx;        //表示数据线接收到下降沿

always @ (posedge clk or negedge rst_n) begin

if(!rst_n) begin

rs232_rx0 <= 1'b0;

rs232_rx1 <= 1'b0;

rs232_rx2 <= 1'b0;

rs232_rx3 <= 1'b0;

rs232_rx4 <= 1'b0;

end

else begin

rs232_rx0 <= rs232_rx ;

rs232_rx1 <= rs232_rx0;

rs232_rx2 <= rs232_rx1;

if(rs232_rx1&&rs232_rx2)

rs232_rx3 <= 1'b1;

else if(~(rs232_rx1||rs232_rx2))

rs232_rx3 <= 1'b0;

else

rs232_rx3 <= rs232_rx3;        

rs232_rx4 <= rs232_rx3;

end

end

//下降沿检测

assign neg_rs232_rx = rs232_rx4 & (~rs232_rx3);        //接收到下降沿后neg_rs232_rx置高一个时钟周期

//----------------------------------------------------------------

reg bps_start_r;

reg[3:0] num;        //移位次数

reg rx_int;                //接收数据中断信号,接收到数据期间始终为高电平

reg start_bit_check ; //起始位错误标志

always@(posedge clk,negedge rst_n)

if(~rst_n)

start_bit_check <= 1'b0 ;

else                

start_bit_check <= clk_bps && (num == 4'd0) && rs232_rx3 ;

always @ (posedge clk or negedge rst_n)

if(!rst_n)

bps_start_r <= 1'b0;

else if(neg_rs232_rx)                //接收到串口接收线rs232_rx的下降沿标志信号

bps_start_r <= 1'b1;            //启动串口准备数据接收

else if(start_bit_check)//检测到起始位错误

bps_start_r <= 1'b0   ;           

else if(num==4'd9)         //接收完有用数据信息

bps_start_r <= 1'b0 ;          //数据接收完毕,释放波特率启动信号

assign bps_start = bps_start_r;

//----------------------------------------------------------------

reg[7:0] rx_data_r;                       //串口接收数据寄存器,保存直至下一个数据来到

//----------------------------------------------------------------

reg[7:0] rx_temp_data;             //当前接收数据寄存器

always @ (posedge clk or negedge rst_n)

if(!rst_n) begin

rx_temp_data <= 8'd0 ;

num          <= 4'd0 ;

rx_data_r    <= 8'd0 ;

rx_int       <= 1'b0 ;

end

else if(start_bit_check)begin

num    <= 4'd0 ;        

rx_int <= 1'b0 ;

end

else if(bps_start_r) begin        //接收数据处理

if(clk_bps) begin        //读取并保存数据,接收数据为一个起始位,8bit数据,1或2个结束位                

num <= num+1'b1;

case (num)

4'd1: rx_temp_data[0] <= rs232_rx3;        //锁存第0bit

4'd2: rx_temp_data[1] <= rs232_rx3;        //锁存第1bit

4'd3: rx_temp_data[2] <= rs232_rx3;        //锁存第2bit

4'd4: rx_temp_data[3] <= rs232_rx3;        //锁存第3bit

4'd5: rx_temp_data[4] <= rs232_rx3;        //锁存第4bit

4'd6: rx_temp_data[5] <= rs232_rx3;        //锁存第5bit

4'd7: rx_temp_data[6] <= rs232_rx3;        //锁存第6bit

4'd8: rx_temp_data[7] <= rs232_rx3;        //锁存第7bit

default:;

endcase

end

else if(num == 4'd9) begin                //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据

  rx_int    <= 1'b1        ;

num       <= 4'd0        ;                                //接收到STOP位后结束,num清零

rx_data_r <= rx_temp_data;        //把数据锁存到数据寄存器rx_data中

end

end

else begin

rx_int  <= 1'b0 ;

num     <= 4'd0 ;        

end

assign rx_data = rx_data_r;        

endmodule

如果细心的朋友可以看到这里的speed_select和tx篇中的是一样的。所以在设计代码时,可以使用一个就可以了。