基于fpga的uart实验报告
1. 整体思路
1.1设计总框图:
1.2设计RTL视图
2. 模块电路介绍与说明
2.1 UART分频器
根据波特率要求,对时钟进行分频操作从而实现正常的通信。 module speed_select(
);
clk,rst_n,
bps_start,clk_bps
input clk; // 12MHz主时钟
input rst_n; //低电平复位信号 input bps_start; //接收到数据后,波特率时钟启动信号置位 output clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点
/*
parameter
bps9600 = 5207, //波特率为9600bps
bps19200 = 2603, //波特率为19200bps bps38400 bps57600 bps115200
= 1301, //波特率为38400bps = 867, = 433;
//波特率为57600bps //波特率为115200bps
parameter
bps9600_2 = 2603, bps19200_2 = 1301, bps38400_2 = 650, bps57600_2 = 433, bps115200_2 = 216;
*/
//以下波特率分频计数值可参照上面的参数进行更改
`define BPS_PARA 5207 //波特率为9600时的分频计数值 `define BPS_PARA_2 2603 //波特率为9600时的分频计数值的一半,用于数据采样
reg[12:0] cnt; reg clk_bps_r;
//分频计数
//波特率时钟寄存器
//---------------------------------------------------------- reg[2:0] uart_ctrl; // uart波特率选择寄存器 //----------------------------------------------------------
always @ (posedge clk or negedge rst_n) if(!rst_n) cnt <= 13'd0; else if((cnt == `BPS_PARA) || !bps_start) cnt <= 13'd0; //波特率计数清零 else cnt <= cnt+1'b1; //波特率时钟计数启动
always @ (posedge clk or negedge rst_n) if(!rst_n) clk_bps_r <= 1'b0; else if(cnt == `BPS_PARA_2) clk_bps_r <= 1'b1; // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点
else clk_bps_r <= 1'b0;
assign clk_bps = clk_bps_r;
endmodule
2.2 UART数据发送模块
UART发送模块功能:接收到发送指令以后,把数据按UART协议格式输出,先输出一个电平的起始位,然后从低到高传送八位的数据位,最后传送结束位,其verliog代码如下:
module my_uart_tx( clk,rst_n,
);
// 12MHz主时钟 rx_data,rx_int,rs232_tx, clk_bps,bps_start
input clk;
input rst_n; input clk_bps; //低电平复位信号 // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送
数据的数据改变点
input[7:0] rx_data; //接收数据寄存器 input rx_int; //接收数据中断信号,接收到数据期间始终为高电平,在该模块中利用它的下降沿来启动串口发送数据
output rs232_tx; // RS232发送数据信号
output bps_start; //接收或者要发送数据,波特率时钟启动信号置位
//---------------------------------------------------------
reg rx_int0,rx_int1,rx_int2; //rx_int信号寄存器,捕捉下降沿滤波用 wire neg_rx_int; // rx_int下降沿标志位
always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin
rx_int0 <= 1'b0; rx_int1 <= 1'b0; rx_int2 <= 1'b0;
end else begin
rx_int0 <= rx_int; rx_int1 <= rx_int0;
end
rx_int2 <= rx_int1; end
assign neg_rx_int = ~rx_int1 & rx_int2; //捕捉到下降沿后,neg_rx_int拉高保持一个主时钟周期
//--------------------------------------------------------- reg[7:0] tx_data; //待发送数据的寄存器 //--------------------------------------------------------- reg bps_start_r;
reg tx_en; //发送数据使能信号,高有效 reg[3:0] num;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin bps_start_r <= 1'bz;
tx_en <= 1'b0; tx_data <= 8'd0;
end
else if(neg_rx_int) begin //接收数据完毕,准备把接收到的数据发回去
bps_start_r <= 1'b1;
tx_data <= rx_data; //把接收到的数据存入发送数据寄存器 tx_en <= 1'b1; //进入发送数据状态中
//数据发送完成,复位
end
else if(num==4'd11) begin
end
bps_start_r <= 1'b0; tx_en <= 1'b0;
end
assign bps_start = bps_start_r;
//--------------------------------------------------------- reg rs232_tx_r;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin num <= 4'd0;
rs232_tx_r <= 1'b1;
end
else if(tx_en) begin
if(clk_bps)
begin num <= num+1'b1;
case (num) 4'd0: rs232_tx_r <= 1'b0; //发送起始位 4'd1: rs232_tx_r <= tx_data[0]; //发送bit0
end
4'd2: rs232_tx_r <= tx_data[1]; 4'd3: rs232_tx_r <= tx_data[2]; 4'd4: rs232_tx_r <= tx_data[3]; 4'd5: rs232_tx_r <= tx_data[4]; 4'd6: rs232_tx_r <= tx_data[5]; 4'd7: rs232_tx_r <= tx_data[6]; 4'd8: rs232_tx_r <= tx_data[7];
//发送bit1 //发送bit2 //发送bit3 //发送bit4 //发送bit5 //发送bit6 //发送bit7
4'd9: rs232_tx_r <= 1'b1; //发送结束位 default: rs232_tx_r <= 1'b1; endcase
end
else if(num==4'd11) num <= 4'd0; //复位
end
assign rs232_tx = rs232_tx_r;
endmodule 波形如下
2.3 UART数据接收模块
接收模块功能:时时检测电路,当线路产生下降沿时,则认为线路有数据要进行传送,启动接收数据模块进行数据的接收,数据按从低到高进行接收,其代码如下: module my_uart_rx( clk,rst_n,
);
//12MHz主时钟 rs232_rx,rx_data,rx_int, clk_bps,bps_start
input clk;
input rst_n; //低电平复位信号
input rs232_rx; // RS232接收数据信号
input clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点 output bps_start; //接收到数据后,波特率时钟启动信号置位 output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 output rx_int; //接收数据中断信号,接收到数据期间始终为高电平
//----------------------------------------------------------------
reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; //接收数据寄存器,滤波用 wire neg_rs232_rx; //表示数据线接收到下降沿
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; rs232_rx3 <= 1'b0;
end else begin
rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2;
end end
//下面的下降沿检测可以滤掉<20ns-40ns的毛刺(包括高脉冲和低脉冲毛刺), //这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍)
//(当然我们的有效低脉冲信号肯定是远远大于40ns的)
assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; //接收到下降沿后neg_rs232_rx置高一个时钟周期
//---------------------------------------------------------------- reg bps_start_r; reg[3:0] num; //移位次数 reg rx_int; //接收数据中断信号,接收到数据期间始终为高电平
always @ (posedge clk or negedge rst_n) if(!rst_n) begin
bps_start_r <= 1'bz; rx_int <= 1'b0;
//接收到串口接收线rs232_rx的下降沿标志信号 //启动串口准备数据接收 //接收数据中断信号使能
//接收完有用数据信息
//数据接收完毕,释放波特率启动信号 //接收数据中断信号关闭
end
else if(neg_rs232_rx) begin
bps_start_r <= 1'b1;
rx_int <= 1'b1; end
else if(num==4'd12) begin bps_start_r <= 1'b0;
end
rx_int <= 1'b0;
assign bps_start = bps_start_r;
//---------------------------------------------------------------- reg[7:0] rx_data_r; //串口接收数据寄存器,保存直至下一个数据来到 //----------------------------------------------------------------
reg[7:0] rx_temp_data; //当前接收数据寄存器
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
rx_temp_data <= 8'd0; num <= 4'd0;
rx_data_r <= 8'd0; end
else if(rx_int) begin //接收数据处理 if(clk_bps) begin //读取并保存数据,接收数据为一个起始位,8bit数据,1或
num <= num+1'b1;
case (num) 4'd1: rx_temp_data[0] <= rs232_rx; 4'd2: rx_temp_data[1] <= rs232_rx;
4'd3: rx_temp_data[2] <= rs232_rx; 4'd4: rx_temp_data[3] <= rs232_rx; 4'd5: rx_temp_data[4] <= rs232_rx; 4'd6: rx_temp_data[5] <= rs232_rx; 4'd7: rx_temp_data[6] <= rs232_rx; 4'd8: rx_temp_data[7] <= rs232_rx;
2个结束位
//锁存第0bit //锁存第1bit //锁存第2bit //锁存第3bit //锁存第4bit //锁存第5bit //锁存第6bit //锁存第7bit
default: ; endcase end else if(num == 4'd12) begin 的有效数据
assign rx_data = rx_data_r;
endmodule
输出波形图如下:
//我们的标准接收模式下只有1+8+1(2)=11bit
num <= 4'd0; //接收到STOP位后结束,num清零
rx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中
end end
2.4上位机效果图
3设计总结
这次课程设计在老师的辅导之下顺利的完成了,虽然部分功能未能最终实现,但整体框架基本建立,基本功能也可以实现,没白费这一周以来的努力,在这次设计当中自己从波特率的设置开始入手然后到发送接收模块的设计,虽然中间也遇到了不少困难如对上学期所学的verliog语言有所遗忘,模块设计思路不清晰,这些问题在不断的深入学习当中都很好的得到了解决,总之这次课程设计的收获还是很大的,既了解了串口通信的机理,自己又重新复习了一边verliog语言可以说是一举两得啊,希望自己在以后的课程设计当中也能不断学习不断进步!
因篇幅问题不能全部显示,请点此查看更多更全内容