题目要求
要求:
通过串口接收要播放的音符,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) 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
。