UART双向通信实现(序列机)
前言
UART(通用异步收发传输器)是一种串行通信协议,用于在电子设备之间进行数据传输。RS232是UART协议的一种常见实现标准,广泛应用于计算机和外围设备之间的通信。它定义了串行数据的传输格式和电气特性,以确保不同设备之间的兼容性和可靠性。RS232协议采用异步串行通信方式,通过数据线将并行数据转换为串行数据进行传输,接收端再将串行数据恢复为并行数据。RS232的标准包括信号电平、连接器类型和数据格式等规范,确保了设备之间的正确通信。它的常见应用包括计算机串口、调制解调器、打印机等设备的连接。
UART通信实现与验证(RS232)
正文
一、UART双向通信实现(序列机)的设计验证
1.项目需求
完成9600波特率串口的数据收发实验
2.技术介绍
采用序列机架构,使用锁相环产生一个16倍9600波特率的时钟,当该时钟计数到16时,表示串口数据发送的1bit数据传输完成(即1bit数据在计数0时放置与txd数据线上,在16时完成该数据传输,下次计数0时传输下1bit数据)。为保证数据接收正常,数据接收需要在9600波特率的时钟的周期中心接收,对应16倍时钟,在计数器到7或8的时刻进行数据接收。
为完成数据收发实验,将接收的数据在发送出去,完成数据回环,可以通过上位机去观察接收的数据是否完整以此验证实验成功。
涉及到数据传递,虽然时钟相同但是正常情况需要进行数据缓存(建议,如果是异步时钟,必须进行数据缓存),常用的数据缓存有异步fifo,双口ram(本实验实验异步fifo)
3.顶层架构
4.端口描述
clk | 时钟接口(50Mhz) |
rst_n | 复位按键(低电平有效) |
rxd | 数据接收接口 |
txd | 数据发送接口 |
二、代码验证
顶层连线
module uart_tx_rx(
input clk ,
input rst_n ,
input rxd ,
output txd
);
wire clk_01536;
wire rst_en;
clk_uart clk_uart_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( clk_01536 ),
.locked ( rst_en )
);
wire[7:0]data,q_sig;
wire rdempty,rdreq,down;
uart_rx rx(
.clk (clk_01536 ),
.rst_n (rst_en ),
.rxd (rxd ),//数据接收
.data (data ),//接收数据打包
.down (down ) //输出有效
);
fifo fifo_inst (
.data (data ),
.rdclk (clk_01536 ),
.rdreq (rdreq ),
.wrclk (clk_01536 ),
.wrreq (down ),
.q (q_sig ),
.rdempty (rdempty ),
.wrfull ( )
);
uart_txd_v1 tx(
.clk (clk_01536 ),
.rst_n (rst_en ),
.data (q_sig ),
.done (rdempty ),
.txd (txd ),
.rd_en (rdreq )
);
endmodule
收数据模块
module uart_rx(
input clk ,
input rst_n ,
input rxd ,//数据接收
output reg[7:0]data ,//接收数据打包
output reg down //输出有效
);
reg state;
reg [7:0]temp;
reg [7:0]cnt;
always@(posedge clk,negedge rst_n)//cnt在工作状态计数
begin
if(!rst_n)
cnt <= 0;
else if(state == 1)
cnt <= cnt + 1;
else
cnt <= 0;
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
state <= 0;
else
case(state)
0: if(rxd == 0)//等待起始信号
state <= 1;
else
state <= 0;
1: if(cnt == 153)//完成一包数据接收
state <= 0;
else
state <= 1;
default:state <= 0;
endcase
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
begin
temp <= 0;
down <= 0;
data <= 0;
end
else
case(cnt)
0:
begin
temp <= 0;
down <= 0;
data <= data;
end
1*16+7:temp[0] <= rxd;//在每个时序的中间收数据,数据在N*16时放在rxd上,保证数据稳定,在N*16 + 7时读
2*16+7:temp[1] <= rxd;
3*16+7:temp[2] <= rxd;
4*16+7:temp[3] <= rxd;
5*16+7:temp[4] <= rxd;
6*16+7:temp[5] <= rxd;
7*16+7:temp[6] <= rxd;
8*16+7:temp[7] <= rxd;
9*16+7:
begin
down <= 1;
data <= temp;
end
9*16+7+1:down <= 0;
endcase
end
endmodule
发数据模块
module uart_txd(//fifo不为空时发
input clk ,//0.1536 = 9600 * 16 = 153600hz = 0.1536Mhz
input rst_n ,
input [7:0] data ,
input done ,
output reg txd ,
output reg rd_en
);
reg [7:0]temp;
reg [7:0]cnt;
reg state;
always@(posedge clk,negedge rst_n)//计数器在工作时进行计数
begin
if(!rst_n)
cnt <= 0;
else if(state == 1)//fifo不空,开始发送
if(cnt < 10*16)
cnt <= cnt + 1;
else
cnt <= 0;
else
cnt <= 0;
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
state <= 0;
else case(state)
0: if(done == 0)
state <= 1;
else
state <= 0;
1: if(cnt == 10*16)
state <= 0;
else
state <= 1;
default:state <= 0;
endcase
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
rd_en <= 0;
else
case(cnt)
0:rd_en <= 0;
1:rd_en <= 1;
2:rd_en <= 0;
endcase
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
txd <= 1;
else
case(cnt)
0:txd <= 1;
1:txd <= 0;//起始位
3:temp <= data;
1*16:txd <= temp[0];//数据在时序开始时放在txd,
2*16:txd <= temp[1];
3*16:txd <= temp[2];
4*16:txd <= temp[3];
5*16:txd <= temp[4];
6*16:txd <= temp[5];
7*16:txd <= temp[6];
8*16:txd <= temp[7];
9*16:txd <= 1;
endcase
end
endmodule