北邮小学期AVR单片机模拟电梯系统实验报告副本.docx
《北邮小学期AVR单片机模拟电梯系统实验报告副本.docx》由会员分享,可在线阅读,更多相关《北邮小学期AVR单片机模拟电梯系统实验报告副本.docx(36页珍藏版)》请在冰豆网上搜索。
北邮小学期AVR单片机模拟电梯系统实验报告副本
小学期单片机实验报告
姓名:
班级:
学号:
班内序号:
时间:
基于AVR单片机的模拟电梯系统制作
目录
基于AVR单片机的模拟电梯系统制作2
1.简介3
1.1课题名称3
1.2摘要3
2.前期准备3
2.1流水灯3
2.1.1功能3
2.1.2程序代码3
2.2蜂鸣器/按键蜂鸣器4
2.2.1功能4
2.2.2程序代码4
2.3秒表计时器6
2.3.1功能6
2.3.2程序代码6
2.4流水灯与60秒秒表计时器8
2.4.1功能8
2.4.2程序代码8
3.设计过程11
3.1设计流程11
3.2实验元器件11
3.3实验程序主要流程图12
3.4实验原理及原理图13
3.4.1实验原理13
3.4.2原理图13
3.4.3各模块的设计与详解:
13
4.程序源代码及程序分析15
5.实验结果22
5.1操作过程22
6.排错过程24
7.心得体会25
8.参考文献26
9.意见与建议26
1.简介
1.1课题名称
基于AVR单片机的模拟电梯系统
1.2摘要
本实验设计制作一个基于单片机Atmega16的模拟电梯系统。
此单片机模拟电梯用红色和绿色发光二极管分别来指示电梯当前是处于上升状态还是下降状态,用数码管显示当前是处于哪一层,能够通过键盘控制实现电梯的上下运行来到达指定楼层,此外,在出现意外情况时可以通过按键实现电梯的紧急停止及恢复运行。
关键词:
单片机,键盘扫描,按键检测,电机的正反转,数码管显示,蜂鸣器,模拟电梯
2.前期准备
在之前的学习中我们从未学习单片机,所以在确定选题前需要一定的学习和练习。
我们小组一共练习了3个工程:
流水灯、按键蜂鸣器和秒表计时器,学会了使用AVRstudio工作环境和WINAVR(GCC)编译器,并在板子上写入程序。
学会了I/O端口初始化、输入输出操作,通过端口控制LED序列、8段数码管、蜂鸣器,中断和定时的使用。
2.1流水灯
2.1.1功能
学会I/O端口的初始化及通过端口控制LED,使得LED呈现流水灯效果,我们小组用的PB端口作为控制LED的端口,并且由于人眼频率和单片机频率的关系加了延迟函数,使得流水灯每个状态保持1s
2.1.2程序代码
#include
intmain(void)
{
chartemp;//用来存储当前A端口的输出
unsignedinti,k;//循环变量
DDRA=0xff;//将A端口设为输出
PORTA=0b00000001;//初始化A端口,从接入PA0的LED灯亮
while
(1)
{
temp=PORTA;
PORTA=PORTA<<1;
if(temp&0b10000000)//若接入7的LED灯亮
{
PORTA=PORTA|0b00000001;//则点亮接入PA0的LED灯
}//即实现流水灯循环
for(i=0;i<50;i++)//延时,约1秒钟
{
for(k=0;k<1000;k++);
}
}
}
2.2蜂鸣器/按键蜂鸣器
2.2.1功能
按键蜂鸣器主要为了了解按键的使用,并且学会中断的应用
2.2.2程序代码
蜂鸣器:
#include
intmain(void)
{
unsignedinti,k;
DDRB|=(1<<3);//对B端口的设置,使得PD3设置为输出
PORTB&=~(1<<3);//初始时蜂鸣器不响
while
(1)
{
PORTB^=(1<<3);//设置蜂鸣器每隔约一秒响一次
for(i=0;i<50;i++)
{
for(k=0;k<1000;k++);
}
}
}
按键蜂鸣器:
#include
intmain(void)
{
DDRA&=~(1<<6);//按钮6的设置
PORTA|=(1<<6);
DDRA&=~(1<<7);//按钮7的设置
PORTA|=(1<<7);
DDRA&=~(1<<2);//按钮2的设置
PORTA|=(1<<2);
DDRA&=~(1<<3);//按钮3的设置
PORTA|=(1<<3);
DDRB|=(1<<3);//蜂鸣器输出
PORTB&=~(1<<3);
DDRD=0xff;//灯的输出
while
(1)
{
switch(PINA&0b11001100)
{
case0b11001100:
//K1被按下
{
PORTD|=(1<<0);//LED0发光
break;
}
case0b11000000:
//K2被按下
{
PORTD|=(1<<1);//LED1发光
break;
}
case0b10001000:
//K3被按下
{
PORTD|=(1<<2);//LED2发光
break;
}
case0b01001000:
//K4被按下
{
PORTB|=(1<<3);//蜂鸣器鸣响
break;
}
default:
{
PORTB&=~(1<<3);//关蜂鸣器
PORTD=0;//关灯
break;
}
}
}
}
2.3秒表计时器
2.3.1功能
利用两位数码管,实现秒表计时的功能
2.3.2程序代码
#include
#include
inttable[]=//显示0—9的数组
{
0x3f,
0x06,
0x5b,
0x4f,
0x66,
0x6d,
0x7d,
0x07,
0x7f,
0x6f};
intmain(void)
{
DDRA=0xff;
DDRB=0xff;
DDRD=0b11110111;
PORTA=0b00000001;
PORTD=(1<<3);//设置中断
PORTB=0b00001000;
MCUCR|=(1<GICR|=(1<sei();
unsignedinti,j,k,x,y;
unsignedchartemp;
TCCR0|=(1<while
(1)
{
for(i=0;i<60;i++)
{
x=i/10,y=i%10;//x为十位数,y为个位数
PORTD=table[x];//接入PD口的数码管显示十位数
PORTB=table[y];//接入PB口的数码管显示个位数
temp=PORTA;//流水灯的显示
PORTA=PORTA<<1;
if(temp&(1<<7))
{
PORTA|=1;
}
TCNT0=55;
for(k=0;k<3;k++)//延时
for(j=0;j<10000;j++)
{
while(!
(TIFR&(1<TCNT0=55;
}
}
}
}
SIGNAL(SIG_INTERRUPT1)//中断程序
{intm=0;
while
(1)
{if(PIND&(1<<2))
{delay(10);
while
(1)
{
m++;
if(!
(PIND&(1<<2)))
{
m++;
break;
}
}
}
delay(500);
if(m==2)
{
delay(100);
break;
}
}
2.4流水灯与60秒秒表计时器
2.4.1功能
学会I/O端口的初始化及通过端口控制LED,使得LED呈现流水灯效果,此外,利用两个数码管,实现60秒秒表计时功能,可随时停止。
2.4.2程序代码
#include
#include
intmain(void)
{
charTEMP;
DDRB=0xff;//将B端口设为输出
PORTB=0b11001100;//初始化B端口,最开始第一个灯亮
while
(1)//主循环
{
TEMP=PORTB;
PORTB=PORTB<<1;
if(TEMP&0b10000000)
{
PORTB=PORTB|0b00000001;
}
for(i=0;i<100;i++)
{
for(j=0;j<1000;j++);
}
}
}
intmain(void)
{
charnum[10]=
{
0b00111111,//0
0b00000110,//1
0b01011011,//2
0b01001111,//3
0b01100110,//4
0b01101101,//5
0b01111101,//6
0b00000111,//7
0b01111111,//8
0b01101111,//9
};
charshuma[10]=
{
0b10111111,
0b10000110,
0b01011111,
0b11001111,
0b11100110,
0b11101111,
0b11111101,
0b10000111,
0b11111111,
0b11101111,
};
unsignedinta=0,tag=0;
chartemp;
unsignedinti,j;
DDRA=0xff;
PORTA=0b10001100;
DDRC&=~(1<<7);
PORTC|=(1<<7);
DDRB|=(1<<7);
DDRD|=(1<<7)|(0<<2);
PORTC&=~(1<<6);//关数码管
TCNT0=55;
TCCR0|=(1<DDRB=0xff;//DDRD=0xff;
DDRA|=0xf0;
TCNT0=55;
PORTD|=(1<<2);
MCUCR|=(1<GICR|=(1<sei();
while
(1)
{
/*if(PINC&(1<<7))//按键没被按下
{
if(a==9)
{
tag=(tag+1)%6;
}
a=(a+1)%10;
PORTD=num[a];
PORTB=num[tag];
}
Else//按键按下
{
PORTD=PORTD;//保持原状态
PORTB=PORTB;
}
}*/
PORTA=0b11000000;
temp=PORTA;
PORTA=PORTA<<1;
if(temp&0b10000000)//使最后一个等亮起后,又从第一个亮起
{
PORTA=PORTA|0b00000001;
}
for(i=0;i<50000;i++)
{
while(!
(TIFR&(1<TCNT0=55;
}
}
}
SIGNAL(SIG_INTERRUPT0)//中断程序
{
PORTA=0xff;
for(intp=0;p<10000;p++)
PORTD|=(1<<2);
while(!
(~(PORTD|0b11111011)))
{
}
}
3.设计过程
3.1设计流程
(1)了解AVR单片机原理及编程规则.
(2)编写代码,然后接好电路,下载到单片机测试
(3)所有部分完成后,进行整体测试,有错的话继续整改,无错直接下载测试
3.2实验元器件
Atmeal16单片机1块
JTAG下载器1个
4X4矩阵键盘1块
电机1个
蜂鸣器1个
数码显示管1个
导线若干
3.3实验程序主要流程图
运行结果及组员分工:
申宇飞:
主要负责模拟电梯系统程序的编写
徐萌扬:
主要负责硬件的连接和实物的制作
3.4实验原理及原理图
3.4.1实验原理
单片机识别按键按下的是哪个键,随之进行判断,如果需要进行移动,则驱动电机,在到达指定的楼层后停止,期间可以不断扫描输入,不断更新路线,被按下楼层有指示灯显示,到达该楼层后灯灭掉,蜂鸣器响一下。
在电梯运动同时到达相应楼层时,数码管显示当前楼层,用红色和绿色发光二极管组成的箭头来指示电梯当前是处于上升状态还是下降状态。
此外,如果按下按键,还可以实现电梯的紧急停止和恢复启动。
3.4.2原理图
3.4.3各模块的设计与详解:
3.4.3.1中央处理器MCU
中央处理器
中央处理器用的是ATMega16,如图所示。
PA0~PA7用于连接键盘输入,PC0驱动蜂鸣器,PC1和PC7口设置为电机接入端口,PB0~PB7用于连接数码管显示器,PD2设置为中断按键,PD3~PD7为LED灯阵。
当PC1输出高电平PC7输出低电平时,电动机逆时针旋转;反之,电动机顺时针旋转。
由此实现电梯上下行功能。
3.4.3.24x4键盘
图3
键盘与接PB口连接,见图3。
键盘的工作原理:
按键设置在行、列线交点上,行、列线分别连接到按键开关的两端。
行线通过上拉电阻接到+5V电源上。
无按键按下时,行线处于高电平的状态,而当有按键按下时,行线电平与此行线相连的列线电平决定。
将行列线值组合后即得到一个两位为0六位为1的八位二进制数。
由此八位二进制数即可确定按键并设置相应数值。
4.程序源代码及程序分析
5.#include
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
intw_counter=0,d_counter=0;//计数按键次数
intdirection;//标志上下坡
intfloor_now=1;//当前楼层号
intfloor_go=0;//紧接着要去的楼层号
intfloor_wait[6]={0,0,0,0,0,0};//有人等着的楼层号
intfloor_des[6]={0,0,0,0,0,0};//目的楼层号
ucharkey,key_temp;//键盘输入;存key以判断输入
chardata[10]=
{
0b00111111,//0
0b00000110,//1
0b01011011,//2
0b01001111,//3
0b01100110,//4
0b01101101,//5
0b01111101,//6
0b00000111,//7
0b01111111,//8
0b01101111,//9
};
voidalarm();//蜂鸣器控制函数
voidlight(intdirection);//上下行亮灯函数
voidkeyscan()//4*4键盘的扫描
{
ucharcord_h,cord_l,cord;
DDRB=0x0f;
PORTB=0xf0;//行线输出全为0
delay
(1);
cord_h=PINB&0xf0;//读入行线值
if(cord_h!
=0xf0)//先检测有无按键按下
{
//delay(10);//去抖
if(cord_h!
=0xf0)
{
DDRB=0xf0;
PORTB=0x0f;//输出当前列线值
delay
(1);
cord_l=PINB&0x0f;//读入列线值
cord=cord_l|cord_h;//键盘最后组合码值
switch(cord)
{
case0b11101110:
floor_wait[1]=1;PORTD|=0b00000001;break;//1外部
case0b11011110:
floor_wait[2]=2;PORTD|=0b00000010;break;//2
case0b10111110:
floor_wait[3]=3;PORTD|=0b00000100;break;//3
case0b01111110:
floor_wait[4]=4;PORTD|=0b00001000;break;//4
case0b11101101:
floor_wait[5]=5;PORTD|=0b00010000;break;//5
case0b11011101:
floor_wait[0]=6;PORTD|=0b00100000;break;//6
case0b10111011:
floor_des[1]=1;PORTD|=0b00000001;break;//1内部
case0b01111011:
floor_des[2]=2;PORTD|=0b00000010;break;//2
case0b11100111:
floor_des[3]=3;PORTD|=0b00000100;break;//3
case0b11010111:
floor_des[4]=4;PORTD|=0b00001000;break;//4
case0b10110111:
floor_des[5]=5;PORTD|=0b00010000;break;//5
case0b01110111:
floor_des[0]=6;PORTD|=0b00100000;break;//6
default:
break;//键盘对应的楼层号的设置,记录等待楼层号
}
}
}
}
voiddelay(intms)//延时函数
{
inti,j;
for(i=0;i{
for(j=0;j<111;j++);
}
}
voidtoNext(intfn,intfg)//去往下一次
{
intdis=fn-fg;
//floor_now=fg;
PORTA=data[floor_now];
if((dis==0)||(fg==0))
{
PORTD&=0b00111111;
delay(500);
}
elseif(dis>0)//去的楼在当前楼的下面
{
direction=0;
downstair(dis);
}
elseif(dis<0)//去的楼在当前楼的上面
{
direction=1;
upstair(-dis);
}
}
voidupstair(intdis)//上楼
{
light
(2);
intdiv=abs(dis);
light(direction);
while(div>0)
{
clean(floor_now,floor_wait,floor_des);
for(intk=0;k<6;k++)
{
if((floor_des[k]!
=0)||(floor_wait[k]!
=0))
{
if(k==0){PORTD|=0b00100000;}
else{PORTD|=(1<<(k-1));}
}
else
{
if(k==0){PORTD&=0b11011111;}
else{PORTD&=~(1<<(k-1));}
}
}
PORTD|=0b10000000;
PORTD&=0b10111111;
for(inti=0;i<1500;i++)
{
keyscan();
while
(1)
{
if(!
(PINC&0b00000010))//按下
{
while(!
(PINC&0b00000010))
{
PORTD&=0b00111111;
alarm();
}
PORTD&=0b10111111;
PORTD|=0b10000000;
break;
}
else{PORTD&=0b10111111;PORTD|=0b10000000;break;}
//if(PINC&0b00000010)
//{PORTD&=0b00111111;break;}
}
}
div--;
floor_now++;
PORTA=data[floor_now];
//clean(floor_now,floor_wait,floor_des);
if((floor_wait[floor_now]!
=0)||(floor_des[floor_now]!
=0))
{
PORTD&=0b00111111;
alarm();
delay(500);
clean(floor_now,floor_wait,floor_des);
}
clean(floor