我是靠谱客的博主 欣喜红牛,最近开发中收集的这篇文章主要介绍用Verilog写一个串口接收程序异步串口通信协议串口接收原理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

用Verilog写一个异步串口UART接收程序

  • 异步串口通信协议
  • 串口接收原理
    • 接收流程
    • 状态机流图
    • RTL图
    • 源代码

异步串口通信协议

信息帧从一个低电平起始位开始,后面是5个至8个数据位(这里串口助手可以调),一个可选的奇偶校验位和1个或几个高电平停止位。

串口接收原理

假设串口的波特率是115200bps(波特率是指1秒最大传输的数据位数),这里为了提高接收机的抗干扰能力,采用8倍发射波特率的时钟去接收数据。对于一位数据,在接收时钟下如果接收到的’0’的数量多于’1’的数量,则判定为’0’,否则判定为’1’。

接收流程

  1. 首先将接收到的数据与接收时钟对其,这里可以用D触发器实现。
  2. 判断下降沿的到来:当检测到第一个低电平时,状态机状态将从R_IDLE跳到R_START状态。
  3. R_START状态中判断接下来的几个时钟是否是’0’多于’1’。如果是,则表明起始位的到来,并跳转到R_RECV状态。
  4. R_RECV中设置一个计数器,用于接收一定数量的数据位,接收完成后跳转到R_STOP状态。(这里没有用到奇偶校验位)
  5. 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写一个串口接收程序异步串口通信协议串口接收原理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部