Verilog——串口数据接收(状态机)

串口协议简介

串口时序图:

串口发送端口空闲时为高;
发送端口拉低表示数据传送即将开始;
字节数据低位先发;
字节发送后拉高,表示字节传送结束;
字节位宽可以不为8 ;
常用波特率有4800、9600、 1 15200等。

串口接收模块

RX为串口输入;

data_out为接收到的串口字节(8位);

每接收完成一个字节,en_data_out就产生一个同步脉冲;

用户见到en_data_out即可收数;

波特率为4800,系统时钟频率24MHz。

串口数据接收

空闲识别:一直为1,如果连续收到15个1,则一定在空闲状态。

找起始位:找下降沿

将下降沿(RX)做一个时钟周期的延时(RX_delay)

将RX反向,与RX_delay相与,得到一个尖。

看到这个尖,就知道起始位到了。

收数据:(数据中间比较可靠)

起始位等1.5T bit之后收b0,

        再过1T bit收b1,

        再过1T bit收b2,

.........

        一直收到b7。

这个字节收完,回到到起始位。

整个流程:

Verilog代码:

`timescale 1ns/10ps//testbench时间单位
module UART_RXer(
						clk,
						res,
						RX,
						data_out,
						en_data_out
						);

input					clk;
input					res;
input					RX;
output[7:0]		    data_out;//接收字节输出
output				en_data_out;//输出使能

reg[7:0]				state;//主状态机
reg[12:0]				con;//用于计算比特宽度;
//系统时钟频率24兆赫兹(24,000,000),支持4800波特率
//计数24000000/4800=5000(0001 0011 1000 1000),13位
//1.5倍宽度,5000*1.5=7500,算8000(0001 1111 0100 0000),13位
reg[4:0]				con_bits;//用于计算比特数,计转了多少圈

reg						RX_delay;//RX延时
reg                     en_data_out;

reg[7:0]			    data_out;

always@(posedge clk or negedge res)

if(~res)begin
	state<=0;con<=0;con_bits<=0;RX_delay<=0;
	data_out<=0;en_data_out;<=0;
end
else begin

RX_delay<=RX;//有时钟就在动,不需要条件


	case(state)
	0://等空闲,10个bit以上连续的1
	begin
			if(con==5000-1)begin
				con<=0;//计数转了一圈
			end
			else begin
				con<=con+1;
			end
			if(con==0)begin
				if(RX)begin
					con_bits<=con_bits+1;
				end
				else begin
					con_bits<=0;
				end
		end
		
		if(con_bits==12)begin
			state<=1;
		end
	end
	
	1://等起始位;
	begin
	en_data_out<=0;
		if(~RX&RX_delay)begin
			state<=2;
		end
	end
	2://收最低位b0;
	begin
			//要等1.5Tbit,5000*1.5=7500
			if(con==7500-1)begin
				con<=0;
				data_out[0]<=RX;
				state<=3;
			end
			else begin
				con<=con+1;		
			end
	end
	3://收最低位b1;
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[1]<=RX;
				state<=4;
			end
			else begin
				con<=con+1;		
			end
	end
	4://收最低位b2
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[2]<=RX;
				state<=5;
			end
			else begin
				con<=con+1;		
			end
	end
	5://收最低位b3
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[3]<=RX;
				state<=6;
			end
			else begin
				con<=con+1;		
			end
	end
	6://收最低位b4
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[4]<=RX;
				state<=7;
			end
			else begin
				con<=con+1;		
			end
	end
	7://收最低位b5
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[5]<=RX;
				state<=8;
			end
			else begin
				con<=con+1;		
			end
	end
	8://收最低位b6
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[6]<=RX;
				state<=9;
			end
			else begin
				con<=con+1;		
			end
	end
	9://收最低位b7
	begin
	//要等1Tbit,5000*1=5000
			if(con==5000-1)begin
				con<=0;
				data_out[7]<=RX;
				state<=10;
			end
			else begin
				con<=con+1;		
			end
	end
	10://产生使能脉冲
	begin
		en_data_out<=1;
		state<=1;
	end
	
	default://其他未定义状态
	begin
		state<=0;
		con<=0;
		con_bits<=0;
		en_data_out<=0;
	
	end
	
	
	endcase

end

endmodule

测试代码testbench:

//-------testbench-----------
module UART_RXer_tb;
reg						clk,res;
wire					RX;
wire[7:0]			    data_out;
wire					en_data_out;
//一个字节的数据(8位),里面有起始位和结束位(2位),带有16个1(16位),一共26位
reg[25:0]			    RX_send;//里面装有串口字节发送数据
assign				    RX=RX_send[0];//连接RX

reg[12:0]			    con;

//同名例化
//上面的量和下面的端口一一对应,而且名字完全一样,可以不打.和()
//例化很多的时候,用异名例化
UART_RXer UART_RXer(
							clk,
							res,
							RX,
							data_out,
							en_data_out
							);
initial begin
						clk<=0;res<=0;con<=0;
						RX_send<={1'b1,8'haa,1'b0,16'hffff};
//1‘b1结束位,8'haa发送的数据,1'b0起始位,16'hffff空闲位接收数据
		#17			    res<=1;
		#4000000		$stop;//仿真结束
end

always #5 clk<=~clk;

//发送数据
//连续右移
always@(posedge clk)begin

	if(con==5000-1)begin
		con<=0
	end
	else begin
		con<=con+1;
	end

	if(con==0)begin
		RX_send[24:0]<=RX_send[25:1];//低25位等于高25位,错开一项
		RX_send[25]<=RX_send[0];//反复右移旋转
	end
	
end

endmodule

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值