串口协议简介
串口时序图:
串口发送端口空闲时为高;
发送端口拉低表示数据传送即将开始;
字节数据低位先发;
字节发送后拉高,表示字节传送结束;
字节位宽可以不为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