前言
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在工作状态计数beginif(!rst_n)cnt <= 0;else if(state == 1)cnt <= cnt + 1;elsecnt <= 0;endalways@(posedge clk,negedge rst_n)beginif(!rst_n)state <= 0;elsecase(state)0: if(rxd == 0)//等待起始信号state <= 1;elsestate <= 0;1: if(cnt == 153)//完成一包数据接收state <= 0;elsestate <= 1;default:state <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)begintemp <= 0;down <= 0;data <= 0;endelsecase(cnt)0:begintemp <= 0;down <= 0;data <= data;end1*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:begindown <= 1;data <= temp;end9*16+7+1:down <= 0;endcaseendendmodule
发数据模块
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)//计数器在工作时进行计数beginif(!rst_n)cnt <= 0;else if(state == 1)//fifo不空,开始发送if(cnt < 10*16)cnt <= cnt + 1;elsecnt <= 0;elsecnt <= 0;endalways@(posedge clk,negedge rst_n)beginif(!rst_n)state <= 0;else case(state)0: if(done == 0)state <= 1;elsestate <= 0;1: if(cnt == 10*16)state <= 0;elsestate <= 1;default:state <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)rd_en <= 0;elsecase(cnt)0:rd_en <= 0;1:rd_en <= 1;2:rd_en <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)txd <= 1;elsecase(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;endcaseendendmodule