极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 23650|回复: 7

用示波器“看” arduino (2) ----精确的延时

[复制链接]
发表于 2015-10-19 16:47:49 | 显示全部楼层 |阅读模式
有一个网友提出一个问题“现在要进行一个0.4us的延时,发现不管怎么调都只能调到15us,根本达不到要求,我用的芯片是MEGA32U4-AU,外部晶振是16MHz,求见解!!!!!”
我试验了一下,最终的程序如下:
  1. const int PinA =  13;      
  2. void setup() {
  3.   pinMode(PinA, OUTPUT);
  4.   digitalWrite(PinA,LOW);
  5. }

  6. void loop() {
  7.   PORTB = B100000; //digitalWrite(PinA,HIGH);
  8.   PORTB = B000000; //digitalWrite(PinA,LOW);  
  9.     for (long zdelay=0;zdelay<9; zdelay++) {
  10.     __asm__("nop\n\t");
  11.   }
  12.   PORTB = B100000; //digitalWrite(PinA,HIGH);
  13.   PORTB = B000000; //digitalWrite(PinA,LOW);
  14.   PORTB = B100000; //digitalWrite(PinA,HIGH);  
  15.   PORTB = B000000;  //digitalWrite(PinA,LOW);  
  16. }
复制代码


这个程序运行之后的波形如下

可以看到中间的延时差不多有4.1331us(我用游标对齐,右下角显示x=4.1331). 让然这个值中还包括了一个拉GPIO的指令周期,大约会有 62.1ns的影响。此外,如果要求特别精确,在使用时还要考虑周期性中断的影响。这里就不说了…….

下面我们继续实验,尝试找到循环次数和实际delay时间的关系(因为涉及到编译器优化, long int的计算和判断,直接尝试计算机器周期不可行)。
首先尝试zdelay<8,测量结果是3.7013us

根据上述值结合循环简单猜测一下,对于这个循环体,固定部分耗时0.2469us (比如给变量赋初始值),循环部分每次耗时0.4318us
就是 T= 0.2469 + n *0.4318
根据这个计算循环zdelay<5应该是 2.4059us测量结果是2.3722us
加入我们打算delay 100us 根据上述公式应该循环 231次
代码:

  1. const int PinA =  13;      
  2. void setup() {
  3.   pinMode(PinA, OUTPUT);
  4.   digitalWrite(PinA,LOW);
  5. }

  6. void loop() {
  7.   PORTB = B100000; //digitalWrite(PinA,HIGH);
  8.   PORTB = B000000; //digitalWrite(PinA,LOW);  
  9.   
  10.   for (long zdelay=0;zdelay<231; zdelay++) {
  11.     __asm__("nop\n\t");
  12.   }

  13.   PORTB = B100000; //digitalWrite(PinA,HIGH);
  14.   PORTB = B000000; //digitalWrite(PinA,LOW);
  15.   PORTB = B100000; //digitalWrite(PinA,HIGH);  
  16.   PORTB = B000000;  //digitalWrite(PinA,LOW);  
  17. }
复制代码


实际测试结果是 101us, 符合理论…….


提示:如果你打算用上面的方法来做精确的延时,那么首先你要确保你有一台好用的示波器.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2015-10-19 20:44:25 | 显示全部楼层
你好,可以关于这句话,问一下双引号里面的内容的作用__asm__("nop\n\t");
回复 支持 反对

使用道具 举报

发表于 2015-10-19 21:08:55 | 显示全部楼层
我等穷人一般用几十块的USB SALEAE解决这个问题尤其是做遥控
回复 支持 反对

使用道具 举报

发表于 2015-10-19 21:09:45 | 显示全部楼层
本帖最后由 sanyouhi 于 2015-10-19 21:39 编辑

有点南辕北辙了,你的程序直接写成这样就行
  1. #define F_CPU 16000000
  2. #include <util/delay.h>

  3. void setup()
  4. {
  5.   DDRB = 0X20;
  6. }

  7. void loop()
  8. {
  9. PORTB = 0X20;
  10. _delay_us(0.4);
  11. PORTB = 0;
  12. }
复制代码
实际测量是438ns左右,因为他必定是62.5的整数倍,不可能得到400ns(不禁让我想起茶啊二中)。这样从大循环里用for延时一般很难得到准确的延时结果,不如用现成的函数。
回复 支持 反对

使用道具 举报

发表于 2015-10-19 21:15:58 | 显示全部楼层
叶斌远行 发表于 2015-10-19 20:44
你好,可以关于这句话,问一下双引号里面的内容的作用__asm__("nop\n\t");

那个语句应该是__asm__("nop");这是一个在C语言里调用汇编语言的语句,调用的是汇编语言的NOP语句,NOP的作用就是让机器空跑一个时钟周期。
回复 支持 反对

使用道具 举报

发表于 2015-10-20 07:30:19 | 显示全部楼层
sanyouhi 发表于 2015-10-19 21:15
那个语句应该是__asm__("nop");这是一个在C语言里调用汇编语言的语句,调用的是汇编语言的NOP语句,NOP的 ...

哦,原来是这样子啊!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-20 07:59:11 | 显示全部楼层
sanyouhi 发表于 2015-10-19 21:09
有点南辕北辙了,你的程序直接写成这样就行实际测量是438ns左右,因为他必定是62.5的整数倍,不可能得到400 ...

不错啊  受教了~
回复 支持 反对

使用道具 举报

发表于 2015-10-20 17:25:04 | 显示全部楼层
好办法
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 01:37 , Processed in 0.041480 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表