zoukankan      html  css  js  c++  java
  • AVR单片机教程——随机点亮LED

    本文隶属于AVR单片机教程系列。

    之前我们做的闪烁LED和流水灯,灯效都是循环的。这次我们来尝试一些不一样的——每一次随机选择一个LED并点亮。

    要实现随机的效果,我们要用C语言标准库中的相关设施:

    1 #define RAND_MAX /*implementation defined*/
    2 int rand();
    3 void srand(unsigned seed);

    以上设施都定义在 <stdlib.h> 中。其中,rand() 可以返回[0, RAND_MAX ]范围内的伪随机整数,srand() 用于给 rand() 提供种子,当种子相同时,多次调用 rand() 得到的序列是相同的,这就是为什么称 rand() 产生的数为“伪随机数”。如果使用 rand() 之前没有调用过 srand() ,则相当于调用过 srand(1) 。

    利用这些工具,很容易就能写出一个随机LED的程序:

     1 #include <ee1/led.h>
     2 #include <ee1/delay.h>
     3 
     4 #include <stdlib.h>
     5 
     6 int main()
     7 {
     8     led_init();
     9     // srand(1);
    10     while (1)
    11     {
    12         led_set(rand() % 4, LED_ON);
    13         delay(200);
    14         led_off();
    15     }
    16 }

    rand() 返回[0, RAND_MAX ]范围内的整数,但 led_set 的第一个参数只有在 [0, 3] 范围内才有效,因此我们把 rand() 的返回值对4取模。

    srand(1) 被打上注释,是因为这行调用没有必要。

    把这段代码编译并烧写进单片机,你会发现LED闪烁的时间是不等长的,这是因为可能存在连续两次亮相同灯的情况。为了解决这个问题,我们引入一个变量,保存当前亮的LED,并让下一个亮的LED与当前的不同。代码如下:

     1 #include <ee1/led.h>
     2 #include <ee1/delay.h>
     3 
     4 #include <stdint.h>
     5 #include <stdlib.h>
     6 
     7 int main()
     8 {
     9     led_init();
    10     // srand(0);
    11     uint8_t cur = rand() % 4;
    12     while (1)
    13     {
    14         led_set(cur, LED_ON);
    15         delay(200);
    16         uint8_t next = rand() % 3;
    17         if (next >= cur)
    18             next++;
    19         led_set(cur, LED_OFF);
    20         cur = next;
    21     }
    22 }

    使连续两次不亮相同灯的核心代码是16~18行。程序生成一个[0, 2]范围内的随机值,3种取值概率相等,然后当此值大于或等于当前亮灯值时,让它自增。假设当前亮灯为1,则生成的随机数在值为0、1、2的情况下分别变成(映射为)0、2、3,因此下一次亮灯就是在当前没有亮的3个灯中等概率地选择一个。

    按开发板上的RESET键可以让单片机复位。观察LED序列,你会发现对于每一次复位,LED序列都是一样的。这个问题我们暂时无法解决。

    今天的作业:一个更复杂的随机效果,每次亮1~2个灯,连续两次不能有相同的灯亮,也不能都亮2个,总体来看亮2个的概率为1/3。

    这里有一个hex文件,是作业的一个实现,以及一个.c源文件,把单片机程序的main函数复制到文件最后,用计算机的C编译器编译运行可以检查算法是否正确。一个正确的结果应该跟这个差不多:

  • 相关阅读:
    利用单片机构成高精度PWM式12位D/A
    【转】FORMAT在DELPHI中的用法
    可定时温湿控制器
    用C#获取硬盘序列号,CPU序列号,网卡MAC地址
    Oracle笔记:查询表相关
    Oracle笔记:视图
    Oracle笔记:维护数据的完整性
    Oracle笔记:索引
    Oracle笔记:pl/sql例外处理
    Oracle笔记:逻辑备份与恢复
  • 原文地址:https://www.cnblogs.com/jerry-fuyi/p/11331642.html
Copyright © 2011-2022 走看看