实验(1)名称 :I/O控制
一、 实验要求
将8个LED灯分别接入任何一个端口(P0、P1、P2、P3),让LED灯不停止地进行循环亮/灭(亮/灭现象也可以自由发挥,如并列2个LED或交叉几个LED灯进行循环亮/灭)。
二、实验原理
用红外对管输入一个脉冲,利用了左移函数_crol_()使得LED巡回亮灭,中间加入了延迟函数,使得LED的亮灭,让我们可以明显看到在通过红外对管输入一个脉冲时,数码管依次亮灭。
三、程序设计
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define aint unsigned int
void delay(uchar);
void main()
{
uchar led;
led=0Xfe;
P1=led;
while(1)
{
led=_crol_(led,1); //左移函数
delay(50);
P1=led;
delay(50);
}
}
void delay(uint c)
{
uchar a,b;
for(a=c;a>0;a--)
{
for(b=200;b>0;b--);
}
}
四、现象及结果
从红外对管处给一个脉冲,流水灯亮一个,依次循环。
实验(2)名称:中断与定时
一、实验要求
(1)外部中断的使用
采用2种触发方式(边沿与电平)进行。每次中断点亮/灭掉一个LED即可。
(2)Timer定时器的使用
使用16位和8位自动装载方式定时1/2/3秒,循环亮/灭LED灯。
三、程序设计
(1)外部中断的使用
#include<reg52.h>
sbit p10=P1^0;
sbit p17=P1^7;
sbit key=P3^2;
sbit key1=P3^3;
void init();
void delay(unsigned z);
int b;
void main()
{
init();
while(1);
}
void init()
{
TCON=0x05;
EA=1;
EX0=1;
EX1=1;
P1=0xfe;
}
void out_interrupt0() interrupt 0
{
if(!key)
{
delay(20);
if(!key)
{b=p17;
P1=P1<<1;
p10=b;
while(!key);
delay(20);
while(!key);
}
}
}
void out_interrupt1() interrupt 2
{
if(!key1)
{
delay(20);
if(!key1)
b=p17;
P1=P1>>1;
p10=b;
delay(2000);
}
}
void delay(unsigned z) //延迟
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
(2)Timer定时器的使用
1.16位定时器
#include<reg52.h>
sbit p10=P1^0;
sbit p17=P1^7;
sbit speak=P2^7;
void init();
int time=0,b;
//unsigned char code table[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void main()
{
init();
while(1)
{
if(time==20)
{
time=0;
b=p17;
P1=P1<<1;
p10=b;
}
}
}
void init()
{
TMOD=0x01;
P1=0xfe;
EA=1;
ET0=1;
TR0=1;
TH0=0x3c;
TL0=0xb0;
time=0;
}
void timer0() interrupt 1
{
TH0=0x3c;
TL0=0xb0;
time++;
}
2.8位自动重装
#include<reg52.h>
sbit p10=P1^0;
sbit p17=P1^7;
sbit speak=P2^7;
void init();
int time=0,b;
void main()
{
init();
while(1)
{
if(time==5000)
{
time=0;
b=p17;
P1=P1<<1;
p10=b;
}
}
}
void init()
{
TMOD=0x02;
P1=0xfe;
EA=1;
ET0=1;
TR0=1;
TH0=0x37;
TL0=0x37;
time=0;
}
void timer0() interrupt 1
{
time++;
}
四、现象及结果
(1)外部中断:
当按下K1键,LED灯左移。按下K2键,LED右移一位。
(2)Timer定时器
LED灯以1秒的间隔循环亮灭。
实验(3)名称:键盘键值的读取
一、实验要求
完成4X4的矩阵键盘键值的读取。采用联机调试的方式,将读取的键值赋给一变量,在keil变量观察窗口中查看键值。
二、实验原理
三、程序设计
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uint key;
uint code table[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 ,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
uint key_scan()
{
uint cord,cord_hang,cord_lie;
P3=0xf0;
cord_lie=P3;
P3=0x0f;
cord_hang=P3;
cord=cord_hang+cord_lie;
if(cord!=0xff)
{
return(cord);
}
return(cord);
}
void main()
{
uint temp;
P2=0xfe;
P1=0xfe;
while(1)
{
temp=key_scan();
if(temp!=0xff)
{
switch(temp)
{
case 0xee:key=0;break;
case 0xed:key=1;break;
case 0xeb:key=2;break;
case 0xe7:key=3;break;
case 0xde:key=4;break;
case 0xdd:key=5;break;
case 0xdb:key=6;break;
case 0xd7:key=7;break;
case 0xbe:key=8;break;
case 0xbd:key=9;break;
case 0xbb:key=10;break;
case 0xb7:key=11;break;
case 0x7e:key=12;break;
case 0x7d:key=13;break;
case 0x7b:key=14;break;
case 0x77:key=15;break;
}
P2=~key;
P0=~table[key];
}
}
四、现象及结果
当按下0—16的按键时,数码管显示相应的键值。
实验(4)名称:LED数码管的显示
一、 实验内容及目的
用4支8段数码管分别用动态和静态显示4位数,如1234和1111。硬件电路自行搭接。
二、实验原理
通过控制数码管的段选和位选,让数码管显示不同的值。
(1)静态扫描
给位选低电平,数码管亮,给段选段码信号,
(2) 动态扫描
控制位选,选择一个数码管亮,然后给段选分别送相应的值,通过调节延时的长短和数码管的余晖,让数码管动态显示出1234,而人为的感觉像是静态显示。
三、程序设计
(1)静态扫描
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uint code table[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 ,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
while(1)
{
P1=0x00;
delay(10);
P0=0xc0;
}
}
(2) 动态扫描
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uint code table[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 ,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
while(1)
{ P1=0xfe;
P0=~table[0];
delay(10);
P1=0xfd;
P0=~table[1];
delay(10);
P1=0xfb;
P0=~table[2];
delay(10);
P1=0xf7;
P0=~table[3];
delay(10);
}
}
四、现象及结果
(1)静态扫描
数码管显示0000。
(2) 动态扫描
数码管显示1234。
实验(5)名称:串口通讯
一、实验要求
通过单片机的UART,完成单片机对PC(计算机)的通讯。学会使用上位机串口助手,通过该助手完成单片机与PC之间的“接收”与“发送”数据(任意字符串)。具体要求:
(1) 通过矩阵键盘输入数值,并设计功能键(如”A”发送);
(2) 键盘输入数值放入显示缓冲单元(显缓)中,通过4位LED数码管显示;
(3) 按下“功能键”,实现发送(显缓中的数据)与接收(上位机发送的数据,并在LED上显示)。
二、实验原理
通过单片机的TXD、 RXD引脚实现串行口的收发数据,让后用RS232线实现单片机和电脑之间的链接,其中要经过MAX232进行电平转换。
三、程序设计
#include<reg52.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;
sbit wela=P2^7;
uint cord_hang,cord_lie,shu,send,accept=1;
uint code table[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 ,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
void serial_accept();
uint a=16,b=16,c=16,d=16;
uint wei=0,key,temp,s1,s2,s3,s4;
uint e=1,flag=0;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void display(uchar a,uchar b,uchar c,uchar d)
{
dula=0;
P0=table[a];
dula=1;
dula=0;
wela=0;
P0=0xfe;
wela=1;
wela=0;
delay(1);
P0=table[b];
dula=1;
dula=0;
P0=0xfd;
wela=1;
wela=0;
delay(1);
P0=table[c];
dula=1;
dula=0;
P0=0xfb;
wela=1;
wela=0;
delay(1);
P0=table[d];
dula=1;
dula=0;
P0=0xf7;
wela=1;
wela=0;
delay(1);
}
uint key_scan()
{
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff) //消抖
{
delay(20);
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff)
{
delay(20);
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff)
return(cord_hang); //有键按下时候的返回值
}
}
return(cord_hang); //无键按下时候的返回值,为0xff
}
void key_num(int j)
{
wei++;
if(wei==5)
{wei=1;a=16;b=16;c=16;d=16;}
if(wei!=0) //实时显示
{
switch(wei)
{
case 1: a=j;s1=a; break;
case 2: b=j;s2=b; break;
case 3: c=j;s3=c; break;
case 4: d=j;s4=d; break;
}
}
}
void key_combin()
{
switch(wei)
{
case 1: shu=s1; break;
case 2: shu=s2+s1*10; break;
case 3: shu=s3+s2*10+s1*100; break;
case 4: shu=s4+s3*10+s2*100+s1*1000; break;
}
}
void key_accept()
{
printf("请输入数据:");
TI=0; //使不会应为发送标示位而进入中断函数
EA=1;
ES=1; //打开串行中断
while (flag==0); //原地等待发送完数据
flag=0;
b=e&0x0f; //显示低4位
a=e&0xf0; //显示高4位;
a=a>>4;
c=16;
d=16;
wei=4;
EA=0;
ES=0;
TI=1;
}
void serial_init()
{
SM0=0;
SM1=1;
REN=1;
TMOD=0x20;
TR1=1;
TH1=0xfd;
TL1=0xfd;
TI=1;
//RI=1;
EA=0;
ES=0;
}
void serial() interrupt 4
{
if(RI==1)
{ e=SBUF;
flag = 1;
RI=0;}
}
void main()
{
serial_init();
while(1)
{
temp=key_scan();
if(temp!=0xff)
{
switch(temp)
{
case 0xee:key_num(1);break;
case 0xde:key_num(2);break;
case 0xbe:key_num(3);break;
case 0x7e:key_num(4);break;
case 0xed:key_num(5);break;
case 0xdd:key_num(6);break;
case 0xbd:key_num(7);break;
case 0x7d:key_num(8);break;
case 0xeb:key_num(9);break;
case 0xdb:key_num(10);break;
case 0xbb:key_num(11);break;
case 0x7b:key_num(12);break;
case 0xe7:key_num(13);break;
case 0xd7:key_combin();break; //组合成10进制数
case 0xb7:printf("%d",shu);break; //把10进制数输出
case 0x77:key_accept();break; //接收PC机的值。
}
while(key_scan()!=0xff);//松手检测
}
display(a,b,c,d);
}
}
四、现象及结果
矩阵键盘的第一个到第13个键盘,按下后,数码管会显示0—C十六进制数。
按下第14个按键后,最新按下的4个数会整合成一个4位数,并在数码管在显示。
按下第15个案件后,会吧数据发送到PC机的串口调试助手里面。
按下第16个按键后,会等待PC机串口发送数据并显示在数码管上。
实验(6)名称:综合实验
一、实验内容及目的
通过功能按键(A,B,C,D等)实现“秒表”、“通讯”和“步进电机的控制”等组合功能。
二、实验原理
本次实验是综合前面七次的实验,从而达到综合应用的目的。
三、程序设计
#include<reg52.h>
#include<stdio.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;
sbit wela=P2^7;
//sbit key_en=P1^0;
uint cord_hang,cord_lie,shu,send,accept=1;
uint code table[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 ,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
void serial_accept();
uint a=16,b=16,c=16,d=16;
uint wei=0,key,temp,s1,s2,s3,s4,flag_dian_ji;
uint e=1,flag=0,timer,miao_biao;
bit dian_ji_fangxiang;
uchar dot;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void display(uchar a,uchar b,uchar c,uchar d,uchar dt)
{
dula=0;
P0=table[a];
dula=1;
dula=0;
wela=0;
P0=0xfe;
wela=1;
wela=0;
delay(1);
P0=table[b]|dt;
dula=1;
dula=0;
P0=0xfd;
wela=1;
wela=0;
delay(1);
P0=table[c];
dula=1;
dula=0;
P0=0xfb;
wela=1;
wela=0;
delay(1);
P0=table[d];
dula=1;
dula=0;
P0=0xf7;
wela=1;
wela=0;
delay(1);
}
uint key_scan()
{
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff) //消抖
{
delay(20);
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff)
{
delay(20);
P3=0xf0;
cord_hang=P3;
P3=0x0f;
cord_lie=P3;
cord_hang=cord_hang|cord_lie;
if(cord_hang!=0xff)
return(cord_hang); //有键按下时候的返回值
}
}
return(cord_hang); //无键按下时候的返回值,为0xff
}
void key_num(int j)
{
wei++;
if(wei==5)
{wei=1;a=16;b=16;c=16;d=16;}
if(wei!=0) //实时显示
{
switch(wei)
{
case 1: a=j;s1=a; break;
case 2: b=j;s2=b; break;
case 3: c=j;s3=c; break;
case 4: d=j;s4=d; break;
}
}
}
void key_combin()
{
switch(wei)
{
case 1: shu=s1; break;
case 2: shu=s2+s1*10; break;
case 3: shu=s3+s2*10+s1*100; break;
case 4: shu=s4+s3*10+s2*100+s1*1000; break;
}
//s1=0;s2=0;s3=0;s4=0;
}
void key_accept()
{
printf("请输入数据:");
TI=0; //使不会应为发送标示位而进入中断函数
EA=1;
ES=1; //打开串行中断
while (flag==0); //原地等待发送完数据
flag=0;
//P1=e;
b=e&0x0f; //显示低4位
a=e&0xf0; //显示高4位;
a=a>>4;
c=16;
d=16;
wei=4;
EA=0;
ES=0;
TI=1;
}
void serial_init()
{
SM0=0;
SM1=1;
REN=1;
TMOD|=0x20;
TR1=1;
TH1=0xfd;
TL1=0xfd;
TI=1;
EA=0;
ES=0;
}
void miaobiao_init()
{
TMOD|=0x01;
TH0=0xfc;
TL0=0x18;
EA=1;
ET0=1;
// TR0=1;
timer=0;
}
void timer0() interrupt 1
{
TH0=0xfc;
TL0=0x18;
timer++;
if(timer==10)
{
timer=0;
miao_biao++;
if(miao_biao==5999)
miao_biao=0;
}
}
void serial() interrupt 4
{
if(RI==1)
{ e=SBUF;
flag = 1;
RI=0;}
}
void dian_ji_wei()
{
flag_dian_ji=~flag_dian_ji;
a=16;
b=16;
c=16;
d=16;
}
void dian_ji_qudong()
{
uint num=0;
P2=0x08;
for(num=0;num<3;num++)
{
if(dian_ji_fangxiang)
{P2=_crol_(P2,1);if(P3==0x80)P3=0x08;}
else
{P2=_cror_(P2,1);if(P3==0x08)P3=0x80;}
delay(5);
}
}
void main()
{
uchar clr;
serial_init();
miaobiao_init();
while(1)
{
temp=key_scan();
if(temp!=0xff)
{
switch(temp)
{
case 0xee:key_num(1);break;
case 0xed:key_num(2);break;
case 0xeb:key_num(3);break;
case 0xe7:key_num(4);break;
case 0xde:key_num(5);break;
case 0xdd:key_num(6);break;
case 0xdb:key_num(7);break;
case 0xd7:key_num(8);break;
case 0xbe:key_num(9);break;
case 0xbd:key_num(10);break;
case 0xbb:{TR0=~TR0,wei=0;}break; //秒表显示
case 0xb7:dian_ji_fangxiang=~dian_ji_fangxiang;break; //电机反向
case 0x7e:dian_ji_wei();break;
case 0x7d:key_combin();break; //组合成10进制数
case 0x7b:printf("%d",shu);break; //把10进制数输出
case 0x77:key_accept();break; //接收PC机的值。
}
while(key_scan()!=0xff);//松手检测
}
if(flag_dian_ji)
{dian_ji_qudong();}
else if(wei==0)
{
clr=1;
dot=0x80;
d=miao_biao%10;
c=miao_biao/10%10;
b=miao_biao/100%10;
a=miao_biao/1000;
}
else if(wei!=0)
{
dot=0;
if(clr)
{a=16;b=16;c=16;d=16;clr=16;}
}
display(a,b,c,d,dot);
}
}
四、结果与现象
矩阵键盘的第一个到第10个键盘,按下后,数码管会显示0—a ,按下第11个键后,数码管显示4位秒表;按下12个键后:电机反向;按下第13个键后:电机启动;按下第14个按键后,最新按下的4个数会整合成一个4位数,并在数码管在显示。按下第15个按键后,会把数据发送到PC机的串口调试助手里面。按下第16个按键后,会等待PC机串口发送数据并显示在数码管上。