|
蜂鳴器放歌程序用到兩個定時器,分別用于精準(zhǔn)控制頻率和時間。
賀卡音樂芯片唯一的制作方法,可加入其他功能,音樂數(shù)據(jù)可隨意修改。
可直接移植到其他芯片中,在中斷外的程序會嚴(yán)重影響到軟件延時。
單片機(jī)型號:STC15F104E或STC15L104E或其他8腳STC芯片。
晶振頻率:24Mhz
硬件連接:
紅色到P3.3
公共極直接到P3.2
綠色到P3.1
藍(lán)色到P3.0
蜂鳴器連接P3.5(不同型號芯片可能會有不同,根據(jù)寄存器決定)
版本更新歷史:
1.修正為逐漸導(dǎo)通掃描LED,防止3v芯片不接電阻,多個LED同時導(dǎo)通而導(dǎo)致顏色顯示不正常。
2.添加了顏色漸變功能。
3.P3.0~P3.3口可直接連接4腳全彩LED,可設(shè)置共陰共陽。
注意:
片內(nèi)必須包含控制IO口輸出頻率的特殊功能寄存器,否則將無法輸出頻率。
晶振頻率過高會導(dǎo)致低頻信號不能鳴叫,同時耗電量增加,看門狗更容易跑飛,
過低則會導(dǎo)致時間頻率誤差加大。
源碼:
#include <reg51.h>
#include<intrins.h>
#include <stdlib.h>
#include <stdio.h>
//#include <eeprom.h>
#define FOSC 24000000L //晶振頻率
#define public 1 //共陽為1,共陰為0
unsigned int T1MS=65536-FOSC/1000; //計算定時器計時1毫秒需要的時間
sbit io=P3^2; //公共極
sbit io_blue=P3^0; //藍(lán)色LED通道
sbit io_green=P3^1;//綠色LED通道
sbit io_red=P3^3;//紅色LED通道
sbit led=P3^4;
//***********************
sfr P3M0 = 0xB1; // 定義P3M1寄存器
sfr P3M1 = 0xB2; // 定義P3M0寄存器
sfr eeprom_data = 0xC2; //EEPROM數(shù)據(jù)地址寄存器
sfr eeprom_addrh = 0xC3; //EEPROM高8位地址寄存器
sfr eeprom_addrl = 0xC4; //EEPROM低8位地址寄存器
sfr eeprom_cmd = 0xC5; //EEPROM模式操作寄存器
sfr eeprom_trig = 0xC6; //EEPROM命令有效寄存器
sfr eeprom_contr = 0xC7; //EEPROM命令有效寄存器
sfr CLK_DIV = 0x97;
sfr AUXR = 0x8e; //輔助特殊功能寄存器
sfr INT_CLKO = 0x8f; //喚醒和時鐘輸出功能寄存器
sbit T1CLKO = P3^5; //蜂鳴器連接VCC和P3.5
bit bit_blue=1;
bit bit_green=1;
bit bit_red=1;
unsigned int p=0; //延遲毫秒替減,為0則切換頻率
unsigned char m=0;//當(dāng)前音樂數(shù)據(jù)指向的指針
unsigned int code md[212]={ //音樂數(shù)據(jù),包含頻率和持續(xù)時間的數(shù)據(jù)。
0,580,600,300,600,100,900,200,1200,350,900,170,1200,200,1500,170,1600,260,1500,260,1180,180,1350,350,0,360,600,250,600,100,900,170,1200,360,900,170,1200,180,1500,170,1600,260,1500,260,1200,170,1330,200,0,150,1500,240,1330,100,1200,350,1200,270,1330,80,1500,170,2000,180,2000,175,1800,170,1600,170,1500,180,1330,170,1600,180,1500,180,1200,170,900,350,1000,350,1000,250,1100,100,1200,180,1500,350,1200,180,1340,170,1500,180,1600,170,1670,170,1800,190,1340,150,900,150,750,200,600,300,600,100,900,200,1200,350,900,170,1200,200,1500,170,1600,260,1500,260,1180,180,1350,350,0,360,600,250,600,100,900,170,1200,360,900,170,1200,180,1500,170,1600,260,1500,260,1200,170,1330,200,0,150,1500,260,1330,90,1200,350,1200,260,1330,90,1500,170,2000,350,1800,170,1600,170,1500,180,1330,170,1600,170,1500,180,1200,170,900,350,1000,350,1000,260,1100,90,1200,170,1500,340,1200,180,1330,170,1200,170,1120,180,1330,170,1200,350,0,250
};
void InitTimer0(void){ //初始化1ms中斷定時器
TMOD = 0x01;
TL0 = T1MS; //設(shè)置計數(shù)器低8位
TH0 = T1MS >> 8; //設(shè)置計數(shù)器高8位
EA = 1;
ET0 = 1;
TR0 = 1;
}
void set_hz(unsigned int hz){ //設(shè)置蜂鳴器頻率
if(0 < (int)(65536-FOSC/2/hz)) { //頻率計算溢出
hz=65535; //設(shè)置頻率為65535Hz
}
TMOD = 0x00; //設(shè)置定時器為模式1(16位自動重裝載)
TMOD &= ~0x40; //C/T1=0, 對內(nèi)部時鐘進(jìn)行時鐘輸出
TL1 = (65536-FOSC/2/hz); //初始化計時值
TH1 = (65536-FOSC/2/hz) >> 8;
INT_CLKO = 0x02;
TR1 = 1; //開始計數(shù)
}
void eeprom_init(){ //EEPROM初始化程序
eeprom_contr = 0x83; //把第7位置1允許EEPROM可以讀寫
eeprom_cmd = 0x00; //待機(jī)模式無ISP操作
eeprom_addrh = 0x00;
eeprom_addrl = 0x00;
}
unsigned char eeprom_read_dat(unsigned char addr_h,unsigned char addr_l){ //讀取EEPROM數(shù)據(jù)
unsigned char e_dat = 0x00;
eeprom_cmd = 0x01; //模式選擇為讀EEPROM
eeprom_addrh = addr_h;
eeprom_addrl = addr_l;
eeprom_trig = 0x5A; //使命令有效
eeprom_trig = 0xA5; //使命令有效
e_dat = eeprom_data;
return e_dat;
}
void eeprom_write_dat(unsigned char addr_h,unsigned char addr_l,unsigned char w_dat){ //寫入EEPROM數(shù)據(jù)
eeprom_cmd = 0x02; //模式選擇為寫EEPROM
eeprom_addrh = addr_h;
eeprom_addrl = addr_l;
eeprom_data = w_dat;
eeprom_trig = 0x5A; //使命令有效
eeprom_trig = 0xA5; //使命令有效
}
void eeprom_erase_dat(unsigned char addr_h,unsigned char addr_l){ //擦除EEPROM數(shù)據(jù)
eeprom_cmd = 0x03; //模式選擇為擦除EEPROM
eeprom_addrh = addr_h;
eeprom_addrl = addr_l;
eeprom_trig = 0x5A; //使命令有效
eeprom_trig = 0xA5; //使命令有效
}
unsigned char delay_led=0; //LED延時
unsigned char srand_add=0; //隨機(jī)數(shù)種子(累加)
unsigned char red_size=0; //當(dāng)前紅色LED亮度
unsigned char green_size=0;//當(dāng)前綠色LED亮度
unsigned char blue_size=0;//當(dāng)前藍(lán)色LED亮度
unsigned char new_red_size=0; //到達(dá)的紅色LED亮度
unsigned char new_green_size=0;//到達(dá)的綠色LED亮度
unsigned char new_blue_size=0;//到達(dá)的藍(lán)色LED亮度
unsigned int delay_rand=0; //隨機(jī)延時
void set_led_color(unsigned char red,unsigned char green,unsigned char blue){//設(shè)置LED顏色(3路不同占空比方波)
unsigned char input_red,input_green,input_blue;
unsigned char rgb_switch=1; //RGB切換開關(guān),1是紅色,2是綠色,3是藍(lán)色。
unsigned char while_delay=0xFF; //該變量循環(huán)替減,變量等于0后退出循環(huán)。
unsigned char red_delay=input_red; //紅色LED占空比
unsigned char green_delay=input_green; //綠色LED占空比
unsigned char blue_delay=input_blue; //藍(lán)色LED占空比
unsigned char not_red_delay=0xFF-input_red; //紅色LED占空比【位取反】
unsigned char not_green_delay=0xFF-input_green; //綠色LED占空比【位取反】
unsigned char not_blue_delay=0xFF-input_blue; //藍(lán)色LED占空比【位取反】
bit red_on=1;bit green_on=1;bit blue_on=1; //LED亮滅狀態(tài),1滅0亮。
bit not_red=1;bit not_green=1; bit not_blue=1; //是否處理某顏色通道 1處理0不處理
if(public == 1){ //共陽極
input_red=0xFF-red; //紅色位取反
input_green=0xFF-green; //綠色位取反
input_blue=0xFF-blue; //藍(lán)色位取反
} else { //共陰級
input_red=red; //紅色位賦值
input_green=green; //綠色位賦值
input_blue=blue; //藍(lán)色位賦值
}
if(red==0x00){ //紅色亮度等于0
not_red=0; //不處理紅色通道
bit_red=public; //紅色亮滅等于公共極
}
if(red==0xFF){ //紅色亮度等于255
not_red=0; //不處理紅色通道
bit_red=!public; //紅色亮滅等于取反公共極
}
if(green==0x00){ //綠色亮度等于0
not_green=0; //不處理綠色通道
bit_green=public; //綠色亮滅等于公共極
}
if(green==0xFF){ //綠色亮度等于255
not_green=0; //不處理綠色通道
bit_green=!public; //綠色亮滅等于取反公共極
}
if(blue==0x00){ //藍(lán)色亮度等于0
not_blue=0; //不處理藍(lán)色通道
bit_blue=public; //藍(lán)色亮滅等于公共極
}
if(blue==0xFF){ //藍(lán)色亮度等于255
not_blue=0; //不處理藍(lán)色通道
bit_blue=!public; //藍(lán)色亮滅等于取反公共極
}
while( while_delay != 0x00 && not_red_delay + red_delay + not_green_delay + green_delay + not_blue_delay + blue_delay != 0x00){ //所有替減變量大于或等于0
while_delay--; //循環(huán)變量替減
if(bit_red==!public){ //紅色LED緩存區(qū)與公共極相反
io_red=!public; //紅色LED的I/O接口等于取反公共極,可以構(gòu)成回路,點亮LED。
io_green=public;//綠色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
io_blue=public; //藍(lán)色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
//delay10us(); //延時10微秒
}
if(bit_green==!public){ //綠色LED緩存區(qū)與公共極相反
io_red=public; //紅色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
io_green=!public; //綠色LED的I/O接口等于取反公共極,可以構(gòu)成回路,點亮LED。
io_blue=public; //藍(lán)色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
//delay10us(); //延時10微秒
}
if(bit_blue==!public){ //藍(lán)色LED緩存區(qū)與公共極相反
io_red=public; //紅色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
io_green=public; //綠色LED的I/O接口等于公共極,無法構(gòu)成回路,熄滅LED。
io_blue=!public; //藍(lán)色LED的I/O接口等于取反公共極,可以構(gòu)成回路,點亮LED。
//delay10us(); //延時10微秒
}
if(rgb_switch == 1 && not_red == 1) { //處理紅色通道
if(red_on == 0){
bit_red=0; //將LED亮滅狀態(tài)放入緩存區(qū)。
not_red_delay--; //紅色LED反占空比減1
if(not_red_delay == 0) red_on=1; //紅色LED亮滅狀態(tài)放入緩存區(qū)
}
if(red_on == 1){
bit_red=1; //將LED亮滅狀態(tài)放入緩存區(qū)。
red_delay--; //紅色LED占空比減1
if(red_delay == 0) red_on=0; //紅色LED亮滅狀態(tài)放入緩存區(qū)
}
rgb_switch++; //切換到綠色通道
} else {
rgb_switch++; //切換到綠色通道
not_red_delay--;
red_delay--;
}
if(rgb_switch == 2 && not_green == 1){ //處理綠色通道
if(green_on == 0){
bit_green=0; //將LED亮滅狀態(tài)放入緩存區(qū)。
not_green_delay--; //綠色LED反占空比減1
if(not_green_delay == 0) green_on=1; //綠色LED亮滅狀態(tài)放入緩存區(qū)
}
if(green_on == 1){
bit_green=1; //將LED亮滅狀態(tài)放入緩存區(qū)。
green_delay--; //綠色LED占空比減1
if(green_delay == 0) green_on=0; //綠色LED亮滅狀態(tài)放入緩存區(qū)
}
rgb_switch++; //切換到藍(lán)色通道
} else {
rgb_switch++; //切換到藍(lán)色通道
not_green_delay--;
green_delay--;
}
if(rgb_switch == 3 && not_blue == 1){ //處理藍(lán)色通道
if(blue_on == 0){
bit_blue=0; //將LED亮滅狀態(tài)放入緩存區(qū)。
not_blue_delay--; //藍(lán)色LED反占空比減1
if(not_blue_delay == 0) blue_on=1; //藍(lán)色LED亮滅狀態(tài)放入緩存區(qū)
}
if(blue_on == 1){
bit_blue=1; //將LED亮滅狀態(tài)放入緩存區(qū)。
blue_delay--; //藍(lán)色LED占空比減1
if(blue_delay == 0) blue_on=0; //藍(lán)色LED亮滅狀態(tài)放入緩存區(qū)
}
rgb_switch=1; //切換紅色通道
} else {
rgb_switch=1; //切換紅色通道
not_blue_delay--;
blue_delay--;
}
}
}
void main(){ //主函數(shù)
AUXR |= 0xC0;
InitTimer0();
eeprom_init(); //EEPROM初始化
srand_add=eeprom_read_dat(0x00,0x01);//從EEPROM中讀取隨機(jī)隨種子
eeprom_erase_dat(0x00,0x01);//從EEPROM中擦除數(shù)據(jù)
srand_add++; //隨機(jī)數(shù)種子累加1個
eeprom_write_dat(0x00,0x01,srand_add); //將新種子寫入EEPROM中
srand(srand_add); //初始化隨機(jī)數(shù)種子,用于每次芯片上電都會產(chǎn)生不重復(fù)的顏色。
delay_led=0; //LED延時計數(shù)器清零
red_size=0x00; //當(dāng)前紅色值為0
green_size=0x00; //當(dāng)前綠色值為0
blue_size=0x00; //當(dāng)前藍(lán)色值為0
if(public==1){ //如果LED為共陽則 (注:修改IO口位置需要修改這里。)
P3M1 = 0x04; //定義P3.2口為強(qiáng)上拉輸出,提供更多電流以驅(qū)動LED彩燈。
} else { //共陰則
P3M1 = 0x0B; //定義P3.0,P3,1,P3,3口為強(qiáng)上拉輸出,提供更多電流以驅(qū)動LED彩燈。
}
io=public; //公共極賦值,否則LED就亮不了。
while(1) { //無限循環(huán)
new_red_size=rand();//紅色亮度取隨機(jī)數(shù)
new_green_size=rand();//藍(lán)色亮度取隨機(jī)數(shù)
new_blue_size=rand();//綠色亮度取隨機(jī)數(shù)
while(new_red_size != red_size && new_green_size != green_size && new_blue_size != blue_size){ //當(dāng)前顏色不等于隨機(jī)到達(dá)的顏色則循環(huán)
if(red_size<new_red_size) { //當(dāng)前紅色亮度小于到達(dá)的紅色亮度
red_size++; //紅色亮度相加
} else { //否則
red_size--; //紅色亮度相減
}
if(green_size<new_green_size) { //當(dāng)前綠色亮度小于到達(dá)的綠色亮度
green_size++; //綠色亮度相加
} else { //否則
green_size--; //綠色亮度相減
}
if(blue_size<new_blue_size) { //當(dāng)前藍(lán)色亮度小于到達(dá)的藍(lán)色色亮度
blue_size++; //藍(lán)色亮度相加
} else { //否則
blue_size--; //藍(lán)色亮度相減
}
delay_led=rand()&0xF+0xF; //設(shè)置替減次數(shù)
while(delay_led--){ //計數(shù)循環(huán)替減
set_led_color(red_size,green_size,blue_size); //設(shè)置輸出LED顏色
}
}
delay_led=rand()&0x7F+0x7F; //持續(xù)執(zhí)行0~127個下面的指令。
while(delay_led--){ //漸變完畢有1段時間保持顏色。
set_led_color(red_size,green_size,blue_size); //設(shè)置輸出LED顏色
}
}
}
void Timer0Interrupt(void) interrupt 1{ //1ms 定時器中斷程序
TH0 = 0x0A2;
TL0 = 0x40;
if(p==0){ //延遲時間減到0
p=md[m+1]; //設(shè)置延遲時間
set_hz(md[m]); //設(shè)置鳴叫頻率
m+=2; //指針加2
if(m>=212) m=0; //指針超過212則清零避免取出其他胡亂的數(shù)據(jù)
} else {
p--; //延遲時間減1
}
}
|
評分
-
查看全部評分
|