|
|
单片机定时器设计的门铃程序 - 51单片机 左侧的链接是本论坛以前的一个贴子,它给出了一个简易的门铃程序,简单模拟的叮咚声音,但这个模拟的声音纯粹噪音,并不好听,下面的本程序带给你真正的声音模拟,C调“高音1”与“中音5”,用来代替“叮”和“咚”,并调整声音响的时间,来模拟节拍。为啥是“高音1”与“中音5”代表“叮咚”,是因为我听着像,你完全可以根据你感觉的来调整。下面上程序:
#include <reg51.h>
sbit BUZZ = P2^6;
sbit KEY=P2^7;
unsigned char T0RH = 0;
unsigned char T0RL = 0;
unsigned char keysta=0xff;
unsigned char backup=0xff;
unsigned char doorbell=0;
void OpenBuzz(unsigned int frequ);
void StopBuzz();
void main()
{
unsigned int i;
TMOD = 0x11; // 本程序没有采用delay()的方式来做按键消抖,额外采用T1定时器来延时消抖。
EA = 1;
TH1=0XFC;
TL1=0X66; //定时器T1采用1ms中断
ET1=1;
TR1=1;
while (1)
{
if(backup!=keysta) //判断是否是一个完整的由弹起到按下的过程,如果是,说明有按键按下
{
backup=keysta;
if(backup!=0x00)
{
doorbell=1;
}
}
if(doorbell==1)
{
OpenBuzz(1047); //输入C调高音1的频率
for (i=0; i<30000; i++); //调整发声时间
StopBuzz(); //得有一定间隔,避免前后声音粘连
for (i=0; i<10000; i++);
OpenBuzz(784); //输入C调中音5的频率
for (i=0; i<30000; i++);
StopBuzz();
for (i=0; i<10000; i++);
doorbell=0;
}
}
}
void OpenBuzz(unsigned int frequ)
{
unsigned int reload;
reload = 65536 - (11059200/12)/(frequ*2); //
T0RH = (unsigned char)(reload >> 8); //
T0RL = (unsigned char)reload;
TH0 = 0xFF; //先让中断运行起来
TL0 = 0xFE;
ET0 = 1;
TR0 = 1;
}
void StopBuzz()
{
ET0 = 0;
TR0 = 0;
}
void InterruptTimer0() interrupt 1
{
TH0 = T0RH;
TL0 = T0RL;
BUZZ = ~BUZZ;
}
void keyscan() interrupt 3
{
static unsigned char keybuff=0xff;
TH1=0XFC;
TL1=0X66;
keybuff=keybuff<<1 | KEY;
if(keybuff==0xff)
{
keysta=0xff;
}
else if(keybuff==0x00)
{
keysta=0x00;
}
}
本程序思路是,先按键扫描,判断按键状态,再分析是否是一个完整的按键由弹起到落下的过程。一共输入8次按键状态,当8次按键状态都是0时,认为按键状态稳定,已经成功消抖。
再在主函数while()循环里,进行上次按键状态与本次按键状态对比,判断是否为一个完整动作,而不是连续按下状态。
理念来自于kinst开发板教程。虽然我用的是普中开发板,按键学习这块我没有采用普中教程。
发声理念也来自于kinst开发板教程。大家都可以在网上搜C调的低中高音声音频率。这里我采用C调高音1与中音5。AI告诉我,开发板蜂鸣器只适合唱C调中音的歌,还得是舒缓类型的。这是蜂鸣器的弊病。由于AI说的太晚,害我浪费好长时间,去逼迫蜂鸣器唱刀郎的歌,最后听起来完全不是那回事,不得不放弃。
看OpenBuzz()与StopBuzz()两个函数,你会觉得很简单,都不过是对定时器与中断的配置而已。关键是reload = 65536 - (11059200/12)/(frequ*2)的值怎么计算。这个连kinst开发板教程都一带而过。
今天重点讲的就是这个:一次中断发声,一次中断闭麦,形成一个完整具有波峰,波谷的声波。频率为f的声音,一秒钟需要2f个中断。假设完成一次中断需要计数X次。一次计数在8051中需要一个机器周期,一个机器周期为12个时钟周期。晶振系统的频率foc为11.0592MHz。
所以完整的公式 为: X * (12/foc) * 2f = 1 (秒)。为了给TH0和TL0赋值,你还需要用65536-X,这就得到了reload值。
附件中的工程文件为proteus 9.0 以上版本
|
评分
-
查看全部评分
|