特别声明:文章是原创但是本文讲述的思想是在国外的开源代码中借鉴的
初学者在编写单片机程序时经常会用到延时函数,但是当系统逐步复杂以后(没有复杂到使用操作系统)延时会因为延时降低MCU的利用率,更严重的会影响系统中的“并行”操作例如一个既有按键又有蜂鸣器的系统中,如果要求按下按键发出不同的声音,每次发声时间在1秒-2秒之间, 如果用延时来做代码很简单:
//蜂鸣器发出“哔-哔-哔”声音时间约1s
void BeepFuction(void)
{
unsigned char i;
for(i=0;i<3;i=++)
{
BeepEn(); //开启蜂鸣器
Delayms(220);//延时220ms
BeepDis();//关闭蜂鸣器
Delayms(110);//延时110ms
}
}
当这段代码执行时MCU不可能同时处理按键检查程序因为它大部分时间在执行Delayms()函数中的nop指令,这样就不可能去执行检查按键了(不使用中断时),如果把程序改成流程形式的写法则结果会大为不同,下面先介绍一下基本原理。
我们都知道一般的定时器为16位或8位循环计数,例如对于16位的计数器当计数器数值从0增加到65535时再加一就会回到0那么我们来比较下面两种情况(不考虑计数器在记录当前时刻T后再次回到或超过T这种情况我暂且称它为“压圈”):
情况1:
T1时刻计数器数值为300
T2时刻计数器数值为400
则T1时刻到T2为100个计数单位。
这段时间差也为100个计数单位。
情况2:
T1时刻计数器数值为65535
T2时刻计数器数值为99
则T1到T2 可以算出为65535到0的1个计数单位再加上 0到99的99个计数单位总共为100个计数单位。
所以时间差还是100个计数单位。
在C语言中如果使用两个无符号数作减法会得到如下结果:99-65535=100,这个很好理解就和10进制的借位一样只不过借位后不用管高位了也就相当于99+65536-65535结果是100了,当然这些前提条件都是计数器不会出现“压圈”。
有了上面对定时器的了解就可以从新写这个Beep函数了
//蜂鸣器发出“哔-哔-哔”声音时间约1s
bit BeepFlag = 0;//蜂鸣流程忙标志位
bit BeepCtrl = 0;//蜂鸣器流程控制标志位
void BeepProc(void)
{
static unsigned int BeepTimer;
static unsigned char BeepStatus = 0;
static unsigned char i;
switch(BeepStatus)
{
case 0://
if(BeepCtrl)
{
i = 3;//蜂鸣次数
BeepFlag = 1;//置位忙标志位
BeepCtrl = 0;//清除控制标志位
BeepTimer = TIMER;//这里TIMER为系统定时器计数时钟为1ms
BeepEn(); //开启蜂鸣器
BeepStatus = 1;//进入下一个状态
}
break;
case 1://蜂鸣状态
if(TIMER-BeepTimer>220)//220ms
{
BeepDis(); //关闭蜂鸣器
BeepTimer = TIMER;//记录时刻
BeepStatus = 2;//进入下一个状态
}
break;
case 2://停止蜂鸣状态
if(TIMER-BeepTimer>110)//110ms
{
if(i!=0)
{
i--;
BeepTimer = TIMER;//记录时刻
BeepEn(); //开启蜂鸣器
BeepStatus = 2;//回到蜂鸣状态
}
else
{
BeepStatus = 0;//回到初始状态
BeepFlag = 0;//清除忙标志位
}
}
break;
default:
BeepFlag = 0;//清除忙标志位
BeepStatus = 0;//回到初始状态
break;
}
}
用这样的方法实现的蜂鸣程序在使用时也有不同的地方,因为使用的switch状态所有在主循环中要一直调用:
void main()
{
SystemInitial();//系统初始化
...............
//主循环
while(1)
{
Fun1Proc();//功能1流程
Fun2Proc();//功能2流程
....
BeepProc();//蜂鸣流程
....
}
}
16
在别的函数中需要使蜂鸣器工作时只需要下面代码即可:
if(!BeepFlag)//检查是否忙
BeepCtrl = 1;//启动蜂鸣器
用这种方法能充分利用MCU,在蜂鸣器发声或发声间隔的等待时间MCU可以处理别的函数,但是还要有几点需要注意
第一,主循环while(1)的循环周期最好小于定时器计数时钟周期
第二,主循环中尽量不要使用硬延时Delayms
第三,代码中如果存在多个地方需要控制一个流程时一定要先读取标志位再控制
上一篇:51单片机自定义多个软件定时器
下一篇:基于C8051F040单片机的CAN总线通信
推荐阅读
史海拾趣
面对不断变化的市场环境和客户需求,亿晶源始终保持敏锐的市场洞察力和创新精神。公司将继续加大研发投入,推出更多具有竞争力的新产品;同时,加强与国际知名企业的合作与交流,提升公司的国际竞争力。展望未来,亿晶源将致力于成为全球领先的LED半导体制造商之一。
请注意,以上故事框架仅为示例,具体细节和事实可能需要根据实际情况进行调整和补充。
在公司快速发展的过程中,High Tech Chips Inc深刻认识到单打独斗的局限性。因此,公司积极寻求与全球知名科技企业的战略合作。通过与华为、三星等手机制造商的合作,High Tech Chips Inc的芯片产品被广泛应用于这些企业的旗舰机型中,极大地提升了产品的知名度和市场占有率。同时,公司还与英伟达、英特尔等芯片巨头建立了技术合作关系,共同推动芯片技术的创新和发展。
在公司快速发展的过程中,High Tech Chips Inc深刻认识到单打独斗的局限性。因此,公司积极寻求与全球知名科技企业的战略合作。通过与华为、三星等手机制造商的合作,High Tech Chips Inc的芯片产品被广泛应用于这些企业的旗舰机型中,极大地提升了产品的知名度和市场占有率。同时,公司还与英伟达、英特尔等芯片巨头建立了技术合作关系,共同推动芯片技术的创新和发展。
进入21世纪,Bals Elektrotechnik继续致力于技术创新和产品升级。1998年,公司推出了具有革命性的CEE插头和插座无螺纹连接技术。这一技术不仅提高了连接的安全性和效率,还为用户节省了大量时间。Bals因此成为第一家提供这种创新技术的公司,进一步巩固了其在电气行业的领先地位。
这些故事虽然基于假设和现有信息,但尽量保持了客观性和事实性。它们展示了Bals Elektrotechnik GmbH & Co. KG公司在电子行业发展的不同阶段和关键事件,从一个运输公司成功转型为电气行业的领军企业。这些故事不仅反映了公司的成长历程,也体现了其不断创新、追求卓越的精神。
高频电子的业务范围广泛且多元化,主要包括FEI-NY、Gillam-FEI和FEI-Zyfer三个部门。FEI-NY部门主要负责纽约总部设施和子公司FEI-Asia与FEI-Elcom的运营;Gillam-FEI部门则负责比利时与法国的业务,并专注于电缆网络同步产品的设计、研发和生产;FEI-Zyfer部门则主要经营公司加州业务,并设计生产附带GPS技术的产品。这种多元化业务布局不仅降低了公司的经营风险,还实现了各业务之间的战略协同和资源共享。
CE驱动程序里跟某外部设备通信,需用到微秒级延时。现在实验用简单的程序循环方式来实现中间的延时: V_pIoPregs->rGPBDAT &= ~(1<<1); //GPB1 set 1 Delay1us(4); //delay 4 us V_pIoPregs->rGPBDAT |= (1< ...… 查看全部问答∨ |
我用到了LM393但使用中用此原理做的板子,有一块之前的板子输出信号没有问题,但这块板子LM393输出电压为0V,1.25V,5V三种状态,只有输入端电压差很多时才输出5V电压,接近时输出1.25V,而之前的那块板只输出0和5V.把CD4541断掉也是一样.为什么会有这种现 ...… 查看全部问答∨ |
第一次向2812的FLASH内下载程序是成功的,且程序也能够执行;第二天擦除后,在下载就不行了,报告: Flash API Error #31: There was a Aero Bit Error on the Program Operation. First Fail Address=0x003D7801 在开发板上和其他产品的板子上 ...… 查看全部问答∨ |
|