FPGA学习笔记(2) 串口发送模块uart_tx

1.串口发送原理介绍

在这里插入图片描述
上图为窗口发送8位数据的原理,可以看出,平常不发送时候数据线处于高电平状态,开始发送时,出现开始标志即低电平,随后传输八bit数据,最后再通过停止位(高电平)来结束数据的发送。

在这里插入图片啊
在这里插入图片描述
在这里插入图片描述

上图为参考小梅哥串口发送模块的设计,信号名称大致不变,接下来主要看代码设计。

2.串口发送代码实现

module uart_tx(
    clk,
    rst_n,
    data_byte,
    send_en,
    baud_set,
    data_tx,
    tx_done,
    uart_state
);

input clk; //clk 时钟
input rst_n;//reset 复位信号
input send_en;//enable 发送使能信号

input [2:0]baud_set;//baud 波特率设置
input [7:0]data_byte;//待发送的一个字节的数据

output reg data_tx;//发送出去的一个字节数据
output reg tx_done;//end_flag 串口发送完成标志
output reg uart_state;//state 串口状态标志

reg bps_clk;//baud clk 波特率时钟 
reg [15:0]div_cnt;// div counter 分频计数
reg [15:0]bps_DR;// div counter max 波特率分频计数的最大值
reg [3:0]bps_cnt;// baud counter 波特率计数,用于发送
reg [7:0]r_data_byte; //暂存的发送数据

localparam start_bit = 1'b0; //开始标志
localparam stop_bit = 1'b1; //结束标志

//uart_state 
//本always块主要用于实现串口状态的转变
always@(posedge clk or negedge rst_n)
begin

    if(!rst_n)uart_state<=1'b0;//复位,状态为0
    else if(send_en)
        uart_state<=1'b1;//发送使能,状态为1,表示正在发送
         else if(bps_cnt == 4'd10)
             uart_state<=1'b0;	//发送完成
              else
                  uart_state<=uart_state;
end

//data reg
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        r_data_byte<=8'b0000_0000;
    else if(send_en)
           r_data_byte<=data_byte;

end

//baud set
//该模块实现波特率的选择,更加利于模块的复用
//计数的最大值通过第一节中的最后一张图得出
always@(posedge clk or negedge rst_n)
begin
     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
end

//counter 分频计数模块
always@(posedge clk or negedge rst_n)
begin
     if(!rst_n)
              div_cnt<=16'd0;
          else if(send_en)begin
                 if(div_cnt == bps_DR)
                     div_cnt<=16'd0;
                 else 
                     div_cnt<=div_cnt+1'b1;         
               end
               else 
                   div_cnt<=16'd0;

end

//bps_clk gen 波特率脉冲生成模块
always@(posedge clk or negedge rst_n)
begin
     if(!rst_n)
              bps_clk<=1'd0;
          else if (div_cnt == 16'd1)//这里有个细节,大家可以研究一下,为什么是计数到1,不是计数到dps_DR
              bps_clk<=1'b1;
          else
              bps_clk<=1'b0;
end

//bps counter 
always@(posedge clk or negedge rst_n)
begin
     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;
          
end

//tx_done 发送结束标志
always@(posedge clk or negedge rst_n)
begin
     if(!rst_n)
              tx_done<=1'd0;
          else  if(bps_cnt ==4'd11)
                     tx_done<<=1'd1;
                 else 
                     tx_done<=1'd0;
        
end

//uart_tx 实际发送实现,注意这边是低位先发送
always@(posedge clk or negedge rst_n)
if(!rst_n)
    data_tx<= 1'b1;
else begin
    case(bps_cnt)
            0:data_tx<=1'b1;
            1:data_tx<=start_bit;
            2:data_tx<=r_data_byte[0];
            3:data_tx<=r_data_byte[1];
            4:data_tx<=r_data_byte[2];
            5:data_tx<=r_data_byte[3];
            6:data_tx<=r_data_byte[4];
            7:data_tx<=r_data_byte[5];
            8:data_tx<=r_data_byte[6];
            9:data_tx<=r_data_byte[7];
            10:data_tx<=stop_bit;
            default:data_tx<=1'b1;
    endcase
end

endmodule

3.串口发送仿真验证

下面是对上面写的串口发送模块进行的仿真
在这里插入图片描述
在这里插入图片描述
PS:本文借鉴了小梅哥的教程

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值