avr-gcc中关于delay延时函数的应用修改版[ourdev]

在51中我们的延时函数都是自己编写的,无论是在汇编中还是在C言语中。虽然有模板,有时还是有点烦。呵呵。不过在应用avr 单片机的时候我们就有福了。因为avr-gcc 提供给我们很方便的delay 延时函数, 只有在源文件包含:

#include <util/delay.h>

就可以使用了。这个头文件定义了两个级别的延时函数分别是:

void  _delay_us (double __us) ;      //微秒级
void  _delay_ms (double __ms);    //毫秒级

不过不可以高兴的太早,因为要在你的avr-gcc中正确使用它们是有条件的,下面我将慢慢道来。

这个参数和 Makefile 中的 F_CPU 值有关,Makefile 所定义的的F_CPU 变量的值会传递给编译器。你如果用AVR_studio 4.1X来编辑和调试,用内嵌AVR-GCC的进行编译,并且让AVR_studio 帮你自动生成Makefile 的话,那你可以在:
Project -> Configuration Options -> Gerneral -> Frequency     如下图:

avr-gcc中关于delay延时函数的应用修改版[ourdev]
写下你的F_CPU的值,F_CPU这个值表示你的AVR单片机的工作频率。单位是 Hz ,不是 MHZ,不要写错。如 7.3728M   则 F_CPU = 7372800。
你会发现在"delay.h" 头文件中有这个样的一个定义如下:
#ifndef F_CPU
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL    // 1MHz
#endif

这是为了在你没有定义F_CPU这个变量(包括空),或是AVR_studio Frequency没有给值的时候,提供一个默认的 1MHz频率值。让编译器编译时不至于出错。

下面是这两个函数的实体:
void _delay_us(double __us)        //  微秒{uint8_t __ticks;double __tmp = ((F_CPU) / 3e6) * __us;   // 3e6 是因为调用的_delay_loop_1()是三条指令的if (__tmp < 1.0)__ticks = 1;else if (__tmp > 255)__ticks = 0;else__ticks = (uint8_t)__tmp;_delay_loop_1(__ticks);}void _delay_ms(double __ms)       // 毫秒{uint16_t __ticks;double __tmp = ((F_CPU) / 4e3) * __ms;  // 4e3 是因为调用的_delay_loop_2()是四条指令的if (__tmp < 1.0)__ticks = 1;else if (__tmp > 65535)__ticks = 0;else__ticks = (uint16_t)__tmp;_delay_loop_2(__ticks);}

你会发现他们都分别调用了  _delay_loop_1(); 和_delay_loop_2(); 这两个函数
而这两个函数又如下所示:
void  _delay_loop_1(uint8_t __count){__asm__ volatile ("1: dec %0" "\n\t""brne 1b": "=r" (__count): "0" (__count));}


从其函数注释里面可以了解到,该函数用来延迟3个晶振时钟周期,不包括程序调用和退出该函数所花费的时间。该函数的形参__count是一个8位的变量,由此,我们就可以根据系统采用的晶振频率算出该函数最大的延迟时间了:
1MHz时:  MAX_DELAY_TIME (1/1000000)*3*256 0.000768 768 uS
8MHz时:  MAX_DELAY_TIME (1/8000000)*3*256 0.000096 96  uS
............
F_CPU     MAX_DELAY_TIME (1/F_CPU)*3*256
依此类推。
void  _delay_loop_2(uint16_t __count){__asm__ volatile ("1: sbiw %0,1" "\n\t""brne 1b": "=w" (__count): "0" (__count));}


该函数延时4个晶振周期,形参是一个16位的变量,同样我们也可以算出该函数最大的延迟时间:
1MHz时:  MAX_DELAY_TIME (1/1000000)*4*65535 0.26214 262.1 mS
8MHz时:  MAX_DELAY_TIME (1/8000000)*4*65535 0.03277 32.8  mS
............
F_CPU     MAX_DELAY_TIME (1/F_CPU)*4*65535
依此类推。
重要提示:_delay_loop_1(0)、_delay_loop_1(256)延时是一样的!!
同理,_delay_loop_2(0)、_delay_loop_2(65536)延时也是一样的!!这些函数的延时都是最长的延时。



这两个函数都是avr-gcc 的 inline汇编格式写的,具体的语法规则我就不多说了。可以参考avr-libc。不过这两个函数很简单,很容易明白。一个是字节递减,一个是字递减。如果你认真看上面几个函数,你就会发现要正确使用它们是有如下条件的:
        1. 首先,你要正确定义你的 F_CPU 的值,也就是你的AVR单片机实际的频率。否则延时不准。(延时只在数字上不准确,具体可以计算)
        2. 你在编译时一定要打开优化,Makefile中OPT 不要选 0 ,如果AVR_studio 不要选O0 。
        3. 你在使用这两个delay()时,传递给两个函数的实参要使用常量,不要使用变量。
        4. 设置的时间参数__ms , __us 是有范围的,不要超过范围。__ms:1 - [262.14 ms / (F_CPU/1e6) ],  __us:1- [768 us / (F_CPU/1e6)]   。 [...]  表取整数部分.(此处结论错误?)。
__us的最大值应该是768us(1M频率下)   MAX_VALUE 256*3/F_CPU s,最小值3个时钟周期MIN_VALUE 1*3/F_CPU s;
,__ms最大值MAX_VALUE 65536*4/F_CPU s,MIN_VALUE 1*4/F_CPU s;



只有具备了上面的条件你才可以正确使用延时函数 _delay_us () 和 _delay_ms () 。对于第三个条件,为什么要选用常量,还有第二个条件为什么要打开优化选项。这是为了让编译器在编译的时候就把延时的值计算好,而不是把它编译到程序中,在运行时才进行计算,那样的话,一是会增加代码的长度,还会使你的延时程序的延时时间加长,或是变得不可预料。产生时序的错误。
在08版本中已经修改,具体函数如下:
void_delay_us(double __us){uint8_t __ticks;double __tmp = ((F_CPU) / 3e6) * __us;if (__tmp < 1.0)__ticks = 1;else if (__tmp > 255){_delay_ms(__us / 1000.0);return;}else__ticks = (uint8_t)__tmp;_delay_loop_1(__ticks);}


当__us过大的时候,就会调用_delay_ms();由上面可以知道8M时候_delay_ms最小可以延时4/8000000=0.5us  1M时,最小延时4/1000000=4us,可以连接上。
void _delay_ms(double __ms){uint16_t __ticks;double __tmp = ((F_CPU) / 4e3) * __ms;if (__tmp < 1.0)__ticks = 1;else if (__tmp > 65535){// __ticks = requested delay in 1/10 ms__ticks = (uint16_t) (__ms * 10.0);while(__ticks){// wait 1/10 ms_delay_loop_2(((F_CPU) / 4e3) / 10);__ticks --;}return;}else__ticks = (uint16_t)__tmp;_delay_loop_2(__ticks);}


当__ms过大时,只采用__ticks --的方式延时。先延时一个262ms(1M,32ms 8M),然后用递减方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/242193.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

laravel数据库相关操作

SQL查询配置好数据库连接后&#xff0c;可以使用 DB facade 运行查询。DB facade 为每种类型的查询提供了方法&#xff1a;select、update、insert、delete 和 statement。 select查询数据1234567891011121314use Illuminate\Support\Facades\DB;//select方法一$users DB::sel…

Laravel 的 Eloquent ORM学习

创建模型首先&#xff0c;创建一个 Eloquent 模型&#xff0c;生成的模型通常放在 app 目录中&#xff0c;但你可以通过 composer.json 随意地将它们放在可被自动加载的地方。所有的 Eloquent 模型都继承了 Illuminate\Database\Eloquent\Model 类。 示例&#xff1a; 12345678…

最后半天时间,支付宝等第三方支付机构备付金必须100%上交

这几天支付宝、微信等第三支付机构备付金100%上交央行的新闻相信大家已经看到很多&#xff0c;对于备付金可能大家都不是很了解&#xff0c;甚至很多人认为这是不是银行又跟支付宝等第三方支付机构过意不去了&#xff0c;今天我们就带大家来了解下事情的经过以及真相。央行铁令…

在WinAVR中设置Makefile自动编译多个源文件

初次使用WinAVR&#xff0c;了解到需要通过Makefile文件来设定程序编译时的一些值&#xff0c;发现当一个工程中加入多个源文件时不能同时编译&#xff0c;网上查了一下&#xff0c;需要修改Makefile文件&#xff1a; # List C source files here. (C dependencies are automat…

顺丰负债300亿就压力山大,而万达曾经负债4000亿却稳如泰山

近段顺丰负债300亿的消息闹得沸沸扬扬&#xff0c;作为国内快递一哥&#xff0c;顺丰借壳上市后市值曾经超过3000亿人民币&#xff0c;然而目前却负债300亿&#xff0c;这对于一家轻资产的快递公司来说可不得了。顺丰目前的处境难免让人联想到2017年的时候万达负债4000个亿的情…

2019年各大银行最新存款利率,这么存可以获得更多的利息!

2019年怎么存款才能获得最高的利率&#xff1f;这个相信口袋里有点钱的人都会关心的问题&#xff0c;今天我们就来跟大家仔细说一下。先来看一下2019年各大银行最新存款利率是多少。目前各大银行的存款利率跟2018年年底其实没有多大的差别&#xff0c;虽然已经过了2018年12月份…

怎样学习MSP430单片机

MSP430是Texas Instrument(TI&#xff0c;德州仪器)推出的一款超低功耗单片机。TI是一个非常有实力的、全球领先的芯片制造公司&#xff0c;MSP430不仅因为其优秀的设计&#xff0c;更因为TI提供的强有力的技术支持&#xff0c;而很快成为今天市场上非常受欢迎的一款单片机。 使…

【原创】“三次握手,四次挥手”你真的懂吗?

记得刚毕业找工作面试的时候&#xff0c;经常会被问到&#xff1a;你知道“3次握手&#xff0c;4次挥手”吗&#xff1f;这时候我会“胸有成竹”地“背诵”前期准备好的“答案”&#xff0c;第一次怎么怎么&#xff0c;第二次……答完就没有下文了&#xff0c;面试官貌似也没有…

17年前存款11万,取款时银行以销户为由拒绝,法院判银行全额赔付

1999年年底&#xff0c;陈伯在某银行的存折中存入2.6万元&#xff0c;加上这一笔&#xff0c;当时存折里总共有116703元&#xff0c;之后存折遗失。2016年&#xff0c;陈伯在搬家时找到这个存折。从2017年开始&#xff0c;陈伯多次拿着存折到银行取款&#xff0c;均被银行告知账…

VS2010 + OpenCV 2.4.1 环境配置

VS2010 OpenCV 2.4.1 环境配置 &#xff08;Windows 7 x64 中文旗舰版&#xff1b;Visual Studio 2010 中文旗舰版&#xff1b;OpenCV2.4.1。&#xff09; 1.用户环境变量&#xff08;或系统环境变量&#xff09;&#xff0c;新建或添加 PATH D:\Program Fil…

上市公司降价200万卖房仍然无人接手,有的甚至降价1900万

房价降价200万甩卖房子还卖不出去&#xff1f;看到这估计很多人不相信&#xff0c;因为通过各种数据统计&#xff0c;我们可以看到2018年中国大部分城市的房价都是上涨的&#xff0c;而且部分城市甚至上涨40%以上&#xff0c;但我们普通老百姓看到的却是有些业主降价几十万甚至…

2013电赛总结【西电专用】

电赛全称全国大学生电子设计竞赛&#xff0c;全国赛在每逢单数年的9月份举行&#xff0c;竞赛时间四天三夜。 竞赛流程 政策可能有变&#xff0c;每一届竞赛流程可能都不一样&#xff0c;这里只是根据我的了解进行总结的。 我们学校电赛差不多是从每年年初新学期开学时开始进行…

写一篇新文章

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

Matlab与C/C++/Java的一些区别

变量 定义和初始化 C/C中要先定义变量&#xff0c;如果未初始化&#xff0c;其值一般是不确定的 Java中变量使用前&#xff0c;须初始化或赋值&#xff08;实例化时&#xff0c;类中的全局变量会自动被初始化为默认值&#xff09; Matlab中变量在写入时不需预先定义&#xff0c…

男子借款70万前后还了1600万仍未还清,如何避免套路贷?

事件回顾&#xff1a;男子借70万陷入套路贷&#xff0c;前后还了1600万。浙江宁波有一侯姓男子&#xff0c;自己是做石材生意的&#xff0c;本来自己一直安安分分做着生意&#xff0c;2013年年底&#xff0c;因为对一个建筑项目投标&#xff0c;急需一大笔钱。他通过中间人向张…

测试下HTML博文

发布测试 <script>window.onload function () {var obj document.getElementById("box");alert("获取#box元素成功");} </script>

一篇故事讲述了计算机网络里的基本概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等

从别处看到的一篇很不错的文章&#xff0c;形象地阐释了网络里的抽象概念。 计算机主机网关的作用是什么? 假设你的名字叫小不点&#xff0c;你住在一个大院子里&#xff0c;你的邻居有很多小伙伴&#xff0c;在门口传达室还有个看大门的李大爷&#xff0c;李大爷就是你的网关…

Photoshop图层学习总结

移动工具选择图层 方式1&#xff1a;按Ctrl键并单击画布相应位置&#xff0c;选择相应图层 方式2&#xff1a;勾选“自动选择” 图层蒙版 图层蒙版中白色部分&#xff0c;对应图层位置会显示&#xff1b;黑色部分&#xff0c;对应图层不显示(即为透明) 1、可在图层面板创建 2、…