8 - 状态机代码设计与仿真
串口数据接收
波特率 VS 比特率:
在信息传输通道中,携带数据信息的信号单元叫码元。
每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。波特率是传输通道频宽的指标。
每秒钟通过信道传输的信息量称为位传输速率,简称比特率。比特率表示有效数据的传输速率。
比特率 = 波特率 * 单个调制状态对应的二进制位数。
UART:串行接口是指数据在有限的几个 IO 上按照顺序,一位一位的进行传输。这类有很多:UART、IIC、SPI、CAN、USB 等等,只要是串行传输的接口,都是串口的一种。但是由于早期人们都习惯把 UART 口称为串口,导致很多人都习惯了说串口的时候特指 UART 口。
识别空闲:可以连续收到 12 个 1。
起始位:等下降沿——反向延时之后相与,有脉冲。
代码:
//2021.11.22 lyw
//Serial port data receiving
`timescale 1ns/10ps
module UART_RXer (
clk,
res,
RX,
data_out,
en_data_out
);
input clk;
input res;
input RX;
output[7:0] data_out; //Receive byte input
output en_data_out; //Output enable
reg [7:0] state; //Main state machine
reg [12:0] con; //count Bit width
//24000000/4800=5000; 1.5*5000=7500=0001_1101_0100_1100 need 13 bits
reg [3:0] con_bits; //count bits
reg RX_delay; //relay of RX
reg [7:0] data_out;
reg en_data_out;
always @(posedge clk or negedge res) begin
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://wait free
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://wait start
begin
en_data_out<=0;
if (~RX&RX_delay) begin
state<=2;
end
end
2://receive b0
begin
if (con==7500-1) begin//wait 1.5T
con<=0;
data_out[0]<=RX;
state<=3;
end
else begin
con<=con+1;
end
end
3://receive b1
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[1]<=RX;
state<=4;
end
else begin
con<=con+1;
end
end
4://receive b2
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[2]<=RX;
state<=5;
end
else begin
con<=con+1;
end
end
5://receive b3
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[3]<=RX;
state<=6;
end
else begin
con<=con+1;
end
end
6://receive b4
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[4]<=RX;
state<=7;
end
else begin
con<=con+1;
end
end
7://receive b5
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[5]<=RX;
state<=8;
end
else begin
con<=con+1;
end
end
8://receive b6
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[6]<=RX;
state<=9;
end
else begin
con<=con+1;
end
end
9://receive b7
begin
if (con==5000-1) begin//wait 1T
con<=0;
data_out[7]<=RX;
state<=10;
end
else begin
con<=con+1;
end
end
10://Generate enable pulse
begin
en_data_out<=1;
state<=1;
end
default:
begin
state<=0;
con<=0;
con_bits<=0;
RX_delay<=0;
data_out<=0;
en_data_out<=0;
end
endcase
end
end
endmodule
//-----testbench of UART_RXer-----
module UART_RXer_tb ;
//Same name instantiation
reg clk,res;
reg RX;
wire [7:0] data_out;
wire en_data_out;
reg [25:0] RX_send; //Equipped with serial byte to send data
reg [12:0] con;
always @* begin
RX=RX_send[0];
end
//Connect RX
//assign RX=RX_send[0];
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};
#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];
RX_send[25]<=RX_send[0];
end
end
endmodule
tips:
一定义了寄存器就要想复位。
同名例化:名字必须相同,不用打点加括号,当例化很多个时需要用异名例化。
关键:
RX_delay<=RX; RX_delay 用上一个时钟的 RX 来表示,自带延时意义。
原因:在时钟沿赋值而不是直接 assign 赋值的,所以 RX_delay 就比 RX 晚了一个时钟周期。
产生使能信号就是冒个尖。
串口发送—>右移,循环右移的实现方式:RX_send[24:0]<=RX_send[25:1]; RX_send[25]<=RX_send[0];
RX_send[0] 不会被覆盖,因为非阻塞赋值语句是并行的。
仿真波形: