main.c
- #include <reg52.h>
- #include <intrins.h>
- #include "keyscan.h"
- // 定时器0初始化
- void Timer0_Init()
- {
- TMOD |= 0x01; // 定时器0,工作模式1
- TH0 = 0xFC; // 1ms定时
- TL0 = 0x18;
- ET0 = 1; // 允许定时器0中断
- TR0 = 1; // 启动定时器0
- EA = 1; // 开启总中断
- }
- // 主函数
- void main()
- {
- // 初始化
- P0 = 0xFF;
- P1 = 0xFF;
- P2 = 0x00; // LED初始全灭
- P3 = 0xFF;
- MAX7219_Init();
- Clear_Display();
- Display_Speed();
- Display_BeatType();
- Timer0_Init();
- while(1)
- {
- Key_Scan();
- }
- }
- // 定时器0中断服务程序
- void Timer0_ISR() interrupt 1
- {
- TH0 = 0xFC; // 重新装载初值
- TL0 = 0x18;
- timer_count++;
- if(is_playing)
- {
- if(timer_count >= interval)
- {
- timer_count = 0;
- // 产生节拍
- Update_LEDs();
- Output_Sound();
- // 更新拍数
- beat_count++;
- if(beat_count >= beats_per_bar[beat_type])
- {
- beat_count = 0;
- }
- }
- }
- }
- keyscan.c
- #include "keyscan.h"
- unsigned int interval = 0;
- unsigned char is_playing = 0;
- unsigned char beat_count = 0;
- unsigned int timer_count = 0;
- // 按键扫描
- void Key_Scan()
- {
- static unsigned char key_up_flag = 1;
- static unsigned char key_down_flag = 1;
- static unsigned char key_type_flag = 1;
- static unsigned char key_start_flag = 1;
- // 速度+按键
- if(KEY_UP == 0)
- {
- if(key_up_flag)
- {
- key_up_flag = 0;
- if(beat_speed < 240)
- {
- beat_speed += 1;
- Display_Speed();
- if(is_playing)
- {
- // 重新计算间隔
- interval = 60000 / beat_speed; // ms
- }
- }
- }
- }
- else
- {
- key_up_flag = 1;
- }
- // 速度-按键
- if(KEY_DOWN == 0)
- {
- if(key_down_flag)
- {
- key_down_flag = 0;
- if(beat_speed > 40)
- {
- beat_speed -= 1;
- Display_Speed();
- if(is_playing)
- {
- interval = 60000 / beat_speed; // ms
- }
- }
- }
- }
- else
- {
- key_down_flag = 1;
- }
- // 拍型选择按键
- if(KEY_TYPE == 0)
- {
- if(key_type_flag)
- {
- key_type_flag = 0;
- beat_type = (beat_type + 1) % 4;
- beat_count = 0;
- Display_BeatType();
- Update_LEDs();
- }
- }
- else
- {
- key_type_flag = 1;
- }
- // 开始/停止按键
- if(KEY_START == 0)
- {
- if(key_start_flag)
- {
- key_start_flag = 0;
- is_playing = !is_playing;
- if(is_playing)
- {
- beat_count = 0;
- interval = 60000 / beat_speed; // 计算每个节拍的时间间隔(ms)
- timer_count = 0;
- // 显示运行状态
- MAX7219_WriteCmd(5, 0x80); // 在第五位显示点
- }
- else
- {
- MAX7219_WriteCmd(5, 0x00); // 显示停止状态
- LED1 = LED2 = LED3 = LED4 = LED5 = LED6 = 0; // 关闭所有LED
- }
- }
- }
- else
- {
- key_start_flag = 1;
- }
- }
- void delay_ms(unsigned int ms)
- {
- unsigned int i, j;
- for(i = 0; i < ms; i++)
- for(j = 0; j < 114; j++);
- }
- // 更新指示灯
- void Update_LEDs()
- {
- LED1 = LED2 = LED3 = LED4 = LED5 = LED6 = 0; // 先关闭所有LED
- switch(beat_type)
- {
- case 0: // 2/4拍
- if(beat_count == 0) LED1 = 1; // 强拍
- if(beat_count == 1) LED2 = 1; // 弱拍
- break;
- case 1: // 3/4拍
- if(beat_count == 0) LED1 = 1; // 强拍
- if(beat_count == 1) LED2 = 1; // 弱拍
- if(beat_count == 2) LED3 = 1; // 弱拍
- break;
- case 2: // 4/4拍
- if(beat_count == 0) LED1 = 1; // 强拍
- if(beat_count == 1) LED2 = 1; // 弱拍
- if(beat_count == 2) LED3 = 1; // 次强拍
- if(beat_count == 3) LED4 = 1; // 弱拍
- break;
- case 3: // 6/8拍
- if(beat_count == 0) LED1 = 1; // 强拍
- if(beat_count == 1) LED2 = 1; // 弱拍
- if(beat_count == 2) LED3 = 1; // 弱拍
- if(beat_count == 3) LED4 = 1; // 次强拍
- if(beat_count == 4) LED5 = 1; // 弱拍
- if(beat_count == 5) LED6 = 1; // 弱拍
- break;
- }
- }
- // 输出音源信号
- void Output_Sound()
- {
- // 根据拍型输出不同的音源
- switch(beat_type)
- {
- case 0: // 2/4拍
- if(beat_count == 0)
- {
- SOUND1 = 1; // 强拍
- delay_ms(20);
- SOUND1 = 0;
- }
- else
- {
- SOUND2 = 1; // 弱拍
- delay_ms(10);
- SOUND2 = 0;
- }
- break;
- case 1: // 3/4拍
- if(beat_count == 0)
- {
- SOUND1 = 1; // 强拍
- delay_ms(20);
- SOUND1 = 0;
- }
- else
- {
- SOUND3 = 1; // 弱拍
- delay_ms(10);
- SOUND3 = 0;
- }
- break;
- case 2: // 4/4拍
- if(beat_count == 0)
- {
- SOUND1 = 1; // 强拍
- delay_ms(20);
- SOUND1 = 0;
- } else if(beat_count == 2)
- {
- SOUND2 = 1; // 次强拍
- delay_ms(15);
- SOUND2 = 0;
- }
- else
- {
- SOUND3 = 1; // 弱拍
- delay_ms(10);
- SOUND3 = 0;
- }
- break;
- case 3: // 6/8拍
- if(beat_count == 0)
- {
- SOUND1 = 1; // 强拍
- delay_ms(20);
- SOUND1 = 0;
- }
- else if(beat_count == 3)
- {
- SOUND2 = 1; // 次强拍
- delay_ms(15);
- SOUND2 = 0;
- }
- else
- {
- SOUND4 = 1; // 弱拍
- delay_ms(10);
- SOUND4 = 0;
- }
- break;
- }
- }
- diplay.c
- #include "display.h"
- unsigned int beat_speed = 120; // 节拍速度(BPM),默认120
- unsigned char beat_type = 0; // 拍型索引 0:2/4, 1:3/4, 2:4/4, 3:6/8
- // 数字字体(0-9)
- unsigned char code font_table[] =
- {
- 0x7E, 0x30, 0x6D, 0x79, 0x33,
- 0x5B, 0x5F, 0x70, 0x7F, 0x7B
- };
- // 拍型对应的每小节拍数
- unsigned char code beats_per_bar[] = {2, 3, 4, 6};
- // MAX7219初始化命令
- unsigned char code init_cmds[][2] =
- {
- {0x0C, 0x01}, // 关闭关机模式
- {0x0B, 0x07}, // 扫描所有8位
- {0x0A, 0x08}, // 亮度
- {0x09, 0x00}, // 解码模式:无
- {0x0F, 0x00} // 显示测试:关闭
- };
- // MAX7219写一个字节
- void MAX7219_WriteByte(unsigned char data_byte)
- {
- unsigned char i;
- for(i = 0; i < 8; i++)
- {
- MAX7219_CLK = 0;
- MAX7219_DIN = (data_byte & 0x80) ? 1 : 0;
- data_byte <<= 1;
- MAX7219_CLK = 1;
- }
- }
- // MAX7219写命令
- void MAX7219_WriteCmd(unsigned char address, unsigned char data_byte)
- {
- MAX7219_CS = 0;
- MAX7219_WriteByte(address);
- MAX7219_WriteByte(data_byte);
- MAX7219_CS = 1;
- }
- // MAX7219初始化
- void MAX7219_Init()
- {
- unsigned char i;
- for(i = 0; i < 5; i++)
- {
- MAX7219_WriteCmd(init_cmds[i][0], init_cmds[i][1]);
- }
- }
- // 在数码管上显示数字
- void Display_Number(unsigned char digit, unsigned char number)
- {
- if(digit >= 1 && digit <= 8)
- {
- MAX7219_WriteCmd(digit, number);
- }
- }
- // 显示当前速度
- void Display_Speed()
- {
- unsigned char bai, shi, ge;
- bai = beat_speed / 100;
- shi = (beat_speed % 100) / 10;
- ge = beat_speed % 10;
- // 显示在4-6位数码管上
- Display_Number(3, font_table[bai]);
- Display_Number(2, font_table[shi]);
- Display_Number(1, font_table[ge]);
- }
- // 显示拍型
- void Display_BeatType()
- {
- switch(beat_type)
- {
- case 0: Display_Number(8, 0x6D); //2
- Display_Number(7, 0x01);
- Display_Number(6, 0x33); break; // 4
- case 1: Display_Number(8, 0x79); // 3
- Display_Number(7, 0x01);
- Display_Number(6, 0x33); break; // 4
- case 2: Display_Number(8, 0x33); // 4
- Display_Number(7, 0x01);
- Display_Number(6, 0x33); break; // 4
- case 3: Display_Number(8, 0x5F); // 6
- Display_Number(7, 0x01);
- Display_Number(6, 0x7F); break; // 8
- }
- }
- // 清除所有显示
- void Clear_Display()
- {
- unsigned char i;
- for(i = 1; i <= 8; i++)
- {
- MAX7219_WriteCmd(i, 0x00);
- }
- }
复制代码
|