您的位置:首页 > 其它

基于FPGA Uart串口通信实验

2017-09-04 19:16 651 查看

基于FPGA Uart串口通信实验

首先需要了解uart串口通信协议,根据个人专业需求不同,了解的层面可以不同。

UART简介

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。UART通信在工作中相当常见,项目中需要生成uart信号,在博客中记录下。uart是异步通信,因为它只有一根线就可以数据的通信。不像SPI,I2C等同步传输信号。所以串口的传输速度和其它协议的速度相比是比较慢的。下面具体讲解一些uart协议以及是如何通信的。

一些概念意义

波特率:此参数容易和比特率混淆,其实他们是由区别的。具体可以百度更清楚。但是我认为uart中的波特率就可以认为是比特率,即每秒传输的位数(bit)。一般选波特率都会有9600,19200,115200等选项。其实意思就是每秒传输这么多个比特位数(bit)。

起始位:先发出一个逻辑”0”信号,表示传输字符的开始。

数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。一般情况下都选择8位而不选择7,因为这样能尽可能避免数据的丢失或者混乱。小端传输(即从LSB_D0端开始发送数据,而且是串行发送)。

校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)

停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。

空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。



注意:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)

时钟程序

`timescale 1ns/1ps
module clkdiv(clk50,rst_n,clkout);
input clk50;  //系统时钟
input rst_n;
output clkout;

reg clkout;
reg [15:0] cnt;
/////分频进程, 50Mhz 的时钟 27 分频/////////
/*计算过程
波特率115200bps
每个bit接收的数据有16个时钟采样
则分频数为:50_000_000/115200/16=27.13
约为27分频
*/
always @(posedge clk50 or negedge rst_n)
begin
if (!rst_n)
begin
clkout <=1'b0;
cnt<=0;
end
else if(cnt == 16'd13)
begin
clkout <= 1'b1;
cnt <= cnt + 16'd1;
end
else if(cnt == 16'd27)
begin
clkout <= 1'b0;
cnt <= 16'd0;
end
else
begin
cnt <= cnt + 16'd1;
end
end
endmodule


串口发送程序

`timescale 1ns/1ps
module uarttx(clk, rst_n, datain, wrsig, idle, tx);
input clk; //UART 时钟
input rst_n; //系统复位
input [7:0] datain; //需要发送的数据
input wrsig; //发送命令,上升沿有效
output idle; //线路状态指示,高为线路忙,低为线路空闲
output tx; //发送数据信号
reg idle, tx;
reg send;
reg wrsigbuf, wrsigrise;
reg presult;
reg[7:0] cnt; //计数器

parameter paritymode = 1'b0;
////////////////////////////////////////////////////////////////
//检测发送命令 wrsig 的上升沿
////////////////////////////////////////////////////////////////

always @(posedge clk)
begin
wrsigbuf <= wrsig;
wrsigrise <= (~wrsigbuf) & wrsig;
end
////////////////////////////////////////////////////////////////
//启动串口发送程序
////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
if (wrsigrise && (~idle)) //当发送命令有效且线路为空闲时,启动新的数据发送进程
begin
send <= 1'b1;
end
else if(cnt == 8'd168) //一帧数据发送结束
begin
send <= 1'b0;
end
end
////////////////////////////////////////////////////////////////
//串口发送程序, 16 个时钟发送一个 bit
////////////////////////////////////////////////////////////////
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
tx <= 1'b0;
idle <= 1'b0;
cnt<=8'd0;
presult<=1'b0;
end
else if(send == 1'b1)
begin
case(cnt) //产生起始位
8'd0:
begin
tx <= 1'b0;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd16:
begin
tx <= datain[0]; //发送数据 0 位
presult <= datain[0]^paritymode;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd32:
begin
tx <= datain[1]; //发送数据 1 位
presult <= datain[1]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd48:
begin
tx <= datain[2]; //发送数据 2 位
presult <= datain[2]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd64:
begin
tx <= datain[3]; //发送数据 3 位
presult <= datain[3]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd80:
begin
tx <= datain[4]; //发送数据 4 位
presult <= datain[4]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd96:
begin
tx <= datain[5]; //发送数据 5 位
presult <= datain[5]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd112:
begin
tx <= datain[6]; //发送数据 6 位
presult <= datain[6]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd128:
begin
tx <= datain[7]; //发送数据 7 位
presult <= datain[7]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd144:
begin
tx <= presult; //发送奇偶校验位
presult <= datain[0]^paritymode;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd160:
begin
tx <= 1'b1; //发送停止位
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd168:
begin
tx <= 1'b1;
idle <= 1'b0; //一帧数据发送结束
cnt <= cnt + 8'd1;
end
default:
begin
cnt <= cnt + 8'd1;
end
endcase
end
else
begin
tx <= 1'b1;
cnt <= 8'd0;
idle <= 1'b0;
end
end
endmodule


测试模块程序

`timescale 1ns / 1ps
module testuart(clk, rst_n, dataout, wrsig);
input clk;
input rst_n;
output[7:0] dataout;
output wrsig;
reg [7:0] dataout;
reg wrsig;
reg [7:0] cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<=8'd0;
wrsig<=1'b0;
end
else
begin
if(cnt == 254)
begin
dataout <= dataout + 8'd1; //每次数据加“1”
wrsig <= 1'b1; //产生发送命令
cnt <= 8'd0;
end
else
begin
wrsig <= 1'b0;
cnt <= cnt + 8'd1;
end
end
end
endmodule


创建并编译顶层文件



实验结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  fpga 串口通信