Загрузка данных
// ============================================================
// Модуль: multi_melody_player
// 8 мелодий, выбираемых кнопками btn[7:0]
// LED индикация: [7:0] показывают номер выбранной мелодии
// и текущий шаг.
// 4-разрядный 7-сегм. дисплей: номер мелодии, символ ноты,
// октава, P (пауза) или длительность.
// Тактовая: 12 МГц, темп фиксированный ♩=60.
// ============================================================
module multi_melody_player(
input wire clk,
input wire [7:0] btn, // кнопки выбора мелодии
output wire [7:0] led, // светодиоды
output wire [6:0] seg, // сегменты A..G (общий катод)
output wire [3:0] an, // аноды (выбор разряда)
output wire audio
);
// ----------------------------------------------------------
// Антидребезг кнопок + выбор активной мелодии
// ----------------------------------------------------------
reg [19:0] debounce_cnt = 0; // примерно 20 мс при 12 МГц (240000 тактов)
// Для простоты будем считывать кнопки каждые 2^19 /12e6 ≈ 43 мс
wire sample_tick = (debounce_cnt == 20'd1_000_000); // ~83 мс на самом деле, можно точнее
reg [7:0] btn_r1 = 8'hFF, btn_r2 = 8'hFF;
reg [7:0] stable_btn = 8'h00;
reg [2:0] melody_select = 3'd0; // выбранная мелодия 0..7
always @(posedge clk) begin
debounce_cnt <= debounce_cnt + 1'b1;
if (sample_tick) begin
btn_r1 <= btn;
btn_r2 <= btn_r1;
if (btn_r1 == btn_r2) // стабильно в течение двух выборок
stable_btn <= btn_r1;
end
end
// Приоритетный шифратор 8 в 3 (можно простой энкодер)
always @* begin
casez(stable_btn)
8'b1111_1110: melody_select = 3'd0;
8'b1111_1101: melody_select = 3'd1;
8'b1111_1011: melody_select = 3'd2;
8'b1111_0111: melody_select = 3'd3;
8'b1110_1111: melody_select = 3'd4;
8'b1101_1111: melody_select = 3'd5;
8'b1011_1111: melody_select = 3'd6;
8'b0111_1111: melody_select = 3'd7;
default: melody_select = 3'd0; // если ничего не нажато
endcase
end
// ----------------------------------------------------------
// Генератор темпа (как раньше)
// ----------------------------------------------------------
localparam [23:0] TEMPO_MAX = 24'd2_999_999; // 0.25 с на шаг
reg [23:0] tempo_cnt = 0;
reg [5:0] step_num = 0; // 64 шага
always @(posedge clk) begin
if (tempo_cnt == TEMPO_MAX) begin
tempo_cnt <= 0;
step_num <= step_num + 1'b1;
end else begin
tempo_cnt <= tempo_cnt + 1'b1;
end
end
// ----------------------------------------------------------
// ПЗУ мелодий (таблица шаг -> код ноты)
// для каждой из 8 мелодий. Здесь заполним только первые 3,
// остальные можно сделать аналогично.
// ----------------------------------------------------------
reg [3:0] note_num;
always @* begin
case(melody_select)
3'd0: // Дебюсси (те же данные, что и раньше, но ноты из новой таблицы)
case(step_num)
6'd0,6'd1: note_num = 4'd4; // F4
6'd2,6'd3: note_num = 4'd14; // Bb4
6'd4,6'd5: note_num = 4'd15; // Db4 (C#4)
// ... далее заполнить соответственно новым кодам
default: note_num = 4'd0;
endcase
3'd1: // Ода к радости (упрощённо)
case(step_num)
6'd0,6'd1: note_num = 4'd3; // E4
6'd2,6'd3: note_num = 4'd3; // E4
6'd4,6'd5: note_num = 4'd4; // F4
6'd6,6'd7: note_num = 4'd5; // G4
6'd8,6'd9: note_num = 4'd5; // G4
6'd10,6'd11: note_num = 4'd4; // F4
6'd12,6'd13: note_num = 4'd3; // E4
6'd14,6'd15: note_num = 4'd2; // D4
6'd16,6'd17: note_num = 4'd1; // C4
6'd18,6'd19: note_num = 4'd1; // C4
6'd20,6'd21: note_num = 4'd2; // D4
6'd22,6'd23: note_num = 4'd3; // E4
6'd24,6'd25,6'd26,6'd27: note_num = 4'd3; // E4 (четверть с точкой)
6'd28,6'd29: note_num = 4'd2; // D4
6'd30,6'd31: note_num = 4'd2; // D4
default: note_num = 4'd0;
endcase
3'd2: // Happy Birthday
case(step_num)
6'd0: note_num = 4'd5; // G4
6'd1: note_num = 4'd5;
6'd2: note_num = 4'd6; // A4
6'd3: note_num = 4'd5;
6'd4: note_num = 4'd8; // C5
6'd5: note_num = 4'd7; // B4
6'd6,6'd7: note_num = 4'd5; // G4 G4
6'd8,6'd9: note_num = 4'd5; // G4
6'd10,6'd11: note_num = 4'd6; // A4
6'd12,6'd13: note_num = 4'd5; // G4
6'd14,6'd15: note_num = 4'd9; // D5
6'd16,6'd17: note_num = 4'd8; // C5
6'd18,6'd19: note_num = 4'd5; // G4
default: note_num = 4'd0;
endcase
// ... ещё 5 мелодий аналогично
default: note_num = 4'd0;
endcase
end
// ----------------------------------------------------------
// Таблица делителей для новых кодов нот (0..15)
// ----------------------------------------------------------
reg [15:0] clkdivider;
always @* begin
case(note_num)
4'd0: clkdivider = 16'd0; // пауза
4'd1: clkdivider = 16'h5996; // C4
4'd2: clkdivider = 16'h4FD2; // D4
4'd3: clkdivider = 16'h471A; // E4
4'd4: clkdivider = 16'h431F; // F4
4'd5: clkdivider = 16'h3BCA; // G4
4'd6: clkdivider = 16'h3544; // A4
4'd7: clkdivider = 16'h2F74; // B4
4'd8: clkdivider = 16'h2CCB; // C5
4'd9: clkdivider = 16'h27E9; // D5
4'd10: clkdivider = 16'h238D; // E5
4'd11: clkdivider = 16'h218F; // F5
4'd12: clkdivider = 16'h1DE5; // G5
4'd13: clkdivider = 16'h1AA2; // A5
4'd14: clkdivider = 16'h3245; // Bb4
4'd15: clkdivider = 16'h5490; // C#4 (Db4)
default: clkdivider = 16'd0;
endcase
end
// ----------------------------------------------------------
// Генератор звука (аналогичен предыдущему)
// ----------------------------------------------------------
reg [15:0] counter = 0;
reg audio_reg = 0;
always @(posedge clk) begin
if (clkdivider == 16'd0) begin
counter <= 0;
audio_reg <= 1'b0;
end else begin
if (counter == 16'd0) begin
counter <= clkdivider;
audio_reg <= ~audio_reg;
end else begin
counter <= counter - 1'b1;
end
end
end
assign audio = audio_reg;
// ----------------------------------------------------------
// LED индикация: показываем выбранную мелодию на 3 битах,
// и анимируем младшие 5 бит по step_num (для эффекта)
// ----------------------------------------------------------
wire [2:0] led_melody = melody_select;
wire [4:0] led_step = step_num[4:0];
assign led = {led_melody, led_step}; // 8 бит
// ----------------------------------------------------------
// Динамическая индикация для 4х 7-сегм. индикаторов
// ----------------------------------------------------------
// Разряды: an[3] = левый, an[0] = правый
// Назначение:
// an[3] -> номер мелодии (0-7)
// an[2] -> символ ноты (C,D,E,F,G,A,B,P или диез/бемоль) – упростим до цифры кода ноты 0..15
// an[1] -> октава (3,4,5) или '-'
// an[0] -> 'P' если пауза, иначе пробел/ничего
// Для простоты будем выводить шестнадцатеричные цифры, соответствующие кодам.
// Таблица символов 7-сегм (0..F), общий катод.
//-----------------------------------------------------------
reg [15:0] seg_data; // 4 ниббла
always @* begin
seg_data[15:12] = {1'b0, melody_select}; // номер мелодии 0..7
seg_data[11:8] = note_num; // код ноты
// октава: определим по note_num (C4..B4 => октава 4, C5..A5 => октава 5)
case(note_num)
4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd14,4'd15: seg_data[7:4] = 4'h4;
4'd8,4'd9,4'd10,4'd11,4'd12,4'd13: seg_data[7:4] = 4'h5;
default: seg_data[7:4] = 4'hA; // "-"
endcase
seg_data[3:0] = (note_num == 4'd0) ? 4'hP : 4'hF; // P (код 16) или F (пусто)
end
// Сканирование индикаторов с частотой ~1 кГц
reg [16:0] scan_cnt = 0;
wire scan_tick = (scan_cnt == 17'd119999); // 100 Гц на разряд
reg [1:0] digit_sel = 0;
always @(posedge clk) begin
scan_cnt <= scan_cnt + 1'b1;
if (scan_tick) begin
scan_cnt <= 0;
digit_sel <= digit_sel + 1'b1;
end
end
// Дешифратор выбора разряда
reg [3:0] an_reg;
always @* begin
case(digit_sel)
2'b00: an_reg = 4'b1110; // правый
2'b01: an_reg = 4'b1101;
2'b10: an_reg = 4'b1011;
2'b11: an_reg = 4'b0111; // левый
default: an_reg = 4'b1111;
endcase
end
assign an = an_reg;
// Мультиплексор данных для сегментов
reg [3:0] current_nibble;
always @* begin
case(digit_sel)
2'b00: current_nibble = seg_data[3:0];
2'b01: current_nibble = seg_data[7:4];
2'b10: current_nibble = seg_data[11:8];
2'b11: current_nibble = seg_data[15:12];
default: current_nibble = 4'h0;
endcase
end
// Преобразователь 4 бит -> 7 сегментов (a,b,c,d,e,f,g)
function [6:0] hex_to_7seg;
input [3:0] hex;
begin
case(hex)
4'h0: hex_to_7seg = 7'b1000000; // 0
4'h1: hex_to_7seg = 7'b1111001; // 1
4'h2: hex_to_7seg = 7'b0100100; // 2
4'h3: hex_to_7seg = 7'b0110000; // 3
4'h4: hex_to_7seg = 7'b0011001; // 4
4'h5: hex_to_7seg = 7'b0010010; // 5
4'h6: hex_to_7seg = 7'b0000010; // 6
4'h7: hex_to_7seg = 7'b1111000; // 7
4'h8: hex_to_7seg = 7'b0000000; // 8
4'h9: hex_to_7seg = 7'b0010000; // 9
4'hA: hex_to_7seg = 7'b0001000; // A
4'hB: hex_to_7seg = 7'b0000011; // b
4'hC: hex_to_7seg = 7'b1000110; // C
4'hD: hex_to_7seg = 7'b0100001; // d
4'hE: hex_to_7seg = 7'b0000110; // E
4'hF: hex_to_7seg = 7'b1111111; // всё выкл (или 0)
4'hP: hex_to_7seg = 7'b0001100; // P (приблизительно)
default: hex_to_7seg = 7'b1111111;
endcase
end
endfunction
assign seg = hex_to_7seg(current_nibble);
endmodule