FPGA入门学习笔记(十二)Vivado实现UART接收控制LED任务

任务要求

通过串口向FPGA开发板发送指令以控制LED灯的工作状态。

工作状态要求:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,有用户随机指定。8个状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择。


在这里插入图片描述


存在问题:由于实际板级运行时,当我们的Time值更新时,counter计数值已经大于该值,所以无法通过计数比较的方式清零,直到32位计满溢出后,才能正常的循环计数。

//解决方法:
if(counter >= Time - 1)
        counter <= 0;

仿真波形

在这里插入图片描述

设计文件程序

module counter_led(
    input Clk,
    input Reset_n,
    input [7:0] sel,
    input [31:0] Time,
    output reg Led
);

reg [31:0]counter;
always @(posedge Clk or negedge Reset_n) begin
    if(!Reset_n)
        counter <= 0;
    else if(counter >= Time - 1)
        counter <= 0;
    else
        counter <= counter + 1'd1;
end

reg [2:0]counter2;
always @(posedge Clk or negedge Reset_n) begin
    if(!Reset_n)
        counter2 <= 0;
    else if(counter >= Time - 1)
        counter2 <= counter2 + 1'b1;
end

always @(posedge Clk or negedge Reset_n) begin
    if(!Reset_n)
        Led <= 0;
    else case(counter2)
            0: Led <= sel[0];
            1: Led <= sel[1];
            2: Led <= sel[2];
            3: Led <= sel[3];
            4: Led <= sel[4];
            5: Led <= sel[5];
            6: Led <= sel[6];
            7: Led <= sel[7];
        default:Led <= Led;
    endcase
end
endmodule
`timescale 1ns/1ns

module UART(
        Clk,
        Reset_N,
        Baud_Set,
        UART_RX,
        Data,
        Rx_Done
    );
    input Clk;
    input Reset_N;
    input [2:0]Baud_Set;
    input UART_RX;
    output reg [7:0]Data;
    output reg Rx_Done;
    
    reg [1:0]UART_RX_R;
    always@(posedge Clk)begin
        UART_RX_R[0] <= #1 UART_RX;
        UART_RX_R[1] <= #1 UART_RX_R[0];
    end
    
    wire pedge_UART_RX;
    wire nedge_UART_RX;
    //上升沿检测
//    assign pedge_UART_RX = ((UART_RX_R[0] == 1) && (UART_RX_R[1] == 0));
    assign pedge_UART_RX = (UART_RX_R == 2'b01);
    //下降沿检测
//    assign nedge_UART_RX = ((UART_RX_R[0] == 0) && (UART_RX_R[1] == 1));
    assign nedge_UART_RX = (UART_RX_R == 2'b10);
    
        // Baud_Set        BaudRate
    //  0               9600
    //  1               19200
    //  2               38400
    //  3               57600
    //  4               115200
    //针对不同的波特率,计算相对应的时间长度
    reg [17:0]bps_DR;
    parameter Time = 32'd1000000000;
    always@(*)
        case(Baud_Set)
            // 16:16倍采样
            0: bps_DR = Time/9600/16/20 - 1;
            1: bps_DR = Time/19200/16/20 - 1;
            2: bps_DR = Time/38400/16/20 - 1;
            3: bps_DR = Time/57600/16/20 - 1;
            4: bps_DR = Time/115200/16/20 - 1;
            default: bps_DR = Time/9600/16/20 - 1;
        endcase
    
    // 16段中心采样位置
    wire bps_clk_16x;
    assign bps_clk_16x = (div_cnt == bps_DR / 2);
    
    reg RX_EN;
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N)
        RX_EN <= #1 0;
    else if(nedge_UART_RX)
        RX_EN <= #1 1;
    else if(Rx_Done || (start_bit >= 4))
        RX_EN <= #1 0;
        
    // 每小分段计数器
    reg [8:0]div_cnt;
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N)
        div_cnt <= #1 0;
    else if(RX_EN)begin
            if(div_cnt == bps_DR)
                div_cnt <= #1 0;
            else
                div_cnt <= #1 div_cnt + 1'd1;
    end
    else
        div_cnt <= #1 0;
    
    // 每帧数据中160小段计数器
    reg [7:0]bps_cnt;
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N)
        bps_cnt <= #1 0;
    else if(RX_EN)begin
        if(bps_clk_16x)begin
            if(bps_cnt == 160)
                bps_cnt <= #1 0;
            else
                bps_cnt <= #1 bps_cnt + 1'd1;
        end
        else
            bps_cnt <= #1 bps_cnt;
    end
    else
        bps_cnt <= #1 0;
    // 二维寄存器  reg width name number
    reg [2:0]r_data[7:0];
    reg [2:0]start_bit;
    reg [2:0]end_bit;
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N)begin
        r_data[0] <= #1 0;
        r_data[1] <= #1 0;
        r_data[2] <= #1 0;
        r_data[3] <= #1 0;
        r_data[4] <= #1 0;
        r_data[5] <= #1 0;
        r_data[6] <= #1 0;
        r_data[7] <= #1 0;
        start_bit <= #1 0;
        end_bit <= #1 0;
    end
    else if(bps_clk_16x)begin
        case(bps_cnt)
            0:begin
                r_data[0] <= #1 0;
                r_data[1] <= #1 0;
                r_data[2] <= #1 0;
                r_data[3] <= #1 0;
                r_data[4] <= #1 0;
                r_data[5] <= #1 0;
                r_data[6] <= #1 0;
                r_data[7] <= #1 0;
                start_bit <= #1 0;
                end_bit <= #1 0;
            end
            5,6,7,8,9,10,11: start_bit <= #1 start_bit + UART_RX;
            21,22,23,24,25,26,27: r_data[0] <= #1 r_data[0] + UART_RX;
            37,38,39,40,41,42,43: r_data[1] <= #1 r_data[1] + UART_RX;
            53,54,55,56,57,58,59: r_data[2] <= #1 r_data[2] + UART_RX;
            69,70,71,72,73,74,75: r_data[3] <= #1 r_data[3] + UART_RX;
            85,86,87,88,89,90,91: r_data[4] <= #1 r_data[4] + UART_RX;
            101,102,103,104,105,106,107: r_data[5] <= #1 r_data[5] + UART_RX;
            117,118,119,120,121,122,123: r_data[6] <= #1 r_data[6] + UART_RX;
            133,134,135,136,137,138,139: r_data[7] <= #1 r_data[7] + UART_RX;
            149,150,151,152,153,154,155: end_bit <= #1 end_bit + UART_RX;
            default:;
        endcase
    end
    
    always@(posedge Clk or negedge Reset_N)    
    if(!Reset_N)
        Data <= #1 0;
    else if(bps_clk_16x && (bps_cnt == 159))begin
        //Data[0] <= #1 r_data[0][2];
        Data[0] <= #1 (r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= #1 (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= #1 (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= #1 (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= #1 (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= #1 (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= #1 (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= #1 (r_data[7] >= 4)?1'b1:1'b0;
    end
    
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N) 
        Rx_Done <= #1 0;
    else if((div_cnt == bps_DR / 2) && (bps_cnt == 160))
        Rx_Done <= #1 1;
    else
        Rx_Done <= #1 0;
endmodule
module UART_CMD(
        Clk,
        Reset_N,
        Data,
        Rx_Done,
        Time,
        Sel
    );
    input Clk;
    input Reset_N;
    input [7:0]Data;
    input Rx_Done;
    output reg [31:0]Time;
    output reg [7:0]Sel;
    
    //移位寄存器复位置零无意义可忽略
    reg [7:0]Data_str[7:0];
    always@(posedge Clk)
    if(Rx_Done)begin
        Data_str[0] <= Data_str[1];
        Data_str[1] <= Data_str[2];
        Data_str[2] <= Data_str[3];
        Data_str[3] <= Data_str[4];
        Data_str[4] <= Data_str[5];
        Data_str[5] <= Data_str[6];
        Data_str[6] <= Data_str[7];
        Data_str[7] <= Data;
    end
    
    //滞后一个时钟周期
    reg r_Rx_Done;
    always@(posedge Clk)
    r_Rx_Done <= Rx_Done;
    
    always@(posedge Clk or negedge Reset_N)
    if(!Reset_N)begin
        Time <= 0;
        Sel <= 0;
    end
    else if(r_Rx_Done)begin
        if((Data_str[0] == 8'h55) && (Data_str[1] == 8'ha5) && (Data_str[7] == 8'hf0))begin
            Time[7:0]   <=  Data_str[2];
            Time[15:8]  <=  Data_str[3];
            Time[23:16] <=  Data_str[4];
            Time[31:24] <=  Data_str[5];
            Sel <= Data_str[6];
        end
    end
endmodule

仿真文件程序

`timescale 1ns / 1ns


module UART_LED_tb();

    reg Clk;
    reg Reset_N;
    reg UART_RX;
    wire Led;
    
    UART_LED UART_LED(
            Clk,
            Reset_N,
            UART_RX,
            Led
        );
    
    initial Clk <= 0;
    always #10 Clk <= !Clk;
    initial begin
        Reset_N <= 0;UART_RX = 1;
        #201;
        Reset_N <= 1;
        #200;
        uart_tx_byte(8'h55);
        #9000;
        uart_tx_byte(8'ha5);
        #9000;
        uart_tx_byte(8'h12);
        #9000;
        uart_tx_byte(8'h34);
        #9000;
        uart_tx_byte(8'h56);
        #9000;
        uart_tx_byte(8'h78);
        #9000;
        uart_tx_byte(8'haa);
        #9000;
        uart_tx_byte(8'hf0);
        #9000;
        $stop;
    
    end
    task uart_tx_byte;
        input [7:0]tx_data;
        begin
            UART_RX = 1;
            #20;
            UART_RX = 0;
            #8680;
            UART_RX = tx_data[0];
            #8680;
            UART_RX = tx_data[1];
            #8680;
            UART_RX = tx_data[2];
            #8680;
            UART_RX = tx_data[3];
            #8680;
            UART_RX = tx_data[4];
            #8680;
            UART_RX = tx_data[5];
            #8680;
            UART_RX = tx_data[6];
            #8680;
            UART_RX = tx_data[7];
            #8680;
            UART_RX = 1;
            #8680;
        end
    endtask
endmodule

板级验证

UART发送成功后可以观察到LED灯以0.5s的频率闪烁
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值