做一个这样的网站应该报价多少,不会编程能建网站,惠州的服装网站建设,wordpress 08第五节#xff1a;蜂鸣器的驱动程序。 开场白#xff1a; 上一节讲了利用累计定时中断次数实现LED灯闪烁#xff0c;这个例子同时也第一次展示了我最完整的实战程序框架#xff1a;用switch语句实现状态机#xff0c;外加定时中断。这个框架看似简单#xff0c;实际上就是…第五节蜂鸣器的驱动程序。 开场白 上一节讲了利用累计定时中断次数实现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)/27444 */ #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_drP2^7; //蜂鸣器的驱动IO口 sbit led_drP3^5; //LED灯的驱动IO口 unsigned char ucLedStep0; //LED灯的步骤变量 unsigned int uiTimeLedCnt0; //LED灯统计定时中断次数的延时计数器 unsigned char ucAlarmStep0; //报警的步骤变量 unsigned int uiTimeAlarmCnt0; //报警统计定时中断次数的延时计数器 unsigned int uiVoiceCnt0; //蜂鸣器鸣叫的持续时间计数器 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(uiTimeLedCntconst_time_05s) //时间到 { uiTimeLedCnt0; //时间计数器清零 led_dr1; //让LED亮 ucLedStep1; //切换到下一个步骤 } break; case 1: if(uiTimeLedCntconst_time_05s) //时间到 { uiTimeLedCnt0; //时间计数器清零 led_dr0; //让LED灭 ucLedStep0; //返回到上一个步骤 } break; } } void alarm_run() //第三区 报警器的应用程序 { switch(ucAlarmStep) { case 0: if(uiTimeAlarmCntconst_time_3s) //时间到 { uiTimeAlarmCnt0; //时间计数器清零 /* 注释二 * 只要变量uiVoiceCnt不为0蜂鸣器就会在定时中断函数里启动鸣叫并且自减uiVoiceCnt * 直到uiVoiceCnt为0时才停止鸣叫。因此控制uiVoiceCnt变量的大小就是控制声音的长短。 */ uiVoiceCntconst_voice_short; //蜂鸣器短叫 ucAlarmStep1; //切换到下一个步骤 } break; case 1: if(uiTimeAlarmCntconst_time_6s) //时间到 { uiTimeAlarmCnt0; //时间计数器清零 uiVoiceCntconst_voice_long; //蜂鸣器长叫 ucAlarmStep0; //返回到上一个步骤 } break; } } void T0_time() interrupt 1 { TF00; //清除中断标志 TR00; //关中断 if(uiTimeLedCnt0xffff) //设定这个条件防止uiTimeLedCnt超范围。 { uiTimeLedCnt; //LED灯的时间计数器累加定时中断的次数 } if(uiTimeAlarmCnt0xffff) //设定这个条件防止uiTimeAlarmCnt超范围。 { uiTimeAlarmCnt; //报警的时间计数器累加定时中断的次数 } /* 注释三 * 为什么不把驱动蜂鸣器这段代码放到main函数的循环里去? * 因为放在定时中断里能保证蜂鸣器的声音长度是一致的 * 如果放在main循环里声音的长度就有可能受到某些必须 * 一气呵成的任务干扰得不到及时响应影响声音长度的一致性。 */ if(uiVoiceCnt!0) { uiVoiceCnt--; //每次进入定时中断都自减1直到等于零为止。才停止鸣叫 beep_dr0; //蜂鸣器是PNP三极管控制低电平就开始鸣叫。 } else { ; //此处多加一个空指令想维持跟if括号语句的数量对称都是两条指令。不加也可以。 beep_dr1; //蜂鸣器是PNP三极管控制高电平就停止鸣叫。 } TH00xf8; //重装初始值(65535-2000)635350xf82f TL00x2f; TR01; //开中断 } void delay_long(unsigned int uiDelayLong) { unsigned int i; unsigned int j; for(i0;iuiDelayLong;i) { for(j0;j500;j) //内嵌循环的空指令数量 { ; //一个分号相当于执行一条空语句 } } } void initial_myself() //第一区 初始化单片机 { beep_dr1; //用PNP三极管控制蜂鸣器输出高电平时不叫。 led_dr0; //LED灭 TMOD0x01; //设置定时器0为工作方式1 TH00xf8; //重装初始值(65535-2000)635350xf82f TL00x2f; } void initial_peripheral() //第二区 初始化外围 { EA1; //开总中断 ET01; //允许定时中断 TR01; //启动定时中断 } 总结陈词 本节程序已经展示了一个多任务处理的基本思路假如要实现一个独立按键检测能不能也按照这种思路来处理呢欲知详情请听下回分解-----在主函数中利用累计主循环次数来实现独立按键的检测。 未完待续下节更精彩不要走开哦