查看: 198|回复: 9
收起左侧

[牛人杂谈] delay()延时实现LED灯的闪烁

[复制链接]

73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-6 18:51 | 显示全部楼层 |返回版面|阅读模式
一个好的程序结构,本身就是一个微型的多任务操作系统。鸿哥教给大家的就是如何编写这个简单的操作系统。在main函数循环中用switch语句实现多任务并行处理的任务切换,再外加一个定时器中断,这两者的结合就是鸿哥多年来所有实战项目的核心。
  1. #include "REG52.H"

  2. void initial_myself();
  3. void initial_peripheral();

  4. void delay_short(unsigned int uiDelayshort);
  5. void delay_long(unsigned int uiDelaylong);
  6. void led_flicker();

  7. /* 注释一:
  8. * 吴坚鸿个人的命名风格:凡是输出后缀都是_dr,凡是输入后缀都是_sr。
  9. * dr代表drive驱动,sr代表sensor感应器
  10. */
  11. sbit led_dr = P3 ^ 5;

  12. void main()  //学习要点:深刻理解鸿哥首次提出的三区一线理论
  13. {
  14.     /* 注释二:
  15.     * initial_myself()函数属于鸿哥三区一线理论的第一区,
  16.     * 专门用来初始化单片机自己的寄存器以及个别外围要求响应速度快的输出设备,
  17.     * 防止刚上电之后,由于输出IO口电平状态不确定而导致外围设备误动作,
  18.     * 比如继电器的误动作等等。
  19.     */
  20.     initial_myself();

  21.     /* 注释三:
  22.     * 此处的delay_long()延时函数属于第一区与第二区的分割线,
  23.     * 延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定。
  24.     * 比如液晶模块,AT24C02存储芯片,DS1302时钟芯片,
  25.     * 这类芯片有个特点,一般都是跟单片机进行串口或并口通讯的,
  26.     * 并且不要求上电立即处理的。
  27.     */
  28.     delay_long(100);

  29.     /* 注释四:
  30.     * initial_peripheral()函数属于鸿哥三区一线理论的第二区,
  31.     * 专门用来初始化不要求上电立即处理的外围芯片和模块.
  32.     * 比如液晶模块,AT24C02存储芯片,DS1302时钟芯片。
  33.     * 本程序基于朱兆祺51单片机学习板。
  34.     */
  35.     initial_peripheral();

  36.     /* 注释五:
  37.     * while(1){}主函数循环区属于鸿哥三区一线理论的第三区,
  38.     * 专门用来编写被循环扫描到的非中断应用程序
  39.     */
  40.     while(1)
  41.     {
  42.         led_flicker();   //LED闪烁应用程序
  43.     }
  44. }

  45. void led_flicker() //LED闪烁应用程序
  46. {
  47.     led_dr = 1; //LED亮
  48.     delay_short(50000);  //延时50000个空指令的时间

  49.     /* 注释六:
  50.     * delay_long(100)延时50000个空指令的时间,因为内嵌了一个500次的for循环
  51.     */
  52.     led_dr = 0; //LED灭
  53.     delay_long(100);    //延时50000个空指令的时间
  54. }

  55. /* 注释七:
  56. * delay_short(unsigned int uiDelayShort)是小延时函数,
  57. * 专门用在时序驱动的小延时,一般uiDelayShort的数值取10左右,
  58. * 最大一般也不超过100.本例为了解释此函数的特点,取值范围超过100。
  59. * 此函数的特点是时间的细分度高,延时时间不宜过长。uiDelayShort数值
  60. * 的大小就代表里面执行了多少条空指令的时间。数值越大,延时越长。
  61. * 时间精度不要刻意去计算,感觉差不多就行。
  62. */
  63. void delay_short(unsigned int uiDelayShort)
  64. {
  65.     unsigned int i;
  66.     for(i = 0; i < uiDelayShort; i++)
  67.     {
  68.         ;   //一个分号相当于执行一条空语句
  69.     }
  70. }

  71. /* 注释八:
  72. * delay_long(unsigned int uiDelayLong)是大延时函数,
  73. * 专门用在上电初始化的大延时,
  74. * 此函数的特点是能实现比较长时间的延时,细分度取决于内嵌for循环的次数,
  75. * uiDelayLong的数值的大小就代表里面执行了多少次500条空指令的时间。
  76. * 数值越大,延时越长。时间精度不要刻意去计算,感觉差不多就行。
  77. */
  78. void delay_long(unsigned int uiDelayLong)
  79. {
  80.     unsigned int i;
  81.     unsigned int j;
  82.     for(i = 0; i < uiDelayLong; i++)
  83.     {
  84.         for(j = 0; j < 500; j++) //内嵌循环的空指令数量
  85.         {
  86.             ; //一个分号相当于执行一条空语句
  87.         }
  88.     }
  89. }

  90. void initial_myself()  //初始化单片机
  91. {
  92.     led_dr = 0; //LED灭
  93. }
  94. void initial_peripheral() //初始化外围
  95. {
  96.     ;   //本例为空
  97. }
复制代码


73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-6 18:52 | 显示全部楼层 |返回版面
Delay()函数的长延时适用在上电初始化。
Delay()函数的短延时适用在驱动时序的脉冲延时,此时的时间不能太长,本例中暂时没有列出这方面的例子,在后面的章节中会提到。
在本例源代码中,在led_flicker()闪烁应用程序里用到的两个延时delay,它们的延时时间都太长了,在实战项目中肯定不能用这种延时,因为消耗的时间太长了,其它任务根本没有机会执行。

15

主题

364

帖子

1074

积分

助理工程师

发表于 2017-7-6 19:05 | 显示全部楼层 |返回版面
在那额搞的。51单片机OUTlet。

73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-9 15:19 | 显示全部楼层 |返回版面
在初始化时候还是用得着的。

48

主题

1675

帖子

5005

积分

高级工程师

发表于 2017-7-11 20:54 | 显示全部楼层 |返回版面
常用的这种方式

73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-13 18:51 | 显示全部楼层 |返回版面
51里面很多延时都是这么实现。

62

主题

1667

帖子

4999

积分

中级工程师

发表于 2017-7-13 22:50 | 显示全部楼层 |返回版面
不用这个,真是想不到怎么弄。

33

主题

891

帖子

2668

积分

初级工程师

发表于 2017-7-17 21:41 | 显示全部楼层 |返回版面
delay通常要了解空指令占用多少周期,每个周期多长。

73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-18 10:57 | 显示全部楼层 |返回版面
有不少单片机也会提供一些库函数,里面就包含这个延时函数。

73

主题

1702

帖子

5106

积分

高级工程师

 楼主| 发表于 2017-7-18 11:04 | 显示全部楼层 |返回版面
一般ARM内核的单片机都会提供这个库函数支持delay.
*滑动验证:
您需要登录后才可以回帖 登录 | 注册 手机登录

本版积分规则

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