基于fpga的串口控制的音乐播放器

发布于:2025-06-30 ⋅ 阅读:(16) ⋅ 点赞:(0)


题目要求

要求:
通过串口接收要播放的音符,do、re、mi、fa、sol、la、ti和高音do分别用数字1~8表示
收到音符后自动播放,每个音符的音长为0.5s
可在播放的同时接收新的音符,支持单个和批量发送(同一时刻待播放的音符数不超过100个)
在六位七段数码管上显示播放的音符,当前播放的显示在最右侧,每播放一个新的音符较早的音符左移

一、总体框架

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
串口驱动-----数码管驱动------蜂鸣器pwm驱动-------数码管显示数据切换--------FIFO数据写入和读出

二、verilog代码

1.串口驱动

//****************************************Copyright (c)***********************************//

//****************************************************************************************//

module uart_top(
    input            sys_clk  ,   //�ⲿ50MHzʱ��
    input            sys_rst_n,   //ϵ�ⲿ��λ�źţ�����Ч
    
    //UART�˿�   
    input            uart_rxd ,   //UART���ն˿�
    output           uart_txd ,    //UART���Ͷ˿�
    input            uart_tx_en,    //UART���������ź�
    output wire         uart_rx_done,    //UART���������ź�  
    output wire         uart_tx_done,    //UART���������ź�  
    
         
    input        [7:0]  uart_tx_data,    //UART��������     
    output wire  [7:0]  uart_rx_data    //UART��������         
    );

//parameter define
parameter CLK_FREQ = 50000000;    //����ϵͳʱ��Ƶ��
parameter UART_BPS = 115200  ;    //���崮�ڲ�����

//wire define
//wire         uart_rx_done;    //UART���������ź�
//wire  [7:0]  uart_rx_data;    //UART��������

//*****************************************************
//**                    main code
//*****************************************************

//���ڽ���ģ��
uart_rx #(
    .CLK_FREQ  (CLK_FREQ),
    .UART_BPS  (UART_BPS)
    )    
    u_uart_rx(
    .clk           (sys_clk     ),
    .rst_n         (sys_rst_n   ),
    .uart_rxd      (uart_rxd    ),
    .uart_rx_done  (uart_rx_done),
    .uart_rx_data  (uart_rx_data)
    );

//���ڷ���ģ��
uart_tx #(
    .CLK_FREQ  (CLK_FREQ),
    .UART_BPS  (UART_BPS)
    )    
    u_uart_tx(
    .clk          (sys_clk     ),
    .rst_n        (sys_rst_n   ),
    .uart_tx_en   (uart_tx_en),
    .uart_tx_data (uart_tx_data),
    .uart_tx_done (uart_tx_done),
    .uart_txd     (uart_txd    ),
    .uart_tx_busy (            )
    );
    
endmodule

//****************************************Copyright (c)***********************************//
//ԭ�Ӹ����߽�ѧƽ̨��www.yuanzige.com
//����֧�֣�http://www.openedv.com/forum.php
//�Ա����̣�https://zhengdianyuanzi.tmall.com
//��ע΢�Ź���ƽ̨΢�źţ�"����ԭ��"�����ѻ�ȡZYNQ & FPGA & STM32 & LINUX���ϡ�
//��Ȩ���У�����ؾ���
//Copyright(C) ����ԭ�� 2023-2033
//All rights reserved                                  
//----------------------------------------------------------------------------------------
// File name:           uart_rx
// Created by:          ����ԭ��
// Created date:        2023��2��16��14:20:02
// Version:             V1.0
// Descriptions:        UART���ڽ���ģ��
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_rx(
    input               clk         ,  //ϵͳʱ��
    input               rst_n       ,  //ϵͳ��λ������Ч

    input               uart_rxd    ,  //UART���ն˿�
    output  reg         uart_rx_done,  //UART���������ź�
    output  reg  [7:0]  uart_rx_data  //UART���յ�������
    
    );

//parameter define
parameter CLK_FREQ = 50000000;               //ϵͳʱ��Ƶ��
parameter UART_BPS = 115200  ;                 //���ڲ�����
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //Ϊ�õ�ָ�������ʣ���ϵͳʱ�Ӽ���BPS_CNT��

//reg define
reg          uart_rxd_d0;
reg          uart_rxd_d1;
reg          uart_rxd_d2;
reg          rx_flag    ;  //���չ��̱�־�ź�
reg  [3:0 ]  rx_cnt     ;  //�������ݼ�����
reg  [15:0]  baud_cnt   ;  //�����ʼ�����
reg  [7:0 ]  rx_data_t  ;  //�������ݼĴ���

//wire define
wire        start_en;

//*****************************************************
//**                    main code
//*****************************************************
//�������ն˿��½���(��ʼλ)���õ�һ��ʱ�����ڵ������ź�
assign start_en = uart_rxd_d2 & (~uart_rxd_d1) & (~rx_flag);

//�����첽�źŵ�ͬ������
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;
        uart_rxd_d2 <= 1'b0;
    end
    else begin
        uart_rxd_d0 <= uart_rxd;
        uart_rxd_d1 <= uart_rxd_d0;
        uart_rxd_d2 <= uart_rxd_d1;
    end
end

//�����ձ�־��ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        rx_flag <= 1'b0;
    else if(start_en)    //���⵽��ʼλ
        rx_flag <= 1'b1; //���չ����У���־�ź�rx_flag���
    //��ֹͣλһ����ʱ�򣬼����չ��̽�������־�ź�rx_flag���
    else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1'b1))
        rx_flag <= 1'b0;
    else
        rx_flag <= rx_flag;
end        

//�����ʵļ�������ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        baud_cnt <= 16'd0;
    else if(rx_flag) begin     //���ڽ��չ���ʱ�������ʼ�������baud_cnt������ѭ������
        if(baud_cnt < BAUD_CNT_MAX - 1'b1)
            baud_cnt <= baud_cnt + 16'b1;
        else 
            baud_cnt <= 16'd0; //�����ﵽһ�����������ں�����
    end    
    else
        baud_cnt <= 16'd0;     //���չ��̽���ʱ����������
end

//�Խ������ݼ�������rx_cnt�����и�ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        rx_cnt <= 4'd0;
    else if(rx_flag) begin                  //���ڽ��չ���ʱrx_cnt�Ž��м���
        if(baud_cnt == BAUD_CNT_MAX - 1'b1) //�������ʼ�����������һ������������ʱ
            rx_cnt <= rx_cnt + 1'b1;        //�������ݼ�������1
        else
            rx_cnt <= rx_cnt;
    end
    else
        rx_cnt <= 4'd0;                     //���չ��̽���ʱ����������
end        

//����rx_cnt��Ĵ�rxd�˿ڵ�����
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        rx_data_t <= 8'b0;
    else if(rx_flag) begin                           //ϵͳ���ڽ��չ���ʱ
        if(baud_cnt == BAUD_CNT_MAX/2 - 1'b1) begin  //�ж�baud_cnt�Ƿ�����������λ���м�
           case(rx_cnt)
               4'd1 : rx_data_t[0] <= uart_rxd_d2;   //�Ĵ����ݵ�����λ
               4'd2 : rx_data_t[1] <= uart_rxd_d2;
               4'd3 : rx_data_t[2] <= uart_rxd_d2;
               4'd4 : rx_data_t[3] <= uart_rxd_d2;
               4'd5 : rx_data_t[4] <= uart_rxd_d2;
               4'd6 : rx_data_t[5] <= uart_rxd_d2;
               4'd7 : rx_data_t[6] <= uart_rxd_d2;
               4'd8 : rx_data_t[7] <= uart_rxd_d2;   //�Ĵ����ݵĸߵ�λ
               default : ;
            endcase  
        end
        else
            rx_data_t <= rx_data_t;
    end
    else
        rx_data_t <= 8'b0;
end        

//�����������źźͽ��յ������ݸ�ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        uart_rx_done <= 1'b0;
        uart_rx_data <= 8'b0;
    end
    //���������ݼ�����������ֹͣλ����baud_cnt������ֹͣλ���м�ʱ
    else if(rx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX/2 - 1'b1) begin
        uart_rx_done <= 1'b1     ;  //��߽��������ź�
        uart_rx_data <= rx_data_t;  //����UART���յ������ݽ��и�ֵ
    end    
    else begin
        uart_rx_done <= 1'b0;
        uart_rx_data <= uart_rx_data;
    end
end

endmodule
//****************************************Copyright (c)***********************************//
//ԭ�Ӹ����߽�ѧƽ̨��www.yuanzige.com
//����֧�֣�http://www.openedv.com/forum.php
//�Ա����̣�https://zhengdianyuanzi.tmall.com
//��ע΢�Ź���ƽ̨΢�źţ�"����ԭ��"�����ѻ�ȡZYNQ & FPGA & STM32 & LINUX���ϡ�
//��Ȩ���У�����ؾ���
//Copyright(C) ����ԭ�� 2023-2033
//All rights reserved                                  
//----------------------------------------------------------------------------------------
// File name:           uart_tx
// Created by:          ����ԭ��
// Created date:        2023��2��16��14:20:02
// Version:             V1.0
// Descriptions:        UART���ڷ���ģ��
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_tx(
    input               clk         , //ϵͳʱ��
    input               rst_n       , //ϵͳ��λ������Ч
    input               uart_tx_en  , //UART�ķ���ʹ��
    input     [7:0]     uart_tx_data, //UARTҪ���͵�����
    output  reg         uart_txd    , //UART���Ͷ˿�
    output  reg  [3:0]  tx_cnt      ,  //�������ݼ�����
    output  reg  [15:0] baud_cnt    ,  //�����ʼ�����
    output  reg         uart_tx_done,
    output  reg         uart_tx_busy  //����æ״̬�ź�
    );

//parameter define
parameter CLK_FREQ = 50000000;               //ϵͳʱ��Ƶ��
parameter UART_BPS = 115200  ;               //���ڲ�����
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //Ϊ�õ�ָ�������ʣ���ϵͳʱ�Ӽ���BPS_CNT��

//reg define
reg  [7:0]  tx_data_t;  //�������ݼĴ���
//�����ʵļ�������ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        uart_tx_done<=1'b0;
    else if(tx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX - 1) begin
       uart_tx_done<=1'b1;
    end    
    else
        uart_tx_done<=1'b0;     //���͹��̽���ʱ����������
end


//*****************************************************
//**                    main code
//*****************************************************

//��uart_tx_enΪ��ʱ���Ĵ������IJ������ݣ������BUSY�ź�
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        tx_data_t <= 8'b0;
        uart_tx_busy <= 1'b0;
    end
    //����ʹ��ʱ���Ĵ�Ҫ���͵����ݣ������BUSY�ź�
    else if(uart_tx_en) begin
        tx_data_t <= uart_tx_data;
        uart_tx_busy <= 1'b1;
    end
    //��������ֹͣλ����ʱ��ֹͣ���͹���
    else if(tx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX - 1) begin
        tx_data_t <= 8'b0;     //���շ������ݼĴ���
        uart_tx_busy <= 1'b0;  //�����BUSY�ź�
    end
    else begin
        tx_data_t <= tx_data_t;
        uart_tx_busy <= uart_tx_busy;
    end
end

//�����ʵļ�������ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        baud_cnt <= 16'd0;
    else if(uart_tx_en)  
        baud_cnt <= 16'd0;      
    //�����ڷ��͹���ʱ�������ʼ�������baud_cnt������ѭ������
    else if(uart_tx_busy) begin
        if(baud_cnt < BAUD_CNT_MAX - 1'b1)
            baud_cnt <= baud_cnt + 16'b1;
        else 
            baud_cnt <= 16'd0; //�����ﵽһ�����������ں�����
    end    
    else
        baud_cnt <= 16'd0;     //���͹��̽���ʱ����������
end

//tx_cnt���и�ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        tx_cnt <= 4'd0;
    else if(uart_tx_en)  
        tx_cnt <= 16'd0;         
    else if(uart_tx_busy) begin             //���ڷ��͹���ʱtx_cnt�Ž��м���
        if(baud_cnt == BAUD_CNT_MAX - 1'b1) //�������ʼ�����������һ������������ʱ
            tx_cnt <= tx_cnt + 1'b1;        //�������ݼ�������1
        else
            tx_cnt <= tx_cnt;
    end
    else
        tx_cnt <= 4'd0;                     //���͹��̽���ʱ����������
end

//����tx_cnt���uart���Ͷ˿ڸ�ֵ
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        uart_txd <= 1'b1;
    else if(uart_tx_busy) begin
        case(tx_cnt) 
            4'd0 : uart_txd <= 1'b0        ; //��ʼλ
            4'd1 : uart_txd <= tx_data_t[0]; //����λ����λ
            4'd2 : uart_txd <= tx_data_t[1];
            4'd3 : uart_txd <= tx_data_t[2];
            4'd4 : uart_txd <= tx_data_t[3];
            4'd5 : uart_txd <= tx_data_t[4];
            4'd6 : uart_txd <= tx_data_t[5];
            4'd7 : uart_txd <= tx_data_t[6];
            4'd8 : uart_txd <= tx_data_t[7]; //����λ����λ
            4'd9 : uart_txd <= 1'b1        ; //ֹͣλ
            default : uart_txd <= 1'b1;
        endcase
    end
    else
        uart_txd <= 1'b1;                    //����ʱ���Ͷ˿�Ϊ�ߵ�ƽ
end

endmodule

2.数码管驱动

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/05/03 20:43:29
// Design Name: 
// Module Name: seg_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module seg_ctrl( 
    input				   clk		,
    input				   rst_n	,
    input		[23:0]	din		,
    input      [5:0]    point_n ,
    output	reg	[5:0]	sel	,
    output	reg	[7:0]	dig  
);								 

    parameter TIME_1MS = 50_000;//1ms

    localparam NUM_0 = 7'b100_0000,//0
               NUM_1 = 7'b111_1001,//1
               NUM_2 = 7'b010_0100,//
               NUM_3 = 7'b011_0000,//
               NUM_4 = 7'b001_1001,//
               NUM_5 = 7'b001_0010,//
               NUM_6 = 7'b000_0010,//
               NUM_7 = 7'b111_1000,//
               NUM_8 = 7'b000_0000,//
               NUM_9 = 7'b001_0000,//
               A     = 7'b000_1000,//
               B     = 7'b000_0011,//b
               C     = 7'b100_0110,//
               OFF   = 7'b111_1111,//???
               CROSS = 7'b011_1111,//????
               //D     = 7'b010_0001,//d
               //E     = 7'b000_0110,//
               F     = 7'b000_1110;//

//---------<?????????>-----------------------------------------------------
    reg			[15:0]	cnt_1ms	   	;//1ms???????????????????????
    wire				add_cnt_1ms	;
    wire				end_cnt_1ms	;

    reg         [3:0]   disp_data   ;//??¦Ë??????????????
    reg                 point_n_r   ;//??¦Ë???????????§³????
    
//****************************************************************
//--cnt_1ms
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_1ms <= 'd0;
        end 
        else if(add_cnt_1ms)begin 
            if(end_cnt_1ms)begin 
                cnt_1ms <= 'd0;
            end
            else begin 
                cnt_1ms <= cnt_1ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_1ms = 1'b1;//??????????
    assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS - 1;
    
//****************************************************************
//--seg_sel
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            sel <= 6'b111_110;//?????¦Ë???????????¦Ë??????
        end 
        else if(end_cnt_1ms)begin 
            sel <= {sel[4:0],sel[5]};//???????
        end 
    end

//****************************************************************
//--disp_data
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            disp_data <= 'd0;
            point_n_r <= 1'b1;
        end 
        else begin 
            case (sel)
                6'b111_110 : begin disp_data <= din[3:0]  ; point_n_r <= point_n[0]; end//???¦Ë??????????????
                6'b111_101 : begin disp_data <= din[7:4]  ; point_n_r <= point_n[1]; end
                6'b111_011 : begin disp_data <= din[11:8] ; point_n_r <= point_n[2]; end
                6'b110_111 : begin disp_data <= din[15:12]; point_n_r <= point_n[3]; end
                6'b101_111 : begin disp_data <= din[19:16]; point_n_r <= point_n[4]; end
                6'b011_111 : begin disp_data <= din[23:20]; point_n_r <= point_n[5]; end
                default: disp_data <= 'd0;
            endcase
        end 
    end

//****************************************************************
//--seg_dig
//****************************************************************
    always @(*)begin 
        case (disp_data)
            0 :  dig = {point_n_r,NUM_0};
            1 :  dig = {point_n_r,NUM_1};
            2 :  dig = {point_n_r,NUM_2};
            3 :  dig = {point_n_r,NUM_3};
            4 :  dig = {point_n_r,NUM_4};
            5 :  dig = {point_n_r,NUM_5};
            6 :  dig = {point_n_r,NUM_6};
            7 :  dig = {point_n_r,NUM_7};
            8 :  dig = {point_n_r,NUM_8};
            9 :  dig = {point_n_r,NUM_9};
            10 : dig = {point_n_r,A    };
            11 : dig = {point_n_r,B    };
            12 : dig = {point_n_r,C    };
            13 : dig = {point_n_r,CROSS};
            14 : dig = {point_n_r,OFF  };
            15 : dig = {point_n_r,F    };
            default: dig = 8'hff;
        endcase
    end


endmodule



3.顶层模块

module top(
    input                     sys_clk  ,  
    input                     rst_n, 
	 input            		   uart_rxd ,   
    output           		   uart_txd ,
	 output				wire		beep,
	 output wire [5:0]	      sel	,
    output wire [7:0]	      dig   ,
	 // UART相关信号
	 output wire         uart_tx_en,
	 output wire         uart_rx_done,
	 output wire         uart_tx_done,
	 output wire [7:0]   uart_tx_data,
	 output wire [7:0]   uart_rx_data,
	 
	 // FIFO相关信号 
	 output wire         rd_en,
	 output wire         wr_en,
	 output wire         empty,
	 output wire         full,
	 output reg          rd_en_reg,
	 output wire [7:0]   q,
	 output wire [23:0]	seg_data,
	 output wire [6:0]   data_count
	 
);

parameter TIME_250MS =   24'd12500000;
uart
//wire            uart_tx_en; 
//wire            uart_rx_done; 
//wire            uart_tx_done; 
//wire  [7:0]     uart_tx_data; 
//wire  [7:0]     uart_rx_data; 

fifo
//wire empty;
//wire full;
//wire [7:0]  q;
//wire [6:0]  data_count;
reg	[23:0]	cnt;

assign rd_en=(cnt==TIME_250MS && ~empty)?1'b1:1'b0;
assign wr_en=(data_count<7'd100)? uart_rx_done : 1'b0;

always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
		cnt<=24'd0;
	 end
	 else if(cnt<TIME_250MS)begin
		cnt<=cnt+1;
	 end
	 else begin
		cnt<=24'd0;
	 end
end

always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
		rd_en_reg<=1'b0;
	 end
	 else begin
		rd_en_reg<=rd_en;
	 end
end



uart_top u_uart_top(
    .sys_clk(sys_clk)  ,   
    .sys_rst_n(rst_n),   
    
    .uart_rx_done  (uart_rx_done),
    .uart_rx_data  (uart_rx_data),
    .uart_tx_en   (uart_tx_en),
    .uart_tx_data (uart_tx_data),
    .uart_tx_done (uart_tx_done),
    
    .uart_rxd(uart_rxd) ,  
    .uart_txd(uart_txd)    
    );

fifo	fifo_inst (
	.clock ( sys_clk ),
	.data  ( uart_rx_data ),
	.rdreq ( rd_en ),
	.wrreq ( wr_en),
	.empty ( empty ),
	.full  ( full ),
	.q ( q ),
	.usedw ( data_count )
	);

beep_uart u_beep_uart(
    .sys_clk    (sys_clk),
    .sys_rst_n  (rst_n),
    .beep_start (rd_en_reg),
    .uart_data  (q),
    .beep       (beep)
);

display_data u_display_data(
    .sys_clk    (sys_clk),
    .sys_rst_n  (rst_n),
    .move_start (rd_en_reg),
    .uart_data  (q),
    .seg_data   (seg_data)
);

seg_ctrl u_seg_ctrl(
    .clk     (sys_clk),         // 系统时钟
    .rst_n   (rst_n),       // 系统复位
    .din     (seg_data),   // 显示数据输入
    .point_n (6'b111111),   // 小数点选择
    .sel     (sel),     // 位选输出
    .dig     (dig)      // 段选输出
);
	 
	 
endmodule

4.蜂鸣器驱动

module  beep_uart
(
    input   wire        sys_clk     ,   //系统时钟,频率50MHz
    input   wire        sys_rst_n   ,   //系统复位,低有效
	 input	wire			beep_start  ,
	 input	wire	[7:0] uart_data   ,
    output  reg         beep            //输出蜂鸣器控制信号
);

//后台私信获取


endmodule


网站公告

今日签到

点亮在社区的每一天
去签到