程序:
#include<p18f45k20.h>
#define uchar unsigned char
#define uint unsigned int
#define ADGO ADCON0bits.GO #define fmq PORTEbits.RE0
#define m1l 57904 //低8度#define m2l 58736
#define m3l 59472
#define m4l 59804
#define m5l 60432
#define m6l 60992
#define m7l 61488
#define m1 61712 //中
#define m2 62168
#define m3 62500
#define m4 62672
#define m5 62984
#define m6 63264
#define m7 63512
#define m1h 63624 //高8度#define m2h 63832
#define m3h 64048
#define m4h 64104
#define m5h 64260
#define m6h 64400
#define m7h 64524
#define p 1000 //节拍时长
#define ph p/2 //半拍
#define pd p*2 //双拍
#define pf p*3/4
#define pg p/4
uint
song[]={m6l,m1,m3,m4,m2,m3,m4,m6,m5,m4,m3,m1,m1,m2,m3,m5,m4,m3,m2,m2,m2,m7l,m1, m2,m4,m3,m2,m2,m2,m2,m3,m3,m3,m5,m6,m3,m3,m3,m3,m5,m2,m2,m2,m3,m5,m2,m2,m3,m6 l,m6l};//《手掌心》简谱
uint
time[]={p,ph,ph,pf*2,pg,pg,ph,ph,ph,ph,p,ph,pg,pg,ph,ph,ph,pg,pg,p,ph,pg,pg,ph,ph,pg,pg,pg,pg, pg,pf,pd,ph,ph,pg,pg,pg,pg,pg,ph,pg,p,ph,ph,ph,ph,pg,ph,pg,p};//对应的歌曲节拍
uint total = 50;
uint counter = 0,num = 0, i = 0;
uint flag=0;
uint a1=0,a2=0,a3=0,a4=0;
uint lednum=0;
uchar num_h[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//共阳数码管“0.—9.”定义
uchar num_l[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳数码管“0 --9”定义
void Delay25us(unsigned int x);//延时函数声明
unsigned int AD_Trs();//Ad转换函数声明
void display(void);//数码管显示函数声明
void Tmr_Init(void);//定时器初始化函数声明
void High_Interrupt(void);//定时器中断跳转函数声明
void Stopwatch(void);//定时器中断执行函数声明
void main(void)//主函数
{
WDTCONbits.SWDTEN = 0;//关闭看门狗
TRISC=0X00;//输入输出端口初始化
TRISD=0X00;
PORTC=0X00;
TRISE=0X00;
PORTEbits.RE0=0;//用于音乐输出
TRISAbits.TRISA0=1; //AD转换采集电压输入
PORTAbits.RA0=0;
ADCON0=0x01;//使能ADC,模拟通道选择AN0(RA0)
ADCON1 = 0x00;//正负参考电压从单片机内部获取
ADCON2 = 0xa5;//A/D 转换结果格式为右对齐
//采样周期8TAD
//AD转换时钟频率FOSC/16
Tmr_Init();//定时器初始化
while(1)//等待中断
{
ClrWdt();
lednum = AD_Trs();//获取AD转换得到的数据
if(lednum >= 3300)//测得电压达最大量程3.3V时开定时器,播音乐{
fmq = 0 ; //拉低
INTCONbits.TMR0IE = 1;
T0CONbits.TMR0ON = 1;
display();//数码管显示当前电压
}
else//不足3.3V时关闭定时器
{
fmq = 1 ; //拉高
T0CONbits.TMR0ON = 0;
INTCONbits.TMR0IE = 0;
INTCONbits.TMR0IF = 0;//定时器溢出标志位清零
i = 0;//重新定位音乐至开头
num = 0;
TMR1H = song[num]/256;//定时器赋初值
TMR1L = song[num]%256;
display();
}
}
}
unsigned int AD_Trs()//AD转换程序
{
unsigned int adval;
float advalf;
ADGO = 1; //启动AD转化
while(ADGO); //说明AD转化完成
adval= ADRESH;
adval = adval<<8|ADRESL;
advalf = adval/1023.0*3.3; //因为参考电压为3.3伏
adval = advalf*1000; //转化为整数,以便显示
return (adval);
}
void Delay25us(uint x) //延时函数
{
unsigned int a,b;
for(a=x;a>0;a--)
for(b=110;b>0;b--);//执行空语句实现延时
}
void Tmr_Init(void)//定时器初始化函数
{
i = 0;
num = 0;
INTCON = 0XF0;//开全局中断,允许定时器0溢出中断T0CON = 0X08;//配置Timer0为16 位定时器
TMR0H = song[num]/256;
TMR0L = song[num]%256;
}
#pragma code high_vector = 0x0008
void High_Interrupt(void)//定时器溢出时跳转
{
if(INTCONbits.TMR0IF && INTCONbits.TMR0IE)
{
_asm
goto Stopwatch
_endasm
}
}
#pragma code
#pragma interrupt Stopwatch
void Stopwatch(void)//中断执行函数
{
if(INTCONbits.TMR0IF && INTCONbits.TMR0IE) {
T0CONbits.TMR0ON = 0;//关中断,以便为定时器赋初值INTCONbits.TMR0IF = 0;//溢出标志位清零
counter++;
if(counter == time[i])//实现音乐节拍
{
counter = 0;
i++;
num++;
if(i >= total || num >= total)//音乐播完后重头开始
{
i = 0;
num = 0;
}
}
TMR0H = song[num]/256;
TMR0L = song[num]%256;
if(flag)
{
flag=0;
PORTEbits.RE0=0;//蜂鸣器驱动端输出低电平
}
else
{
flag=1;
PORTEbits.RE0=1;//蜂鸣器驱动端输出高电平
}
T0CONbits.TMR0ON = 1;//开中断
INTCONbits.TMR0IE = 1;
}
}
#pragma code
void display(void)//数码管显示函数
{
uint j=20;//数码管扫描时间变量
a1 = lednum/1000; //此算法用于取出一个整数的各个位,来显示在数码管上a2 = lednum%1000/100;
a3 = lednum%100/10;
a4 = lednum%10;
PORTC=0X00;
PORTC=0x01;//依次选通数码管
PORTD=num_h[a1];//查找表并显示数值
Delay25us(j); //延时
PORTC=0X00;
PORTC=0x02;
PORTD=num_l[a2];
Delay25us(j);
PORTC=0X00;
PORTC=0x04;
PORTD=num_l[a3];
Delay25us(j);
PORTC=0X00;
PORTC=0x08;
PORTD=num_l[a4];
Delay25us(j);
}。