应用:使用uart串口接收模块接收信号,控制led灯闪烁

功能描述:

  使用遵循uart协议的接收模块接收控制信号,用来控制led的闪烁。

设计输入:

  1.uart输入信号

  2.时钟信号

  3.复位信号

  4.led信号

设计思路:

  总体上:前面已经写了串口接收模块,led闪烁模块。现在要把接收到的多个数据对应传送给led闪烁模块的输入(闪烁周期,亮灭模式设置),我们再写一个模块来实现传输的功能,然后在顶层把这三个模块进行连线就可以了。

  细节处:单个数据的传输遵循uart协议,而为了确定传送来的数据哪个对应led的时间设置,哪个对应亮灭模式设置,我们也需要人为再设定一个协议,第一,二个数据为某固定值时,视为开端,然后接着是对应数据,最后一个数据是固定值。发送数据端应按照这个协议来发送各个数据,这样子接收端就可以按照这个协议来控制输入led的信号了。

注意

  ①在代码中用到了延时,如#xx......等,则应在文件第一行写明时间单位和精度:·timescale ns/ns 。

  ②如果想让某个标志信号siagnl_a 延后一个周期,可以新设定一个信号siagnl_b,让siagnl_b永远等于siagnl_a就行。

  ③在本次设计中,修正了receive_rx_1代码中把r_data赋给data的时刻以及清零时刻。

学习:

  ①设计底层模块convert,顶层直接连线很方便。

  ②对于串口通信的应用,一般都有串口接收模块+移位寄存器+协议+应用功能 四个部分组成,其中,串口模块和功能模块一般已经设计好了,我们要设计移位寄存器和协议,即接收到的数据用来干嘛,怎么排序对应。

  ③判断条件设定的技巧: if(const <= variable),有两个好处:Ⅰ.常数const不能被变量variabl赋值,以此检查会不会把比较符写成赋值符。Ⅱ.用<=取代 == ,可以避免 == 的时刻已经被跳过,导致判断条件无法实现。

设计:

代码:

`timescale 1ns / 1ns
module uart_rx_ctrl_led(//顶层,就是连线
    clk,
    reset,
    uart_tx,
    led    
    );
    input clk;
    input reset;
    input uart_tx;
    output led;
    
    //本模型由uart_receive到led_chang的传输协议为:
    //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
   
   //首先例化三个模块进来
   wire [2:0]baud_rate ;
   assign baud_rate = 3'd5 ;
   wire [7:0]data;
   wire rx_done;
   uart_receive_1   uart_receive(//接收模块
    clk ,
    reset ,
    baud_rate ,
    uart_tx, 
    data ,
    rx_done   
    );
    
    wire [31:0]tim;
    wire [7:0]ctrl;
    uart_led_convert uart_led_convert(//转换模块
    data,
    rx_done,
    clk,
    reset,
    tim,
    ctrl
    );
    
    led_change4 led_change4(//led闪烁模块
    clk,
    reset,
    ctrl,
    tim,
    led
    );
    
    
endmodule
module uart_receive_1(
    clk ,
    reset ,
    baud_rate ,
    uart_tx, 
    data ,
    rx_done   
    );
    input  clk ;
    input reset ;
    input [2:0]baud_rate ;
    input uart_tx ;
    output reg [7:0]data ;
    output reg rx_done ;
    
    reg [2:0]r_data[7:0] ;//接收每一位数据
    reg [2:0]sta_bit ;
    reg [2:0]sto_bit ;
    
    reg [17:0]bit_tim ;//每一位持续的时间(计数)
    always@(baud_rate)  //在这里一个 码元由一位组成,所以波特率=比特率
        begin
            case(baud_rate)         //常见的串口传输波特率
            3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300
            3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200
            3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400
            3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600
            3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200
            3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200
            default bit_tim = 1000000000/9600/20 ;   //多余的寄存器位置放什么:默认速率
            endcase
     end
    
    wire [17:0]bit_tim_16 ;//每1/16位的持续时间(计数)
    assign bit_tim_16 = bit_tim / 16;
    
    wire [8:0]bit16_mid ; //在中心点产生采样脉冲 
    assign bit16_mid = bit_tim_16 / 2 ;
    
    //边沿检测
    reg [1:0]edge_detect ;
    always @( posedge clk or negedge reset )
    begin
        if (!reset )
            edge_detect <= 2'd0 ;
        else 
            begin
            edge_detect[0] <= uart_tx ;
            edge_detect[1] <= edge_detect[0] ;
            end
    end    

    wire byte_sta_neg ;
    assign byte_sta_neg = ( edge_detect == 2'b10 ) ? 1 : 0 ;//输入的数据开始出现下降沿,说明出现了起始位(一直运行?)
         
    reg receive_en ;//接收使能端
    reg [17:0]div_cnt ;//每1/16bit内的计数
     reg [7:0]bit16_cnt ;//计数到了第几个状态(10位,每位分成16份,总共160个状态)
    always @( posedge clk or negedge reset )
    begin
         if (!reset )
            receive_en <= 1'd0 ;
        else if ( byte_sta_neg )    //检测到下降沿,使能段有效(只要有下降沿就使能?)
            receive_en <= 1'd1 ;
        else if ( (rx_done) || (sta_bit >= 3'd4 ))    
            receive_en <= 1'd0 ;    //检测到结束信号,使能端无效
        else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后re_en置零
            receive_en <= 1'd0 ;
    end
             
    
    always@( posedge clk or negedge reset )
    begin
        if ( ! reset )
            div_cnt <= 18'd0 ;
        else if (receive_en)
        begin
            if ( div_cnt == bit_tim_16 - 1'd1 )//计数,每1/16bit清零
                div_cnt <= 18'd0 ;               
            else
                div_cnt <= div_cnt + 1'b1 ; 
        end
        else 
            div_cnt <= 18'd0 ;
    end
    
    reg bit16_pulse ;//产生采样脉冲
    always@( posedge clk or negedge reset )
    begin
        if ( ! reset )
            bit16_pulse <= 18'd0 ;
        else if (receive_en)
            if ( div_cnt == bit16_mid )
                bit16_pulse <= 1'd1 ;
            else
                bit16_pulse <= 1'd0 ;
        else
                bit16_pulse <= 1'd0 ;                
    end       
   
    always@( posedge clk or negedge reset )
    begin
        if ( ! reset )
            bit16_cnt <= 8'd0 ;
        else if (receive_en)
        begin    
            if (( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ))
                bit16_cnt <= 8'd0 ;
            else if ( div_cnt == bit_tim_16 - 1'd1 )
                bit16_cnt <= bit16_cnt + 1'b1 ;
        end
    end
      
    always@(posedge clk or negedge reset)
    begin
    if(!reset)
    begin
        sta_bit   <= 3'd0 ;
        r_data[0] <= 3'd0 ;
        r_data[1] <= 3'd0 ;
        r_data[2] <= 3'd0 ;
        r_data[3] <= 3'd0 ;
        r_data[4] <= 3'd0 ;
        r_data[5] <= 3'd0 ;
        r_data[6] <= 3'd0 ;
        r_data[7] <= 3'd0 ;
        sto_bit   <= 3'd0 ;
    end
    else if (bit16_pulse)//舍弃前5后4取中7
        case(bit16_cnt)
            0: 
            begin 
            sta_bit   <= 3'd0 ;
            r_data[0] <= 3'd0 ;
            r_data[1] <= 3'd0 ;
            r_data[2] <= 3'd0 ;
            r_data[3] <= 3'd0 ;
            r_data[4] <= 3'd0 ;
            r_data[5] <= 3'd0 ;
            r_data[6] <= 3'd0 ;
            r_data[7] <= 3'd0 ;
            sto_bit   <= 3'd0 ;
            end
            5,6,7,8,9,10,11 : sta_bit <= sta_bit + uart_tx ;
            21,22,23,24,25,26,27 : r_data[0] <= r_data[0] + uart_tx ;
            37,38,39,41,42,43,44 : r_data[1] <= r_data[1] + uart_tx ; 
            53,54,55,56,57,58,59 : r_data[2] <= r_data[2] + uart_tx ;
            69,70,71,72,73,74,75 : r_data[3] <= r_data[3] + uart_tx ;
            85,86,87,88,89,90,91 : r_data[4] <= r_data[4] + uart_tx ;
            101,102,103,104,105,106,107 : r_data[5] <= r_data[5] + uart_tx ;
            117,118,119,120,121,122,123 : r_data[6] <= r_data[6] + uart_tx ;
            133,134,135,136,137,138,139 : r_data[7] <= r_data[7] + uart_tx ;
            149,150,151,152,153,154,155 : sto_bit <= sto_bit + uart_tx ;
            default ;
        endcase
    end

    always@( posedge clk or negedge reset )
    begin
        if ( ! reset )
            rx_done <= 8'd0 ;
        else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后产生一个rx_done信号
            rx_done <= 8'd1 ;
        else if (rx_done <= 8'd1 )
            rx_done <= 8'd0 ;
    end         
    
    always@( posedge clk or negedge reset )//接收完数据发出rx_done后,把数据从r_data传递给data
    begin
        if ( ! reset )
            data <= 8'd0 ;
        else if (bit16_pulse)//舍弃前5后4取中7
        case(bit16_cnt)
            28:data[0] = ( r_data[0] >3 ) ? 1 : 0 ;
            44:data[1] = ( r_data[1] >3 ) ? 1 : 0 ;
            60:data[2] = ( r_data[2] >3 ) ? 1 : 0 ;
            76:data[3] = ( r_data[3] >3 ) ? 1 : 0 ;
            92:data[4] = ( r_data[4] >3 ) ? 1 : 0 ;
            108:data[5] = ( r_data[5] >3 ) ? 1 : 0 ;
            124:data[6] = ( r_data[6] >3 ) ? 1 : 0 ;
            140:data[7] = ( r_data[7] >3 ) ? 1 : 0 ;
        endcase
        else if(rx_done)
            data <= 8'd0 ;
    end
         
    
endmodule
`timescale 1ns / 1ns
module uart_led_convert(
    data,
    rx_done,
    clk,
    reset,
    tim,
    ctrl
    );
    input [7:0]data;
    input rx_done;
    input clk;
    input reset;
    output reg [31:0]tim;
    output reg [7:0]ctrl;
    
    //设定本模型由uart_receive到led_chang的传输协议为:
    //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
    //设计一个二维移位寄存器
    reg [7:0]data_regist[7:0];
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
        begin
            data_regist[0] <= 0;
            data_regist[1] <= 0;
            data_regist[2] <= 0;
            data_regist[3] <= 0;
            data_regist[4] <= 0;
            data_regist[5] <= 0;
            data_regist[6] <= 0;
            data_regist[7] <= 0;
        end
        else if(rx_done)
        begin
            data_regist[0] <=      data      ;
            data_regist[1] <= data_regist[0] ;
            data_regist[2] <= data_regist[1] ;
            data_regist[3] <= data_regist[2] ;
            data_regist[4] <= data_regist[3] ;
            data_regist[5] <= data_regist[4] ;
            data_regist[6] <= data_regist[5] ;
            data_regist[7] <= data_regist[6] ;
        end
    end
    
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
        begin
            tim <= 0 ;
            ctrl <= 0 ;
        end
        else if ( ( data_regist[0] == 8'ha5 ) && ( data_regist[6] == 8'hab ) && ( data_regist[7] == 8'h0f ) )
            begin
            ctrl[7:0]  <= data_regist[1] ;
            tim[7:0]   <= data_regist[2] ;
            tim[15:8]  <= data_regist[3] ;
            tim[23:16] <= data_regist[4] ;
            tim[31:24] <= data_regist[5] ;
            end
    end
endmodule
module led_change4(      //以tim*20/8 ns为变化周期,tim*20 ns为一个循环,每个周期的亮灭模式,tim由用户设置。.
    clk,
    reset,
    ctrl,
    tim,
    led
    );
    input clk;
    input reset;
    input [7:0]ctrl;
    input [31:0]tim;
    output reg led ;
    
    reg [31:0]counter0;
    
    always@( posedge clk or negedge reset )
    begin       
        if ( reset == 0 )
        counter0 <= 32'b0 ;
        else if ( tim - 1 <= counter0 )
        counter0 <= 0 ;
        else 
        counter0 <= counter0 + 1'd1;  
    end 
     
    always@( posedge clk or negedge reset ) 
    begin
        if ( reset == 0 )
        led <= 0 ;
        else case( counter0 )                   //可以用第二个计数器的方法来设置判断条件
        tim * 1 / 8 - 1 : led <= ctrl[0] ;
        tim * 2 / 8 - 1 : led <= ctrl[1] ;
        tim * 3 / 8 - 1 : led <= ctrl[2] ;
        tim * 4 / 8 - 1 : led <= ctrl[3] ;
        tim * 5 / 8 - 1 : led <= ctrl[4] ;
        tim * 6 / 8 - 1 : led <= ctrl[5] ;
        tim * 7 / 8 - 1 : led <= ctrl[6] ;
        tim * 8 / 8 - 1 : led <= ctrl[7] ;
        default led <= led ;
        endcase
    end    
endmodule

激励代码:

`timescale 1ns / 1ns
module uart_receive_ctrl_led_tb();
    
    reg clk;
    reg reset;
    reg uart_tx;
    wire led;
    
    uart_rx_ctrl_led uart_rx_ctrl_led_sim(
    clk,
    reset,
    uart_tx,
    led    
    );
    
    initial clk = 1 ;
    always #10 clk = ! clk ;
    initial 
    begin
    reset = 0 ;
    #201 ;
    reset = 1 ;
    #200;
    uart_txx(8'h0f);
    uart_txx(8'hab);
    uart_txx(8'h00);//time
    uart_txx(8'h00);//time
    uart_txx(8'h65);//time
    uart_txx(8'h00);//time
    uart_txx(8'h5a);//ctrl
    uart_txx(8'ha5);
    #900000;
    $stop ;
    end
    
    task uart_txx;
    input [7:0]sim_data ;    
    begin
        uart_tx = 1 ;
        #200 ;
        uart_tx = 0 ;
        #8640 ;
        uart_tx = sim_data[0];
        #8640 ;
        uart_tx = sim_data[1];
        #8640 ;
        uart_tx = sim_data[2];
        #8640 ;
        uart_tx = sim_data[3];
        #8640 ;
        uart_tx = sim_data[4];
        #8640 ;
        uart_tx = sim_data[5];
        #8640 ;
        uart_tx = sim_data[6];
        #8640 ;
        uart_tx = sim_data[7];
        #8640 ;
        uart_tx = 1 ;
        #8640 ;
    end
    
    endtask
    
   
endmodule

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值