前言
通过前一篇文章的分享,我们已经成功搭建好了一个普适性的单片机框架,而这篇文章我们将开始编写第一个实验:LED闪烁实验。
代码的编写均在VSCode编辑器中进行;编写代码的文件为main.c文件和main.h文件!
步骤一
首先需要先在单片机上任意找一个IO口,如:P2_0
,
接着在main.h文件中写入代码:
#define P_led1 P2_0
#define F_led1On() P_led1 = 0
#define F_led1Off() P_led1 = 1
然后在main.c文件的主函数中写入:
#define __main_c
#include "includeAll.h"
//============================================
void main() {
F_turnOnWDT(); // 看门狗寄存器
InitSys();
while (1) {
F_led1On();
F_led1Off();
}
}
//============================================
void InitSys() {
// system clock
CLKCON = 0x03; // Clock div 1
STPPCK = 0;
STPFCK = 0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SELFCK = 1;
// I/O init
P2MOD = 0xa;
}
//============================================
void DisplayProcess() {}
//============================================
void UserSettingProcess() {}
//============================================
void TaskProcess() {}
//============================================
void TimeProcess() {}
//============================================
然后,在Keil C51编译器中进行debug测试。看看该单片机是当给一个低电压(即“P_led1 = 0”)时,P2_0引脚上的LED灯亮还是当给一个高电压(即“P_led1 = 1”)时,P2_0引脚上的LED灯亮,即IO口是共阳极还是共阴极。
测试结果是:当给一个低电压(即“P_led1 = 0”)时,P2_0引脚上的LED灯亮,当给一个高电压(即“P_led1 = 1”)时,P2_0引脚上的LED灯灭。
步骤二:编写逻辑代码
- main.h
#ifndef __main_h
#define __main_h
#define P_led1 P2_0
#define P_led2 P2_1
#define F_led1On() P_led1 = 0
#define F_led1Off() P_led1 = 1
#define F_led2On() P_led2 = 0
#define F_led2Off() P_led2 = 1
void InitSys();
void DisplayProcess();
void UserSettingProcess();
void TimeProcess(int time);
void TaskProcess();
#endif
- main.c
#define __main_c
#include "includeAll.h"
//============================================
void main() {
F_turnOnWDT(); // 看门狗寄存器
InitSys();
while (1) {
F_led1On();
TimeProcess(2000);
F_led1Off();
TimeProcess(2000);
}
}
//============================================
void InitSys() {
// system clock
CLKCON = 0x03; // Clock div 1
STPPCK = 0;
STPFCK = 0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SELFCK = 1;
// I/O init
P2MOD = 0xa;
}
//============================================
void DisplayProcess() {}
//============================================
void UserSettingProcess() {}
//============================================
void TaskProcess() {}
//============================================
void TimeProcess(int time) {
int i, j;
for (i = 0; i < time; i++)
for (j = 0; j < 1000; j++)
CLRWDT = 1;
}
细节解说
- main.h文件中属于框架的部分:
#ifndef __main_h
#define __main_h
#endif
- main.h文件中六个#define的声明时为了更明确的表示IO口“P2_0”及其 0 和 1 的状态,关于名称的命名规则可以参考我的上一篇文章中第8点:取名字规则,这里不再赘述:
#define P_led1 P2_0
#define P_led2 P2_1
#define F_led1On() P_led1 = 0
#define F_led1Off() P_led1 = 1
#define F_led2On() P_led2 = 0
#define F_led2Off() P_led2 = 1
- main.c文件中属于框架的部分:
#define __main_c
#include "includeAll.h"
//============================================
void main() {
// do something
while (1) {}
}
//============================================
void InitSys() {}
//============================================
void DisplayProcess() {}
//============================================
void UserSettingProcess() {}
//============================================
void TaskProcess() {}
//============================================
void TimeProcess() {}
- main.c文件中:
F_turnOnWDT();
会被编译为:CFGWL = (CFGWL & 0x3f) | 0xC0
“CFGWL”是“CFGW”寄存器的低八位。当其被赋值(CFGWL & 0x3f) | 0xC0
,即“11?? ???”(?表示可能为1也可能为0)时,表示“看门狗定时器复位始终启用”,而这就有可能会发生看门狗定时器溢出的情况,因此需要在“TimeProcess()”当中加上CLRWDT = 1;
,即设置以清除看门狗定时器。 - main.c文件中,
InitSys();
是初始化函数,其中CLKCON = 0x03;
用于设置系统时钟的初始化状态及系统时钟是快/慢时钟除以1;STPPCK = 0;
当将其设置为1时将停止UART/Timer0/Timer1/Timer2/ADC在空闲模式的时钟;STPFCK = 0;
当将其设置为1时将停止快时钟以节省慢钟/空闲;SELFCK = 1;
将系统时钟源选择设置为快时钟;_nop_();
是指包括在库函数INTRINS.H
中的表示空循环一个机器指令的时间。关于系统时钟的更多信息如下图所示:
- main.c文件中,InitSys()函数中的
P2MOD = 0xa;
将单片机上P2MOD寄存器中的特殊功能位P2MOD1和P2MOD0置为“10”,即模式2:CMOS推挽输出:
- main.c文件中的
void TimeProcess() {}
同时编写一个嵌套的for循环来实现延时。