FPGA verilog uart串口收发代码ART波形图如下图所示,最简单的一种形式:1位起始位(低),8位数据位,1位停止位(高)。UART没有同步时钟,按照约定好的时间(波特率)进行间隔采样。
1, UART 数据发送模块
只需按照上图所示的波形图把需要传输的数据输出即可,由于发射时钟和系统时钟同步,我们使用一个计数器对50MHz系统时钟分频产生发送数据时钟。建立一个发送状态机,共四种状态,在每个状态输出相应的信息。
本模块为了方便调试,输出一个闪烁灯,按下一个键,发送一个固定的数据。代码如下:
module UART_TX(
tx,
rx,
sw0...
ART波形图如下图所示,最简单的一种形式:1位起始位(低),8位数据位,1位停止位(高)。UART没有同步时钟,按照约定好的时间(波特率)进行间隔采样。
1, UART 数据发送模块
只需按照上图所示的波形图把需要传输的数据输出即可,由于发射时钟和系统时钟同步,我们使用一个计数器对50MHz系统时钟分频产生发送数据时钟。建立一个发送状态机,共四种状态,在每个状态输出相应的信息。
本模块为了方便调试,输出一个闪烁灯,按下一个键,发送一个固定的数据。代码如下:
module UART_TX(
tx,
rx,
sw0,
sendkey0,
clk,
rst,
led
);
output tx;
input rx;
input [3:0] sw0;
input sendkey0;
input clk,rst;
output led;
//output discribe
reg led;
reg tx;
// baud rate:38400
parameter UART_CLK_DIV =50000000/38400/2;//额外的/2是因为产生时钟使用了~方式
//发送数据状态机
parameter sstate_idle =0;
parameter sstate_begin =1;
parameter sstate_sdat =2;
parameter sstate_end =3;
reg [2:0] curstate; //当前状态
reg [7:0] senddata; //需要发送的数据
reg [3:0] tosendcnt; //需要发送计数器计数
reg [3:0] alsendcnt; //已经发送数据计数
reg sendclk; //数据发送时钟
reg [15:0] clk_divcnt; //发送时钟分频计数器
reg [2:0] bitcnt; //发送数据的位选择
//产生发送数据的对应时钟
always@(posedgeclk, negedgerst)begin
if(!rst)begin
sendclk<=1'b0;
clk_divcnt<=0;
end else begin
if(clk_divcnt==UART_CLK_DIV-1)begin
clk_divcnt<=0;
sendclk<=~sendclk;
end else begin
clk_divcnt<=clk_divcnt+1;
end
end
end
//状态转换
always@(posedgesendclk,negedgerst)begin
if(!rst)begin
alsendcnt<=0;
curstate<=sstate_idle;
end else begin
case(curstate)
sstate_idle:begin
if(alsendcnt!=tosendcnt)begin // have data to send
alsendcnt<=alsendcnt+1; // count the number have send
curstate<=sstate_begin;
end else begin
curstate<=sstate_idle;
end
end
sstate_begin:begin
curstate<=sstate_sdat;
bitcnt<=3'b0;
senddata<=sw0+8'd97; // get the data to send
end
sstate_sdat:begin
if(bitcnt==7)begin
curstate<=sstate_end;
end else begin
bitcnt<=bitcnt+1;
end
end
sstate_end:begin
curstate<=sstate_idle;
end
default:curstate<=sstate_idle;
endcase
end
end
//输出数据
always@(*)begin
if(~rst)tx<=1;
else begin
case(curstate)
sstate_idle:begin
tx<=1;
end
sstate_begin:begin
tx<=1'b0;
end
sstate_sdat:begin
tx<=senddata[bitcnt];
end
sstate_end:begin
tx<=1'b1;
end
endcase
end
end
//按下一个键发送一个数据
always@(posedge sendkey0, negedgerst)begin
if(!rst)begin
tosendcnt<=0;
end else begin
tosendcnt<=tosendcnt+1'b1;
end
end
// led debug use
reg [31:0] ledcnt;
always@(posedgeclk,negedgerst)begin
if(!rst)begin
ledcnt<=0;
led<=1'b1;
end else begin
if(ledcnt<20000000)begin
ledcnt<=ledcnt+1'b1;
end else begin
led<=~led;
ledcnt<=0;
end
end
end
endmodule
2, UART数据接收模块
由于不清楚何时数据到达,即时钟并不同步,使用和串口一样的时钟来判断输入数据并不适合。这里为了稳定,在每个数据波形的中间进行采样。代码如下:
module UART_RX(
tx,
rx,
hex1,//使用数码管显示收到的数据
hex0,
clk,
rst,
led
);
output tx;
input rx;
output [6:0] hex1,hex0;
input clk,rst;
output led;
//output declaration
reg led;
reg [7:0] dispdat;
assign tx =1'b1;
// baud rate:38400
//
parameter UART_CLK_DIV =50000000/38400;//需要分频比例
//状态
parameter rstate_idle =0;
parameter rstate_beginq =1;//是否真的有数据传输
parameter rstate_begin =2;
parameter rstate_rdata =3;
parameter rstate_end =4;
reg [2:0] curstate;
reg [15:0] clkcnt;
reg [2:0] bitcnt;
reg [7:0] recdata;
always@(posedgeclk, negedgerst)begin
if(!rst)begin
curstate<=rstate_idle;
clkcnt<=0;
end else begin
case(curstate)
rstate_idle:begin
if(~rx)begin
curstate<=rstate_beginq;
bitcnt<=0;
clkcnt<=0;
recdata<=0;
end else
curstate<=rstate_idle;
end
rstate_beginq:begin
if(clkcnt==UART_CLK_DIV/2-1)begin//1/2是为了在每个波形的中间进行判断
clkcnt<=0;
if(~rx)begin
curstate<=rstate_rdata;
end else begin
curstate<=rstate_idle;
end
end else begin
clkcnt<=clkcnt+1'b1;
end
end
rstate_rdata:begin
if(clkcnt==UART_CLK_DIV-1)begin
clkcnt<=0;
recdata[bitcnt]<=rx;
if(bitcnt==7)begin
curstate<=rstate_end;
end else begin
bitcnt<=bitcnt+1'b1;
end
end else begin
clkcnt<=clkcnt+1'b1;
end
end
rstate_end:begin
if(clkcnt==UART_CLK_DIV-1)begin
clkcnt<=0;
curstate<=rstate_idle;
end else begin
clkcnt<=clkcnt+1'b1;
end
end
default:curstate<=rstate_idle;
endcase
end
end
always@(curstate,bitcnt)begin
case(curstate)
rstate_rdata:begin
end
rstate_end:begin
dispdat<=recdata;/////////////debug
end
default:begin
end
endcase
end
// led debug use
reg [31:0] ledcnt;
always@(posedgeclk,negedgerst)begin
if(!rst)begin
ledcnt<=0;
led<=1'b1;
end else begin
if(ledcnt<20000000)begin
ledcnt<=ledcnt+1'b1;
end else begin
led<=~led;
ledcnt<=0;
end
end
end
SEG7 seg1(
.oSEG(hex1),
.Sel(dispdat[7:4]));
SEG7 seg0(
.oSEG(hex0),
.Sel(dispdat[3:0]));
endmodule
本文档为【FPGA verilog uart串口收发代码】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。