找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机门铃教程-发音原理

[复制链接]
跳转到指定楼层
楼主
单片机定时器设计的门铃程序 - 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 以上版本


doorbell.jpg (363.43 KB, 下载次数: 0)

proteus 9.0版本

proteus 9.0版本

doormusic.7z

21.04 KB, 下载次数: 0, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表