特别声明:文章是原创但是本文讲述的思想是在国外的开源代码中借鉴的
初学者在编写单片机程序时经常会用到延时函数,但是当系统逐步复杂以后(没有复杂到使用操作系统)延时会因为延时降低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
第三,代码中如果存在多个地方需要控制一个流程时一定要先读取标志位再控制
关键字:单片机 软件定时器 使用方法
引用地址:
单片机软件定时器的使用方法
推荐阅读最新更新时间:2024-03-16 16:12
MSP430单片机常见加密总结
1、为什么要加密,如何加密? 当您的产品推向市场的时候,您的竞争对手就开始盯上它了,如果您的产品硬件很容易被模仿,而且您使用的MSP430单片机没有被加密的话,那么您辛辛苦苦的劳动成功就很容易成为您竞争对手的产品了,使用JTAG调试工具FET虽然可以将程序下载到芯片内部,但只有使用专业编程器能够防止程序被 窃取。 2、JTAG、BSL、BOOTLOADER、熔丝的区别和关系是什么? JTAG接口能够访问MSP430单片机内部所有资源,通过JTAG可以对芯片进行程序下载、代码调试、内存修改等等,通过JTAG还能烧断加密熔丝,熔丝一旦被烧断,JTAG接口绝大部分功能失效,就再也不能通过它进行编程了。 BSL接口是利用芯
[单片机]
51单片机外中断计数器C语言程序设计
#include REG51.H #define uchar unsigned char #define uint unsigned int unsigned char code tab ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0xBF}; sbit P32=P3^2; sbit P25=P2^5; sbit P26=P2^6; sbit P27=P2^7; uint cnt; void init(void) { EX0=1; IT0=1; EA=1; ET0 = 1; //定时器0中断打开 TMOD = 0x1;
[单片机]
基于单片机内部定时器中断计数器设计
电源电路就是单片机的供电电路,一般是3.3V或者5V,具体多少要参考各种型号的单片机的工作电压,通常情况下是5V,这里是指通常情况下。 整体设计思路: 单片机中断初始化程序应完成du如下工作: 1、对TMOD赋值,以确定T0和T1的工作方式。 2、计算初值,并将其写入TH0、TL0或TH1、TL1。 3、中断方式时,则对IE赋值,开放中断。 4、使TR0或TR1置位,启动定时/计数器定时或计数。 整体设计思路 单片机的中断为向量中断,即一响应中断就转入固定入口地址执行中断服务程序。各中断源服务程序的入口地址 两个中断入口间只相隔8字节,难以安放一个完整的中断服务程序。因此,通常在中断入口地址处放置一条无条件转移指令,使程序执行转向
[单片机]
单片机轻松入门之三:蜂鸣器
单片机轻松入门之三蜂鸣器 该电路较简单,用PNP型三极管驱动蜂鸣器,当P3.7为低电平时,PN结正向偏置,三极管导通,蜂鸣器发声。 程序如下: #include reg52.h #define uchar unsigned char sbit sounder=P3^7; void delay(uchar z) { uchar j,i; for(i=z;i 0;i--) for(j=110;j 0;j--); } void main() { sounder=1; while(1) { sounder=~sounder; delay(500); } 仿真结果如下:
[单片机]
基于单片机的智能密码锁
该密码锁控制器 ,键盘上有0-9个数字按键,功能键:确认和取消等,可设置复合键。密码的位数及密码可以任意设定,,当输入数字和设置的密码相同的时候,锁打开,否则无法打开。采用IIC通信方式,密码锁的密码掉电不丢失。 #include #include #define uint unsigned int #define uchar unsigned char uchar old1,old2,old3,old4,old5,old6; //原始密码000000 uchar new1,new2,new3,new4,new5,new6; //每次MCU采集到的密码输入 uchar a=10,b=10,c=10,d=10,e=10,f=
[单片机]
单片机+ULN2003A步进电机控制系统(正反转+加减速)
51单片机步进电机的正反转。加减速控制 电路原理图如下: 仿真原理图如下 单片机源程序如下: #include reg52.h #include stdio.h #include intrins.h #define uchar unsigned char #define uint unsigned int sbit RS = P2^4;//1602数据/命令选择端(H:数据寄存器L:指令寄存器) sbit RW = P2^5;//1602读/写选择端 sbit E = P2^6;//1602使能信号端 sbit key1=P3^0;//用户按键 sbit key2=P3^1; sbit key3=P3^
[单片机]
深入理解MSP430单片机IO
一、MSP430单片机的端口概述 P1~P6每组有8个I/O 口,P3,P4,P5,P6具有I/O,及其它片内外设功能,每组具有4个寄存器。P1,P2除具有上述功能外还具有中断能力,每组具有7个寄存器。 二、PX端口 1. P1,P2端口 (1)PxDIR 输入/输出方向寄存器(x代表1,2) 相互独立的八位分别定义了Px7~Px0,8个引脚的输入输出方向。 0 输入模式,只能读。 1 输出模式,可读可写。 8为在PUC后都被复位及置为0. Eg:P1DIR=0X0F; 这里0X0F为16进制表示,对应的二进制为00001111,即将P1DIR的高4位置0,低4位置1,也就是将P1.7,P1.6,P1.5,P1
[单片机]
单片机的结构原理详细说明
8051是MCS-51系列单片机的非常典型的产品,我们用这一个代表性的型号进行系统的单片机原理讲解。 8051单片机包含中央处理器、数据存储器(RAM)、定时/计数器、程序存储器(ROM)、并行接口、串行接口和中断系统等几大单元及数据总线、地址总线和控制总线等三大总线,现在我们分别对其原理加以说明: ·数据存储器(RAM): 8051内部有128个8位用户数据存储单元和128个专用寄存器单元,它们是统一编址的,专用寄存器只能用于存放控制指令数据,用户只能访问,而不能用于存放用户数据,所以,用户能使用的的RAM只有128个,可存放读写的数据,运算的中间结果或用户定义的字型表。 ·中央处理器: 中央处理器(CPU)是整个单
[单片机]