概述
目录
前言
1、UART串口的介绍
2、实验开始前一些参数的计算
3、UART通信的时序
4、代码部分
1、接收部分代码
2、发送部分的代码
前言
本篇文章是为了记录自己FPGA的学习过程,不完全正确,仅供参考!!!
1、UART串口的介绍
uart串口是我们常用的一种通讯协议,它的中文名称是通用异步收发传输器,像我们常见的RS232、RS485都是uart串口的一种,只不过是电平不同,通讯时序上都是一样的,像是RS232,只需要用MAX3232芯片进行电平转换就可以,那么uart串口既然是串行的通行协议,我们在使用的时候一般需要将并行数据转换成串行数据,这点需要注意,uart一般有四条线,VCC、GND、RX、TX,在使用的时候通讯双方一定要共地,因为其有tx和rx两根线,所以uart是全双工的通讯,但是uart是通讯速率比较慢的一种。
2、实验开始前一些参数的计算
首先我们需要知道波特率是啥,波特率就是表示uart串口传输速度的一个表示方式,常见的有4800、9600、115200,其实波特率就是uart串口传输一个bit数据所需要的时间,也是uart窗口工作时做基本的时间单位,时间=1/bound,我们在使用uart之前,需要约定好bound和奇偶效验位,本次实验以9600的波特率和无奇偶效验位来做,那么我需要知道约定好波特率之后,我们一个bit的数据需要保持相应的时间啊,那我们来计算下(1/9600)x10*9约等于10416ns,我们系统的时间周期为20ns,那么我们需要进行计数的值为5207(从0开始)
3、UART通信的时序
程序就是按照这个图中的时序写的,其中需要注意的是uart串口的空闲状态是高电平,起始位是一个bit的低电平(实际操作是我们可以去捕获下降沿),然后传输8位数据,先传输的是低位数据 ,然后是高位数据,在八位数据结束后,可以约定奇偶效验位,然后就是停止位和空闲状态,实际上直接拉高电平,就结束传送了,本实验室将接收的数据发送出去。
4、代码部分
1、接收部分代码
module uart_rx
(
input wire sys_clk,
input wire sys_rst,
input wire rx_data,
output reg [7:0] out_data,//串转并并输出
output reg out_reg//接收完成的标志
);
parameter [12:0] UART_MAX = 13'd5207,
[3:0] BIT_MAX = 4'd9;
reg [12:0] uart_cnt;//利用该计数器来计算不同波特率下传送一bit数据的时间
reg uart_data1; //打三拍的中间变量
reg uart_data2; //打三拍的中间变量
reg uart_data3; //打三拍的中间变量
reg begin_flag;//传输开始标志
reg data_en;//数据有效信号
reg [3:0] bit_cnt;//位数计数
wire data_flag;//该标记主要用于取中中间部分的数据,主要是中间数据较为稳定
reg [7:0] tx_data;
reg rx_end_flag;
/*波特率为9600时,当系统时钟为50MHZ的时候,这时每传输一个bit的数据,每个传输周期相当于5208个周期
所以这边需要一个计数器来计算出一个传输的周期(具体计数值为((1/bound)*10*9)/系统周期)这边的单位是ns*/
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
uart_cnt <= 13'd0;
else if((uart_cnt == UART_MAX)||(data_en == 1'd0))
uart_cnt <= 13'd0;
else
uart_cnt <= uart_cnt +13'd1;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
bit_cnt <= 4'd0;
else if((bit_cnt == BIT_MAX)&&(uart_cnt == UART_MAX))
bit_cnt <= 4'd0;
else if(uart_cnt == UART_MAX)
bit_cnt <= bit_cnt + 4'd1;
else
bit_cnt <= bit_cnt;
end
//对输入的数据打三拍这边一定要注意,uart串口空闲状态为高电平,开始标志为高电平到下降沿的一个下降沿,所以在给初值的时候,需要赋值为高电平
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
{uart_data3,uart_data2,uart_data1} <= 3'b111;
else
{uart_data3,uart_data2,uart_data1} <= {uart_data2,uart_data1,uart_data};
end
//因为空闲状态到开始的状态是一个下降沿,这边判断是下降沿就把开始标志置一
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
begin_flag <= 1'b0;
else if((uart_data2 == 1'b0)&&(uart_data3 == 1'b1)&&(data_en == 1'b0))
begin_flag <= 1'b1;
else
begin_flag <= 1'b0;
end
/*数据使能信号,因为我们判断开始信号是用下降沿来判断的,但是这可能产生一个误判,
因为串行数据传输的时候,也会产生下降沿,所以这里我们用data_en变量来辅助判断*/
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
data_en <= 1'b0;
else if(begin_flag == 1'b1)
data_en <= 1'b1;
else if((bit_cnt == 4'd9)&&(data_flag == 1'b1))
data_en <= 1'b0;
else
data_en <= data_en;
end
assign data_flag = ((bit_cnt >= 4'd1)&&(bit_cnt < 4'd9)&&(uart_cnt == 13'd2603))? 1'b1 : 1'b0;
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
tx_data <= 8'b0;
else if((data_flag == 1'b1))
tx_data <= {uart_data3,tx_data[7:1]};
else
tx_data <= tx_data;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
rx_end_flag <= 1'b0;
else if((bit_cnt == 4'd8)&&(data_flag == 1'b1))
rx_end_flag <= 1'b1;
else
rx_end_flag <= 1'b0;
end
/*开始我以为代码写到这里就结束了,但其实我还是太年轻了,为了使我们的输出的数据和输出的接收完成的标志信号同步(这样在标志有效的时候,读的数据才对)
其实上面的数据也是对齐的,但是为了养成一个良好的习惯,下面还是在同一条件下对数据和标志信号进行输出*/
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
out_data <= 8'b0;
else if(rx_end_flag == 1)
out_data <= tx_data;
else
out_data <= out_data;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
out_reg <= 1'b0;
else if(rx_end_flag == 1)
out_reg <= rx_end_flag;
else
out_reg <= 1'b0;
end
endmodule
2、发送部分的代码
module uart_tx
(
input wire sys_clk,
input wire sys_rst,
input wire [7:0] in_data,
input wire in_flag,//这个是rx模块输出的标志信号
output reg [7:0] tx_data
);
parameter [12:0] UART_MAX = 13'd5207,
[3:0] BIT_MAX = 4'd9;
reg [12:0] uart_cnt;//利用该计数器来计算不同波特率下传送一bit数据的时间
reg data_en;//数据有效信号
reg [3:0] bit_cnt;//位数计数
wire data_flag;//
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
uart_cnt <= 13'd0;
else if((uart_cnt <= UART_MAX)||(data_en == 1'b0))
uart_cnt <= 13'd0;
else
uart_cnt <= uart_cnt + 13'd1;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
bit_cnt <= 4'd0;
else if((uart_cnt == UART_MAX)&&(bit_cnt == BIT_MAX))
bit_cnt <= 4'd0;
else
bit_cnt <= bit_cnt +4'd1;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
data_en <= 1'b0;
else if(in_flag == 1'b1)
data_en <= 1'b1;
else if((bit_cnt == 4'd9) && (data_flag == 1'b1))
data_en <= 1'b0;
else
data_en <= data_en;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
data_flag <= 1'b0;
else if(uart_cnt == 13'd2605)
data_flag <= 1'b1;
else
data_flag <= 1'b0;
end
always@(posedge sys_clk)
begin
if(sys_rst == 1'b0)
data_flag <= 1'b0;
else if(data_flag == 1'b1)
case(bit_cnt)
4'd0 : tx_data <= 1'b0;
4'd1 : tx_data <= in_data[0];
4'd2 : tx_data <= in_data[1];
4'd3 : tx_data <= in_data[2];
4'd4 : tx_data <= in_data[3];
4'd5 : tx_data <= in_data[4];
4'd6 : tx_data <= in_data[5];
4'd7 : tx_data <= in_data[6];
4'd8 : tx_data <= in_data[7];
4'd9 : tx_data <= 1'b1;
default: tx_data <= 1'b1;
endcase
end
endmodule
最后
以上就是缥缈彩虹为你收集整理的FPGA-UART串口通信前言1、UART串口的介绍2、实验开始前一些参数的计算3、UART通信的时序4、代码部分的全部内容,希望文章能够帮你解决FPGA-UART串口通信前言1、UART串口的介绍2、实验开始前一些参数的计算3、UART通信的时序4、代码部分所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复