新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 基于STEP FPGA的UART串口通信模块驱动

基于STEP FPGA的UART串口通信模块驱动

作者: 时间:2023-11-29 来源:电子森林 收藏

硬件说明

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。
异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。两个相邻位间的时间间隔与UART通信的波特率有关,波特率用来表征UART通信中数据传输的速率,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。

本文引用地址://www.cazqn.com/article/202311/453398.htm

  • 起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
  • 数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
  • 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
  • 停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
  • 空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。


我们这里使用的时序为去掉校验位的时序

本设计共有四个模块,一个top模块,一个baud模块,一个接收模块和一个发送模块,大家可以根据自己的需求进行调整。


Verilog代码

// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Uart_bus
// 
// Author: Step
// 
// Description: The module for uart communication
// 
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2016/04/20   |Initial ver
// --------------------------------------------------------------------
module Uart_Bus #
(
parameter				BPS_PARA = 1250 //当使用12MHz时钟时波特率参数选择1250对应9600的波特率
)
(
input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效
input					rs232_rx,		//FPGA中UART接收端,分配给UART模块中的发送端TXD
output					rs232_tx		//FPGA中UART发送端,分配给UART模块中的接收端RXD
);		 /////////////////////////////////UART接收功能模块例化////////////////////////////////////
wire					bps_en_rx,bps_clk_rx;
wire			[7:0]	rx_data; //UART接收波特率时钟控制模块 例化
Baud #
(
.BPS_PARA				(BPS_PARA		)
)
Baud_rx
(	
.clk_in					(clk_in			),	//系统时钟
.rst_n_in				(rst_n_in		),	//系统复位,低有效
.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		)	//接收时钟输出
); 
//UART接收数据模块 例化
Uart_Rx Uart_Rx_uut
(
.clk_in					(clk_in			),	//系统时钟
.rst_n_in				(rst_n_in		),	//系统复位,低有效
.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		),	//接收时钟输入
.rs232_rx				(rs232_rx		),	//UART接收输入
.rx_data				(rx_data		)	//接收到的数据
); 
 /////////////////////////////////UART发送功能模块例化////////////////////////////////////
 wire					bps_en_tx,bps_clk_tx; 
 //UART发送波特率时钟控制模块 例化
 Baud #
 (
 .BPS_PARA				(BPS_PARA		)
 )
 Baud_tx
 (
 .clk_in					(clk_in			),	//系统时钟
 .rst_n_in				(rst_n_in		),	//系统复位,低有效
 .bps_en					(bps_en_tx		),	//发送时钟使能
 .bps_clk				(bps_clk_tx		)	//发送时钟输出
 ); 
 //UART发送数据模块 例化
 Uart_Tx Uart_Tx_uut(.clk_in					(clk_in			),	//系统时钟
 .rst_n_in				(rst_n_in		),	//系统复位,低有效
 .bps_en					(bps_en_tx		),	//发送时钟使能
 .bps_clk				(bps_clk_tx		),	//发送时钟输入
 .rx_bps_en				(bps_en_rx		),	//因需要自收自发,使用接收时钟使能判定:接收到新的数据,需要发送
 .tx_data				(rx_data		),	//需要发出的数据
 .rs232_tx				(rs232_tx		)	//UART发送输出
 ); 
 endmodule
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Baud
// 
// Author: Step
// 
// Description: Beat for uart transfer and receive baud rate
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2016/04/20   |Initial ver
// --------------------------------------------------------------------
module Baud #
(
parameter				BPS_PARA = 1250 //当使用12MHz时钟时波特率参数选择1250对应9600的波特率
)
(
input					clk_in,		//系统时钟
input					rst_n_in,	//系统复位,低有效
input					bps_en,		//接收或发送时钟使能
output	reg				bps_clk		//接收或发送时钟输出
);	 
reg				[12:0]	cnt;//计数器计数满足波特率时钟要求
always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) 
		cnt <= 1'b0;
	else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数
		cnt <= 1'b0;						
		//当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期
	else 
		cnt <= cnt + 1'b1;end //产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收
		always @ (posedge clk_in or negedge rst_n_in)
	begin
		if(!rst_n_in) 
			bps_clk <= 1'b0;
		else if(cnt == (BPS_PARA>>1)) 	
		//BPS_PARA右移一位等于除2,因计数器终值BPS_PARA为数据更替时间点,所以计数器中值时为数据最稳定时间点
			bps_clk <= 1'b1;	
		else 
			bps_clk <= 1'b0;
	end 
	endmodule
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Uart_Rx
// 
// Author: Step
// 
// Description: The receive module of uart interface
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2016/04/20   |Initial ver
// --------------------------------------------------------------------
module Uart_Rx(input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效 
output	reg				bps_en,			//接收时钟使能
input					bps_clk,		//接收时钟输入 
input					rs232_rx,		//UART接收输入
output	reg		[7:0]	rx_data			//接收到的数据
);	 
reg	rs232_rx0,rs232_rx1,rs232_rx2;	//多级延时锁存去除亚稳态
always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) begin
		rs232_rx0 <= 1'b0;
		rs232_rx1 <= 1'b0;
		rs232_rx2 <= 1'b0;
	end else begin
		rs232_rx0 <= rs232_rx;
		rs232_rx1 <= rs232_rx0;
		rs232_rx2 <= rs232_rx1;
	endend //检测UART接收输入信号的下降沿
	wire	neg_rs232_rx = rs232_rx2 & rs232_rx1 & (~rs232_rx0) & (~rs232_rx);	 
	reg				[3:0]	num;			//接收时钟使能信号的控制
	always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in)
		bps_en <= 1'b0;
	else if(neg_rs232_rx && (!bps_en))	
	//当空闲状态(bps_en为低电平)时检测到UART接收信号下降沿,进入工作状态(bps_en为高电平),控制时钟模块产生接收时钟
		bps_en <= 1'b1;		
	else if(num==4'd9)		      		//当完成一次UART接收操作后,退出工作状态,恢复空闲状态
		bps_en <= 1'b0;			
		end 
		reg				[7:0]	rx_data_r;//当处于工作状态中时,按照接收时钟的节拍获取数据
		always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) begin
		num <= 4'd0;
		rx_data <= 8'd0;
		rx_data_r <= 8'd0;
	end else if(bps_en) begin	
		if(bps_clk) begin			
			num <= num+1'b1;
			if(num<=4'd8)
			rx_data_r[num-1]<=rs232_rx;	//先接受低位再接收高位,8位有效数据
		end else if(num == 4'd9) begin	//完成一次UART接收操作后,将获取的数据输出
			num <= 4'd0;			
			rx_data <= rx_data_r;	
		end
	end
	end 
	endmodule
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Uart_Tx
// 
// Author: Step
// 
// Description: The transfer module of uart interface
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2016/04/20   |Initial ver
// --------------------------------------------------------------------
module Uart_Tx
(
input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效
output	reg				bps_en,			//发送时钟使能
input					bps_clk,		//发送时钟输入
input					rx_bps_en,		
//因需要自收自发,使用接收时钟使能判定:接收到新的数据,需要发送
input			[7:0]	tx_data,		//需要发出的数据
output	reg				rs232_tx		//UART发送输出
); 
reg						rx_bps_en_r;//延时锁存接收时钟使能信号
always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) rx_bps_en_r <= 1'b0;
	else rx_bps_en_r <= rx_bps_en;end //检测接收时钟使能信号的下降沿,因为下降沿代表接收数据的完成,以此作为发送信号的激励
	wire	neg_rx_bps_en = rx_bps_en_r & (~rx_bps_en); 
	reg				[3:0]	num;
	reg				[9:0]	tx_data_r;	//根据接收数据的完成,驱动发送数据操作
	always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) begin
		bps_en <= 1'b0;
		tx_data_r <= 8'd0;
	end else if(neg_rx_bps_en)begin	
		bps_en <= 1'b1;						
		//当检测到接收时钟使能信号的下降沿,表明接收完成,需要发送数据,使能发送时钟使能信号
		tx_data_r <= {1'b1,tx_data,1'b0};	
	end else if(num==4'd10) begin	
		bps_en <= 1'b0;	//一次UART发送需要10个时钟信号,然后结束
	endend //当处于工作状态中时,按照发送时钟的节拍发送数据
	always @ (posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) begin
		num <= 1'b0;
		rs232_tx <= 1'b1;
	end else if(bps_en) begin
		if(bps_clk) begin
			num <= num + 1'b1;
			rs232_tx <= tx_data_r[num];
		end else if(num>=4'd10) 
			num <= 4'd0;	
	end
	end 
	endmodule

小结

本节主要为大家讲解了UART通信的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。



评论


相关推荐

技术专区

关闭