单 片 机 验 收 报 告
- 1 - 姓名:郗啸锋 学号:311308000931班级:电科1301 学院:电气学院
实验一 流水灯实验
一、实验目的
(1)简单I/O引脚的输出
(2)掌握软件延时编程方法
(3)简单按键输入捕获判断
二、实验实现的功能
(1)开机是点亮12发光二极管,闪烁三下
(2)按照顺时针循环依次点亮发光二极管
(3)通过按键将发光二极管的显示改为顺逆时针方式
三、系统硬件设计
(1)AT89C51单片机
(2)12个LED数码管
(3) K1正反转转换开关
四、系统软件设计
/****头文件*****/
#include<reg51.h>
/****宏定义****/
#define uchar unsigned char
#define uint unsigned int
/***定义按键端口***/
sbit key = P3^6;
sbit keyl = P0^5;
/****总线控制数组******/
uchar table[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xfb,0xf7,0xef,0xdf};
//当引脚电平为时,引脚对应的led亮
/******子函数定义*******/
void delay1ms(); //延时函数1ms时间
void delaynms(uint); //延时函数自定义毫秒数
void delay(); //定义延时函数100ms时间
void led_init(); //初始化led全体同时亮灭三次
/**主函数**/
void main()
{
uchar m = 0;
uchar k = 0;
keyl = 0 ;
led_init(); //led初始化为全体led同时闪灭三次
while(1)
{
if(!key)
{
delaynms(5);
if(!key)
- 2 -
{
m++;
if(m == 2) {
m = 0; }
while(!key); }
}
if(m == 0)
{
k++;
if(k == 13)k=1; }
else k--;
if(k == 0)k = 12;
switch(k-1)
{
case 0 : P2 = table[0]; P3 = 0xff;
delay(); break; case 1 : P2 = table[1]; delay(); break; case 2 : P2 = table[2]; delay(); break; case 3 : P2 = table[3]; delay(); break; case 4 : P2 = table[4]; delay(); break; case 5 : P2 = table[5]; delay(); break; case 6 : P2 = table[6]; delay(); break; case 7 : P2 = table[7]; P3 = 0xff; delay(); break; case 8 : P3 = table[8]; P2 = 0xff; delay(); break; case 9 : P3 = table[9]; delay(); break; case 10 : P3 = table[10]; delay(); break; case 11 : P3 = table[11]; P2 = 0xff;
delay(); break; }
}
}
/******子函数体********/
void delay1ms(void) //误差 0us {
unsigned char a,b,c;
for(c=1;c>0;c--)
- 3 -
for(b=222;b>0;b--)
for(a=12;a>0;a--);
}
void delaynms(uint z)
{
while(z--)
{
delay1ms();
}
}
void delay()
{ uchar z = 100;
while(z--)
{
delay1ms();
}
}
void led_init()
{
uchar i ;
for(i = 0; i<3;i++)
{
P2 = 0x00;
P3 = 0x00;
delaynms(500);
P2 = 0xff;
P3 = 0xff;
delaynms(500);
}
}
五、实验过程中遇到的问题及解决方法
在运行试验时发现单片机焊接过程中把LED焊反了,导致实验过程中灯不会亮,之后重新按顺序焊接后,问题解决,灯顺利点亮,完成实验。
实验二 定时器、时钟实验
一、实验目的
⑴数码管动态显示技术
⑵定时器的应用
⑶按键功能定义
二、实验实现的功能
⑴通过按键可以设定定时时间,启动定时器,定时时间到,让12个发光二极管闪烁,完成定时器功能,按键可重新从设定值开始计时。
⑵实时时钟,可以设定当前时间,完成钟表功能(四位数码管分别显示分钟和秒)。 ⑶定时时间到,灯闪后按6号键返回重新计时。
三、系统硬件设计
实时时钟、定时器
四、系统软件设计
#include<reg52.h>
- 4 -
#define uint unsigned int
#define uchar unsigned char
sbit H1=P3^6;
sbit H2=P3^7;
sbit L1=P0^5;
sbit L2=P0^6;
sbit L3=P0^7;
sfr P1M1=0x91;
sfr P1M0=0x92;
tab1[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; tab2[]={0xf7,0xfb,0xfd,0xfe};
tab3[4]={0};
uint a=0;
uint b=0;
int n;
void Delay1()
{ unsigned char i,j,k;
for(i=0;i<15;i++)
for(j=0;j<202;j++)
for(k=0;k<81;k++) ;
}
void Delay2()
{ unsigned char i;
for(i=0;i<2;i++) ;
}
void flicker()
{
uchar n=0;
while(n<=2)
{
P2=0x00;
P3=0xc3;
Delay1();
P2=0xff;
P3=0xff;
Delay1();
n++;
}
}
void show()
{
char j;
switch(j)
{
- 5 -
case 0:P0=tab2[j];j++;P1=tab1[tab3[0]];break;
case 1:P0=tab2[j];j++;P1=tab1[tab3[1]];break;
case 2:P0=tab2[j];j++;P1=tab1[tab3[2]];break;
case 3:P0=tab2[j];j=0;P1=tab1[tab3[3]];break;
default:break;
}
}
void interrupt_timer1() interrupt 3
{
TH1=0xfc;
TL1=0x67;
a++;
if(a==1000) //每隔1ms中断一次并作一个计数,1000次中断为 1s {
b++;
a=0;
tab3[0]=b%10; //十进制进位即个、十、百、千 tab3[1]=b/10%10;
tab3[2]=b/100%10;
tab3[3]=b/1000%10;
}
show();
}
void main()
{
int m,k;
n=1;
P1M1=0x00;
P1M0=0xff; //P1口设为强推挽输出
TMOD=0x10; // T1方式一
TH1=0xfc; //送初值
TL1=0x67;
ET1=1; //开中断
EA=1;
while(1)
{
if(!TR1)
{
k=0;
for(k=0;k<50;k++)
{
H1=0;
H2=0;
L1=1;
- 6 -
加2 100
L2=1; L3=1; if(!L1) //按键1按下,启动定时 { Delay2(); if(!L1) //消抖 { TR1=1; break; } while(!L1); } if(!L2) //按键2按下,对定时时间修改,按一下 { Delay2(); if(!L2) //消抖 n+=10; while(!L2); } if(!L3) //按键3按下,对定时时间修改,按一下加 { Delay2(); if(!L3) //消抖 n+=100; while(!L3); } tab3[0]=n%10; //十进制进位个十百千 tab3[1]=n/10%10; tab3[2]=n/100%10; tab3[3]=n/1000%10; for(m=0;m<4;m++) //送个、十、百、千显示 { P0=tab2[m]; P1=tab1[tab3[m]]; Delay2(); } if(m==4) m=0; } } if(b==n) {
- 7 -
TR1=0; //定时时间到,停止计时,闪三次 b=0;
n=1;
flicker();
}
}
}五、实验过程中遇到的问题及解决方法
1、动态显示中,一次点亮数码管,无法出现稳定全亮的效果。
解决:缩短每个数码管点亮时间,并且在每个数码管亮过之后熄灭一定时间。
2、设定当前时间时,扫描按键与点亮数码管交替进行,数码管几乎不亮。 解决:点亮一次数码管只有几毫秒,而按键扫描要几百毫秒,这样,数码管亮的时间可以忽略,所以不亮。加for循环,使数码管循环点亮一段时间,再扫描按键,由于视觉暂留,即可看到数码管全亮。
3、数码管亮度不够。
解决:使用推挽式输出。
4、若用一个数组控制时钟的四位数,则四个小数点全亮或全不亮,不能达到两位表示分钟,两位表示秒钟的目的。
解决:用两个数组分别控制十位和各位,其中一个数组小数点亮,另一个不亮。
5、时钟调节当前时间时,时钟边走边调影响调节如何实现先调当前时间再让时钟走?
解决:建立while(1)死循环,在其中写设置时间的程序,调节完成后,当某一按键按下,写入break跳出死循环。
实验三 双机通信实验
一、实验目的
UART 串行通信接口技术应用
二、实验实现的功能
用两片核心板之间实现串行通信,将按键信息互发到对方数码管显示。
三、系统硬件设计
(1)实验所需硬件:电脑一台;
(2)开发板一块;
(3)串口通信线一根;
(4)USB线一根;
四、系统软件设计
实验所需软件:编译软件:keil uvision3;
程序下载软件:STC_ISP_V480;
试验程序:
#include <reg51.h>
#define uint8 unsigned char
#define uint16 unsigned int
sbit keyl = P3^6;
sbit key = P0^5;
sbit w1 = P0^0;
sfr P1M1=0x91;
- 8 -
sfr P1M0=0x92;
uint8 k = 0; //按键次数变量
char dat;
uint8 code str[] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
/**********子函数预定义***********/
void delay1ms(void); //延时函数,精确延时1毫秒
void Send(void); //发送函数,发送数据
void rec(void); //接收函数,接收数据
void main(void)
{
keyl = 0 ;
TMOD=0x20;
TH1=0xfa;
TH0=0xfa;
TR1=1;
PCON=0x00;
SCON=0x50;
TI=1;
P1M0 = 0xff;
P1M1 = 0x00;
while(1)
{
if(!key)
{
delay1ms();
if(!key)
{
Send();
while(!key);
}
}
rec();
w1 = 0;
P1 = str[k];
}
}
void delay1ms(void)
{
unsigned char a,b,c;
for(c=1;c>0;c--)
- 9 -
for(b=222;b>0;b--)
for(a=12;a>0;a--);
}
void Send()
{
int i=0;
if(TI){
TI=0;
SBUF=1;
while(!TI);
}
}
void rec()
{
if(RI)
{
dat=SBUF;
k ++;
if(k == 10)
k = 0;
RI=0;
}
}
五、实验过程中遇到的问题及解决方法
本次实验的实现采用的是两块AT89C51型号的单片机来完成双机串口通信的。本次实验涉及到较多的硬件设备和寄存器,重难点就在于较多的初始化变量需要设置和计算,所以本次实验中遇到了较多的问题。
本次遇到的比较棘手的问题就是波特率的设置。涉及到寄存器设置的寄存器有PCON和SMOD两个,通过SMOD可以设置波特率模式,而寄存器PCON则控制波特率是否加倍。我编程时选择的是串行口的工作方式1,此工作方式下波特率可变,这里选择的是2400。
PCON=0xff;所以波特率不加倍。然后将所选的波特率带入公式算出定时计数器的初值,并完成初始化。
再次就是硬件上的问题。查询过相关资料我明白了一块单片机的TXD引脚要与另一块的RXD相连,将程序分别烧进两块单片机中然后给它们供电后,便可以实现彼此的通信了。
实验四 交通灯实验
一、实验目的
(1)按键、数码管、发光二极管综合应用编程技术
- 10 -
(2)数据存储于EEPROM的技术(也可以不使用)
(3)定时中断技术
(4)按键中断技术
二、实验实现的功能
(1)对每个路口(主干道、次干道)的绿灯时间,及黄灯时间的设定。
(2)紧急按键功能,当按下该键时,所有路口变成红灯,相当于交警指挥特殊车辆通过。再按该键,恢复正常显示。
三、系统硬件设计
(1)单片机模板
(2)12个二极管
(3)复位键
四、系统软件设计
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define LedData P1
sbit key = P0^5; //紧急按键端口定义
sbit keyl = P3^6; //按键的接地端口
sbit w1 = P0^2; //设置数码管十位数的端口
sbit w2 = P0^3; //设置数码管个位数的端口
sfr P1M1=0x91;
sfr P1M0=0x92;
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,
0x6d,0x7d,0x07,0x7f,0x6f}; //数码管显示编码
uint num1 ; //数码管显示变量
uint num = 11;
uint time_num; //溢出计数变量
uint k = 0,x = 0; //选择变量
void delay1ms();
void delaynms(uint);
void LedDisplay(uint);
void init();
void urgency();
void hengroad();
void zongroad();
void main()
{
init();
P1M0 = 0xff;
P1M1 = 0x00;
while(1)
{
hengroad();
zongroad();
}
}
void timer0() interrupt 1
{
TH0 = 0x0D4;
TL0 = 0x0CD; //每次都装入初值,每一毫秒溢出一次
time_num ++;
if(time_num == 50)
- 11 -
{
time_num = 0;
num --;
}
}//延时1毫秒
void delay1ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=222;b>0;b--)
for(a=12;a>0;a--);
}//延时n毫秒
void delaynms(uint z)
{
while(z --)
{
delay1ms();
}
}//定时器中断初始化函数
void init()
{
TMOD = 0x01; //定时器0 方式1
TH0 = 0x0D4;
TL0 = 0x0CD; //装入初值,每一毫秒溢出一次
EA = 1;
ET0 = 1;
TR0 = 1;
}//数码管显示函数
void LedDisplay(uint num)
{
uint ge,shi;
ge = num % 10 ;
shi = num / 10 ;
w1 = 0;
w2 = 1;
LedData = table[shi];
delaynms(5);
w1 = 1;
w2 = 0;
LedData = table[ge];
delaynms(5);
}//紧急情况函数
void urgency()
{
keyl = 0;
if(!key)
{
delay1ms();
if(!key)
{
while(!key);
while(key)
{
delay1ms();
while(key) //当key按下又松开后进入紧急状态 当再次按下后解除 {
- 12 -
LedDisplay(num);
EA = 0;
P2 = 0xb6;
P3 = 0x34;
}
}
while(!key); //当松开后定时器继续工作
EA = 1;
}
}
}//横向通道通行
void hengroad()
{
num = 20;
while(num > 3)
{
urgency();
LedDisplay(num);
P2 = 0xf3;
P3 = 0x30; // 纵向红灯,横向绿灯
}
while(num > 0)
{
urgency();
LedDisplay(num);
P2 = 0x75;
P3 = 0x34; //纵向红灯,横向黄灯
}
}//纵向通道通行
void zongroad()
{
num = 15;
while(num > 3)
{
urgency();
LedDisplay(num);
P2 = 0x9e;
P3 = 0x1c; //纵向绿灯,横向红灯
}
while(num > 0)
{
urgency();
LedDisplay(num);
P2 = 0xae;
P3 = 0x2c; //纵向黄灯,横向红灯
}
}
五、实验过程中遇到的问题及解决方法
本次试验实现红绿灯转换时,是对于定时变换总是编程失败,无法实现试验所要求的功能,尤其对于亮灯时间以及亮灯顺序的把握不太好。我和同组人员一起上网搜索有用的资料和程序,认真思考探索计算后,多次调试程序直到功能达到实验目的。
指导老师签字: 日期:
- 13 -