首页 > 编程语言 >【51编程经验笔记】第五节:蜂鸣器的驱动程序

【51编程经验笔记】第五节:蜂鸣器的驱动程序

时间:2024-12-07 16:13:49浏览次数:2  
标签:蜂鸣器 驱动程序 中断 void 51 time const 定时

第五节:蜂鸣器的驱动程序。

开场白:
上一节讲了利用累计定时中断次数实现LED灯闪烁,这个例子同时也第一次展示了我最完整的实战程序框架:用switch语句实现状态机,外加定时中断。这个框架看似简单,实际上就是那么简单。我做的所有开发项目都是基于这个简单框架,但是非常好用。上一节只有一个单任务的LED灯在闪烁,这节开始,我们多增加一个蜂鸣器报警的任务,要教会大家四个知识点:
第一点:蜂鸣器的驱动程序框架编写。
第二点:多任务处理的程序框架。
第三点:如何控制蜂鸣器声音的长叫和短叫。
第四点:如何知道1秒钟需要多少个定时中断,也就是如何按比例修正时间精度。

具体内容,请看源代码讲解。

(1)硬件平台:基于朱兆祺51单片机学习板。

(2)实现功能:同时跑两个任务,第一个任务让一个LED灯1秒钟闪烁一次。第二个任务让蜂鸣器在前面3秒发生一次短叫报警,在后面6秒发生一次长叫报警,反复循环。

(3)源代码讲解如下:


#include "REG52.H"

/* 注释一:
* 如何知道1秒钟需要多少个定时中断?
* 这个需要编写一段小程序测试,得到测试的结果后再按比例修正。
* 步骤:
* 第一步:在程序代码上先写入1秒钟大概需要200个定时中断。
* 第二步:基于以上1秒钟的基准,编写一个60秒的简单测试程序(如果编写超过
* 60秒的时间,这个精度还会更高)。比如,编写一个用蜂鸣器的声音来识别计时的
* 起始和终止的测试程序。
* 第三步:把程序烧录进单片机后,上电开始测试,手上同步打开手机里的秒表。
*         如果单片机仅仅跑了27秒。
* 第四步:那么最终得出1秒钟需要的定时中断次数是:const_time_1s=(200*60)/27=444
*/
#define const_time_05s 222   //0.5秒钟的时间需要的定时中断次数
#define const_time_1s 444   //1秒钟的时间需要的定时中断次数
#define const_time_3s 1332   //3秒钟的时间需要的定时中断次数
#define const_time_6s 2664   //6秒钟的时间需要的定时中断次数

#define const_voice_short  40   //蜂鸣器短叫的持续时间
#define const_voice_long   200  //蜂鸣器长叫的持续时间

void initial_myself();    
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void led_flicker();
void alarm_run();   
void T0_time();  //定时中断函数

sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
sbit led_dr=P3^5;  //LED灯的驱动IO口

unsigned char ucLedStep=0; //LED灯的步骤变量
unsigned int  uiTimeLedCnt=0; //LED灯统计定时中断次数的延时计数器

unsigned char ucAlarmStep=0; //报警的步骤变量
unsigned int  uiTimeAlarmCnt=0; //报警统计定时中断次数的延时计数器

unsigned int  uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器

void main() 
  {
   initial_myself();  
   delay_long(100);   
   initial_peripheral(); 
   while(1)  
   { 
      led_flicker();  //第一个任务LED灯闪烁
          alarm_run();    //第二个任务报警器定时报警
   }

}

void led_flicker() //第三区 LED闪烁应用程序
{
  
  switch(ucLedStep)
  {
     case 0:

           if(uiTimeLedCnt>=const_time_05s) //时间到
           {
             uiTimeLedCnt=0; //时间计数器清零
             led_dr=1;    //让LED亮
             ucLedStep=1; //切换到下一个步骤
           }
           break;
     case 1:
           if(uiTimeLedCnt>=const_time_05s) //时间到
           {
              uiTimeLedCnt=0; //时间计数器清零
              led_dr=0;    //让LED灭
              ucLedStep=0; //返回到上一个步骤
           }
           break;
  }

}

void alarm_run() //第三区 报警器的应用程序
{
  
  switch(ucAlarmStep)
  {
     case 0:

           if(uiTimeAlarmCnt>=const_time_3s) //时间到
           {
             uiTimeAlarmCnt=0; //时间计数器清零
/* 注释二:
* 只要变量uiVoiceCnt不为0,蜂鸣器就会在定时中断函数里启动鸣叫,并且自减uiVoiceCnt
* 直到uiVoiceCnt为0时才停止鸣叫。因此控制uiVoiceCnt变量的大小就是控制声音的长短。
*/
             uiVoiceCnt=const_voice_short;  //蜂鸣器短叫
             ucAlarmStep=1; //切换到下一个步骤
           }
           break;
     case 1:
           if(uiTimeAlarmCnt>=const_time_6s) //时间到
           {
              uiTimeAlarmCnt=0; //时间计数器清零
              uiVoiceCnt=const_voice_long;  //蜂鸣器长叫
              ucAlarmStep=0; //返回到上一个步骤
           }
           break;
  }

}

void T0_time() interrupt 1
{
  TF0=0;  //清除中断标志
  TR0=0; //关中断

  if(uiTimeLedCnt<0xffff)  //设定这个条件,防止uiTimeLedCnt超范围。
  {
      uiTimeLedCnt++;  //LED灯的时间计数器,累加定时中断的次数,
  }

  if(uiTimeAlarmCnt<0xffff)  //设定这个条件,防止uiTimeAlarmCnt超范围。
  {
      uiTimeAlarmCnt++;  //报警的时间计数器,累加定时中断的次数,
  }


/* 注释三:
* 为什么不把驱动蜂鸣器这段代码放到main函数的循环里去?
* 因为放在定时中断里,能保证蜂鸣器的声音长度是一致的,
* 如果放在main循环里,声音的长度就有可能受到某些必须
* 一气呵成的任务干扰,得不到及时响应,影响声音长度的一致性。
*/


  if(uiVoiceCnt!=0)
  {
     uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
         beep_dr=0;  //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。
  }
  else
  {
     ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
           beep_dr=1;  //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
  }


  TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f
  TL0=0x2f;
  TR0=1;  //开中断
}


void delay_long(unsigned int uiDelayLong)
{
   unsigned int i;
   unsigned int j;
   for(i=0;i<uiDelayLong;i++)
   {
      for(j=0;j<500;j++)  //内嵌循环的空指令数量
          {
             ; //一个分号相当于执行一条空语句
          }
   }
}


void initial_myself()  //第一区 初始化单片机
{
  beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
  led_dr=0;  //LED灭

  TMOD=0x01;  //设置定时器0为工作方式1


  TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f
  TL0=0x2f;

}
void initial_peripheral() //第二区 初始化外围
{
  EA=1;     //开总中断
  ET0=1;    //允许定时中断
  TR0=1;    //启动定时中断

}


总结陈词:
本节程序已经展示了一个多任务处理的基本思路,假如要实现一个独立按键检测,能不能也按照这种思路来处理呢?欲知详情,请听下回分解-----在主函数中利用累计主循环次数来实现独立按键的检测。

(未完待续,下节更精彩,不要走开哦)

标签:蜂鸣器,驱动程序,中断,void,51,time,const,定时
From: https://www.cnblogs.com/FBsharl/p/18592320

相关文章

  • 【51编程经验笔记】第四节:累计定时中断次数使LED灯闪烁
    第四节:累计定时中断次数使LED灯闪烁。开场白:上一节提到在累计主循环次数来实现计时,随着主函数里任务量的增加,为了保证延时时间的准确性,要不断修正设定上限阀值const_time_level。我们该怎么解决这个问题呢?本节教大家利用累计定时中断次数的方法来解决这个问题。这一节要教会大家......
  • 【51编程经验笔记】第三节:累计主循环次数使LED灯闪烁
    第三节:累计主循环次数使LED灯闪烁。开场白:上一节鸿哥提到delay()延时函数消耗的时间太长了,其它任务根本没有机会执行,我们该怎么改善?本节教大家利用累计主循环次数的方法来解决这个问题。这一节要教会大家两个知识点:第一点:利用累计主循环次数的方法实现时间延时第二点:switch核心语......
  • 【51编程经验笔记】第二节:鸿哥的三区一线理论 & delay()延时实现LED灯的闪烁
    第二节:delay()延时实现LED灯的闪烁。开场白:  上一节鸿哥列出了初学者七大误区,到底什么才是初学者关注的核心?那就是裸机奔跑的程序结构。一个好的程序结构,本身就是一个微型的多任务操作系统。鸿哥教给大家的就是如何编写这个简单的操作系统。在main函数循环中用switch语句实现......
  • P9751 [CSP-J 2023] 旅游巴士
    $P9751$部分分思路题目要求时间必须是$k$的非负整数倍,所以想到了升维。这样就变成了一道分层图最短路的题目。用BFS算法可以拿到$A_i=0$的$35$分。满分思路其实部分分的思路已经很接近正解了,想要拿到满分只需要做一点小小的调整。虽然说不能在路上停留,但是......
  • 基于51单片机和16X16LED点阵屏(MAX7219驱动)的自制独立按键控制的小游戏《贪吃蛇》
    目录系列文章目录前言一、效果展示二、原理分析三、各模块代码1、定时器02、自制独立按键(8位)3、16X16LED点阵屏(MAX7219驱动)四、主函数总结系列文章目录前言《贪吃蛇》,一款经典的、怀旧的小游戏,单片机入门必写程序。基于51单片机和8X8LED点阵屏(板载74HC595驱动)的......
  • 洛谷 P1651 塔(DP)
    题目传送门https://www.luogu.com.cn/problem/P1651解题思路设  表示前  个积木,两塔高度差为 (第一个比第二个高多少),的最大高度。易得:首先,不选当前的积木:其次,选当前积木,将它拼到第一个塔上:最后,选当前积木,将它拼到第二个塔上:由于,第二维可能为负数,所以,我们可以以 (数......
  • DedeCMS最新注入漏洞(CNVD-2024-44514、CVE-2024-9076)
    DedeCms系统(织梦系统)是一套PHP开发的网站管理系统,因其功能强大,操作使用简单,具有非常高的知名度,拥有大量用户。 国家信息安全漏洞共享平台于2024-11-07公布其存在跨站脚本漏洞。漏洞编号:CNVD-2024-44514、CVE-2024-9076影响产品:DeDeCMS<=5.7.115漏洞级别:中公布时间:2024-11-......
  • P7518 [省选联考 2021 A/B 卷] 宝石
    P7518[省选联考2021A/B卷]宝石Solution:首先我们注意到宝石收集器上的顺序是不变的,所以我们考虑将每个点的点权转化为其在宝石收集器上的排名(后文的权值都是这个意思)然后我们记录两个数组:\(f_1[u][i]和f_2[u][i]\)用来表示在rt->u这段路径上,权值为\(w[u]+2^i\)or\(w[......
  • 按键 芯片twl4030 linux 驱动程序
    /**twl4030-pwrbutton.c-TWL4030PowerButtonInputDriverCopyright©2008-2009NokiaCorporationThisfileissubjecttothetermsandconditionsoftheGNUGeneralPublicLicense.Seethefile“COPYING”inthemaindirectoryofthisarchive......
  • 企业如何选择内训机构?TsingtaoAI、51CTO、极客邦各有千秋,学会这几点就能选对!
    如何选择一个最合适的内训机构,可能是许多HR、企业高管和培训负责人面临的共同挑战。随着各类新兴技术的崛起和企业对数字化、智能化转型的强烈需求,传统的培训模式已经不能满足大多数企业对员工技能提升的要求。在众多的企业内训机构中,哪家才是最专业、最能符合企业当下业务需求......