第二周 第一讲笔记

单片机点灯大师成长记:从指挥小管家到打造流光溢彩的灯带

1. 启程:认识你的“单片机小管家”

可以把单片机想象成你雇佣的一个不知疲倦的“小管家”。你的任务,就是给它下达明确的指令,让它帮你控制连接在它身上的各种设备(比如LED灯)。

  • 新建工程:这就像是给小管家准备一份专属的**“工作任务书”**。这份文件里规定了小管家的型号(8051单片机)、它需要使用的工具(编译环境等),以及它具体要做什么工作。

温馨提示:就像不同品牌的手机充电器可能不通用一样,为8051小管家写的“工作任务书”(代码),不能直接发给其他家族(如ARM Cortex-M)的小管家,它们“听不懂”。

2. 第一项任务:认识电灯开关(LED原理图)

在让小管家干活前,你得先搞清楚家里的电灯开关在哪里,以及是怎么接线的。原理图就是单片机的“电路接线图”。

  • 开关逻辑:对你的这个小管家来说,让它控制LED灯的开关有一个简单的“密码”:向对应的引脚(控制针脚)输出一个特定的电平信号

    • 密码 0= 开灯:可以想象成你对小管家说:“把第0号开关摁下去(输出低电平)。”
    • 密码 1= 关灯:就是:“把第0号开关抬起来(输出高电平)。”

所以,点亮一个LED的本质,就是准确地告诉小管家:“请把P1口的第0个开关,摁下去(设为0)。”

3. 下达指令:编写“工作任务书”(程序)

3.1 核心框架:一个“无限待命”的管家

单片机小管家有一个特点:如果没有新的指示,它就会停下来发呆。但我们希望它持续工作,所以需要给它一个永不结束的终极指令——while(1)死循环。

比喻while(1)就像是你对小管家说:“只要这个世界还在运转,你就必须不停地循环执行我接下来交代的任务。” 这保证了小管家能7x24小时待命,永远不会主动“下班”。

3.2 具体指令:点灯!

在永不结束的框架内,我们写下具体的指令。下面的代码翻译成自然语言就是:

“小管家,听好了,你的长期任务是:首先,点亮连接在你身上P1_0这个引脚上的灯;然后,再点亮P1_7引脚上的灯。就这两件事,重复执行。”

void main()
{
	while(1) // 核心魔法:让任务永远重复的咒语
	{
		P1_0 = 0; // 对小管家说:打开P1_0口的灯(0代表开)
		P1_7 = 0; // 再打开P1_7口的灯
	} // 回到while循环开始,无限重复
}

4. 验收与调试:在模拟中检查工作

在把程序烧录进实体芯片前,先用仿真软件模拟运行,这相当于让“数字版小管家”先预演一遍,确保逻辑正确。

  • 一个小发现:你可能注意到,在仿真中,实际亮起的灯和代码里指定的位置好像不太一样(比如代码是P1_0,但亮的是原理图上排在最上面的灯)。这是因为:

    • 编码顺序:在代码里,我们习惯说P1_0, P1_1, …, P1_7

    • 物理布局:但在原理图上,LED可能是从上到下(或从右到左)排列的,有时最上面的灯对应的就是P1_0

      这就像看地图,代码是“地理名称”,而原理图是“实际方位”,需要找到它们的对应关系。你的观察非常敏锐!

5. 让灯光舞动起来:流水灯的实现

只让灯亮着太枯燥了,我们来让灯光动起来,实现“流水灯”效果。

5.1 核心魔法:延时函数

小管家执行命令的速度快得超乎想象(纳秒级别),如果让它“开灯-关灯”直接切换,人眼根本看不清。我们需要让它“等待一会儿”。

比喻Delay(1000)函数就像是给小管家一个指令:“在继续做下一件事之前,先专心数1000毫秒(1秒)的羊。” 这样就能创造出肉眼可见的明灭变化了。

5.2 三种高级指挥技法

如何高效地指挥8个灯依次亮灭?这里有三种方法,一种比一种优雅:

  • 方法一:直接点名法(笨拙但直接)

    • 就像老师点名:“P1_0亮!……好,P1_0灭,P1_1亮!……”
    • 缺点:代码冗长,容易出错。
  • 方法二:密码指挥法(更聪明)

    • 直接告诉小管家一个8位的“密码”(一个十六进制数),来控制所有灯的状态。

    • 例如:

      • 0xFE的二进制是 1111 1110,意思是“只点亮第0盏灯”。
      • 0xFD的二进制是 1111 1101,意思是“只点亮第1盏灯”。
    • 代码变得非常简洁:

      P1 = 0xFE; Delay(100); // 点亮第0盏灯
      P1 = 0xFD; Delay(100); // 点亮第1盏灯
      // ... 依次类推
      
  • 方法三:魔法移位法(最优雅)

    • 利用一个现成的“魔法”(库函数 _crol_),让“亮灯密码”像流水一样自动向左移动一位。

    • 比喻:你只需要告诉小管家一个初始密码(0xFE),然后每次循环都命令它:“将当前的密码向左滚动一位!” 灯光就会自动流起来了。

    • 这是最常用、最专业的实现方式,代码如下:

      #include <intrins.h> // 引入“魔法”库
      unsigned char led_code = 0xFE; // 初始密码:只有第0盏灯亮
      void main()
      {
          while(1)
          {
              led_code = _crol_(led_code, 1); // 核心魔法:密码向左滚动1位
              P1 = led_code; // 用新密码控制灯
              Delay(100);
          }
      }
      

6. 终极挑战:创造有节奏的流水灯

现在,我们来实现你最酷的想法:让流水灯的速度越来越快,到达最快后再变回初始速度,循环往复。

逻辑讲解

我们需要一个变量(比如 time)来记录当前“数羊”的时间。在主循环中,每完成一次流水,就让这个时间减少一点(比如 time = time - 100;),这样延时就会变短,灯流动的速度自然就快了。

同时,要设置一个条件判断(if语句),当时间减少到一个下限(比如100毫秒)时,就将时间重置回初始值(如1000毫秒)。这样,速度就会在“从慢到快”和“从快回到慢”之间循环,形成有节奏的变化。