控制/MCU
进制实际是一个非常简单易懂的概念,对于初学者来说也很容易上手。我们接触最多的就是十进制了,它的特点为逢十进一,包含0,1,2,3,4,5,6,7,8,9共十个元素。在生活中我们用到的基本都是十进制了,所以大家对它已经非常熟悉并能应用自如,但是在计算机(包括单片机)世界里,所有都是以二进制为基础的。二进制的特点为逢二进一,包含0,1共两个元素。计算机中的数据都是以二进制存储的,这就是我们所说的0,1世界。通常我们讲的32位或64位操作系统这里的位指的就是二进制位数。因为我们实际多用十进制,那么我们在和计算机系统沟通过程中,十进制与二进制之间的转换就变得很重要了。进制之间的转换如下表所示。
二进制转换十进制公式如下:
其中,n表示二进制的位数。
下面我们举个例子来更加直观的说明这个公式:
例如:1101,这是一个4位的二进制数,计算如下,
大家可以利用这个公式计算的结果和上表进行一一对照。
十六进制也是我们常用的进制,它的特点为逢十六进一,包括0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共十六个元素。实际上十六进制是二进制的一种特殊形式,十六进制的1位等价于二进制的4位,在C语言编程中我们常用十六进制来表示二进制数。在实际应用中我们常常该数字之前加一个前缀来表示他的进制:“0b”表示二进制,“0x”表示十六进制。下面我们举例说明:
0b10010010 = 0x92
上面一个八位的二进制数转换为一个两位的十六进制数。二进制的前4位等于十六进制的第1位:
0b1001 = 0x9
二进制数的后4位等于十六进制的第2位:
0b0010 = 0x2
在计算机中,我们通常所说的二进制的1位也叫1bit,8位表示1个字节,也叫1Byte。根据二进制与十六进制的关系,一个2位的十六进制数则可表示1个字节。在运用的过程中牢记0~15的十进制与二进制、十六进制之间的转换关系对于程序的编写有很大的好处。
怎么让LED小灯闪烁?我们最先想到的办法当然是先让LED小灯点亮,延时一段时间,熄灭LED小灯,再延时一段时间,一直循环上面的步骤就能实现LED小灯的闪烁了。根据第3章的知识我们知道点亮LED的语句为“led0 = 0;”,熄灭LED的语句为“led0 = 1;”。按照第3章介绍我们重新建立一个LED小灯闪烁的工程。程序代码设计如下:
#include< reg52.h > //寄存器声明头文件
sbit led0 = P1^0; // 位声明,将P1.0管脚声明为led0
void main() //程序主函数入口,每个C语言程序有且只有一个
{
int i; //变量声明
while(1) //循环
{
led0 = 0; //赋值管脚P1.0为低电平,点亮LED小灯
for(i=0;i< 5000;i++);//延时一段时间
led0 = 1;//熄灭LED小灯
for(i=0;i< 5000;i++);//再延时一段时间
}
}
在我们的开发板上设计了8个依次排列的LED小灯,让小灯依次点亮和熄灭实现跑马灯的效果是我们这一节的主要内容。
8个LED小灯的硬件电路设计原理图如下图所示:
如上图所示,8个LED小灯LED0-LED7的正极和电源VCC之间均串联了一个1K的限流电阻。LED7-LED0的负极与74HC573锁存器的Q0-Q7一一相连接。锁存器74HC573的功能我们这里不详细介绍,把它的D0-D7与Q0-Q7之间看作是电气上一一联通的。由图所示,锁存器的D0-D7和单片机的P1.7-P1.0是一一连接的。因此,LED小灯LED7-LED0的负极与单片机的P1.7~P1.0管脚一一相连,在单片机程序中通过控制P1.7-P1.0管脚的高低电平便可控制8个LED小灯的亮灭。
该实验要实现的功能为:首先点亮LED0,然后延迟一段时间,熄灭LED0,熄灭LED0点亮LED1,延迟一段时间,熄灭LED1点亮LED2,延迟一段时间,一直到熄灭LED6点亮LED7,依照上面的步骤一直循环下去,便实现了一个简单的跑马灯的效果。
前面我们试验中都是只对P1.0这个管脚进行赋值,来控制LED小灯led0的亮灭。实际在编写程序的过程中我们可以对P1寄存器进行直接赋值来同时控制8个LED小灯。
如上表所示,P1寄存器是一个8位的寄存器,最高位到最低位依次对应的P1.7管脚到P1.0管脚。点亮某个LED小灯的二进制,十六进制赋值如上表所示。例如P1 = 0xFE;表示点亮led0,P1=0x7F;则表示点亮led7。在软件代码设计时,我们想到的第一个方法为依次点亮小灯并延时,代码如下所示。
#include< reg52.h > //加载头文件
int i;
void main()//主函数入口
{
P1 = 0xFE; //点亮LED0
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xFD; //点亮LED1
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xFB; //点亮LED2
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xF7; //点亮LED3
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xEF; //点亮LED4
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xDF; //点亮LED5
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0xBF; //点亮LED6
for(i=0;i< 5000;i++);//延时一段时间
P1 = 0x7F; //点亮LED7
for(i=0;i< 5000;i++);//延时一段时间
}
我们对代码进行一下小的改进,这个方法这里称之为“左移取反”法,这个方法在很多的应用中都能用到,非常实用。代码如下图所示。
#include< reg52.h > //加载头文件
int i;
int flag=0;
void main()//主函数入口
{
P0 = 0xff;
while(1)
{
P1 = ~(0x01<
我们对上面代码进行分析,flag是一个从0到7依次循环的数,P1等于1向左移flag位再取反。当flag等于2时,0b0000,0001左移2位等于0b0000,0100,再取反等于0b1111,1011=0xFB,并赋值给P1,点亮了小灯led2。同理,当flag等于6时,0b0000,0001左移6位等于0b0100,0000,再取反等于0b1011,1111=0xBF并赋值给P1,点亮了小灯led6。flag为其他值时,大家可以进行一一分析。
将程序通过STC-isp软件下载到单片机,观察8个LED小灯效果与设想的效果是否一致?至此,本章的内容讲解完毕,内容包括进制转换的基础知识、LED小灯闪速程序以及跑马灯的两种程序。大家在动手操作的过程中多多下载到单片机中观察现象,加深印象。
全部0条评论
快来发表一下你的评论吧 !