赞
踩
串口系列知识分享:
(1)串口通信实现-串口发送
(2)串口通信发送多字节数据
(3)串口通信实现-串口接收
(4)UART 通信-使用VIO进行板级验证
(5)串口接收-控制LED闪烁
(6)使用串口发送实现ACX720开发板时钟显示
(7)串口发送+RAM+VGA传图
此文介绍uart串口协议(串口发送)的verilog实现和testbench的编写,仿真环境为vivado 2018.3。
提示:以下是本篇文章正文内容,下面案例可供参考
串口作为常用的三大低速总线(UART、SPI、IIC)之一,在设计众多通信接口和调试时占有重要地位。串口(UART)全称通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),主要用于数据间的串行传递,是一种全双工传输模式。它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。(具体应用可自行百度)
UART 在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如上图所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。
起始位:起始位标志。低有效。
数据位:一帧数据中的有效数据。注意,串口协议规定了数据位长度只能位 6 7 8 位。要想发多位数据,只能将其切分为多个过程发送。
奇偶校验位:是用来验证数据的正确性。奇偶校验一般不使用,如果 使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。其实就是发的时候如果奇校验位为1,表面数据中1的个数为奇数个,再看接受端的奇校验位是否依旧为1。如果是的话,校验成功。在一定概率上保证了传输的正确性。当然,只是概率上的传输正确。此次试验不同奇偶校验。
停止位:停止位标志着一帧数据的结束,高有效。
空闲时,传输 1 。
波特率设置 : 由于是异步通信,所以没有一个统一的时钟,需要双方约定传输传输速率。常见的波特率有:300, 1200, 2400, 9600, 19200, 115200 等.即一秒发送多少位数据。
所以我们需要实现下面的时序图。当使能信号到来时,发送起始位,数据位,停止位,一帧数据发送结束。
module uart_byte_tx( Clk, Reset_n, Data, Send_Go, // 改成单脉冲启动信号 启动一个内部 send_en 信号 Baud_set, uart_tx, Tx_done ); input Clk; input Reset_n; input [7:0]Data; input Send_Go; input [2:0]Baud_set; output reg uart_tx; output reg Tx_done; //Baud_set = 0 就让波特率 = 9600; //Baud_set = 1 就让波特率 = 19200 //Baud_set = 2 就让波特率 = 38400; //Baud_set = 3 就让波特率 = 57600; //Baud_set = 4 就让波特率 = 115200; reg [17:0]bps_DR; always@(*) case(Baud_set) 0:bps_DR = 1000000000/9600/20; 1:bps_DR = 1000000000/19200/20; 2:bps_DR = 1000000000/38400/20; 3:bps_DR = 1000000000/57600/20; 4:bps_DR = 1000000000/115200/20; default:bps_DR = 1000000000/9600/20; endcase reg Send_en; always@(posedge Clk or negedge Reset_n) if(!Reset_n) Send_en <= 0; else if(Send_Go) Send_en <= 1; else if(Tx_done) Send_en <= 0; reg [7:0]r_Data; always@(posedge Clk) //进行数据寄存,防止当Send_Go脉冲出现时,Data数据发生偏差 if(Send_Go) r_Data <= Data; else r_Data <= r_Data; wire bps_clk; assign bps_clk = (div_cnt == 1); reg [17:0]div_cnt; always@(posedge Clk or negedge Reset_n) if(!Reset_n) div_cnt <= 0; else if(Send_en)begin if(div_cnt == bps_DR - 1) div_cnt <= 0; else div_cnt <= div_cnt + 1'b1; end else div_cnt <= 0; reg [3:0]bps_cnt; always@(posedge Clk or negedge Reset_n) if(!Reset_n) bps_cnt <= 0; else if(Send_en)begin if(bps_clk)begin if(bps_cnt == 11) bps_cnt <= 0; else bps_cnt <= bps_cnt + 1'b1; end end else bps_cnt <= 0; always@(posedge Clk or negedge Reset_n) if(!Reset_n) begin uart_tx <= 1'b1; end else begin case(bps_cnt) 1:uart_tx <= 0; 2:uart_tx <= r_Data[0]; 3:uart_tx <= r_Data[1]; 4:uart_tx <= r_Data[2]; 5:uart_tx <= r_Data[3]; 6:uart_tx <= r_Data[4]; 7:uart_tx <= r_Data[5]; 8:uart_tx <= r_Data[6]; 9:uart_tx <= r_Data[7]; 10:uart_tx <= 1; 11:begin uart_tx <= 1;end default:uart_tx <= 1; endcase end always@(posedge Clk or negedge Reset_n) if(!Reset_n) Tx_done <= 0; else if((bps_clk == 1) && (bps_cnt == 10)) Tx_done <= 1; else Tx_done <= 0; endmodule
此模块用于对uart_byte_tx模块进行测试,将uart_byte_tx模块中的Data输入设为每次发送加1。即第一次发送8’d0,第二次发送8’d1,依次加1发送。
module uart_tx_test( Clk, Reset_n, uart_tx, ); input Clk; input Reset_n; output uart_tx; reg Send_Go; reg [7:0]Data; uart_byte_tx uart_byte_tx( .Clk(Clk), .Reset_n(Reset_n), .Data(Data), .Send_Go(Send_Go), .Baud_set(3'd4), .uart_tx(uart_tx), .Tx_done(Tx_done) ); reg [24:0]counter; always@(posedge Clk or negedge Reset_n) if(!Reset_n) counter <= 0; else if(counter == 4999999) //每10ms发送一次数据 counter <= 0; else counter <= counter + 1; always@(posedge Clk or negedge Reset_n) if(!Reset_n) Send_Go <= 0; else if(counter == 1) Send_Go <= 1; else Send_Go <= 0; always@(posedge Clk or negedge Reset_n) if(!Reset_n) Data <= 0; else if(Tx_done) Data <= Data + 1'b1; endmodule
`timescale 1ns / 1ps module uart_tx_test_tb(); reg Clk; reg Reset_n; wire uart_tx; uart_tx_test uart_tx_test( .Clk(Clk), .Reset_n(Reset_n), .uart_tx(uart_tx) ); initial Clk = 1; always#10 Clk = ~Clk; initial begin Reset_n = 0; #201; Reset_n = 1; #50000000; end endmodule
【附件:】链接:https://pan.baidu.com/s/1KNI2lWvdekhcJ-VJukWNeg?pwd=78h6
提取码:78h6
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。