串口发送源码解析

串口作为电子世界中最简单的通信协议,再单片机,fpga,各种嵌入式系统中发挥了举足轻重的作用,串口通信的协议非常简单,最经典的就是RS232标准,但是当前大多数电脑主机因为RS232接口体积很大,逐渐的放弃了这种接口,为了能实现串口通信,常常在开发板上用芯片进行转接,构成USB转TTL电路,作为一个串口使用。

串口通信的协议一般是具有一个开始位,一个停止位,8个数据位,Verilog的实现就是根据串口通信的标准进行设置。

模块端口如下

module uart_byte_tx(
	Clk,
	Rst_n,
  
	data_byte,
	send_en,   
	Baud_Set,  
	
	uart_tx,  
	Tx_Done,   
	uart_state 
);

    input Clk ;    //模块全局时钟输入,50M

    input Rst_n;    //复位信号输入,低有效

    input [7:0]data_byte;  //待传输8bit数据

    input send_en;    //发送使能

    input [2:0]Baud_Set;   //波特率设置

   

    output reg uart_tx;    //串口输出信号

    output reg Tx_Done;    //1byte数据发送完成标志

    output reg uart_state; //发送数据状态

上面就是串口发送模块的端口,下面简单介绍下实现过程

首先是串口发送状态信号,标志着串口发送模块正在工作,此时不应该让模块进行其他工作

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		uart_state <= 1'b0;
	else if(send_en)
		uart_state <= 1'b1;
	else if(bps_cnt == 4'd11)
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;

再就是串口发送数据缓存,防止再发送过程中数据被改变,导致串口发出的数据出错

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		data_byte_reg <= 8'd0;
	else if(send_en)
		data_byte_reg <= data_byte;
	else
		data_byte_reg <= data_byte_reg;

因为串口是异步通信,通信双方要提前约定通信速率(波特率)

这里采用多路选择器对通信速率进行选择

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_DR <= 16'd5207;
	else begin
		case(Baud_Set)
			0:bps_DR <= 16'd5207;
			1:bps_DR <= 16'd2603;
			2:bps_DR <= 16'd1301;
			3:bps_DR <= 16'd867;
			4:bps_DR <= 16'd433;
			default:bps_DR <= 16'd5207;			
		endcase
	end	

例如,工作时钟是50M,波特率是9600,则上述选择应该是0(50M/9600≈5207)

定义一个计数器,进行分频,生成串口的通信速率

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		div_cnt <= 16'd0;
	else if(uart_state)begin
		if(div_cnt == bps_DR)
			div_cnt <= 16'd0;
		else
			div_cnt <= div_cnt + 1'b1;
	end
	else
		div_cnt <= 16'd0;
	

串口通信时钟生成,根据上面的分频,生成一个对应的串口时钟,供发送时使用

	// bps_clk gen
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_clk <= 1'b0;
	else if(div_cnt == 16'd1)
		bps_clk <= 1'b1;
	else
		bps_clk <= 1'b0;

定义一个bit计数器,表明发送状态中每一时刻应该处在什么状态(发送启停位还是数据)

	//bps counter
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	
		bps_cnt <= 4'd0;
	else if(bps_cnt == 4'd11)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;

生成一个发送完成信号,告诉其他模块已经发送完成,可以进行下次发送

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Tx_Done <= 1'b0;
	else if(bps_cnt == 4'd11)
		Tx_Done <= 1'b1;
	else
		Tx_Done <= 1'b0;

根据bit计数器,生成最终的串口接口数据

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		uart_tx <= 1'b1;
	else begin
		case(bps_cnt)
			0:uart_tx <= 1'b1;
			1:uart_tx <= START_BIT;
			2:uart_tx <= data_byte_reg[0];
			3:uart_tx <= data_byte_reg[1];
			4:uart_tx <= data_byte_reg[2];
			5:uart_tx <= data_byte_reg[3];
			6:uart_tx <= data_byte_reg[4];
			7:uart_tx <= data_byte_reg[5];
			8:uart_tx <= data_byte_reg[6];
			9:uart_tx <= data_byte_reg[7];
			10:uart_tx <= STOP_BIT;
			default:uart_tx <= 1'b1;
		endcase
	end	

当bps_cnt==0时,在空闲状态,串口线为高电平

当bps_cnt==1时,发送起始位,串口线为高电平

当bps_cnt==2~9时,发送需要发送的数据,低位先发送

当bps_cnt==10时,发送停止位,串口线为高电平

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值