目录
一、点亮一个led
要点亮一个led,首先我们要学会看单片机的原理图,这里我就以普中HC6800 ES V2.0为例。
由上图可知,P2口控制了前面8个led,最左边接VCC,也就是高电平1,所以要想点亮led的话,P2口这端只需给低电平0,并且P2口是一个8位寄存器,那么我们就会想到让P2=0xFE(1111 1110),因为代码太短,后面程序运行不可控,我们再给它加上一个死循环,如果循环里啥也不执行,也可以直接以while(1);程序代码如下:
#include <regex51.h>
void main()
{
P2=0xFE; //1111 1110
while(1) //while(1);
{
}
}
第一步:点击编译小图标。
第二步:点击运行小图标前,特别注意图1.1-1这个标志,我们点进去,点击Output,看一下图1.1-2中Create HEX File前面有没有打“√”,如果没有,记得选上,不然在STC-ISP中就找不到对应的文件了(.hex)。
图1.1-1
图1.1-2
第三步:打开STC-ISP,首先,选择芯片型号,这在芯片上有注释,选择对应型号即可。其次,选择扫描串口,一般情况是默认的,也是最长的那个,如果串口不匹配,我们要去打开计算机管理-设备管理器-端口查看,如果左下角有一个黄色的三角形图标,就是驱动程序没有安装,安装好驱动程序就能正常显示端口了。最后,就是打开程序文件,找到我们保存keil文件的路径,点击Objects 找到以.hex为后缀的文件打开。
图1.1-3
第四步:点击下载/编程按钮,重启单片机,右下角文字框里会显示操作成功的字样,观察单片机是否与我们预期的效果一样。
二、led闪烁
首先,要让一个led闪烁,也就是让它在亮灭之间循环,由于led闪烁频率过快,我们要加一个延时函数,方便我们观察,就以延时500ms为例。
#include <REGX52.H>
#include <INTRINS.H> //含_nop_的头文件
void Delay500ms(void) //@12.000MHz,由STC-ISP生成的延时函数,延时500ms
{
unsigned char data i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0xFE;
Delay500ms();
P2=0xFF;
Delay500ms();
}
}
小技巧tips1:
STP-ISP生成延时函数:首先,找到软件延时计算器。其次,因为普中HC6800 ES V2.0晶振是12MH,所以系统频率选12MH。然后,选择定时长度,这里选择500ms。接下来,点击8051指令集,它左边会相应出现适用型号的字样,根据单片机主芯片型号进行选择,这里选择STC-Y1。最后,点击生成C代码,复制代码两步就可以生成一个延时函数了。
图2.1-1
三、led流水灯
第一种方法:
思路:要让led流动,我们就要让8个led依次置低电平0。
C语言基础知识:
图3.1-1
将P2口8位寄存器,亮取0,灭取1,每两个灯之间别忘加延时,不然灯闪频率太快,难以观察现象。代码如下:
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms(void)
{
unsigned char data 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();
}
}
小技巧tips2:
STP-ISP生成延时任意毫秒的延时函数,先生成1毫秒的延时函数如下:
void Delay1ms(void) //@12.000MHz
{
unsigned char data i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
将1毫秒延时放入一个循环里,任意毫秒每次递减1。
void Delay(xms) //@12.000MHz
{
unsigned char data i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
第二种方法:
思路:P2=0x01,将0x01依次右移并取反(这里听不懂没关系,下面会介绍),这里别忘了加延时哦!再设置一个整型变量count计数,0x01每移动一位,count就加一,从0开始,加到7后,然后又要返回0,不然灯就走完一圈就不亮了。
C语言基础知识:
图3.1-2
图3.1-3
所以,如果将P2=0x01,移位取反就会有:
图3.1-5
然后,当count=8时,左移加取反,就得到全为1的高电平,这也是为什么流水灯只走一圈就灭的原因。
为了解决这个问题,就要设计一个判断语句,来判断count值有没有等于8,当led亮到最后一个灯时,就到临界点了,当coun=8时,应将count值赋为0,将上面分析的代码放在一个死循环,就能达到流水的效果,具体代码如下:
#include <REGX52.H>
void Delay()
{
unsigned char i, j, k;
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
unsigned int count=0;
while(1)
{
if(count>=8) //count计数达到8,进行归0操作
count=0;
else
{
P2=~(0x01<<count); //0x01依次右移并进行取反
Delay(); //延时500ms
count++; //计数加1
}
}
}
四、独立按键控制led亮灭
(1)一个按键控制亮灭
首先,先来看一下独立按键的原理图。
图4.1-1
由上图可知按键按下与GND接通,会产生一个低电平0信号,K1按键对应P3.1,当按键按下(P3.1=0),led要亮(这里以第一个led为例),只需将0赋给它,即:P2=0xFE;当按键松开(P3.1=1),灯灭,即:P2=0xFF。为了程序的稳定性,将上面的代码依旧放在一个死循环里。具体代码如下:
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1==0) //检测k1按键有没有按下
P2=0xFE;
else
P2=0xFF;
}
}
(2)通过按键控制灯的状态
因为按键的金属弹片有弹性,所以在按下和松开之后都有好多次振荡(大约5~10ms),为避免这种抖动对效果的影响,可以加延时函数。条件判断:当按键按下,延时20ms,用while语句检测是否松手,while里什么也不做,可以直接在其后加“;”,延时20ms,位寄存器P2_0按位取反,具体代码如下:
#include <REGX52.H>
void Delay(xms)
{
unsigned char data i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
while(1)
{
if(P3_1==0)
{
Delay(20); //按键按下消抖
while (P3_1==0); //检测是否松手
Delay(20); //按键松开消抖
P2_0=~P2_0;
}
}
}
(3)按键控制led显示二进制
思路:如果让一个16进制的数从0x00递增到0xFF确实实现了1的二进制递增,但led是接低电平0才点亮,所以我们取反一下就能实现这个效果啦,如下图所示:
如上一个编程一样,先设计一个初值为0的整型变量count,条件判断:是否按下按键,延时,检测是否松手,延时,count自增,寄存器P2=~count,具体代码如下:
#include <REGX52.H>
void Delay(xms)
{
unsigned char data i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
unsigned int count=0; //初始化
while(1)
{
if(P3_1==0)
{
Delay(20);
while(P3_1==0);
Delay(20);
count++;
P2=~count; //取反
}
}
}
在视频的弹幕中也有网友说直接让P2--,确实也是可以的,这样我们还省去定义一个变量呢。
(4)按键控制led移位
在流水灯的第二种方法那里,我们是让0x01移位来实现led依次点亮,同样在这里,我们把按键想成是一个脉冲,按一下就移动一位,所以定义一个整型变量count来记数,初始值赋为0。在左移时,count自增,我们要注意当count值为8的情况,归零处理;在右移时,count自减,我们要注意当count值为0的情况,将count=7处理。具体代码如下:
#include <REGX52.H>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
unsigned int count=0;
P2=0xFE; //让第一个灯亮
Delay(20);
while(1)
{
if(P3_1==0) //判断是否是K1按键按下,进行左移操作
{
Delay(20);
while(P3_1==0);
Delay(20);
count++;
if(count>=8)
count=0;
P2=~(0x01<<count);
}
if(P3_0==0) //判断是否是K2按键按下,进行右移操作
{
Delay(20);
while(P3_0==0);
Delay(20);
if(count==0)
count=7;
else
count--;
P2=~(0x01<<count);
}
}
}