得而不惜就该死。
--小泽
继续傻冒开始,这次的傻冒之旅是关于嵌入式的51单片机开发,这个系列只讲程序开发逻辑,如需初始环境安装配置,建议移步B站江协科技大佬,本系列也是对大佬所讲内容的复刻,同时添加一些自己的学习感受,权当自己的复习笔记了。废话不多,开始干!
一、点亮第一个LED
1、创建工程
1.1 Project->New

1.2 创建51Project文件夹,用于存放之后的项目文件
(此操作便于日后项目管理)



1.3 选择单片机型号:AT89C52



1.4 创建第一个C语言项目文件


简单初始程序
cpp
#include <REGX52.H>
void main(){
return;
}

快捷插入头文件

1.5 点亮第一个LED灯
那么我们该如何进行点亮,这里面的底层逻辑涉及到什么呢?首先看一看开发板的原理图。
这张图涉及到很多口,我们此时只关注右下角的21-28(p20-p27),这是用于连接LED的接口

在来看看LED灯的接口,LED的左侧接口与上述MCU的右下角一一对应,但是发现LED的右侧统一接上VCC电源正极,并且我们知道对于任何灯来说,需要在灯的两端接上正负,才能使其点亮。由于右侧恒为正,所以我们只需要控制p20-p27的正负就能控制这八个灯的点亮状态,而p20到p27的正负可以使用代码控制,0为负,1为正。

由于我们的目标是点亮一个LED灯,所以只需要将p20-p27任意一个设置为0即可,我们选择点亮p20处LED
修改后的代码
cpp
#include <REGX52.H>
void main(){
P2 = 0xFE; //1111 1110
//使用十六进制 标识:0x
return;
}
1.6 运行生成
对keil5的一些简单配置
1.6.1 此设置能在build编译后生成HEX文件,用于后续板子测试

1.6.2 此设置编码格式,UTF-8能够兼容中文字体

1.6.2 控制设置代码字体大小

开始编译build

2、操作
2.1 选择板子类型和串口
对于串口,插上板子后会自动检测

2.2 打开程序文件,选中刚刚生成的HEX文件

2.3 下载源程序,查看结果

二、LED闪烁
1、创建工程
步骤和一同理,不再赘述,说一个区别,在51Project文件夹中创建2-2 LED闪烁,保存即可,其余操作均一致。
选择单片机型号:AT89C52

1.1 初始工程模样

1.2 编程
根据我们实验一的描述, LED为正负则亮,0 1分别表示正负,所以控制LED闪烁则需要控制0 1交替变换,代码如下
cpp
#include <REGX52.H>
void main(){
while(1){
P2 = 0xFE;//p20Ϊ0ʱ ÁÁ
P2 = 0xFF;//p20Ϊ1ʱ °µ
}
return;
}
但是按照此逻辑去下载程序,我们观察到单片机板子的p20恒亮,这是因为单片机切换速度太块,导致肉眼就看不出变化所以我们借助stc-isp.exe去生成停顿函数,控制切换速度。
设置如下
系统频率:12MHz
定时长度:500毫秒
8051指令集:STC-Y1

1.3 编译代码
修改后代码:
cpp
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
//_nop_()函数在INTRINS.H头文件中
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
while(1){
P2 = 0xFE;//p20Ϊ0ʱ ÁÁ
Delay500ms();
P2 = 0xFF;//p20Ϊ1ʱ °µ
Delay500ms();
}
return;
}
在编译前我们设置输出文件HEX

开始编译

2、操作
2.1单片机类型: STC89C52RC/LE52RC
2.2串口号:插入板子后自动识别
2.3打开源文件程序
2.4下载/编程

2.5查看结果
三、LED流水线
1、创建工程
创建工程同上,不在赘述。
选择单片机型号:AT89C52。
1.1 工程结构

1.2 代码如下:
cpp
#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);
}
void 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();
}
return;
}
1.3勾选output HEX输出

1.4编译

2、操作
同一和二中的操作。
2.1单片机类型: STC89C52RC/LE52RC
2.2串口号:插入板子后自动识别
2.3打开源文件程序
2.4下载/编程

3、进阶
修改Delay500ms()函数,变成传参函数,传入参数标识停顿的毫秒数。
修改的方向:由于我们的单片机为12MHz,12.000MHz 的时钟频率下,一个机器周期是 1 微秒(因为 1 / 12MHz * 12 = 1μs),又因为500毫秒为500,000微秒,所以我们让循环接近500,000即可。
3.1函数解释
(1)函数定义:void DelayMs(unsigned int ms)
定义了一个名为 DelayMs
的函数,它接收一个无符号整型参数 ms
,代表要延时的毫秒数,函数无返回值。
(2)外层循环:for (i = 0; i < ms; i++)
这个循环会执行 ms
次,每次循环会产生大约 1 毫秒的延时。
(3)内层嵌套循环:
for (j = 0; j < 123; j++)
:外层循环,循环 123 次。
for (k = 0; k < 4; k++);
:内层循环,循环 4 次。
这两层嵌套循环的组合能让 CPU 执行一定数量的空操作,从而实现大约 1 毫秒的延时。
(4)空操作指令:_nop_();
执行一个空操作,占用一个机器周期,在这可能用于微调延时时间。
cpp
#include <intrins.h>
// 定义一个函数用于实现毫秒级延时
void DelayMs(unsigned int ms) {
unsigned int i;
unsigned char j, k;
// 外层循环,循环次数为传入的毫秒数
for (i = 0; i < ms; i++) {
// 空操作,可能用于微调延时
_nop_();
// 以下循环用于实现约 1 毫秒的延时
for (j = 0; j < 123; j++) {
for (k = 0; k < 4; k++);
}
}
}
至此,初步结束