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篇中的是一样的。所以在设计代码时,可以使用一个就可以了。