接下来的学习将主要转为使用keil编程,并使用proteus进行仿真,推荐有条件的同学可以购买一个板子进行实物的练习
发光二极管常用来指示系统工作状态,制作节日彩灯、广告牌匾等。大部分发光二极管工作电流1到5mA之间,其内阻为20到100Ω。电流越大,亮度也越高。为保证发光二极管正常工作,同时减少功耗,限流电阻选择十分重要,若供电电压为+5V,则限流电阻可选1~3kΩ。
前面文章讲到,P0口作通用I/O用,由于漏极开路,需外接上拉电阻。而P1~P3口内部有30kΩ左右上拉电阻。
发光二极管两个管脚分为阴极和阳极,哪个管脚接单片机便是个选择,两种接法是否相同?下图为两种接法,其中(a)为拉电流,(b)为灌电流:
当P0口某位为高电平时,可提供400µA的拉电流;当P0口某位为低电平(0.45V)时,可提供3.2mA的灌电流,而P1~P3口内有30kΩ左右上拉电阻,如高电平输出,则从P1、P2和P3口输出的拉电流Id仅几百µA,驱动能力较弱,亮度较差,见(a)。
如端口引脚为低电平,能使灌电流Id从单片机外部流入内部,则将大大增加流过的灌电流值,见(b)。AT89S51任一端口要想获得较大的驱动能力,要用低电平输出。如一定要高电平驱动,可在单片机与发光二极管间加驱动电路,如74LS04、74LS244等。
单灯练习
【例1】 利用AT89C51单片机点亮灯led,灯led接单片机P1.0引脚上,编写程序使led点亮。
#include
sbit led=P1^0;
void main()
{
led=0;
}
#include
void main()
{
P1=0xfe; //11111110
while(1); //使程序停留在这条指令上
}
流水灯练习
一组灯并且在控制系统的控制下按照设定的顺序和时间来发亮和熄灭。来形成一定的视觉效果,常安装于店面和招牌上。要想实现流水灯,必须要进行延时操作,编写延时程序或延时子函数程序,由本人之前的文章C51语言,for循环可以实现一段时间的空操作,我们就用for循环来编写一段延时程序。
void delay(void) //延时1ms 晶振12mhz
{
unsigned char a,b;
for(b=199;b>0;b--)
for(a=1;a>0;a--);
}
void delay() //延时1s 晶振11.0592mhz
{
unsigned char a,b;
for(a=1000;a>0;a--)
for(b=110;b>0;b--)
}
#define uint unsigned int //宏定义uint 为unsigned int
void delayms(uint xms) //可变的延时时长的子程序,单位1ms
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
由此可以看出,使用for循环编写延时程序时,需要不同的变量值来调试出一段延时时间,延时时间并不精准。较为精准的定时器延时将在后文讲到。
【例2】 制作流水灯,8个发光二极管LED0~LED7经限流电阻分别接至P1口的P1.0~P1.7引脚上,阳极共同接高电平。编写程序来控制发光二极管由上至下的反复循环流水点亮,每次点亮一个发光二极管,时间间隔1S。
#include
#define uint unsigned int //宏定义
void delayms(uint xms); //函数声明
void main()
{
while(1)//循环点亮
{
P1=0xfe; delayms(1000); //11111110
P1=0xfd; delayms(1000); //11111101
P1=0xfb; delayms(1000); //11111011
P1=0xf7; delayms(1000); //11110111
P1=0xef; delayms(1000); //11101111
P1=0xdf; delayms(1000); //11011111
P1=0xbf; delayms(1000); //10111111
P1=0x7f; delayms(1000); //01111111
}
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
#include
#define uint unsigned int
sbit led0=P1^0;
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
sbit led4=P1^4;
sbit led5=P1^5;
sbit led6=P1^6;
sbit led7=P1^7;
void delayms(uint xms);
void main()
{
while (1)
{
led0=0;led7=1;delayms(1000);
led1=0;led0=1;delayms(1000);
led2=0;led1=1;delayms(1000);
led3=0;led2=1;delayms(1000);
led4=0;led3=1;delayms(1000);
led5=0;led4=1;delayms(1000);
led6=0;led5=1;delayms(1000);
led7=0;led6=1;delayms(1000);
}
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
#include
#define uint unsigned int
#define uchar unsigned char
void delayms(uint xms); //函数声明
unsigned char table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //建立数组
void main()
{
uint k ;//定义局部变量k
while(1)
{
for(k=0;k<8;k++) //循环读数组中的数
{
P1=table[k];
delayms(1000);
}
}
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
#include
#include //包含移位函数_crol_( )的头文件
#define uint unsigned int
#define uchar unsigned char
void delayms(uint xms); //函数声明
void main( ) //主程序
{
P1=0xfe; //向P1口送出点亮数据
while(1)
{
P1=_crol_(P1,1) ; //函数_crol_(P1,1)把P1中的数据循环左移1位
delayms(1000);
}
}
void delayms(uint xms) //延时函数
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
#include
#define uint unsigned int
#define uchar unsigned char
void delayms(uint xms); //函数声明
void main( ) //主函数
{
uchar i,temp;
while (1)
{
temp=0x01; //左移初值赋给temp,从低位到高位点亮
for(i=0; i<8; i++)
{
P1=~temp; // temp中的数据取反后送P1口
delayms(1000); // 延时
temp=temp<<1; // temp 中数据左移一位
}
/*
temp=0x80; //赋右移初值给temp,从高位到低位点亮
for(i=0; i<8; i++)
{
P1=~temp; //temp中的数据取反后送P1口
delayms(1000); // 延时
temp=temp>>1; // temp 中数据右移一位
}
*/
}
}
void delayms(uint xms) //延时函数
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
交通灯练习
【例3】东西方向绿灯先亮27S后黄灯亮3S,期间南北方向红灯同时亮30S;然后南北方向绿灯先亮27S后黄灯亮3S,期间东西方向红灯同时亮30S;然后东西方向,如此反复。
#include
#define uint unsigned int
void delays(uint x);
void main()
{
while(1) //东西方向从上到下依次为黄绿红,南北方向从左到右依次为黄绿红
{
P1=0xb7;delays(27000);//南北红27,东西绿27;
P1=0xd7;delays(3000); //南北红3,东西黄3;
P1=0x7b;delays(27000);//南北绿27,东西红27;
P1=0x7d;delays(3000); //南北黄3,东西红3;
}
}
void delays(uint x)
{
uint i,j;
for(i=x;i>0;i--)
for(j=120;j>0;j--);
}