AVR单片机教程——随机点亮LED
本文隶属于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的更多相关文章
- AVR单片机教程——点亮第一个LED
做了这么多准备,我们终于可以开始用开发板做点事了. 单片机编程与计算机编程有一些不同点.程序都要有零个或多个输入.一个或多个输出,这是两者都有的,但是计算机编程的输入输出主要靠控制台,而单片机没有. ...
- AVR单片机教程——闪烁LED
上次我们把LED点亮了.你可能已经试过把 LED_RED 换成其他灯,也可能已经用 led_on() 把所有LED一起点亮了.但是LED点亮以后,程序就退出了,之后LED一直没有暗,直到没有供电.这一 ...
- AVR单片机教程——数码管
先解答之前一个思考题:如果不把引脚配置为输出而写高电平,连接LED会怎样? 实验结果是,LED会亮,但相比于输出高电平的情况,亮度很低.这是为什么呢? 通过上一篇教程我们知道,引脚输入输出模式是由寄存 ...
- AVR单片机教程——数字输出
从上一篇教程中我们了解到,按键与开关的输入本质上就是数字信号的读取.这一篇教程要讲的是,控制LED的原理是数字信号的输出.数字IO是单片机编程之有别于桌面编程的各项内容中最简单.最基础的. 在讲数字信 ...
- AVR单片机教程——按键动作
上一篇教程中我们学习了如何读取按键状态.而按键的动作,比如单击,至少需要两个状态才能判定,长按.双击的判定更加复杂.今天我们来学习如何使用库函数判断按键单击,以及其实现原理. 我们要实现的是:当一个按 ...
- AVR单片机教程——按键状态
好久没更新了,今天开始继续,争取日更. 今天我们来讲按键.开发板的右下角有4个按键,按下会有明显的“咔嗒”声.如何检测按键是否被按下呢?首先要把按键或直接或间接地连接到单片机上.与之前使用的4个LED ...
- AVR单片机教程——烧写hex文件
每一次build项目,编译器都会生成多个文件,其中有一个就是hex文件.之前在IDE中配置的external tools,就是把这个hex文件烧写到单片机中去的. 然而,有些时候你想运行别人的程序,但 ...
- AVR单片机教程——流水灯
上次我们用 delay 函数与 while 循环实现了一个LED的闪烁.这一次我们把所有LED加入进来,让它们依次闪烁,形成流水灯的效果. 开发板上有4个LED,我们可以用不多的语句把循环体直接描述出 ...
- AVR单片机教程——定时器中断
本文隶属于AVR单片机教程系列. 中断,是单片机的精华. 中断基础 当一个事件发生时,CPU会停止当前执行的代码,转而处理这个事件,这就是一个中断.触发中断的事件成为中断源,处理事件的函数称为中断 ...
随机推荐
- Java中对象并不是都在堆上分配内存的
转(https://blog.51cto.com/13906751/2153924) 前段时间,给星球的球友们专门码了一篇文章<深入分析Java的编译原理>,其中深入的介绍了Java中的j ...
- 14.LAMP服务 Linux Apache Mysql Php和防护机制 xinetd、tcp wapper
一.安装LAMP服务 Linux Apache Mysql Php 要求操作系统支持 php解析 apache调用php插件解析 phpmyadmin yum install ...
- HikariCP 连接最快的连接池
三点原因 1.字节码精简 2.自定义 FastList 代替ArrayList ;避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描: 3.优化代码和拦截 ...
- ArcGIS Python人门到精通目录基于ArcGIS10.2,100以上案例15章42个视频806分钟,51GIS网站上线
ArcGIS Python人门到精通目录 闫老师 QQ:276529800 微信13108507190 1. ArcGIS Python基础 1.1 ArcGIS为什么学习Python 1.2 A ...
- [JDBC/Oracle]设置Statement.setQueryTimeout(seconds)并不好用 原因:环境问题
对比实验:https://www.cnblogs.com/xiandedanteng/p/11960320.html 注:setQueryTimeout语句还是好用的,但有些环境不支持,下文是在单位虚 ...
- mysql起容器的最精简命令
亲测有效的 mysql 容器命令: #pull mysql:5.6 docker pull mysql:5.6 #起容器,映射3306端口,配置root用户密码 docker run -di --na ...
- 超级简单的checkbox赋值,用于记住登陆名
<input name="rememberme" type="checkbox" id="rememberme" onclick=&q ...
- MFC加载大型osg模型
MFC加载模型,发现打开 Navid 缓冲等选项后,加载大型模型的速度就快了很多. #include "stdafx.h" #include "OSGObject.h&q ...
- 【DataBase】Hsqldb与项目集成
Hsqldb与项目集成 进行模式下集成 可以集成进行(In-Process)模式下的hsqldb,由于数据存储在文件中,即使程序退出,数据也不会被销毁 采用jdbc集成的方式 package com. ...
- 使用Commons math做数值计算
使用Commons math做数值计算 觉得有用的话,欢迎一起讨论相互学习~Follow Me 最近使用jmetal做多目标的时候,想用一些简单的方法求最大值最小值方差和协方差矩阵,但是原生代码真的是 ...