这才是教学开始
在S2.0 \ S2.1 \ S2.2时我们只是告诉你了一些简单的单片机、电路知识,其一是新年刚刚结束,让大家通过一个渐进式的学习慢慢进入状态;其二是用一个梯度式的强度慢慢往上升,起码不会让你一下面对较为复杂的问题,从而对咱们的课程内容产生厌烦心理。
同时你们的基础我放在了一个可以理解但很难说精通的位置上(比如 单片机晶振是干什么的 、单片机是怎么实现IO口的 、单片机模式寄存器 、为什么电路要这么画,电阻要用330 Ω 等内容我直接将其跳过了,因为需要额外解释很多事情,这包括数电、模电、CPU运行逻辑之类的相关知识),这主要是因为我要用较为白话、通俗的方式让每个人都学会,同时也尽量规避掉这些比较枯燥且无法让你实操的内容。但这并不意味着这些东西你就可以放下,如果你学有余力,我建议你自己好好摸索摸索这些知识。要记住,我的课程设计并不是先让你知道走路是什么,然后再去走路。是先让你走起来,然后自己去想为什么要这么走。 至于怎么走才算好,这个交给完美主义者去做。 路行至此,我们的教学从 S2_3 才能说是正式开始,所以也希望你们能做好准备。
那么废话不提了,本文需要你至少跟着文章画一遍电路,然后跟着文章自己写一遍代码,这也是今日的作业。
按键交互
在上一章我们让你用单片机驱动两颗发光二极管,这对应着IO控制着输出,但如果你留意过身边的家电,实际上都是人操作家电运行,而不是家电通了电就自动运行。所以我们先介绍IO口的输入。
首先我们画出所需要的电路 
我们可以清楚的看到外设总共有两部分组成,其一是左侧的按钮电路,右侧是led灯电路。led灯电路你已经分析过了,我们现在来看按键的电路。这个按键相当于一个开关,当按下时导通,没有按下时则为关闭,我需要你自己能看懂按键没有按下时P1.0处电压为高电平,按下后变成低电平,这个是作业的一部分你需要解释原因。
之后我们在keil中编写代码 :
如果你复制进入后的注释是乱码,请将你的keil设置为utf8编码,而不是gbk
#include <reg51.h>
// sbit 用于标定单个io,方便记认
sbit led = P0^0;
sbit key = P1^0;
void main(){
// 初始赋值
key = 1; //key默认接受的是高电平,所以我们让key保持在1,当检测到key=0时就说明按键被按下
led = 0; //这样我们只需要改变 led的值就能切换灯的开关了
while(1){
//程序陷入while1死循环 一直检测执行while里的代码
if(key == 0) {
//当检测到按键按下
led = ~led; // 反转led
key = 1;
}
}
}
当你将代码烧录到你的单片机中,你就会发现当你鼠标点击按钮时,led灯就会发生点亮和熄灭的交换,如果你点的足够多你就会发现。好像其实按键对于灯的控制并不会按照预想的样子,按一下就切换,反而会有时候闪烁、有时候可以运行。我当然可以告诉你这是什么原因,但我希望你能跟我写一个 没什么用的函数 。并把它在 if(key == 0)当中的 key = 1; 之后调用
void nothing(){
unsigned int i,j = 0;
for(i=0;i<200;i++)
for(j=0;j<200;j++);
}
我们现在再次烧录程序后发现按钮能够如我们所料的正常控制了,当按下一次按键之后,led灯会切换一次。如果我们一直按住按键LED灯会有规律的闪烁。这说明如果我们让 key一直等于0,他就会反复的执行翻转led的命令。那么为什么仅仅一个好像没什么用的函数就能起到这个作用呢?
这就是嵌入式与传统编程不同的一点,它不但需要你有一个良好的软件编程能力,同时需要你对硬件电路有一定的判断。这个问题的原因你可以简单看一看 文章 进行理解,无论是单片机还是FPGA,这都是最常见的问题。
而 nothing() 函数让cpu进行了 200 * 200 次的空任务,他的作用我们简单询问一下ai就知道了 
也就是说我们此先没有考虑到按键的抖动,而CPU的运行频率为12Mhz,也就是说这颗芯片运行每一条代码只需要1us(0.000001s)左右,由于抖动也会让程序认为key的值在变化,所以你会发现 “led灯不听按键的话了”。而我们现在在接收到按键变化的状态后会让他等待80ms跳过抖动区域,然后再从新开始新的循环,所以此时按键就可以很好的控制led灯了。
而当我们一直按住按钮时,他会一直在while循环的过程中一直进入到if判断为真的语句中,所以他会大概以80ms为周期进行闪烁,这就是为什么当我们按住按钮时,灯泡会反复闪烁了。
试一试:如果你只是复制代码,那么就违背学习的初衷了,现在我希望你破坏这个代码。把if代码块内的 key = 1; 删掉编译再运行程序,看看哪里出了问题,是什么原因导致的。
流水灯
也就是说,我们没什么用的nothing其实就是让你的单片机干80ms左右的"没用的事",但没用的事也可以很炫酷。我们来将刚才的电路小小改造一下。

然后运行以下代码
#include <reg51.h>
#include <intrins.h>
// sbit 用于标定单个io,方便记号
sbit key = P1^0;
unsigned char state = 0xf8;
void nothing(){
unsigned int i,j = 0;
for(i=0;i<200;i++)
for(j=0;j<200;j++);
}
void main(){
P0 = state; //提供初始值
while(1){
//程序陷入while死循环 一直检测执行while里的代码
state = _crol_(state, 1); //循环移位
P0 = state;
nothing();
}
}
现在我希望你自己把这个程序读懂,把每一行都在做什么搞清楚,然后试着搞一个不同于这个程序的跑马灯。
作业
- 电路同流水灯电路,编写一个程序 可以实现当按键按下流水灯开始,按键再次按下流水灯熄灭(重复两次)。录制视频并发送到实验室邮箱(标题 : <姓名> - 流水灯作业)