基于fpga的串口控制的音乐播放器
基于fpga的串口控制的音乐播放器
- 题目要求
- 一、总体框架
- 二、verilog代码
- 1.串口驱动
- 2.数码管驱动
- 3.顶层模块
- 4.蜂鸣器驱动
题目要求
要求:
通过串口接收要播放的音符,do、re、mi、fa、sol、la、ti和高音do分别用数字1~8表示
收到音符后自动播放,每个音符的音长为0.5s
可在播放的同时接收新的音符,支持单个和批量发送(同一时刻待播放的音符数不超过100个)
在六位七段数码管上显示播放的音符,当前播放的显示在最右侧,每播放一个新的音符较早的音符左移
一、总体框架
串口驱动-----数码管驱动------蜂鸣器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) beginif(!rst_n) beginuart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0;uart_rxd_d2 <= 1'b0;endelse beginuart_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) beginif(!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;elserx_flag <= rx_flag;
end //�����ʵļ�������ֵ
always @(posedge clk or negedge rst_n) beginif(!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 elsebaud_cnt <= 16'd0; //���չ��̽���ʱ����������
end//�Խ������ݼ�������rx_cnt�����и�ֵ
always @(posedge clk or negedge rst_n) beginif(!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; //�������ݼ�������1elserx_cnt <= rx_cnt;endelserx_cnt <= 4'd0; //���չ��̽���ʱ����������
end //����rx_cnt��Ĵ�rxd�˿ڵ�����
always @(posedge clk or negedge rst_n) beginif(!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 endelserx_data_t <= rx_data_t;endelserx_data_t <= 8'b0;
end //�����������źźͽ��յ������ݸ�ֵ
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_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) beginuart_rx_done <= 1'b1 ; //��߽��������ź�uart_rx_data <= rx_data_t; //����UART���յ������ݽ��и�ֵend else beginuart_rx_done <= 1'b0;uart_rx_data <= uart_rx_data;end
endendmodule
//****************************************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) beginif(!rst_n) uart_tx_done<=1'b0;else if(tx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX - 1) beginuart_tx_done<=1'b1;end elseuart_tx_done<=1'b0; //�����̽���ʱ����������
end//*****************************************************
//** main code
//*****************************************************//��uart_tx_enΪ��ʱ���Ĵ������IJ������ݣ������BUSY�ź�
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_data_t <= 8'b0;uart_tx_busy <= 1'b0;end//����ʹ��ʱ���Ĵ�Ҫ���͵����ݣ������BUSY�ź�else if(uart_tx_en) begintx_data_t <= uart_tx_data;uart_tx_busy <= 1'b1;end//��������ֹͣλ����ʱ��ֹͣ������else if(tx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX - 1) begintx_data_t <= 8'b0; //���շ������ݼĴ���uart_tx_busy <= 1'b0; //�����BUSY�ź�endelse begintx_data_t <= tx_data_t;uart_tx_busy <= uart_tx_busy;end
end//�����ʵļ�������ֵ
always @(posedge clk or negedge rst_n) beginif(!rst_n) baud_cnt <= 16'd0;else if(uart_tx_en) baud_cnt <= 16'd0; //�����ڷ�����ʱ�������ʼ�������baud_cnt������ѭ������else if(uart_tx_busy) beginif(baud_cnt < BAUD_CNT_MAX - 1'b1)baud_cnt <= baud_cnt + 16'b1;else baud_cnt <= 16'd0; //�����ﵽһ�����������ں�����end elsebaud_cnt <= 16'd0; //�����̽���ʱ����������
end//tx_cnt���и�ֵ
always @(posedge clk or negedge rst_n) beginif(!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; //�������ݼ�������1elsetx_cnt <= tx_cnt;endelsetx_cnt <= 4'd0; //�����̽���ʱ����������
end//����tx_cnt���uart���Ͷ˿ڸ�ֵ
always @(posedge clk or negedge rst_n) beginif(!rst_n) uart_txd <= 1'b1;else if(uart_tx_busy) begincase(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;endcaseendelseuart_txd <= 1'b1; //����ʱ���Ͷ˿�Ϊ�ߵ�ƽ
endendmodule
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;//1mslocalparam NUM_0 = 7'b100_0000,//0NUM_1 = 7'b111_1001,//1NUM_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,//bC = 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)begincnt_1ms <= 'd0;end else if(add_cnt_1ms)begin if(end_cnt_1ms)begin cnt_1ms <= 'd0;endelse begin cnt_1ms <= cnt_1ms + 1'b1;end endend 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)beginsel <= 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)begindisp_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]; end6'b111_011 : begin disp_data <= din[11:8] ; point_n_r <= point_n[2]; end6'b110_111 : begin disp_data <= din[15:12]; point_n_r <= point_n[3]; end6'b101_111 : begin disp_data <= din[19:16]; point_n_r <= point_n[4]; end6'b011_111 : begin disp_data <= din[23:20]; point_n_r <= point_n[5]; enddefault: disp_data <= 'd0;endcaseend 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;endcaseendendmodule
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) beginif(!rst_n) begincnt<=24'd0;endelse if(cnt<TIME_250MS)begincnt<=cnt+1;endelse begincnt<=24'd0;end
endalways @(posedge sys_clk or negedge rst_n) beginif(!rst_n) beginrd_en_reg<=1'b0;endelse beginrd_en_reg<=rd_en;end
enduart_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 , //系统时钟,频率50MHzinput wire sys_rst_n , //系统复位,低有效input wire beep_start ,input wire [7:0] uart_data ,output reg beep //输出蜂鸣器控制信号
);//后台私信获取endmodule
。