单片机C语言的精确延时程序设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
法 在生成目标代码时 会有所不同 开发人员必须研 究它生成的汇编语言代码 来保证时间的准确性 这也 许是除了使用嵌入汇编或直接编写汇编函数的唯一方 法 其实在单片机的 C 编译器中 已经有足够底层操作 方面的扩展 所以这里只考虑纯 C 语言的方法
3 延时程序设计
以德国 Keil 公司的 C 5 1 编译器为例 目前它已被公 认为业界的标准 以下讨论均假设 5 1 单片机时钟晶振 为 6 M H z 以小模式下编译 这时程序指令执行的最小 单位是 2 s 如果使用非英特尔且内核优化过的单片 机 应切换回普通Fra Baidu bibliotek式 或仔细研究它的时序 以 D S 1 8 B 2 0 为例 临时在程序中需要延时 2 s 那么可以 用下述程序
1 单总线协议器件
单总线协议(1 wire bus protocol)是单总线器件数据传 输协议 因为数据( 也可以包括电源) 都由一条线来传 输 没有辅助的数据同步信号 这时就只能由时序来解 析协议内容 这样就只有依靠对时序的严格要求 来保 障数据传输的准确性
单总线协议的信号主要有 初始化时序( 包括复位 脉冲和在线脉冲 是主机与器件的联络信号) 和读 写 时序 单总线器件完全依靠对线上的时序来做出响应 这些有效的时序称作时隙 也有称作时间片的 是同一 词汇的不同翻译( 见参考文献[2])
#include< intrins.h> void somefunc(void) { _nop_() }
如果要延时 64 s 甚至 640 s 那么不可能在程序 中重复上述 _ n o p _ ( ) 虽然这并不会出错 可以利用它 来构建延时程序 精确定时的问题就变为延时程序的精 度问题 首先讨论空操作延时
初始化时序时间裕度大 容易实现 读写脉冲对时 序要求相对严格 尤其在慢速的 M C S - 5 1 下 指令的运 行在 s 级 读写时序在 15 s 的后一小部分 大约 4 s 不同批次的芯片会有少许差距 有的会允许你的时序有 少许误差 有的则非常严格
2 C 语言编译器
在用汇编语言编写程序时 很容易控制时间 因为 我们知道每条语句的执行时间 每段宏的执行时间以及 每段子程序加调用语句所消耗的时间 在单片机的 C 语 言开发中 C 语言编译器都对标准 C 作了针对单片机特 点的扩展 但对于不同的单片机 不同的 C 语言编译器 在将源程序翻译成目标机器语言时 会有不同的编译方
定时器启动后 单片机可以作其它事情 如复位看 门狗或 L E D 扫描
调用的短延时函数必须精确地受到控制 先作一个
67 2004.10 Microcontrollers & Embedded Systems
万方数据
经验交流
EXPERIENCE EXCHANGE
几 s 的延时实验程序 以观察它实际的延时时间 在
3.1 空操作延时及延时函数
注意到 D S 1 8 B 2 0 最小时隙除大于 1 s 的外 最小 的就是 1 5 s 而数据的读或写也包含在这 1 5 s 中 由于定时器的延时要对定时器进行初始化 不易得到小 的延时 只能用于复位脉冲 即在 4 8 0  ̄ 9 6 0 s 之间的 延时 程序实现接近 9 6 0 s 的延时 TH0 = -950/256; TL0 = -950%256; TMOD= TMOD|0x01 TR0 = 1;
生成的汇编语言代码不是 LCALL delay1; LCALL delay2;
它被编译器优化 在调用 delay1 进入并执行该函数 返回前直接跳入 d e l a y 2 执行 类似于 delay1
LJMP delay 2;
由 delay 2 执行 RET 返回 这样连续调用两个函数时
就变成一次调用加跳转 结果会省去 2 s 解决了延
_nop_()
//2 s
_nop_()
//2 s
_nop_()
//2 s
D0 = 1
/ / 恢复高电平
_nop_()
//2 s
_nop_()
//2 s
if(D0) value|=0x80 _nop_(); //2 s
delay(10)
/ / 等待
}
_delay4:
M O V vd?040,R7
2s
DJNZ R7, ¥
RET
END OF _delay4
注意 这里用于参数传递的 R 7 被复制保存起来了
这样在调用时 比汇编书写的函数多出 2 s
除此之外 还是可以编出全 C 的类似函数
void delay5(unsigned char vd)
{ do {vd--;
参考文献
1 Keil Software Keil uVision2 Reference Keil Electronik GmbH/Keil Software Inc 1995
2 DALLAS MAXIM 产品资料光盘 6.0版, 2002 收稿日期 2004-06-01
PUBLIC _delay3
RSEG ?PR?_delay3?DLY
_delay3:
DJNZ R7, ¥ 4 s
RET
4s
END
嵌入汇编的方法如下
void delay4(unsigned char vd)
{ #pragma asm
DJNZ R7, ¥
#pragma endasm
}
编译后的形式
以上代码调用一次也有 14 s 之多 还是无法使用
也就是说 采用 f o r 形式的语句 生成的汇编代码都是
先减 再比较 还是与 D J N Z 无关 也就不能产生短
延时
3.2 短延时程序编写
首先想到的是用汇编语言函数或嵌入汇编的方法 汇编语言函数实现方法如下
N A M E DLY
?PR?_delay3?DLY SEGMENT CODE
{ for (vd=0 vd<10 vd++)
}
生成的汇编代码如下
RSEG ?PR?_delay2?DLY2
_delay2:
USING0
CLR A
2s
M O V R7,A
2s
?C0002:
INC R7
2s
C J N E R7,#0AH,?C0002 4 s
?C0005:
RET
4s
; END OF _ delay2
68
2004.10
万方数据
EXPERIENCE EXCHANGE 经验交流
控制 因为只有一条延时指令 D J N Z R 7 , ¥ 这时 一 定注意函数传递的参数( 通过 R 7 赋值) 要 2 s 调用函 数时执行的 L C A L L 语句的 4 s 在函数返回时 R E T 指令的 4 s 还要至少执行 D J N Z 指令( R 7 为 0 D J N Z 后 R7=256)4 s 所以至少为 14 s 这应该是函数调 用延时的极限状态 另外还要注意对于连续调用的函 数 例如 { void delay 1(void) void delay2 (void) }
时问题 再根据参考文献[ 2 ] 可写出读字节程序
unsigned char read_byte(void)
{ unsigned char i
unsigned char value = 0
for (i=0 i<8 i++)
{ value>>=1;
//2 s
D0 = 0
/ / 把DQ拉低启动
列单片机进行产品开发工程技术人员的硬件和软件设计参考书 部分内容对其它类型单片机的开发也具有一定的参考价值
69 2004.10 Microcontrollers & Embedded Systems
万方数据
val=val>>1
delay(10)
//因为写时间必须匹配
D0 = 1;
}
delay(2);
}
完整的 1 8 B 2 0 数据采集程序见本刊网站 w w w . d p j .
c o m . c n 其中包含了 CRC 校验
5 结 论
在现代竞争激烈的商品经济环境下 高级语言的运 用大大提高了开发效率 在用 C 等高级语言编写这类时 间要求严格的程序时 分析最终的目标汇编代码是无法 避免的 在现代带有集成开发环境的编译器中 有软件 仿真 或有硬件调试功能 都给精确定时程序的开发带 来方便 充分发挥软件工具的潜力 才能真正在各种环 境下发挥高级语言带来的最大好处 效率
_delay1:
USING0
?C0006:
M O V A,R7
2s
SETB C
2s
S U B B A,#00H
2s
JC ?C0009
2s
D E C R7
2s
S J M P ?C0006
4s
?C0009:
RET
4s
; END OF _delay1
延时至少 18 s 无法用于读写时隙 改用如下程序
void delay2(unsigned char vd)
?PR?_delay4?DLY SEGMENT CODE
?DT?_delay4?DLY SEGMENT DATA OVERLAYABLE PUBLIC
_delay4
RSEG ?DT?_delay4?DLY2
?_delay4?BYTE:
vd?040: DS 1
RSEG ?PR?_delay4?DLY2
新书介绍
C8051F 系 列 单 片 机 开 发 与 C 语 言 编 程 含 光 盘
童长飞 编著
北京航空航天大学出版社出版 即将出版
在介绍 C8 0 5 1Fx x x 单片机工作原理的基础上 对单片机外设 ADC DA C 比较器 定时器 方波输出和定时器捕捉 PWM 等均给出了调试代码 在总线方面 对 CA N SMBUS I2C SPI UART 均给出了双机调试代码和一些高层应用 以帮助读者 更好地理解单片机工作原理 书中还包括 LCD 红外编码解码 步进电机 直流电机 舵机 超声测距 I 2C ROM 串行时钟 等方面的应用 以提高实用性 本书特点是实例较多 而且采用 C 语言编程 程序代码可读性和移植性强 大部分代码稍加修改即 可成为其它型号单片机子程序 书中附光盘一张 包含书中所有例程的源代码 原理图及相关开发软件 本书可作为使用 C8 051 F 系
} while(vd);
}
编译后
RSEG ?PR?_delay5?DLY3
_delay5:
USING0
?C0003:
D J N Z R7,?C0003
RET
看来 do-while 是和 DJNZ 相对应编译的
4 调用时间和某些细节
除了直接插入 _ n o p _ ( ) 语句的短时间延时 在稍长 时间的多变延时程序中 往往需要调用上节讨论的延时 函数来完成延时 其中以汇编语言函数和 do-wh i l e 最易
return(value);
}
写 1 字节的程序
void write_byte(unsigned char val)
{ unsigned char i
for (i=0 i<8 i++) {
D0 = 0
// 把DQ拉低启动
delay(1)
//为4时不能读
D0 = val&0x01
汇编时代常用的延时指令为
MOV R7 DDLY
DJNZ R7 ¥
产生最小 4 s 的延时 仿造的 C 程序如下
void delay1(ndly)
{for( ndly>0 ndly--)
}
生成的汇编代码与 D J N Z 无关 是如下形式的 其
中无关的编译注释已删除
RSEG ?PR?_delay1?DLY2
EXPERIENCE EXCHANGE 经验交流
单片机 C 语言的精确延时程序设计
东北电力学院 盛文利
现在单片机的开发中 C 语言以其方便 灵活 逻 辑性强 易于维护和可移植性好等强大优势 占据了单 片机开发的主要地位 过去 由于单片机 C 语言本身存 在的缺陷 加之单片机工程项目本身都不大 C 语言在 单片机中的应用没有被重视 在 C 语言环境下 只需关 心程序的逻辑关系 实现细节则由编译器完成 这为快 速开发提供了条件 也大大减小了开发工作量 但同 时 实现细节就不被控制了 这个问题对于经常重视实 现细节的单片机 就必须要得到解决 好在一般的 C 语 言编译器都提供嵌入汇编 与汇编互调用和汇编级的代 码察看等功能 现以 Keil C51(见参考文献[1])下的单总线 器件程序开发为例 说明解决方法