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

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

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

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

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

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

 #include <ee1/led.h>
#include <ee1/delay.h> #include <stdlib.h> int main()
{
led_init();
// srand(1);
while ()
{
led_set(rand() % , LED_ON);
delay();
led_off();
}
}

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

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

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

 #include <ee1/led.h>
#include <ee1/delay.h> #include <stdint.h>
#include <stdlib.h> int main()
{
led_init();
// srand(0);
uint8_t cur = rand() % ;
while ()
{
led_set(cur, LED_ON);
delay();
uint8_t next = rand() % ;
if (next >= cur)
next++;
led_set(cur, LED_OFF);
cur = next;
}
}

使连续两次不亮相同灯的核心代码是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编译器编译运行可以检查算法是否正确。一个正确的结果应该跟这个差不多:

AVR单片机教程——随机点亮LED的更多相关文章

  1. AVR单片机教程——点亮第一个LED

    做了这么多准备,我们终于可以开始用开发板做点事了. 单片机编程与计算机编程有一些不同点.程序都要有零个或多个输入.一个或多个输出,这是两者都有的,但是计算机编程的输入输出主要靠控制台,而单片机没有. ...

  2. AVR单片机教程——闪烁LED

    上次我们把LED点亮了.你可能已经试过把 LED_RED 换成其他灯,也可能已经用 led_on() 把所有LED一起点亮了.但是LED点亮以后,程序就退出了,之后LED一直没有暗,直到没有供电.这一 ...

  3. AVR单片机教程——数码管

    先解答之前一个思考题:如果不把引脚配置为输出而写高电平,连接LED会怎样? 实验结果是,LED会亮,但相比于输出高电平的情况,亮度很低.这是为什么呢? 通过上一篇教程我们知道,引脚输入输出模式是由寄存 ...

  4. AVR单片机教程——数字输出

    从上一篇教程中我们了解到,按键与开关的输入本质上就是数字信号的读取.这一篇教程要讲的是,控制LED的原理是数字信号的输出.数字IO是单片机编程之有别于桌面编程的各项内容中最简单.最基础的. 在讲数字信 ...

  5. AVR单片机教程——按键动作

    上一篇教程中我们学习了如何读取按键状态.而按键的动作,比如单击,至少需要两个状态才能判定,长按.双击的判定更加复杂.今天我们来学习如何使用库函数判断按键单击,以及其实现原理. 我们要实现的是:当一个按 ...

  6. AVR单片机教程——按键状态

    好久没更新了,今天开始继续,争取日更. 今天我们来讲按键.开发板的右下角有4个按键,按下会有明显的“咔嗒”声.如何检测按键是否被按下呢?首先要把按键或直接或间接地连接到单片机上.与之前使用的4个LED ...

  7. AVR单片机教程——烧写hex文件

    每一次build项目,编译器都会生成多个文件,其中有一个就是hex文件.之前在IDE中配置的external tools,就是把这个hex文件烧写到单片机中去的. 然而,有些时候你想运行别人的程序,但 ...

  8. AVR单片机教程——流水灯

    上次我们用 delay 函数与 while 循环实现了一个LED的闪烁.这一次我们把所有LED加入进来,让它们依次闪烁,形成流水灯的效果. 开发板上有4个LED,我们可以用不多的语句把循环体直接描述出 ...

  9. AVR单片机教程——定时器中断

    本文隶属于AVR单片机教程系列.   中断,是单片机的精华. 中断基础 当一个事件发生时,CPU会停止当前执行的代码,转而处理这个事件,这就是一个中断.触发中断的事件成为中断源,处理事件的函数称为中断 ...

随机推荐

  1. #C++初学记录(判断子串#数学结合)

    A Count Task Problem Description Count is one of WNJXYK's favorite tasks. Recently, he had a very lo ...

  2. Cheat Engine TUTORIAL 教程 (8个步骤)

    https://www.cnblogs.com/ae6623/archive/2011/04/16/4416874.html https://www.52pojie.cn/thread-828030- ...

  3. Acunetix Web Vulnerability Scanner abbr. AWVS

    awvs 中文手册详细版 - 木讷 - 博客园https://www.cnblogs.com/iamver/p/7124718.html Download Acunetix Trialhttps:// ...

  4. Andorid SQLite数据库开发基础教程(3)

    Andorid SQLite数据库开发基础教程(3) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库. 使用 ...

  5. 文章后面的QA或FAQ

    QA:question&answer FAQ: Frequently Asked Questions的缩写,中文意思就是“经常问到的问题”

  6. 小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_17、SpringBootTest单元测试实战

    笔记 1.@SpringBootTest单元测试实战     简介:讲解SpringBoot的单元测试         1.引入相关依赖              <!--springboot程 ...

  7. Java基础 return 退出main方法的示例

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  8. Error-ASP.NET:由于未能找到 id 为“FileUpload1$gvFiles$ctl02$lnkBtnRemoveFile”的控件或在回发后将同一 ID 分配给另一个控件,导致发生错误。如果未分配 ID,请显式设置引发回发事件的控件的 ID 属性以避免此错误。

    ylbtech-Error-ASP.NET:由于未能找到 id 为“FileUpload1$gvFiles$ctl02$lnkBtnRemoveFile”的控件或在回发后将同一 ID 分配给另一个控件 ...

  9. nginx调优(一)

    (1).隐藏nginx版本号 隐藏版本号可以有效避免黑客根据nginx版本信息,查找对应漏洞进行攻击. 下载nginx源码包(http://nginx.org/en/download.html)并上传 ...

  10. Jrebel激活方法(转)

    本次服务长期稳定提供给各位同学使用哦!服务器地址:https://jrebel.qekang.com/{GUID}在线GUID地址:在线生成GUID如果失效刷新GUID替换就可以!打开jrebel 激 ...