• 基于FPGA的超声波测距


    一、项目框架

    distance超声波测距模块负责数据的采集,vga、uart、beep、数码管根据采集到的数据分别进行vga的屏幕打点、串口输出到上位机、蜂鸣器根据数据大小进行鸣叫以及数码管显示采集到的数据。
    在这里插入图片描述

    RTL视图

    在这里插入图片描述

    二、超声波测距模块

    在这里插入图片描述
    在这里插入图片描述
    代码

    module distance_drive (
        input			wire						clk,
        input			wire						clk_1,
        input			wire						rst_n,
    
        input			wire						echo,
        output			reg						    trig,
        output			wire						data_out_vld,
        output			wire		[ 23:0 ]		distance_data
    );
    localparam	MAX_DISTANCE = 117647; //最大距离 4m
    
    parameter	s_idle = 0;//空闲状态
    parameter	s_send = 1;//发送触发信号
    parameter	s_wait = 2;//等待内部发送脉冲
    parameter	s_accept = 3;//检测回响信号
    parameter	s_accept_wait = 4;//延时等待
    
    
    reg								echo_r0			;
    reg								echo_r1			;
    reg			[ 2:0 ]			    s_current		;
    reg			[ 2:0 ]			    s_next			;
    reg			[ 22 :0 ]		    cnt				;
    reg			[ 22:0 ]			cnt_wait		;
    reg			[ 22:0 ]		    cnt_max			;
    reg			[ 16:0 ]			cnt_distance	;
    // reg			[ 25:0 ]			cnt_distance_r1			;
    // reg			[ 19:0 ]			cnt_distance_r2			;
    
    wire							accept_start_sig			;
    wire							accept_stop_sig			;
    wire							idle_sig			;
    wire							send_sig			;
    // wire							wait_sig			;
    wire							flag_clear_cnt			;
    wire							flag_clear_cnt_wait			;
    reg			[ 19:0 ]			distance_data_r			;
    wire			[ 23:0 ]			distance_data_r1			;
    
    assign idle_sig = s_current == s_idle;
    assign send_sig = s_current == s_send && flag_clear_cnt;
    // assign wait_sig = s_current == s_wait && flag_clear_cnt_wait;
    assign accept_wait_sig = s_current == s_accept_wait &&  flag_clear_cnt_wait;
    assign accept_start_sig = s_current == s_wait && echo_r0 && ~echo_r1;
    assign accept_stop_sig = s_current == s_accept && (~echo_r0 && echo_r1);
    
    
    // always @(posedge clk or negedge rst_n) begin
    //     if(!rst_n) begin
    //         cnt_distance_r1 <= 0;
    //         // cnt_distance_r2 <= 0;
    //     end
    //     else begin
    //         cnt_distance_r1 <= cnt_distance * 340 / 100;
    //         // cnt_distance_r2 <= cnt_distance_r1 >> 4;
    //     end
    // end
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            echo_r0 <= 0;
            echo_r1 <= 0;
        end
        else begin
            echo_r0 <= echo;
            echo_r1 <= echo_r0;
        end
    end
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            s_current <= s_idle;    
        end
        else begin
            s_current <= s_next;
        end
    end
    
    always @(*) begin
        case (s_current)
            s_idle : begin
                if(idle_sig) begin
                    s_next = s_send;
                end
                else begin
                    s_next = s_idle;
                end
            end
            s_send : begin
                if(send_sig) begin
                    s_next = s_wait;
                end
                else begin
                    s_next = s_send;
                end
            end
            s_wait : begin
                if(accept_start_sig) begin
                    s_next = s_accept;
                end
                else begin
                    s_next = s_wait;
                end
            end
            s_accept : begin
                if(accept_stop_sig) begin
                    s_next = s_accept_wait;
                end
                else begin
                    s_next = s_accept;
                end
            end
            s_accept_wait : begin
                if(accept_wait_sig) begin
                    s_next <= s_idle;
                end
                else begin
                    s_next <= s_accept_wait;
                end
            end
            default: s_next = s_idle;
        endcase
    end
    
    //距离
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            distance_data_r <= 0;
        end
        else if(accept_stop_sig) begin
            distance_data_r <= cnt_distance * 340 / 200;
        end
    end
    
    //转BCD码
    assign     distance_data_r1[3:0]   = distance_data_r % 10;
    assign     distance_data_r1[7:4]   = distance_data_r / 10 % 10;
    assign     distance_data_r1[11:8]  = distance_data_r / 100 % 10;
    assign     distance_data_r1[15:12] = distance_data_r / 1000 % 10;
    assign     distance_data_r1[19:16] = distance_data_r / 10000 % 10;
    assign     distance_data_r1[23:20] = distance_data_r / 100000 % 10;
    
    assign data_out_vld = accept_wait_sig;
    assign distance_data = distance_data_r1;
    
    //回响信号计数器
    always @(posedge clk_1 or negedge rst_n) begin
        if(!rst_n) begin
            cnt_distance <= 0;
        end
        else if(accept_start_sig) begin
            cnt_distance <= 0;
        end
        else if(s_current == s_accept) begin
            cnt_distance <= cnt_distance + 1;
        end
        else begin
            cnt_distance <= 0;
        end
    end
    
    //发送触发信号
    always @(posedge clk_1 or negedge rst_n) begin
        case (s_current)
            s_idle : begin
                trig <= 0;
            end
            s_send : begin
                trig <= 1;
            end
            s_wait : begin
                trig <= 0;
            end
            s_accept : begin
                trig <= 0;
            end
            s_accept_wait : begin
                trig <= 0;
            end
            default: begin
                trig <= 0;
            end
        endcase
    end
    //等待发送玩脉冲
    always @( posedge clk_1 or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt <= 0;
        end
        else if ( s_current == s_send ) begin
            if ( flag_clear_cnt == 9 ) begin
                cnt <= 0;
            end
            else begin
                cnt <= cnt + 1;
            end
        end
        else begin
            cnt <= 0;
        end
    end
    assign flag_clear_cnt = cnt == 9;
    
    //延时计数器
    always @( posedge clk_1 or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt_wait <= 0;
        end
        else if ( s_current == s_accept_wait ) begin
            if ( flag_clear_cnt_wait ) begin
                cnt_wait <= 0;
            end
            else begin
                cnt_wait <= cnt_wait + 1;
            end
        end
        else begin
            cnt_wait <= 0;
        end
    end
    assign flag_clear_cnt_wait = cnt_wait == 250_000;
    endmodule //distance
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222

    三、串口模块

    在这里插入图片描述

    1.串口发送模块

    module uart_tx(input			wire						clk,
                   input			wire						rst_n,
                   input			wire						tx_enable, // 发送使能
                   input			wire		[ 07:0 ]		data_in, // 需要发送的数据
                   input			wire		[ 19:0 ]		tx_bps, // 发送的波特率
                   output			wire						data, // 发送的数据
                   output			wire						tx_done);
        
        localparam MAX_BIT = 10;
        
        reg			[ 09:0 ]			data_r			; // 数据寄存器
        reg			[ 12:0 ]			cnt_bps			; // 波特率计数器
        reg			[ 03:0 ]			cnt_bit			; // 数据位计数器
        
        wire		[ 12:0 ]			max_bps			; // 波特率对应频率
    
        wire							flag_clear_cnt_bps			; // 计数器归零
        wire							flag_add_cnt_bit			; // 计数器+1
        wire							flag_clear_cnt_bit			; 
        reg								flag_send_data			    ; //发送数据标志
        
        //输入数据寄存
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                data_r <= 10'b0;
            end
            else if(tx_enable) begin
                data_r <={1'b1, data_in, 1'b0};
            end
    
        end
        
        // 波特率计数器
        always @( posedge clk or negedge rst_n ) begin
            if ( !rst_n ) begin
                cnt_bps <= 0;
            end
            else if ( flag_send_data ) begin
                if ( flag_clear_cnt_bps ) begin
                    cnt_bps <= 0;
                end
                else begin
                    cnt_bps <= cnt_bps + 1;
                end
            end
            else begin
                cnt_bps <= 0;
            end
            
        end
    
        assign flag_clear_cnt_bps  = cnt_bps >= max_bps -1;
        assign max_bps             = 50_000_000 / tx_bps;
        
        // 数据位计数器
        always @( posedge clk or negedge rst_n ) begin
            if ( !rst_n ) begin
                cnt_bit <= 0;
            end
            else if ( flag_send_data ) begin
                if ( flag_clear_cnt_bit ) begin
                    cnt_bit <= 0;
                end
                else if ( flag_add_cnt_bit )begin
                    cnt_bit <= cnt_bit + 1;
                end
                else begin
                    cnt_bit <= cnt_bit;
                end
            end
            else begin
                cnt_bit <= 0;
            end
        end
    
        assign flag_add_cnt_bit   = flag_clear_cnt_bps;
        assign flag_clear_cnt_bit = cnt_bit >= MAX_BIT - 1 && flag_add_cnt_bit ;
    
    
        //发送数据标志
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                flag_send_data <= 0;
            end
            else if(tx_enable) begin
                flag_send_data <= 1;
            end
            else if(flag_clear_cnt_bit) begin
                flag_send_data <= 0;
            end
            else begin
                flag_send_data <= flag_send_data;
            end
        end
        //发送数据
        assign data = flag_send_data ? data_r[cnt_bit]:1;
        assign tx_done = ~flag_send_data  ;
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    2.串口发送控制模块

    串口控制模块把接受到的24位BCD码转换成ASSIC码,并且清除高位零位和添加单位和小数点。把处理好的数据加入FIFO中,再通过串口发送模块进行发送。

    module uart_drive (
        input			wire						clk,
        input			wire						rst_n,
        input			wire		[ 23:0 ]		distance_data,
        input			wire						data_vld,
        output			wire						rx_data,
        output			wire						tx_data
    );
    reg			[ 23:0 ]			distance_data_r			;
    reg			[ 7:0 ]				data		;
    reg			[ 3:0 ]				cnt_byte		;
    reg								send_flag			;
    wire		[ 7:0 ]			    distance			;
    wire							rdreq			;
    wire							wrreq			;
    wire							empty			;
    wire							full			;
    wire		[ 7:0 ]			    data_in			;
    
    reg								flag			;
    //串口
    uart_tx u_uart_tx(
        .clk       ( clk       ),
        .rst_n     ( rst_n     ),
        .tx_enable ( rdreq      ),
        .data_in   ( data_in   ),
        .tx_bps    ( 115200    ),
        .data      ( tx_data      ),
        .tx_done   ( tx_done   )
    );
    
    assign rdreq = tx_done && ~empty;
    assign wrreq = ~full && send_flag && (cnt_byte > 0) && flag;
    assign distance = data;
    tx_fifo	tx_fifo_inst (
    	.aclr ( ~rst_n ),
    	.clock ( clk ),
    	.data ( distance ),
    	.rdreq ( rdreq ),
    	.wrreq ( wrreq ),
    	.empty ( empty ),
    	.full ( full ),
    	.q ( data_in ),
    	.usedw ( usedw_sig )
    	);
    
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            send_flag <= 0;
        end
        else if(cnt_byte == 9) begin
            send_flag <= 0;
        end
        else if(data_vld) begin
            send_flag <= 1;
        end
    
    end
    //数据计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_byte <=0;
        end
        else if(cnt_byte == 9) begin
            cnt_byte <= 0;
        end
        else if(send_flag) begin
            cnt_byte <= cnt_byte + 1;
        end
    end
    //寄存数据
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            distance_data_r <=0;
        end
        else if(data_vld) begin
            distance_data_r <= distance_data;
        end
    end
    
    //去除前面的不必要的0
    always @(*) begin
        if(!rst_n) begin
            flag = 0;
        end
        else if(!send_flag) begin
            flag <= 0;
        end
        else if(cnt_byte > 3 || data> 48) begin
            flag = 1;
        end
        else begin
            flag <= flag;
        end
    end
    //发送距离
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data <=0;
        end
        else if(send_flag) begin
            case (cnt_byte)
                0 : data <= distance_data_r[23:20] + 48;
                1 : data <= distance_data_r[19:19] + 48;
                2 : data <= distance_data_r[15:12] + 48;
                3 : data <= distance_data_r[11:8 ] + 48;
                4 : data <= 46; // .
                5 : data <= distance_data_r[7 : 4] + 48;
                6 : data <= distance_data_r[3 : 0] + 48;
                7 : data <= 99 ; //c
                8 : data <= 109; //m
                default: data <=0;
            endcase
            // data <= distance_data_r[(4 * (6-cnt_byte) -1) -:4] + 48;
        end
    end
    
    endmodule //uart_drive
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119

    四、蜂鸣器模块

    蜂鸣器模块把接受到的数据去掉低两位,也就是精度变成厘米级别。当处理完后的数据在MAX_DISTANCE和MIN_DISTANCE之间,则会根据数据的大小调整蜂鸣器鸣叫间隔,使得蜂鸣器的鸣叫频率随着距离的减少越来越高,当数据小于MIN_DISTANCE时则会一直处在鸣叫。

    module beep_dirve (
        input			wire						clk,
        input			wire						rst_n,
        input			wire						beep_vld,
        input			wire						data_vld,
        input			wire		[ 23:0 ]		distance_data,
        output			reg						    beep
    );
    
    parameter	MAX_DISTANCE = 20;
    parameter	MIN_DISTANCE = 10;
    parameter	MAX_TIME = 50_000_000;
    reg			[ 27:0 ]			cnt			        ;
    wire		[ 27:0 ]			delay			    ;
    wire		[ 19:0 ]			distance			;
    reg			[ 23:0 ]			distance_data_r			;
    // wire			[ 19:0 ]			distance_r			;
    
    //寄存数据
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            distance_data_r <= 0;
        end
        else if(data_vld) begin
            distance_data_r <= distance_data;
        end
    end
    // 根据距离设置翻转频率
    assign distance = distance_data_r[11:8] + distance_data_r[15:12] * 10 + distance_data_r[19:16] * 100 + distance_data_r[23:20] *1000;
    assign delay =  ((distance ) + 1) * 200_000;
    
    // // led
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt <= 0;
        end
        else if ( cnt >= delay  ) begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1; 
        end 
    end
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            beep <= 1;
        end
        else if(~beep_vld) begin
            beep <= 1;
        end
        else if(distance <= MAX_DISTANCE && distance >= MIN_DISTANCE && cnt == 1 && beep_vld) begin
            beep <= ~ beep;
        end
        else if(distance < MIN_DISTANCE && beep_vld) begin
            beep <= 0;
        end
        else if(distance > MAX_DISTANCE) begin
            beep <= 1;
        end
        else begin
            beep <= beep;
        end
    end
    
    endmodule //beep_dirve
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    五、vga显示模块

    在这里插入图片描述

    1.vga协议驱动代码

        module vga_dirve (input			wire						clk,            //系统时钟
                        input			wire						rst_n,          //复位
                        input			wire		[ 15:0 ]		rgb_data,       //16位RGB对应值
                        output			wire						vga_clk,    //vga时钟 25M
                        output			reg							h_sync,     //行同步信号
                        output			reg							v_sync,     //场同步信号
                        output			reg		[ 11:0 ]				addr_h, //行地址
                        output			reg		[ 11:0 ]				addr_v,  //列地址
                        output			wire		[ 4:0 ]				rgb_r,  //红基色
                        output			wire		[ 5:0 ]				rgb_g,  //绿基色
                        output			wire		[ 4:0 ]				rgb_b  //蓝基色
        );
    
    // 640 * 480 60HZ
    localparam	 H_FRONT = 16; // 行同步前沿信号周期长
    localparam	 H_SYNC  = 96; // 行同步信号周期长
    localparam	 H_BLACK = 48; // 行同步后沿信号周期长
    localparam	 H_ACT   = 640; // 行显示周期长
    localparam	 V_FRONT = 11; // 场同步前沿信号周期长
    localparam	 V_SYNC  = 2; // 场同步信号周期长
    localparam	 V_BLACK = 31; // 场同步后沿信号周期长
    localparam	 V_ACT   = 480; // 场显示周期长
    
    // 800 * 600 72HZ
    // localparam	 H_FRONT = 40; // 行同步前沿信号周期长
    // localparam	 H_SYNC  = 120; // 行同步信号周期长
    // localparam	 H_BLACK = 88; // 行同步后沿信号周期长
    // localparam	 H_ACT   = 800; // 行显示周期长
    // localparam	 V_FRONT = 37; // 场同步前沿信号周期长
    // localparam	 V_SYNC  = 6; // 场同步信号周期长
    // localparam	 V_BLACK = 23; // 场同步后沿信号周期长
    // localparam	 V_ACT   = 600; // 场显示周期长
    
    
    localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
    localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期
    
    reg			[ 11:0 ]			cnt_h			; // 行计数器
    reg			[ 11:0 ]			cnt_v			; // 场计数器
    reg			[ 15:0 ]			rgb			; // 对应显示颜色值
    
    // 对应计数器开始、结束、计数信号
    wire							flag_enable_cnt_h			;
    wire							flag_clear_cnt_h			;
    wire							flag_enable_cnt_v			;
    wire							flag_clear_cnt_v			;
    wire							flag_add_cnt_v  			;
    wire							valid_area      			;
    
    
    // 25M时钟 行周期*场周期*刷新率 = 800 * 525 * 60
    reg							clk_25			;
    // 50M时钟 1040 * 666 * 72
    wire							clk_50			;
    //PLL
    // pll	pll_inst (
    // 	.areset ( ~rst_n ),
    // 	.inclk0 ( clk ),
    // 	.c0 ( clk_50 ), //50M
    // 	.c1 ( clk_25 ) //25M
    // 	);
    //根据不同分配率选择不同频率时钟
    assign vga_clk = clk;
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            clk_25 <= 0;
        end
        else  begin
            clk_25 <= ~clk_25;
        end
    end
    // 行计数
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt_h <= 0;
        end
        else if ( flag_enable_cnt_h ) begin
            if ( flag_clear_cnt_h ) begin
                cnt_h <= 0;
            end
            else begin
                cnt_h <= cnt_h + 1;
            end
        end
        else begin
            cnt_h <= 0;
        end
    end
    assign flag_enable_cnt_h = 1;
    assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;
    
    // 行同步信号
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            h_sync <= 1;
        end
        else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
            h_sync <= 0;
        end
        else if ( flag_clear_cnt_h ) begin // 其余为0
            h_sync <= 1;
        end
        else begin
            h_sync <= h_sync;
        end
    end
    
    // 场计数
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt_v <= 0;
        end
        else if ( flag_enable_cnt_v ) begin
            if ( flag_clear_cnt_v ) begin
                cnt_v <= 0;
            end
            else if ( flag_add_cnt_v ) begin
                cnt_v <= cnt_v + 1;
            end
            else begin
                cnt_v <= cnt_v;
            end
        end
        else begin
            cnt_v <= 0;
        end
    end
    assign flag_enable_cnt_v = flag_enable_cnt_h;
    assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
    assign flag_add_cnt_v    = flag_clear_cnt_h;
    
    // 场同步信号
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            v_sync <= 1;
        end
        else if ( cnt_v == V_SYNC - 1 ) begin
            v_sync <= 0;
        end
            else if ( flag_clear_cnt_v ) begin
            v_sync <= 1;
            end
        else begin
            v_sync <= v_sync;
        end
    end
    
    // 对应有效区域行地址 1-640
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            addr_h <= 0;
        end
        else if ( valid_area ) begin
            addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
        end
        else begin
            addr_h <= 0;
        end
    end
    // 对应有效区域列地址 1-480
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            addr_v <= 0;
        end
        else if ( valid_area ) begin
            addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
        end
        else begin
            addr_v <= 0;
        end
    end
    // 有效显示区域
    assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;
    
    
    // 显示颜色
    always @( posedge vga_clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            rgb <= 16'h0;
        end
        else if ( valid_area ) begin
            rgb <= rgb_data;
        end
        else begin
            rgb <= 16'b0;
        end
    end
    assign rgb_r = rgb[ 15:11 ];
    assign rgb_g = rgb[ 10:5 ];
    assign rgb_b = rgb[ 4:0 ];
    
    endmodule // vga_dirve
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194

    2.vga数据控制模块

    横坐标为时间,纵坐标为距离大小。距离大小决定场坐标,第几个距离决定行坐标。

    module data_drive (input			wire						clk,
                        input			wire						vga_clk,
                       input			wire						rst_n,
                       input			wire		[ 11:0 ]		addr_h,
                       input			wire		[ 11:0 ]		addr_v,
                       input			wire						data_vld,
                       input			wire		[ 23:0 ]		distance_data,
                       output			wire		[ 15:0 ]		rgb_data);
    
    localparam	red    = 16'd63488;
    localparam	orange = 16'd64384;
    localparam	yellow = 16'd65472;
    localparam	green  = 16'd1024;
    localparam	blue   = 16'd31;
    localparam	indigo = 16'd18448;
    localparam	purple = 16'd32784;
    localparam	white  = 16'd65503;
    localparam	black  = 16'd0;
    
    parameter	NUM = 100;
    reg			[ 19:0 ]			distance_data_r			;
    reg			[ 15:0 ]			rgb_data_r			;
    reg			[ 10:0 ]			data_r[NUM -1:0]			;
    integer j;
    integer i;
    //寄存数据
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            distance_data_r <= 0;
        end
        else if(data_vld) begin
            distance_data_r <=distance_data[7:4]+ distance_data[11:8]*10 + distance_data[15:12] * 100 ;
        end
    end
    
    //数据打拍
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            for (i = 0; i<NUM - 1;i=i+1 ) begin
                data_r[i] <= 0;
            end
        end
        else if(data_vld) begin
            data_r[0] <= distance_data_r;
            for (i = 1; i<NUM - 1;i=i+1 ) begin
                data_r[i] <= data_r[i-1];
            end
        end
    end
    reg			[ 10:0 ]			cnt			;
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rgb_data_r = 0;
            cnt = 0;
        end
        else if(cnt == NUM) begin
            rgb_data_r = black;
            cnt = 0;
        end
        else if(addr_v > 470 && addr_v < 476 && addr_h >9 && addr_h < 625 ) begin //横坐标
            rgb_data_r = white;
            cnt = cnt;
        end
        else if(addr_h > 9 && addr_h <15 && addr_v >9 && addr_v <= 470) begin //纵坐标
            rgb_data_r = white;
            cnt = cnt;
        end
        else if(addr_h >20 && addr_h < 620 && addr_v >10 && addr_v < 470) begin  //打点
            if ( (cnt+1) * 3 == addr_h -20) begin
                if(data_r[cnt] == 470 - addr_v)begin
                    rgb_data_r = red;
                    cnt = cnt + 1;
                end
                else begin
                    rgb_data_r = black;
                    cnt = cnt + 1;
                end
            end
            else begin
                rgb_data_r = black;
                cnt = cnt;
            end
        end
        else begin
            rgb_data_r = black;
            cnt = cnt;
        end
    end
    assign rgb_data = rgb_data_r;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    六、数码管

    在这里插入图片描述

    1.数码管段选控制

    根据位选信号来显示对应位置的数字

    module seg_drive(input			wire						clk,
                     input			wire						rst_n,
                     input			wire						data_vld,
                     input			wire		[ 23:0 ]		display_data,
                     input			wire		[ 5:0 ]		    sel,
                     output			reg		[ 7:0 ]				seg);
            
    
        localparam	ZERO  = 7'b100_0000;
        localparam	ONE   = 7'b111_1001;
        localparam	TWO   = 7'b010_0100;
        localparam	THREE = 7'b011_0000;
        localparam	FOUR  = 7'b001_1001;
        localparam	FIVE  = 7'b001_0010;
        localparam	SIX   = 7'b000_0010;
        localparam	SEVEN = 7'b111_1000;
        localparam	EIGHT = 7'b000_0000;
        localparam	NINE  = 7'b001_0000;
        localparam	N     = 7'b010_1011;
        localparam	P     = 7'b000_1111;
    
        reg			[ 23:0 ]			display_data_r			;
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                display_data_r <= 0;
            end
            else if(data_vld) begin
                display_data_r <= display_data;
            end
        end
    
        reg dot;
        reg [ 3:0 ] num;
    
        always@( * ) begin
            case( sel )
                6'b111_110: begin
                    // num = display_data / 100000 % 10;
                    num = display_data_r[23 :20];
                    dot = 1;                
                end
                6'b111_101: begin
                    // num = display_data / 10000 % 10;
                    num = display_data_r[19 : 16];
                    dot = 1;
                end
                6'b111_011: begin
                    // num = display_data / 1000 % 10;
                    num = display_data_r[15 : 12];
                    dot = 1;
                end
                6'b110_111: begin
                    // num = display_data / 100 % 10;
                    num = display_data_r[11 :8];
                    dot = 0;
                end
                6'b101_111: begin
                    //num = display_data / 10 % 10;
                    num = display_data_r[7 :4];
                    dot = 1;
                end
                6'b011_111: begin
                    //num = display_data % 10;
                    num = display_data_r[3 :0];
                    dot = 1;
                end
                default num = 4'hf; 
            endcase
        end
        
        always @ ( * ) begin
            case( num )
                4'd0:   seg = {dot,ZERO}; // 匹配到后参考共阳极真值表
                4'd1:   seg = {dot,ONE};
                4'd2:   seg = {dot,TWO};
                4'd3:   seg = {dot,THREE};
                4'd4:   seg = {dot,FOUR};
                4'd5:   seg = {dot,FIVE};
                4'd6:   seg = {dot,SIX};
                4'd7:   seg = {dot,SEVEN};
                4'd8:   seg = {dot,EIGHT};
                4'd9:   seg = {dot,NINE};
                default : seg = {1'b0,ZERO};
            endcase
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    2.数码管位选

    每20000ns刷新一次数码管

    module sel_drive(
    	input clk,
    	input rst_n,
    	
    	output reg [5:0] sel
    );
    localparam state0 = 3'd0;
    localparam state1 = 3'd1;
    localparam state2 = 3'd2;
    localparam state3 = 3'd3;
    localparam state4 = 3'd4;
    localparam state5 = 3'd5;
    
    parameter	MAX_NUM = 1_000;
    
    reg [2:0] current_state;
    reg [2:0] next_state;
    reg    [20:0]	  cnt; //时钟分频计数器
    reg              flag;
    
    //计数器
    always @(posedge clk or negedge rst_n)begin
    	if(!rst_n)begin
    		flag <= 1'b0;
    		cnt <= 0;
    	end
    	else if(cnt == 0)begin//一轮计数完毕
    		flag <= 1'b1;
    		cnt <= 1;
    	end
    	else	begin 
    		flag <= 1'b0;
    		cnt <= (cnt + 1'b1) % MAX_NUM;//循环+1
    	end
    end
    // 状态跳转
    always @(posedge clk or negedge rst_n) begin
    	if(!rst_n) begin
    		current_state <= state0;
    	end
    	else if(flag) begin
    		current_state <= next_state;
    	end
    end
    
    
    //状态判断
    always @(*) begin
    	if(!rst_n) begin
    		next_state <= state0;
    	end
    	else if(flag) begin
    		case(current_state)
    			state0: begin
    				next_state <= state1;
    			end
    			state1: begin
    				next_state <= state2;
    			end
    			state2: begin
    				next_state <= state3;
    			end
    			state3: begin
    				next_state <= state4;
    			end
    			state4: begin
    				next_state <= state5;
    			end
    			state5: begin
    				next_state <= state0;
    			end
    			default:begin
    				next_state <= state0;
    			end
    		endcase
    	end
    	else begin
    		next_state <= next_state;
    	end
    end
    
    
    //状态输出
    always@(current_state) begin
    	case (current_state)
    		state0: begin
    			sel <= 6'b011111;
    		end
    		state1: begin
    			sel <= 6'b101111;
    		end
    		state2: begin
    			sel <= 6'b110111;
    		end
    		state3: begin
    			sel <= 6'b111011;
    		end
    		state4: begin
    			sel <= 6'b111101;
    		end
    		state5: begin
    			sel <= 6'b111110;
    		end
    		default:begin
    			sel <= 6'b111111;
    		end
    	endcase
    
    
    end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111

    七、顶层文件

    由于数码管需要25M时钟,超声波测距需要1M时钟,通过PLL分频得到对应的时钟。

    module distance_top (
        input			wire						clk,
        input			wire						rst_n,
        input			wire						echo,
        
        output			wire						trig,
        output			wire		[ 5:0 ]			sel,
        output			wire		[ 7:0 ]			seg,
        output			reg		    [ 3:0 ]			led,
        output			wire						beep,
        input			wire						key,
        output			wire						h_sync,
        output			wire						v_sync,
        output			wire		[ 4:0 ]			rgb_r,
        output			wire		[ 5:0 ]			rgb_g,
        output			wire		[ 4:0 ]			rgb_b,
        input			wire						rx_data,
        output			wire						tx_data
    );
    
    wire							clk_50			;
    wire							clk_1			;
    wire							clk_25			;
    wire		[ 23:0 ]			distance_data			;
    wire							data_out_vld			;
    reg							    beep_vld			;
    wire							key_out			;
    wire		[ 15:0 ]			rgb_data			;
    wire		[ 11:0 ]		    addr_h;
    wire		[ 11:0 ]		    addr_v;
    pll	pll_inst (
    	.areset ( ~rst_n ),
    	.inclk0 ( clk ),
    	.c0 ( clk_50 ),
    	.c1 ( clk_1 ),
    	.c2 ( clk_25 )
    	);
    
    //vga
    vga_dirve u_vga_dirve(
        .clk      ( clk_25   ),
        .rst_n    ( rst_n    ),
        .rgb_data ( rgb_data ),
        .vga_clk  ( vga_clk  ),
        .h_sync   ( h_sync   ),
        .v_sync   ( v_sync   ),
        .addr_h   ( addr_h   ),
        .addr_v   ( addr_v   ),
        .rgb_r    ( rgb_r    ),
        .rgb_g    ( rgb_g    ),
        .rgb_b    ( rgb_b    )
    );
    //vag数据
    data_drive u_data_drive(
        .clk           (clk),
        .vga_clk       ( vga_clk       ),
        .rst_n         ( rst_n         ),
        .addr_h        ( addr_h        ),
        .addr_v        ( addr_v        ),
        .data_vld      ( data_out_vld   ),
        .distance_data ( distance_data ),
        .rgb_data      ( rgb_data      )
    );
    //数码管
    seg_drive u_seg_drive(
        .clk          ( clk          ),
        .rst_n        ( rst_n        ),
        .data_vld     ( data_out_vld ),
        .display_data ( distance_data),
        .sel          ( sel          ),
        .seg          ( seg          )
    );
    sel_drive u_sel_drive(
        .clk   ( clk_50   ),
        .rst_n ( rst_n ),
        .sel   ( sel   )
    );
    //测距
    distance_drive u_distance(
        .clk           ( clk           ),
        .clk_1          (clk_1),
        .rst_n         ( rst_n         ),
        .echo          ( echo          ),
        .trig          ( trig          ),
        .data_out_vld  ( data_out_vld ),
        .distance_data ( distance_data )
    );
    //串口
    uart_drive u_uart_drive(
        .clk           ( clk           ),
        .rst_n         ( rst_n         ),
        .distance_data ( distance_data ),
        .data_vld      ( data_out_vld   ),
        .rx_data       ( rx_data       ),
        .tx_data       ( tx_data       )
    );
    
    //蜂鸣器
    beep_dirve u_beep_dirve(
        .clk           ( clk           ),
        .rst_n         ( rst_n         ),
        .beep_vld      ( beep_vld      ),
        .data_vld      ( data_out_vld      ),
        .distance_data ( distance_data ),
        .beep          ( beep          )
    );
    //按键消抖
    key_debounce#(.KEY_W   ( 1 )) u_key_debounce(
        .clk     ( clk     ),
        .rst_n   ( rst_n   ),
        .key_in  ( key  ),
        .key_out  ( key_out  )
    );
    
    //控制蜂鸣器使能
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            beep_vld <= 0;
        end
        else if(key_out) begin
            beep_vld <= ~beep_vld;
        end
    end
    reg			[ 27:0 ]			cnt			        ;
    // led
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt <= 0;
        end
        else if ( cnt == 50_000_000 - 1 ) begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1;
        end
    end
    
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            led <= 4'b0000;
        end
        else if ( cnt == 50_000_000 -1 )begin
            led <= ~led;
        end
        else begin
            led <= led;
        end
    end
    endmodule //distance_top
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149

    八、源代码

    https://github.com/TangtangSix/distance

  • 相关阅读:
    详解 Calico 三种模式(与 Fannel 网络对比学习)
    多因素身份认证 (MFA) 插件:手机验证码认证因素配置流程
    流媒体传输 - RTSP 协议认证过程
    用R语言进行时间序列ARMA模型分析
    设计模式之适配器模式
    DirectXShaderCompiler mac编译
    push,pop指令
    static 关键字
    Blazor WebAssembly 渐进式 Web 应用程序 (PWA) 离线处理数据
    JVM学习(尚硅谷)之垃圾回收相关概念
  • 原文地址:https://blog.csdn.net/qq_47281915/article/details/125592938