从这里开始我们需要来看原理图和写代码了哦。
新手会比较懵(我目前也是新手,我确实很懵),所以我会用两个单片机对比着学习,一个是我自己的板,一个是B站up主@江协科技 的板。
三、LED模块
LED与单片机核心板是直接连接的,所以写在核心板上的代码才能控制到LED。
stc89C52:单片机的21~28连接着LED的D1~D8灯。
电阻是1kΩ,用来减少电流保护电路不那么容易烧坏。
stc89c52rc:单片机的21~28连接着LED的D1~D8灯。
电阻是470Ω,用来减少电流保护电路不那么容易烧坏。(读数方法,不想说太多抽象理论,直接以这个为例子说明:471,最后一个数字1表示10的1次幂,剩下的数字直接乘,即47×10¹Ω。如果是473就是47×10³Ω)
代码首先控制的是单片机,然后单片机再控制各种器件。要控制LED模组,实际上控制的是单片机的P2.0~P2.7。
1.点亮一个LED
从物理上看,灯泡发光是因为灯泡两端有电势差,驱动电子运动形成电流,电流使了灯泡发光(这里解释得不够严谨具体,主要是高考完我物理已经忘得差不多了,等我有时间再学清楚再来解释)
由原理图看出,LED的一端由电源正极(5V,理解为一种规范吧,我理解是单片机都用5V和0V表示正负极)控制,我们的单片机只能控制另一端为5V或0V。
二进制里面一般1代表有/真,0代表无/假。这里”有“只有一种情况就是5V,所以1代表输入5V,0代表输入0V。
想要灯泡发光就要有电势差,一段是电源正极5V,另一端之只能是0V,即1代表灭灯,0代表亮灯。不过要用十六进制表示,理论不好解释,直接给例子:
#include <REGX52.H>
int main()
{
P2=0xFE;//1111 1110
}
这里解释一下,二进制数字的顺序对应的LED编号是从右往左算的,即上面代码最右边的LED为0发光,亮的是D1灯,即第一个灯D1是最右边的一个数字。但是实际单片机开发板上的LED排列没有固定是从左往右还是从右到左,上面的代码只能决定亮的是D1灯,但D1灯再开发板上的实物可能是第一个灯也可能是第八个灯。
#include <REGX52.H>
int main()
{
P2=0xFE;//1111 1110
while(1)
{}
}
这段代码和上面的代码基本一样,唯一的区别是上面的代码是不断地开始结束开始结束;而下面的代码开始后进入了死循环,除非手动关机否则不会自主结束。
2.延时:即代码运行的时间长度
为什么要用到延时呢?
我们要实现灯泡闪烁,可进行的操作是“先执行亮的代码,再执行暗的代码,两行代码循环运行”。这是正常的思路,简单的思路,正确的思路,唯一的不足是没有考虑到现实世界物理世界的硬件缺陷。这款单片机的频率是12MHz,它一次亮暗由于速度太快无法被人眼察觉,再循环下次人依旧无法察觉。
因此我们需要延时,这名字起得不好,不顾名思义,它并不延迟时间,而是持续时间(强行解释的话就是延迟结束的时刻,太勉强了,咱实干家不玩文字游戏)。
延时代码可以直接用STC-ISP生成,注意下面圈圈起来的地方。想要代码持续多长时间就在“定时长度”里写数字。
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
int main()
{
while(1)
{
P2=0xFE;
Delay500ms();
P2=0xFF;
Delay500ms();
}
}
注意这里新加了一个头文件,主要应对的是延时代码里的_nop_函数。
利用亮与暗的延时,可以实现灯泡闪烁;要实现灯泡轮流亮起(流水灯)也是同样的道理。
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
int main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay500ms();
P2=0xFD;//1111 1101
Delay500ms();
P2=0xFB;//1111 1011
Delay500ms();
P2=0xF7;//1111 0111
Delay500ms();
P2=0xEF;//1110 1111
Delay500ms();
P2=0xDF;//1101 1111
Delay500ms();
P2=0xBF;//1011 1111
Delay500ms();
P2=0x7F;//0111 1111
Delay500ms();
}
}
这里有个弊端,就是每次延时都需要靠软件生成,比较麻烦。如何改进呢?我们做一个考虑,就是让一个1ms的延时循环执行n次就得到了nms的延时。
#include <REGX52.H>
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
int main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay1ms(1000);
P2=0xFD;//1111 1101
Delay1ms(1000);
P2=0xFB;//1111 1011
Delay1ms(100);
P2=0xF7;//1111 0111
Delay1ms(100);
P2=0xEF;//1110 1111
Delay1ms(100);
P2=0xDF;//1101 1111
Delay1ms(100);
P2=0xBF;//1011 1111
Delay1ms(100);
P2=0x7F;//0111 1111
Delay1ms(100);
}
}
这里循环条件是xms,每执行一次xms自减1,直到为0时结束循环。