先上效果:
最近在学单片机和c语言,买了设备,跟着教程学了基础。
感觉各种语言虽然形式不同,但内核逻辑都大同小异,只要掌握了逻辑,就能很快学会。我从只会python到把c语言入门,只用了一个周,因为这些语言都很相似,,,运算符、变量类型、函数、运算逻辑,,,,,,基本都相通,好学。
唯一一点没习惯的就是换行前老是忘打分号
学完基础,我就手打了一下
不多废话。上代码。
main.c
#include <REGX52.H>
#include <Delay.h>
#include <music.h>
#include <LCD1602.h>
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Playing:");
LCD_ShowString(2,1,"--");
while(1)
{
if (P3_1==0)
{
Delay(2000);
while(P3_1==0);
break;
}
}
LCD_Init();
LCD_ShowString(1,1,"Playing:");
LCD_ShowString(2,1,"Haruhikage");
music('q',1);
music('p',0.5);
music('o',1);
music('p',0.5);
music('q',0.75);
music('r',0.25);
music('q',0.5);
music('p',1.5);
music('q',1);
music('p',0.5);
music('o',1);
music('p',0.5);
music('q',0.75);
music('r',0.25);
music('q',0.5);
music('p',1.5);
music('q',1);
music('p',0.5);
music('o',1);
music('p',0.5);
music('q',0.75);
music('r',0.25);
music('q',0.5);
music('p',1);
music('h',0.25);
music('i',0.25);
music('j',0.5);
music('j',0.5);
music('i',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('i',0.5);
music('i',0.5);
music('h',0.25);
music('h',0.25);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('i',1);
music('h',0.25);
music('i',0.25);
music('j',1.5);
music('z',1.5);
music('j',0.5);
music('l',0.5);
music('o',0.5);
music('n',1);
music('o',0.5);
music('n',1);
music('o',0.5);
music('n',0.25);
music('m',0.25);
music('l',1);
music('l',0.5);
music('i',0.5);
music('k',0.5);
music('k',1);
music('j',0.5);
music('j',1);
music('e',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('j',1);
music('l',0.5);
music('h',1.5);
music('z',1);
music('h',0.5);
music('i',0.5);
music('h',0.75);
music('h',0.25);
music('h',0.5);
music('l',0.5);
music('h',0.5);
music('k',1);
music('j',0.5);
music('i',1);
music('h',0.5);
music('h',1.5);
music('z',1);
music('h',0.25);
music('i',0.25);
music('j',0.5);
music('j',0.5);
music('i',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('i',0.5);
music('i',0.5);
music('h',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('i',1);
music('h',0.25);
music('i',0.25);
music('j',1.5);
music('z',1.5);
music('j',0.5);
music('l',0.5);
music('o',0.5);
music('n',1);
music('o',0.5);
music('n',1);
music('o',0.5);
music('n',0.25);
music('m',0.25);
music('l',1);
music('l',0.5);
music('i',0.5);
music('k',0.5);
music('k',1);
music('j',0.5);
music('j',1);
music('e',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('j',1);
music('l',0.5);
music('h',1.5);
music('z',1);
music('h',0.25);
music('h',0.25);
music('i',0.5);
music('h',1);
music('h',0.5);
music('l',0.5);
music('h',0.5);
music('k',0.5);
music('k',0.25);
music('k',0.25);
music('j',0.25);
music('i',0.25);
music('i',1);
music('h',0.5);
music('h',0.75);
music('z',2.25);
music('t',0.5);
music('s',0.5);
music('s',0.5);
music('s',0.5);
music('r',0.5);
music('r',0.5);
music('q',0.5);
music('p',0.5);
music('p',0.5);
music('p',0.5);
music('z',0.5);
music('s',0.5);
music('l',0.5);
music('k',0.25);
music('k',0.25);
music('k',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('i',1);
music('h',0.25);
music('g',0.25);
music('h',0.75);
music('z',0.75);
music('t',0.5);
music('s',0.5);
music('s',0.5);
music('s',0.5);
music('r',0.5);
music('r',0.5);
music('q',0.5);
music('p',0.5);
music('p',0.5);
music('p',0.5);
music('z',0.5);
music('j',0.5);
music('j',0.5);
music('j',0.25);
music('j',0.25);
music('j',0.25);
music('j',0.25);
music('j',0.5);
music('i',0.5);
music('j',0.5);
music('p',1);
music('o',0.5);
music('o',0.5);
music('z',0.5);
music('o',0.5);
music('n',1);
music('m',0.5);
music('m',1.5);
music('z',1);
music('m',0.5);
music('m',0.5);
music('l',0.5);
music('k',0.25);
music('k',0.25);
music('k',1.5);
music('j',0.25);
music('k',0.25);
music('l',2.5);
music('z',1.5);
music('j',0.25);
music('i',0.25);
music('j',0.25);
music('i',0.25);
music('j',0.25);
music('k',0.25);
music('l',0.5);
music('z',0.5);
music('k',0.25);
music('l',0.25);
music('m',0.5);
music('z',0.5);
music('m',0.25);
music('n',0.25);
music('o',0.5);
music('z',0.5);
music('p',0.25);
music('o',0.25);
music('l',1);
music('z',0.25);
music('h',0.25);
music('l',0.5);
music('k',0.5);
music('k',0.5);
music('j',1);
music('j',0.25);
music('k',0.25);
music('l',1);
music('z',0.5);
music('j',0.25);
music('i',0.25);
music('j',0.25);
music('i',0.25);
music('j',0.25);
music('k',0.25);
music('l',0.5);
music('z',0.5);
music('k',0.25);
music('l',0.25);
music('m',0.5);
music('z',0.5);
music('y',0.25);
music('m',0.25);
music('n',0.5);
music('z',0.75);
music('j',0.25);
music('q',0.5);
music('q',0.5);
music('z',0.25);
music('j',0.25);
music('r',0.5);
music('q',0.5);
music('p',0.5);
music('p',1);
music('o',0.25);
music('n',0.25);
music('o',0.5);
music('z',0.5);
music('l',0.25);
music('o',0.25);
music('p',1);
music('o',0.5);
music('o',0.5);
music('z',0.5);
music('l',0.5);
music('p',1);
music('o',0.5);
music('o',0.5);
music('z',0.5);
music('l',0.25);
music('o',0.25);
music('p',0.75);
music('q',0.25);
music('p',0.5);
music('o',0.5);
music('z',0.5);
music('o',0.5);
music('n',1);
music('m',0.5);
music('m',0.5);
music('z',0.5);
music('l',0.5);
music('l',1);
music('k',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('j',1.5);
music('z',1.5);
music('j',0.5);
music('k',0.5);
music('j',0.5);
music('k',0.5);
music('j',0.5);
music('i',0.5);
music('h',3);
LCD_Init();
LCD_ShowString(1,1,"Playing:");
LCD_ShowString(2,1,"--");
while(1)
{
if (P3_1==0)
{
Delay(2000);
while(P3_1==0);
break;
}
}
}
Delay.c
void Delay(unsigned char x){
while(x--){
unsigned char data i;
i = 2;
while (--i);
}
} //延时10us
music.c
#include <Delay.h>
#include <xiuzhi.h>
void music(char note,float timer)
{
unsigned int i; //定义循环用变量
unsigned int freq; //定义频率,即每次电平翻转相隔时间,单位微秒
unsigned int cycle; //定义循环次数
float time=timer*30000;
switch(note){
case 'a' :freq=203;break;
case 'b' :freq=179;break;
case 'c' :freq=160;break;
case 'd' :freq=152;break;
case 'e' :freq=135;break;
case 'f' :freq=120;break;
case 'g' :freq=107;break;
case 'h' :freq=101;break;
case 'i' :freq=90;break;
case 'j' :freq=80;break;
case 'k' :freq=76;break;
case 'l' :freq=68;break;
case 'm' :freq=60;break;
case 'n' :freq=54;break;
case 'o' :freq=51;break;
case 'p' :freq=45;break;
case 'q' :freq=40;break;
case 'r' :freq=38;break;
case 's' :freq=34;break;
case 't' :freq=30;break;
case 'u' :freq=27;break;
case 'v' :freq=25;break;
case 'z' :freq=0;break;
case 'y' :freq=64;break; //sheng5/jiang6
}
if(freq)
{
cycle=time/freq;
for(i=0;i<cycle;i++){
P2_5=~P2_5;
Delay(freq);
}
}
else
{
float xz=timer*4;
int timexz=(int)xz;
xiuzhi(timexz);
}
}
LCD1602.c
#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
//void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
//{
// LCD_SetCursor(Line,Column);
// LCD_WriteData(Char);
//}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
xiuzhi.c
#include <intrins.h>
void xiuzhi(unsigned char x) //@11.0592MHz 延时150ms
{
while (x--)
{
unsigned char data i, j, k;
_nop_();
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
}
.h头文件就不放了,就是定义了这几个函数。
春日影是86拍的歌,bpm高达194,一拍的时间约为0.3s,music()中的timer即为需要响的拍数,这里因为我一开始算的时候算成了四分音符为一拍,这样每个小节"实际"上就变成了3拍,每拍0.6s。
因为有半拍和四分之一拍,所以timer需要定义为浮点数,乘30000以获得实际时间,单位微秒。
然后用excel拉一个B大调的音阶出来

把这些音阶所对应的延迟时间填进music.c中的switch选择,因为switch只能填一个字母,所以只能用字母代替音阶,所幸这首歌的音域一共二十个音出头,我还能留个z当休止符用。
接下来判断freq是否为0,如果为0即为休止符,不为0则进入播放。由于不同音高的音变换时间不同,而我们要的最终音的长度相同,所以需要循环次数不同,使用cycle定义循环次数。(感觉我最天才的一集)
这样我们的播音乐函数就写好了,接下来是xiuzhi.c,显然这是一个写休止时间的函数,到这里就延迟相应的时间,然后直接过。
接着是lcd1602.c,这是我后来加的lcd显示所用的现成定义文件。可以用lcd屏显示当前播放的haruhikage,后面多做几首歌可以再往上加歌名(((
ok,到这里就结束了,其实这篇文章我一个月之前就在写了,但是延迟问题一直没有解决,就是只需要延迟一半的时间

然而用定时器打断就没这个问题。最后和学长讨论的结果是,能跑就不动((((((

主要是我懒得用定时器再重构了,不太喜欢用,麻烦麻烦麻烦麻烦
最后的最后:

工程文件打包:
Comments NOTHING