1、左右来回循环的流水灯的电路连接见图4-6,显示规律如图4-7。实现本任务要求,可以有多种软件实现方法。下面列出了3种,具体如下
- 数组的字节操作实现
#include <reg51.h>
#define uchar unsigned char
uchar tab[16 ]={ 0xfe , 0xfd , 0xfb , 0xf7 , 0xef , 0xdf , 0xbf , 0x7f ,0xbf ,0xdf , 0xef , 0xf7 , 0xfb , 0xfd, 0xfe,0xff};/*前8个数据为左移点亮数据,后8个为右移点亮数据*/
void delay(uchar k)
{ uchar i,j;
for(i = 0; i < k; i++);
for(j = 0; j < 110; j++);
}
void main( ) /*主函数*/
{ uchar i;
while (1)
{ for(i = 0; i < 15; i++);
{ P1=tab[i];
delay( );}}}
- 移位运算符实现
#include <reg51.h>
#define uchar unsigned char
void delay(uchar k)
{ uchar i,j;
for(i = 0; i < k; i++);
for(j = 0; j < 110; j++);
}
void main( ) /*主函数*/
{ uchar i,temp;
while (1)
{ temp=0x01; /*左移初值赋给temp*/
for(i= 0; i < 8; i++);
{P1=~temp; /* temp取反后送P1口*/
delay( );
temp=temp<<1; } /* temp 中数据左移一位,最右位用0填*/
temp=0x80; /*赋右移初值给temp*/
for(i=0; i < 8; i++);
{ P1=~temp; /* temp取反后送P1口 */
delay( );
temp=temp>>1; /* temp 中数据右移一位*/
}
}
}
- 用移位函数实现
#include <reg51.h>
#include <intrins.h> /*包含左、右移位函数的头文件*/
#define uchar unsigned char
void delay(uchar k)
{ uchar i,j;
for(i = 0; i < k; i++);
for(j = 0; j < 110; j++);
}
void main( ) /*主函数*/
{ uchar i,temp;
while (1)
{ temp=0xfe; /*初值为0x11111110*/
for(i=0; i< 7; i++);
{ P1=temp; /* temp 值送入P1口*/
delay( ); /*延时*/
temp=_crol_( temp,1) ; /*执行左移函数,temp 中的数据循环
左移1位*/
}
for(i=0; i<7; i++);
{ P1=temp; /* temp 值送入P1口*/
delay( ); /*延时*/
temp=_cror_( temp,1) ; /*执行右移函数,temp中的数据循环右
移1位*/
}
}
}
2、开关量检测指示器2,AT89S51单片机P1.0和P1.1引脚接有两只开关S0和S1,两只引脚上的高低电平共有4种组合,这4种组合分别点亮P2.0~P2.3引脚控制的4只LED:LED0~LED3 (高电平点亮),编程实现此功能
#include <reg51.h> /* 包含头文件reg51.h */
void main( ) /* 主函数main( )* /
{ char state;
While(1)
{ P1=0xff; /* P1口为输入* /
state=P1; /* 读入P1口的状态,送入a* /
state=state&0x03; /* 屏蔽P1口的高6位* /
switch ( state ) * 判断P1口的低2位的状态* /
{case 0: P2=0x01; break; /* P1.1、P1.0=00,点亮P2.0脚LED */
case 1: P2=0x02; break; /* P1.1、P1.0=01,点亮P2.1脚LED */
case 2: P2=0x04; break; /* P1.1、P1.0=10,点亮P2.2脚LED */
case 3: P2=0x08; /* P1.1、P1.0=11,点亮P2.3脚LED */
}}
3、时钟:8位Led 动态显示,共阳,无校准电子表
P0.0~7输出段码数据,P1.0~7输出位选信号*/
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar dis_buff[8]={0x00,0x00,0x0b,0x00,0x00,0x0b,0x00,0x00};//显示缓存区时高位低位、分高位低位、秒高位低位
uchar code position[8]={0x01,0x02,0x04,0x08,0x10,0x20};//位选信号
uchar code table[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//共阳码
uchar int_time; //*定义中断次数变量*/
uchar second; /*秒计数变量*/
uchar minute; /*分计数变量*/
uchar hour; /*小时计数变量*/
void delay(uint t)
{uchar i,j;
for(i=0;i<t;i++)
for(j=0;j<120;j++);}
void time_to_disbuff(uchar s, uchar m,uchar h )
{ //修改时分秒显示缓冲区数据
dis_buff[0]=h/10; //保存时到显示缓存区
dis_buff[1]=h%10;
dis_buff[3]=m/10; //保存分到显示缓存区
dis_buff[4]=m%10;
dis_buff[6]=s/10; //保存秒到显示缓存区
dis_buff[7]=s%10;
}
void display(void)
{ uchar i;
for(i=0;i<8;i++)
{
if (i==2|i==5)
{
P0=table[10]//seg,时和分后显示点
P1=position[i]; //pos
}
else
{
P0=table[dis_buff[i]]; //seg
P1=position[i]; //pos
}
delay(2);//2ms
P1=0x00;//注意!!!
}
}
void main()
{
P0=0x00;
P1=0x00;
TMOD=0x01; /*T0方式1*/
EA=1; /* 开总中断 */
ET0=1; /* 开T0中断 */
TH0=(65536-50000)/256=0x3c; /*置T0初值*/
TL0=(65536-50000)%256=0xb0;
TR0=1;
int_time=0; /*中断次数时分秒清0*/
second=0;
minute=0;
hour=0;
while(1)
{
time_to_disbuff(second ,minute, hour);
display();
}
}
void T0_interserve(void) interrupt 1 using 1 /*T0中断服务程序*/
{ TH0=(65536-50000)/256=0x3c; /*置T0初值*/
TL0=(65536-50000)%256=0xb0;
int_time++; /*中断次数1*/
if(int_time==20) /*中断次数满20*/
{ int_time=0; /*中断次数清0*/
second++; /*秒加1*/
}
if(second==60) /*满60s*/
{ second=0; /*秒计数器清0*/
minute ++; /*分计数器加 1*/
}
if(minute==60) /*满60分?*/
{ minute=0; /*分计数器清0*/
hour ++; /*时计数器加1*/
}
if(hour==24)
{ hour=0; /*时计数器满24,清0*/
}
}
4、将外部RAM8000H开始的10个字节的内容送入内部RAM50H开始的10个字节中。
#include<reg51.h>
data unsigned char nram50[10] _at_ 0x50;
xdata unsigned char nram8000[10] _at_ 0x8000;
void main() {
unsigned char i;
for(i=0;i<10;i++)
{
nram8000[i]=i;
nram50[i]=nram8000[i];
}
while(1);
}
5、将内部RAM30H~39H的10个字节的内容移至35H开始的连续10个字节中。
#include<reg51.h>
data unsigned char nram30[10] _at_ 0x30;
void main() {
unsigned char i;
for(i=0;i<10;i++)
{
nram30[i]=i;
}
for(i=10;i>0;i--)
{
nram30[i+4]=nram30[i-1];
}
while(1);
}
7、流水灯(定时:中断、查询)
- 无开关控制
/********流水灯:定时控制,1s循环左移,循环右移,采用中断和查询两种方式************/
/********2018/6/23***********/
/********JZ************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint i;
void main()
{
TMOD=0x01;//定时器的方式控制字,定时/计数器工作于方式1,0000_0001
TH0=0xd8;
TL0=0xf0; //定时10ms,系统周期为12MHZ,1us,2^16-10ms/1us=65536-10000=55536=d8f0H
EA=1; //允许总中断
ET0=1; //允许定时器T0中断
TR0=1; //启动定时器T0
P0=0xfe; //初始化灯的状态,为第一盏灯亮,其他灯不亮
while(1);
}
void time0_int(void) interrupt 1 //定时器0引发的中断函数
{
TH0=0xd8;
TL0=0xf0; //定时/计数器每次都需要重载初值
i++;
if(i==100) //循环100次,及达到了1s
{i=0;P0= _crol_(P0,1); } }//1s之后P0左移1位,循环点亮,间隔时间为1s
/*//P0=0x7f; P0= _cror_(P0,1);//灯初始化为第7盏灯亮,循环右移,从下往上
//P0=0xfe; P0= _crol_(P0,1);//灯初始化为第0盏灯亮,循环左移,从上往下
for(;;) //查询方式定时,放在主函数里面
{
if(TF0) //判断溢出标志位是否为1,为1则计数到
{i++;
TH0=0xd8;TL0=0xf0; TF0=0; //将溢出标志位软件清0
if(i==100) //循环100次,及达到了1s
{
P0= _crol_(P0,1);
i=0;
} }}*/
- 有开关控制
/****流水灯:定时控制,两个定时器,当按下K1时,采用T0定时,当按下K2时,采用T1定时************/
/********2018/6/24***********/
/********JZ************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint i;
sbit P1_0=P1^0;
sbit P1_1=P1^1; //定义并口P1的第0、1位
void main()
{TMOD=0x11; //定时器0、1均采用方式1工作
TH0=0x3c;
TL0=0xb0;
TR0=0;//初始化后并不启动定时器T0,待命初值为100ms
TH1=0x9e;
TL1=0x58;
TR1=0;//初始化后并不启动定时器T1,待命初值为50ms
i=0;
P0=0xff; //上电时, 8个发光二极管全亮
while(1)
{if(P1_0==0) //当P1.0有效时,及开关K1按下
{ EA=1;
TR1=0;//关闭定时器1
TR0=1; ET0=1;//允许中断0,打开定时器0
P0=0x7f; }// 给灯赋初值,第8个灯亮
if(P1_1==0) //当P1.1有效时,及开关K2按下
{ EA=1;
TR0=0; //关闭定时器0
TR1=1; ET1=1; //允许中断1,打开定时器1
P0=0xfe; }}} // 给灯赋初值,第1个灯亮
void time0_int(void) interrupt 1 //定时器0中断服务程序1
{ TH0=0x3c; TL0=0xb0; //每次定时都需要重新赋初值
i++; //计数加1
if(i==20)
{ i=0; P0= _cror_(P0,1);}} //循环右移(向上)1位,点亮下一个灯共定时2s
void time1_int(void) interrupt 3
{ TH1=0x9e;TL1=0x58; //每次定时都需要重新赋初值
i++;
if(i==20)
{i=0;
P0= _crol_(P0,1);}} //循环左移(向下)1位,点亮下一个灯共定时1
8、独立式键盘
/********独立式键盘************/
/********2018/6/23***********/
/********JZ************/
#include<reg51.h>
#define uchar unsigned char
sbit K0=P1^0; //定义位变量
sbit K1=P1^1;
sbit K2=P1^2;
sbit K3=P1^3;
sbit D0=P2^0;
sbit D1=P2^1;
sbit D2=P2^2;
sbit D3=P2^3;
/************延时函数************/
void delay(uchar k)
{
uchar i,j;
for (i=0;i<k;i++)
for (j=0;j<110;j++);//11.0592M晶振,大约延时1ms
}
void main()
{
if (K0==0)
{
delay(10);//延时10ms延时去抖
if(K0==0) {D0=0;D3=1;} //下一个灯亮,上一个灯灭
}
if (K1==0)
{
delay(10);
if(K1==0) {D1=0;D0=1;}
}
if (K2==0)
{
delay(10);
if(K2==0) {D2=0;D1=1;}
}
if (K3==0)
{
delay(10);
if(K3==0) {D3=0;D2=1;}
}}
9、LED
- 无8255
/********LED灯显示,无8255,P0口输出段选码,P2口输出位选码***********/
/********2018/6/23***********/
/********JZ************/
/*共阴极,逐位轮流点亮各个LED,每一位保持3ms,在15~20ms之内再一次点亮,重复不止*/
#include<reg52.h>
#define uchar unsigned char
uchar buf[8]={0,1,2,3,4,5,6,7};//定义显示缓冲区,buf[]数组里面的数表示段码送的数,可以更改,显示其他的数
uchar LED[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //字符为0~F
uchar scan [8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选码表
void delay(uchar k)
{
uchar i,j;
for (i=0;i<k;i++)
for (j=0;j<110;j++);//11.0592M晶振,大约延时1ms
}
void disp()
{
uchar i;
for(i=0;i<8;i++) //8位显示,共阴极
{
P2=scan[i]; //位码送P2口
P0=LED[buf[i]]; //段码送P0口
delay(3); //延时3ms
}
}
void main(void)
{
while(1)
{
disp(); //设显示函数
}
}
- 有8255
/********LED灯显示,有8255,P0口输出段选码,P2口输出位选码A口、B口C口和控制口的地址分别为7F00H、7F01H、7F02H和7F03H(高8位地址线未用的取1,低8位地址线未用的取0)************/
/********2018/6/23***********/
/********JZ************/
#include <reg51.h>
#include <absacc.h> //定义绝对地址访问
#define uchar unsigned char
#define uint unsigned int
void delay(uchar k); //声明延时函数
void display(void); //声明显示函数
uchar disbuffer[8]={0,1,2,3,4,5,6,7}; //定义显示缓冲区
uchar codevalue[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //字符为0~F
uchar chocode[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选码表
void main(void)
{
XBYTE[0x7f03]=0x80; //8255A初始化
while(1)
{
display(); //设显示函数
}
}
void delay(uchar k)
{
uchar i,j;
for (i=0;i<k;i++)
for (j=0;j<110;j++);//11.0592M晶振,大约延时1ms
}
/***********显示函数***********/
void display(void) //定义显示函数
{
uchar i,p,temp;
for (i=0;i<8;i++)
{
temp=chocode[i]; //取当前的位选码
XBYTE[0x7f01]=temp; //送出位选码
p=disbuffer[i]; //取当前显示的字符
temp=codevalue[p]; //查得显示字符的字段码
XBYTE[0x7f00]=temp; //送出字段码
delay(2); //延时1ms
}}
10、定时器:产生方波
/********产生周期为500us的方波************/
/********2018/6/23***********/
/********JZ************/
#include<reg51.h>
sbit P1_0=P1^0;
void main()
{
TMOD=0x02;
TH0=0x06;//定时250us,2^8-250us/1us=6
TL0=0x06;
EA=1;
ET0=1;
TR0=1;
while(1);
}
void time0_int(void) interrupt 1
{
P1_0=!P1_0;
}
/*查询方式
#include<reg51.h>
sbit P1_0=P1^0;
void main()
{
TMOD=0x02;//定时器工作于方式2
TH0=0x06;//定时250us,2^8-250us/1us=6
TL0=0x06;
EA=1;
ET0=1;
TR0=1;
for(; ;)
{
if(TF0)
{
TF0=0;P1_0=!P1_0;}
}
}*/
11、中断
/********外部中断0:在单片机外中断0引脚接一个单脉冲源作为外部输入信号,通过发光二极管显示中断次数************/
/********2018/6/24***********/
/********JZ************/
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar b=0;
void delay(uchar k)
{
uchar i,j;
for (i=0;i<k;i++)
for (j=0;j<110;j++);//11.0592M晶振,大约延时1ms
}
void main()//主函数
{
P0=0xff; //初始化灯,初始状态为全灭
INT0==1;//打开外部中断0
EA=1; //开总中断
EX0=1; //允许中断0
IT0=1; //设置外部中断0边沿触发
while(1);
}
void srv_INT0() interrupt 0 //中断服务程序
{
b=b+1;
P0=0xff-b; //proteus仿真中低电平灯亮,则P0不能直接等于计数的b,需要用0xff-b,才能使灯亮灭
delay();
}