网站做水印有没有影响吗,自己做一个网页怎么做,商场设计总平面图,百度做公司网站多少钱UART 传输数据实验
通信方式在日常的应用中一般分为串行通信#xff08;serial communication#xff09;和并行通信#xff08;parallel communication#xff09;。 我们再来了解下串行通信的特点。串行通信是指数据在一条数据线上#xff0c;一比特接一比特地按顺序传…UART 传输数据实验
通信方式在日常的应用中一般分为串行通信serial communication和并行通信parallel communication。 我们再来了解下串行通信的特点。串行通信是指数据在一条数据线上一比特接一比特地按顺序传送的方式这一点与并行通信是不同的。这里我们以传输一个字节8 位数据为例在并行通信中一个字节的数据是在 8 条并行传输线上同时由源地传送到目的地而在串行通信中因为数据是在一条传输线上一位接一位地顺序传送的所以一个字节的数据要分 8 次进行传送。 如果我们以 T 为一个时间单位的话那么并行通信发送一个字节的数据只需要 1T 的时间而串行通信需要 8T 的时间由此可以总结出串行通信的的特点一是节省传输线大大降低了使用成本二是数据传送速度慢这一点在大位宽的数据传输上尤为明显。综上可知串行通信主要应用于长距离、低速率的通信场合。本次实验我们主要讲解下串行通信。 串行通信一般有 2 种通信方式同步串行通信synchronized serial communication和异步串行通信asynchronous serial communication。同步串行通信需要通信双方在同一时钟的控制下同步传输数据异步串行通信是指具有不规则数据段传送特性的串行数据传输。在常见的通信总线协议中I2CSPI 属于同步通信而 UART 属于异步通信。同步通信的通信双方必须先建立同步即双方的时钟要调整到同一个频率收发双方不停地发送和接收连续的同步比特流。异步通信在发送字符时发送端可以在任意时刻开始发送字符所以在 UART 通信中数据起始位和停止位是必不可少的。
UART 是一种采用异步串行通信方式的通用异步收发传输器universal asynchronous receiver-transmitter它在发送数据时将并行数据转换成串行数据来传输在接收数据时将接收到的串行数据转换成并行数据。 UART 串口通信需要两根信号线来实现一根用于串口发送另外一根负责串口接收如下图所示。对于 PC 来说它的 TX 要和对于 FPGA 来说的 RX 连接同样 PC 的 RX 要和 FPGA 的 TX 连接如果是两个TX 或者两个 RX 连接那数据就不能正常被发送出去或者接收到所以这里大家不要弄混。
UART 在发送或接收过程中的一帧数据由 4 部分组成起始位、数据位、奇偶校验位和停止位
起始位 当不传输数据时UART 数据传输线通常保持高电压电平。若要开始数据传输发送 UART 会将传输线从高电平拉到低电平并保持 1 个波特率周期。当接收 UART 检测到高到低电压跃迁时便开始以波特率对应的频率读取数据帧中的位。 数据帧 数据帧包含所传输的实际数据。如果使用奇偶校验位数据帧长度可以是 5 位到 8 位。如果不使用奇偶校验位数据帧长度可以是 9 位。在大多数情况下数据以最低有效位优先方式发送。 奇偶校验 奇偶性描述数字是偶数还是奇数。通过奇偶校验位接收 UART 判断传输期间是否有数据发生改变。电磁辐射、不一致的波特率或长距离数据传输都可能改变数据位。接收 UART 读取数据帧后将计数值为 1 的位检查总数是偶数还是奇数。如果奇偶校验位为 0偶数奇偶校验则数据帧中的 1 或逻辑高位总计应为偶数。如果奇偶校验位为 1奇数奇偶校验则数据帧中的 1 或逻辑高位总计应为奇数。当奇偶校验位与数据匹配时UART 认为传输未出错。但是如果奇偶校验位为 0而总和为奇数或者奇偶校验位为 1而总和为偶数则 UART 认为数据帧中的位已改变。 停止位 为了表示数据包结束发送 UART 将数据传输线从低电压驱动到高电压并保持 1 到 2 位时间。
UART 通信过程中的数据格式及传输速率是可设置的为了正确的通信收发双方应约定并遵循同样的设置。数据位可选择为 5、6、7、8 位其中 8 位数据位是最常用的在实际应用中一般都选择 8 位数据位校验位可选择奇校验、偶校验或者无校验位停止位可选择 1 位默认1.5 或 2 位。串口通信的速率用波特率表示它表示每秒传输二进制数据的位数单位是 bps位/秒常用的波特率有 9600、19200、38400、57600 以及 115200 等。
那么什么是波特率呢波特率即每秒传输的位数(bit)。一般选波特率都会有 960019200115200等选项。其实意思就是每秒传输这么多个比特位数(bit)。在信息传输通道中携带数据信息的信号单元叫作码元因为串口是 1bit 进行传输的所以其码元就代表一个二进制数每秒通过信号传输的码元数称为码元的传输速率简称“波特率”常用符号“Baud”表示其单位为“波特每秒”Bps。串口常见的波特率有 4800、9600、115200 等此处我们选用 115200 的波特率进行讲解。通信信道每秒传输的信息量称为位传输速率简称“比特率”其单位为“每秒比特数”bps。比特率可由波特率计算得出公式为比特率波特率×单个调制状态对应的二进制位数。如果使用的是 115200 的波特率其串口的比特率为 115200Bps×1bit 115200bps由计算得串口发送或者接收 1bit 数据的时间为一个波特即 1/115200s。 在设置好数据格式及传输速率之后UART 负责完成数据的串并转换而信号的传输则由外部驱动电路实现。电信号的传输过程有着不同的电平标准和接口规范针对异步串行通信的接口标准有 RS232、RS422、RS485 等它们定义了接口不同的电气特性如 RS-232 是单端输入输出而 RS-422/485 为差分输入输出等。RS-232 标准的串口最常见的接口类型为 DB9。
现在来说 对于这样的 大的接口 DB9 来说 现在并不实用 我们用的更多的是 USB的形式 通过 USB 在电脑上 装入USB转串口协议 完成实现功能
实验任务 本节实验任务是上位机通过串口调试助手发送数据给领航者开发板领航者开发板 PL 端通过USB_UART 串口接收数据并将接收到的数据发送给上位机完成串口数据环回。
下面是 发送端的 波形图
top.v
module uart_loopback(input sys_clk , //外部50MHz时钟input sys_rst_n, //系外部复位信号低有效//UART端口 input uart_rxd , //UART接收端口output uart_txd //UART发送端口);//parameter define
parameter CLK_FREQ 50000000; //定义系统时钟频率
parameter UART_BPS 115200 ; //定义串口波特率//wire define
wire uart_rx_done; //UART接收完成信号
wire [7:0] uart_rx_data; //UART接收数据//*****************************************************
//** main code
//*****************************************************//串口接收模块
uart_rx #(.CLK_FREQ (CLK_FREQ),.UART_BPS (UART_BPS)) u_uart_rx(.clk (sys_clk ),.rst_n (sys_rst_n ),.uart_rxd (uart_rxd ),.uart_rx_done (uart_rx_done),.uart_rx_data (uart_rx_data));//串口发送模块
uart_tx #(.CLK_FREQ (CLK_FREQ),.UART_BPS (UART_BPS)) u_uart_tx(.clk (sys_clk ),.rst_n (sys_rst_n ),.uart_tx_en (uart_rx_done),.uart_tx_data (uart_rx_data),.uart_txd (uart_txd ),.uart_tx_busy ( ));endmoduleuart_rx.v
module uart_rx(input clk , //系统时钟input rst_n , //系统复位低有效input uart_rxd , //UART接收端口output reg uart_rx_done, //UART接收完成信号output reg [7:0] uart_rx_data //UART接收到的数据);//parameter define
parameter CLK_FREQ 50000000; //系统时钟频率
parameter UART_BPS 115200 ; //串口波特率
localparam BAUD_CNT_MAX CLK_FREQ/UART_BPS; //为得到指定波特率对系统时钟计数BPS_CNT次//reg define
reg uart_rxd_d0;
reg uart_rxd_d1;
reg uart_rxd_d2;
reg rx_flag ; //接收过程标志信号
reg [3:0 ] rx_cnt ; //接收数据计数器
reg [15:0] baud_cnt ; //波特率计数器
reg [7:0 ] rx_data_t ; //接收数据寄存器//wire define
wire start_en;//*****************************************************
//** main code
//*****************************************************
//捕获接收端口下降沿(起始位)得到一个时钟周期的脉冲信号
assign start_en uart_rxd_d2 (~uart_rxd_d1) (~rx_flag);//针对异步信号的同步处理
always (posedge clk or negedge rst_n) beginif(!rst_n) beginuart_rxd_d0 1b0;uart_rxd_d1 1b0;uart_rxd_d2 1b0;endelse beginuart_rxd_d0 uart_rxd;uart_rxd_d1 uart_rxd_d0;uart_rxd_d2 uart_rxd_d1;end
end//给接收标志赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) rx_flag 1b0;else if(start_en) //检测到起始位rx_flag 1b1; //接收过程中标志信号rx_flag拉高//在停止位一半的时候即接收过程结束标志信号rx_flag拉低else if((rx_cnt 4d9) (baud_cnt BAUD_CNT_MAX/2 - 1b1))rx_flag 1b0;elserx_flag rx_flag;
end //波特率的计数器赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) baud_cnt 16d0;else if(rx_flag) begin //处于接收过程时波特率计数器baud_cnt进行循环计数if(baud_cnt BAUD_CNT_MAX - 1b1)baud_cnt baud_cnt 16b1;else baud_cnt 16d0; //计数达到一个波特率周期后清零end elsebaud_cnt 16d0; //接收过程结束时计数器清零
end//对接收数据计数器rx_cnt进行赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) rx_cnt 4d0;else if(rx_flag) begin //处于接收过程时rx_cnt才进行计数if(baud_cnt BAUD_CNT_MAX - 1b1) //当波特率计数器计数到一个波特率周期时rx_cnt rx_cnt 1b1; //接收数据计数器加1elserx_cnt rx_cnt;endelserx_cnt 4d0; //接收过程结束时计数器清零
end //根据rx_cnt来寄存rxd端口的数据
always (posedge clk or negedge rst_n) beginif(!rst_n) rx_data_t 8b0;else if(rx_flag) begin //系统处于接收过程时if(baud_cnt BAUD_CNT_MAX/2 - 1b1) begin //判断baud_cnt是否计数到数据位的中间case(rx_cnt)4d1 : rx_data_t[0] uart_rxd_d2; //寄存数据的最低位4d2 : rx_data_t[1] uart_rxd_d2;4d3 : rx_data_t[2] uart_rxd_d2;4d4 : rx_data_t[3] uart_rxd_d2;4d5 : rx_data_t[4] uart_rxd_d2;4d6 : rx_data_t[5] uart_rxd_d2;4d7 : rx_data_t[6] uart_rxd_d2;4d8 : rx_data_t[7] uart_rxd_d2; //寄存数据的高低位default : ;endcase endelserx_data_t rx_data_t;endelserx_data_t 8b0;
end //给接收完成信号和接收到的数据赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) beginuart_rx_done 1b0;uart_rx_data 8b0;end//当接收数据计数器计数到停止位且baud_cnt计数到停止位的中间时else if(rx_cnt 4d9 baud_cnt BAUD_CNT_MAX/2 - 1b1) beginuart_rx_done 1b1 ; //拉高接收完成信号uart_rx_data rx_data_t; //并对UART接收到的数据进行赋值end else beginuart_rx_done 1b0;uart_rx_data uart_rx_data;end
endendmoduleuart_tx.v
module uart_tx(input clk , //系统时钟input rst_n , //系统复位低有效input uart_tx_en , //UART的发送使能input [7:0] uart_tx_data, //UART要发送的数据output reg uart_txd , //UART发送端口output reg uart_tx_busy //发送忙状态信号);//parameter define
parameter CLK_FREQ 50000000; //系统时钟频率
parameter UART_BPS 115200 ; //串口波特率
localparam BAUD_CNT_MAX CLK_FREQ/UART_BPS; //为得到指定波特率对系统时钟计数BPS_CNT次//reg define
reg [7:0] tx_data_t; //发送数据寄存器
reg [3:0] tx_cnt ; //发送数据计数器
reg [15:0] baud_cnt ; //波特率计数器//*****************************************************
//** main code
//*****************************************************//当uart_tx_en为高时寄存输入的并行数据并拉高BUSY信号
always (posedge clk or negedge rst_n) beginif(!rst_n) begintx_data_t 8b0;uart_tx_busy 1b0;end//发送使能时寄存要发送的数据并拉高BUSY信号else if(uart_tx_en) begintx_data_t uart_tx_data;uart_tx_busy 1b1;end//当计数到停止位结束时停止发送过程else if(tx_cnt 4d9 baud_cnt BAUD_CNT_MAX - BAUD_CNT_MAX/4) begintx_data_t 8b0; //清空发送数据寄存器uart_tx_busy 1b0; //并拉低BUSY信号endelse begintx_data_t tx_data_t;uart_tx_busy uart_tx_busy;end
end//波特率的计数器赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) baud_cnt 16d0;//当处于发送过程时波特率计数器baud_cnt进行循环计数else if(uart_tx_busy) beginif(baud_cnt BAUD_CNT_MAX - 1b1)baud_cnt baud_cnt 16b1;else baud_cnt 16d0; //计数达到一个波特率周期后清零end elsebaud_cnt 16d0; //发送过程结束时计数器清零
end//tx_cnt进行赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) tx_cnt 4d0;else if(uart_tx_busy) begin //处于发送过程时tx_cnt才进行计数if(baud_cnt BAUD_CNT_MAX - 1b1) //当波特率计数器计数到一个波特率周期时tx_cnt tx_cnt 1b1; //发送数据计数器加1elsetx_cnt tx_cnt;endelsetx_cnt 4d0; //发送过程结束时计数器清零
end//根据tx_cnt来给uart发送端口赋值
always (posedge clk or negedge rst_n) beginif(!rst_n) uart_txd 1b1;else if(uart_tx_busy) begincase(tx_cnt) 4d0 : uart_txd 1b0 ; //起始位4d1 : uart_txd tx_data_t[0]; //数据位最低位4d2 : uart_txd tx_data_t[1];4d3 : uart_txd tx_data_t[2];4d4 : uart_txd tx_data_t[3];4d5 : uart_txd tx_data_t[4];4d6 : uart_txd tx_data_t[5];4d7 : uart_txd tx_data_t[6];4d8 : uart_txd tx_data_t[7]; //数据位最高位4d9 : uart_txd 1b1 ; //停止位default : uart_txd 1b1;endcaseendelseuart_txd 1b1; //空闲时发送端口为高电平
endendmoduleREADME.md
在 tx端的 36行 我们把显示出来 时序提前 四分之一
正点原子做了提前了 16分之一 我在实现的时候 传输的数据一直对不上
else if(tx_cnt 4d9 baud_cnt BAUD_CNT_MAX - BAUD_CNT_MAX/4) begin