概述
用Verilog写一个异步串口UART接收程序
- 异步串口通信协议
- 串口接收原理
- 接收流程
- 状态机流图
- RTL图
- 源代码
异步串口通信协议
信息帧从一个低电平起始位开始,后面是5个至8个数据位(这里串口助手可以调),一个可选的奇偶校验位和1个或几个高电平停止位。
串口接收原理
假设串口的波特率是115200bps(波特率是指1秒最大传输的数据位数),这里为了提高接收机的抗干扰能力,采用8倍发射波特率的时钟去接收数据。对于一位数据,在接收时钟下如果接收到的’0’的数量多于’1’的数量,则判定为’0’,否则判定为’1’。
接收流程
- 首先将接收到的数据与接收时钟对其,这里可以用D触发器实现。
- 判断下降沿的到来:当检测到第一个低电平时,状态机状态将从R_IDLE跳到R_START状态。
- 在R_START状态中判断接下来的几个时钟是否是’0’多于’1’。如果是,则表明起始位的到来,并跳转到R_RECV状态。
- 在R_RECV中设置一个计数器,用于接收一定数量的数据位,接收完成后跳转到R_STOP状态。(这里没有用到奇偶校验位)
- 在R_STOP状态中接收停止位,接收完成则重新跳回R_IDLE状态,等待下一帧数据。
状态机流图
RTL图
源代码
module receive(
input clk_8uart,
input rxd,
output rxd_ena,
output[7:0] rxd_data
);
reg rxd_delay;
reg[3:0] state; //控制状态转换
reg[3:0] rxd_cnt; //计时钟点数
reg[3:0] zero_cnt; //检测0的数量
reg[3:0] one_cnt; //检测1的数量
reg[3:0] bit_cnt; //8bit计数器
reg[7:0] rxd_output;
reg rxd_finish; //指示一个字节接收完成
localparam R_IDLE = 4'b0001;
localparam R_BEGIN = 4'b0010;
localparam R_RECV = 4'b0100;
localparam R_STOP = 4'b1000;
//*********与接收时钟对齐**********
always@(posedge clk_8uart)
begin
rxd_delay <= rxd;
end
//*********状态转换**********
always@(posedge clk_8uart)
begin
case(state)
R_IDLE: //空闲状态,等待下降沿
begin
rxd_finish <= 1'b0;
bit_cnt <= 4'd0;
rxd_output <= 8'd0;
if(rxd_delay == 1'b0)
begin
state <= R_BEGIN;
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
end
else
state <= R_IDLE;
end
R_BEGIN: //接收到下降沿后,判断是否是起始位(1bit低电平)
begin
if(rxd_delay == 1'b0)
zero_cnt <= zero_cnt + 4'd1;
else
one_cnt <= one_cnt + 4'd1;
if(rxd_cnt >= 4'd6)
begin
if(zero_cnt > one_cnt)
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
state <= R_RECV;
end
else
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
state <= R_IDLE;
end
end
else
rxd_cnt <= rxd_cnt + 4'd1;
end
R_RECV: //开始接收8bit数据
begin
if(rxd_delay == 1'b0)
zero_cnt <= zero_cnt + 4'd1;
else
one_cnt <= one_cnt + 4'd1;
if(rxd_cnt >= 4'd7)
begin
if(zero_cnt > one_cnt)
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
rxd_output[bit_cnt] <= 1'b0;
end
else
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
rxd_output[bit_cnt] <= 1'b1;
end
if(bit_cnt < 4'd7)
begin
bit_cnt <= bit_cnt + 4'd1;
state <= R_RECV;
end
else
begin
bit_cnt <= 4'd0;
state <= R_STOP;
end
end
else
rxd_cnt <= rxd_cnt + 4'd1;
end
R_STOP: //接受完8bit数据,接收停止位
begin
if(rxd_delay == 1'b0)
zero_cnt <= zero_cnt + 4'd1;
else
one_cnt <= one_cnt + 4'd1;
if(rxd_cnt >= 4'd7)
begin
if(zero_cnt > one_cnt)
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
rxd_finish <= 1'b0;
state <= R_IDLE;
end
else
begin
rxd_cnt <= 4'd0;
zero_cnt <= 4'd0;
one_cnt <= 4'd0;
rxd_finish <= 1'b1;
state <= R_IDLE;
end
end
else
rxd_cnt <= rxd_cnt + 4'd1;
end
default: state <= R_IDLE;
endcase
end
assign rxd_ena = rxd_finish;
assign rxd_data = rxd_output;
endmodule
总体思路如上,如要加入额外功能,可在此基础上修改。(比如要接收奇偶校验位,并判断接收信息是否正确。)
最后
以上就是欣喜红牛为你收集整理的用Verilog写一个串口接收程序异步串口通信协议串口接收原理的全部内容,希望文章能够帮你解决用Verilog写一个串口接收程序异步串口通信协议串口接收原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复