51单片机编程学习笔记——管脚输出
大纲
在《51单片机编程学习笔记——编译代码点亮LED》一文中,我们看到了如何通过编码控制LED的亮点。其核心代码是
sbit LED1=P2^0; //将P2.0管脚定义为LED1
sbit LED2=P2^1; //将P2.1管脚定义为LED2
LED1=0; //LED1端口设置为低电平
LED2=0; //LED2端口设置为低电平
在这段代码中,我们通过设置管脚为低电平来让LED两端产生电压差,从而点亮LED。此时我们就是将管脚作为输出端口。
为什么P2^0
可以代表P2.0管脚呢?
回顾我们在《51单片机编程学习笔记——LED原理图》中的介绍,LED的电路原理图如下。
VCC作为正极在LED的P端,N端则连着单片机的P20管脚。
我们再在原理图中查看单片机核心的原理图,可以找到P20管脚。
同时我们还发现P系列管脚每8个为一组:
- P00~P07
- P10~P17
- P20~P27
- P30~P37
这4组共28个管脚构成了51单片机核心控制外部器件的端口。
那代码是怎么控制这些端口的呢?我们回到代码上
#include <REG52.H>
sbit LED1=P2^1;
上面代码的第二行中的P2是在REG52.H
中定义的
#ifndef __REG52_H__
#define __REG52_H__
/* BYTE Registers */
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
sfr 关键字是用于定义特殊功能寄存器(Special Function Register,SFR)的关键字。使用 sfr 关键字后,紧跟着是要定义的特殊功能寄存器的名称,然后是等号和该寄存器的地址值。
这就意味着代码中P2表示的特殊功能寄存器,它的地址是0xA0。
P3和P2之间有16bit空间,其中前8bit对应于P20到P27管脚。
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;
sbit LED5=P2^4;
sbit LED6=P2^5;
sbit LED7=P2^6;
sbit LED8=P2^7;
sbit是用于定义可位寻址对象的关键字,主要用于访问可位寻址的特殊功能寄存器中的某位或可位寻址的内部 RAM 单元,方便对这些特定位进行单独操作。简单来说,sbit定义的是“位变量”。这就意味着给它赋值(不是定义),实际修改的是该位空间中的值,而不是该位的地址。
sbit LED1=P2^0; // LED1是位变量,其地址是P2^0
LED1=0; //给变量赋值,而不是修改变量的地址
当理解这个概念后,我们就可以很清晰了解控制管脚输出的代码设计。
比如下面代码,我们设计了一个跑马灯功能。
#include <REG52.H>
#include <intrins.h>
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay(unsigned int millisecond) {
unsigned int i = 0;
for (i = 0; i < millisecond; i++) {
Delay1ms();
}
}
void marquee() {
unsigned char i;
for(i=0;i<8;i++) {
P2=~(0x01<<i);
Delay(200);
}
}
void main() {
while(1) {
marquee();
}
}
0x01<<i
是按位位移1,这样可以构成0x00100000这样的值。然后我们按位取反,就会得到0x11011111。然后将该值赋给P2寄存器空间,这样就让8个LED灯中的某个点亮。