对于STC51单片机来说,延时函数,想必都不陌生。而用的最多的延时基本都是通过软件方法实现的,但由于STC51不同系列的芯片所采用的指令集不同,各指令执行所用机器周期不同。例如STC12Cx的一个振荡周期=一个机器周期,相对STC89Cx的(12个振荡周期=一个机器周期)运行速度快了近10倍有余,就不能用同一个延时函数。
1. STC指令集(版本)
STC_Y1 : STC89Cx/STC90Cx STC89LEx/STC90LEx STC_Y3 : STC12Cx/STC12LEx STC11Fx/STC11Lx/ STC10Fx/STC10Lx STC15F104E/ STC15L104E(A版) STC15F204EA/ STC15L204EA(A版) STC_Y5 : STC15Fxx/STC15Lxx 其中不包含:STC15F104E/STC15L104E (A版) 和 STC15F204EA/STC15L204EA(A版) STC_Y6 : STC8F/ STC8A/ STC8G/ STC8H 通过STC官方提供的 软件STC-ISP可见,不同指令集版本下同一条指令执行所用时钟周期是不同的。因此可能你编写的软件延时函数就不能通用。
2. STC-ISP 软件生成延时函数
可以看到,这种方法还是比较可靠的,也是软件延时比较精确的一种,但是呢我比较喜欢那种想延时多久,给个参数就完了的不专业方法,于是呢就在这个软件生成的基础上进行了点小操作,让它具有通用性,不管是Y1,Y3还是Y5一个函数搞定。
2. STC-Y1/ Y3/ Y5 通用软件延时
首先为了做指令集区分,delay.h写法如下:其中包括了一些常用数据类型的定义,后续为了做通用库函数开发用。
#define _STC_Y3
#include "intrins.h"
#ifndef _TYPE_H
#define _TYPE_H
typedef signed char s8;
typedef unsigned char u8;
typedef signed int s16;
typedef unsigned int u16;
typedef signed long int s32;
typedef unsigned long int u32;
#endif
接下来是delay.c文件的写法,这里我主要使用C语言预编译指令的方法:
#include "delay.h"
#ifdef _STC_Y1
void delay_ms(u16 m)
{
unsigned char i, j;
for(m; m>0; m--){
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
#endif
#ifdef _STC_Y3
void delay_ms(u16 m)
{
unsigned char i, j;
for(m; m>0; m--){
_nop_();
i = 11,j = 190;
do
{
while (--j);
} while (--i);
}
}
void delay_us(u16 u)
{
for(u;(u-1)>0;u--){
_nop_();
}
}
#endif
#ifdef _STC_Y5
void delay_ms(u16 m)
{
unsigned char i, j;
for(m; m>0; m--){
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
void delay_us(u16 u)
{
for(u;u>0;u--){
_nop_();
_nop_();
}
}
#endif
总结:
这种软件延时的方法基本可以满足不同型号STC51单片机,但是由于没有经过精确计算函数调用和循环等一些指令的时间,如果延时参数过大 可能存在us到ms的误差,但是对于,对时间没有太高要求的任务,或者学习使用是没有问题的。经过简单测试,在STC89C52RC和STC12C5A60S2S上,500ms延时误差在几十微秒,还算可以接受。学习笔记 经供参考,大家有更精确的软件延时办法还望指正!
|