Загрузка данных
// ==========================================================================
// multi_melody_player_v2
// Исправлено: 7-сегментная индикация, удлинённые мелодии (до 256 шагов),
// автосброс на начало при смене кнопки.
// ==========================================================================
module multi_melody_player_v2 #(
parameter SEG_INVERT = 1'b0, // 1 = инвертировать все сегменты (для общ. анода)
parameter SEG_ANODE = 1'b0 // если 1, то горящий сегмент = 0 (общ. анод), иначе 1 = горит
)(
input wire clk,
input wire [7:0] btn, // активный 0
output wire [7:0] led,
output wire [7:0] dig0, dig1, dig2, dig3,
output wire speaker
);
// ==========================================================================
// Антидребезг, детектор нажатия, запоминание мелодии и сброс шага
// ==========================================================================
reg [7:0] btn_sync0, btn_sync1;
reg [3:0] btn_cnt [7:0]; // для каждой кнопки
wire [7:0] btn_pressed; // импульс (1 такт) при стабильном нажатии
genvar i;
generate for (i = 0; i < 8; i = i + 1) begin : debounce
always @(posedge clk) begin
btn_sync0 <= ~btn; // инвертируем: теперь 1 = нажата
btn_sync1 <= btn_sync0;
if (btn_sync1[i]) begin
if (btn_cnt[i] < 10) // ~0.83 мкс * 10 = 8.3 мкс минимум
btn_cnt[i] <= btn_cnt[i] + 1'b1;
end else begin
btn_cnt[i] <= 4'd0;
end
end
assign btn_pressed[i] = (btn_cnt[i] == 4'd10); // 1 такт, когда достигли порога
end
endgenerate
reg [2:0] melody = 3'd0;
reg [7:0] step = 8'd0; // 0..255
always @(posedge clk) begin
// Защёлкиваем мелодию по фронту нажатия и сбрасываем шаг
if (btn_pressed[0]) {melody, step} <= {3'd0, 8'd0};
if (btn_pressed[1]) {melody, step} <= {3'd1, 8'd0};
if (btn_pressed[2]) {melody, step} <= {3'd2, 8'd0};
if (btn_pressed[3]) {melody, step} <= {3'd3, 8'd0};
if (btn_pressed[4]) {melody, step} <= {3'd4, 8'd0};
if (btn_pressed[5]) {melody, step} <= {3'd5, 8'd0};
if (btn_pressed[6]) {melody, step} <= {3'd6, 8'd0};
if (btn_pressed[7]) {melody, step} <= {3'd7, 8'd0};
end
// ==========================================================================
// Генератор темпа (шаг 0.25 сек = 1/16 при ♩=60)
// ==========================================================================
localparam [23:0] TEMPO_MAX = 24'd2_999_999;
reg [23:0] tempo_cnt = 0;
always @(posedge clk) begin
if (tempo_cnt == TEMPO_MAX) begin
tempo_cnt <= 0;
step <= step + 1'b1;
end else begin
tempo_cnt <= tempo_cnt + 1'b1;
end
end
// ==========================================================================
// ПЗУ мелодий: 8 мелодий, до 256 шагов, коды нот 0..15
// ==========================================================================
reg [3:0] note;
always @* begin
case(melody)
// Мелодия 0: Дебюсси – можно заполнить позже (пока паузы)
3'd0: note = 4'd0;
// Мелодия 1: Ода к радости (расширенная)
3'd1: case(step)
8'd0,8'd1: note = 4'd3; // E4
8'd2,8'd3: note = 4'd3;
8'd4,8'd5: note = 4'd4; // F4
8'd6,8'd7: note = 4'd5; // G4
8'd8,8'd9: note = 4'd5;
8'd10,8'd11: note = 4'd4;
8'd12,8'd13: note = 4'd3;
8'd14,8'd15: note = 4'd2; // D4
8'd16,8'd17: note = 4'd1; // C4
8'd18,8'd19: note = 4'd1;
8'd20,8'd21: note = 4'd2;
8'd22,8'd23: note = 4'd3;
8'd24,8'd25: note = 4'd3;
8'd26,8'd27: note = 4'd2;
8'd28,8'd29: note = 4'd2; // Конец первой фразы
// Повтор (можно продолжить или поставить паузу)
default: note = 4'd0;
endcase
// Мелодия 2: Happy Birthday (исправленная и удлинённая)
3'd2: case(step)
// Hap-py birth-day to you
8'd0,8'd1: note = 4'd5; // G4
8'd2,8'd3: note = 4'd5;
8'd4,8'd5: note = 4'd6; // A4
8'd6,8'd7: note = 4'd5;
8'd8,8'd9,8'd10,8'd11: note = 4'd8; // C5
8'd12,8'd13,8'd14,8'd15: note = 4'd7; // B4
// Hap-py birth-day to you
8'd16,8'd17: note = 4'd5;
8'd18,8'd19: note = 4'd5;
8'd20,8'd21: note = 4'd6;
8'd22,8'd23: note = 4'd5;
8'd24,8'd25,8'd26,8'd27: note = 4'd9; // D5
8'd28,8'd29,8'd30,8'd31: note = 4'd8; // C5
// Hap-py birth-day dear [Name]
8'd32,8'd33: note = 4'd5;
8'd34,8'd35: note = 4'd5;
8'd36,8'd37: note = 4'd3; // E4
8'd38,8'd39: note = 4'd8; // C5
8'd40,8'd41: note = 4'd7; // B4
8'd42,8'd43: note = 4'd6; // A4
8'd44..8'd47: note = 4'd0; // пауза
// ... to you
8'd48,8'd49: note = 4'd4; // F4
8'd50,8'd51: note = 4'd4;
8'd52,8'd53: note = 4'd3; // E4
8'd54..8'd57: note = 4'd8; // C5
8'd58,8'd59: note = 4'd9; // D5
8'd60..8'd63: note = 4'd8; // C5
default: note = 4'd0;
endcase
// Мелодии 3..7 — аналогично можно расширить до 256 шагов
3'd3: note = (step < 64) ? 4'd3 : 4'd0; // заглушка Imperial March
3'd4: note = (step < 64) ? 4'd3 : 4'd0; // Jingle Bells
3'd5: note = (step < 64) ? 4'd5 : 4'd0; // Mozart
3'd6: note = (step < 64) ? 4'd4 : 4'd0; // Yesterday
3'd7: note = (step < 64) ? 4'd3 : 4'd0; // Tetris
default: note = 4'd0;
endcase
end
// ==========================================================================
// Делители частоты (16 нот)
// ==========================================================================
reg [15:0] divider;
always @* begin
case(note)
4'd0: divider = 16'd0;
4'd1: divider = 16'h5996; // C4
4'd2: divider = 16'h4FD2; // D4
4'd3: divider = 16'h471A; // E4
4'd4: divider = 16'h431F; // F4
4'd5: divider = 16'h3BCA; // G4
4'd6: divider = 16'h3544; // A4
4'd7: divider = 16'h2F74; // B4
4'd8: divider = 16'h2CCB; // C5
4'd9: divider = 16'h27E9; // D5
4'd10: divider = 16'h238D; // E5
4'd11: divider = 16'h218F; // F5
4'd12: divider = 16'h1DE5; // G5
4'd13: divider = 16'h1AA2; // A5
4'd14: divider = 16'h3245; // Bb4
4'd15: divider = 16'h5490; // C#4 (Db4)
default: divider = 16'd0;
endcase
end
// ==========================================================================
// Генератор звука
// ==========================================================================
reg [15:0] cnt = 0;
reg spk = 0;
always @(posedge clk) begin
if (divider == 16'd0) begin
cnt <= 0;
spk <= 1'b0;
end else begin
if (cnt == 16'd0) begin
cnt <= divider;
spk <= ~spk;
end else begin
cnt <= cnt - 1'b1;
end
end
end
assign speaker = spk;
// ==========================================================================
// LED индикация
// ==========================================================================
assign led = {melody, step[4:0]};
// ==========================================================================
// 7-сегментная индикация (настраиваемая)
// ==========================================================================
// Формат: dig3 = номер мелодии (0-7)
// dig2 = код ноты (0-F)
// dig1 = октава (4/5) или '-'
// dig0 = 'P' или пусто
wire [3:0] d3 = {1'b0, melody};
wire [3:0] d2 = note;
reg [3:0] octave;
always @* begin
case(note)
4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd14,4'd15: octave = 4'd4;
4'd8,4'd9,4'd10,4'd11,4'd12,4'd13: octave = 4'd5;
default: octave = 4'd10; // '-'
endcase
end
wire [3:0] d1 = octave;
wire [3:0] d0 = (note == 4'd0) ? 4'd16 : 4'd15; // 16 = 'P', 15 = пусто
// Универсальный дешифратор 5-битного символа в 8-битный код сегментов.
// Порядок бит на выходе: [7]=dp, [6]=g, [5]=f, [4]=e, [3]=d, [2]=c, [1]=b, [0]=a.
// Это наиболее часто встречающаяся распиновка (a — младший бит).
// Если на вашей плате порядок иной, просто измените биты в case.
function [7:0] seg_decode;
input [4:0] sym;
reg [7:0] code;
begin
case(sym)
5'd0: code = 8'b00111111; // 0
5'd1: code = 8'b00000110; // 1
5'd2: code = 8'b01011011; // 2
5'd3: code = 8'b01001111; // 3
5'd4: code = 8'b01100110; // 4
5'd5: code = 8'b01101101; // 5
5'd6: code = 8'b01111101; // 6
5'd7: code = 8'b00000111; // 7
5'd8: code = 8'b01111111; // 8
5'd9: code = 8'b01101111; // 9
5'd10: code = 8'b01000000; // '-'
5'd11: code = 8'b00000000; // пусто
5'd12: code = 8'b00000000;
5'd13: code = 8'b00000000;
5'd14: code = 8'b00000000;
5'd15: code = 8'b00000000; // пусто
5'd16: code = 8'b01110011; // P
default: code = 8'b00000000;
endcase
// Применяем инверсию, если нужно
if (SEG_ANODE)
code = ~code;
if (SEG_INVERT)
code = ~code; // дополнительная глобальная инверсия, если требуется
seg_decode = code;
end
endfunction
assign dig0 = seg_decode({1'b0, d0});
assign dig1 = seg_decode({1'b0, d1});
assign dig2 = seg_decode({1'b0, d2});
assign dig3 = seg_decode({1'b0, d3});
endmodule