51单片机-1

目录

一、点亮一个led

二、led闪烁

三、led流水灯

四、独立按键控制led亮灭

(1)一个按键控制亮灭

(2)通过按键控制灯的状态

(3)按键控制led显示二进制

(4)按键控制led移位

一、点亮一个led

        要点亮一个led,首先我们要学会看单片机的原理图,这里我就以普中HC6800 ES V2.0为例。

478fd27b91524f8baaf3e0096080a936.png

        由上图可知,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)。

ad42db893fb64e1c968a68bc8d89c965.png

图1.1-1

556d8935d9e04bfbb624605b7d5aede1.png

图1.1-2

 第三步:打开STC-ISP,首先,选择芯片型号,这在芯片上有注释,选择对应型号即可。其次,选择扫描串口,一般情况是默认的,也是最长的那个,如果串口不匹配,我们要去打开计算机管理-设备管理器-端口查看,如果左下角有一个黄色的三角形图标,就是驱动程序没有安装,安装好驱动程序就能正常显示端口了。最后,就是打开程序文件,找到我们保存keil文件的路径,点击Objects 找到以.hex为后缀的文件打开。

3e70fbf624884338b43660ffcbae8b9d.png

图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代码,复制代码两步就可以生成一个延时函数了。

162fd8fc026a4b0e8bb791f167270772.png

图2.1-1

三、led流水灯

第一种方法:

思路:要让led流动,我们就要让8个led依次置低电平0。

C语言基础知识:

d3516a00b6704c2b962319085e90574f.jpeg

图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语言基础知识:62c2d230a13343a191c66359dd4314e8.png

图3.1-2

 ea5bab7af15e4620ae46e980f1b4f74b.png

b259d58511594cada47d94ff36630615.png

 图3.1-3

所以,如果将P2=0x01,移位取反就会有:

b9d0503257e4456db5eb8c8b4c6b7640.png

图3.1-5

然后,当count=8时,左移加取反,就得到全为1的高电平,这也是为什么流水灯只走一圈就灭的原因。

12206cff601a4dc4bea16858e64a710d.png

         为了解决这个问题,就要设计一个判断语句,来判断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)一个按键控制亮灭

        首先,先来看一下独立按键的原理图。

d8dd74ff30f2439fae85befce2df5828.png

图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才点亮,所以我们取反一下就能实现这个效果啦,如下图所示:

f451011201b24768af0c305bbfb5efa8.png

 如上一个编程一样,先设计一个初值为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);
			
		}	
	}
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值