单片机 AVR 流水灯 闹钟等_单片机流水灯实验步骤
单片机 AVR 流水灯 闹钟等由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“单片机流水灯实验步骤”。
AVR单片机实验报告
班级: 学号:
班内序号: 姓名: Email: 同组姓名:
实验一:流水灯的设计和实现
实验原理图:
实验原理:
AVR单片机的高低电平和TTL电路的一致,即 高电平=5V,低电平=0V。AVR单片机的驱动能力比51单片机强,可以直接驱动LED。所以将8个LED二极管正极接在ATmega16的PD0~PD7端口,负极经过限流电阻接到GND,通过控制PD口的电平的高低,就可以实现LED的亮灭。
实验源程序:
实验程序使用iccavr编译器编译:
#include #include
void delay(int ms)
{
int i,j;
for(i=ms;i>0;i--)
//延时函数
for(j=0;j
void main(){
int i;
} DDRA=0XFF;
while(1){
for(i=0;i
{
PORTA|=BIT(i);
delay(1000);
PORTA&=~BIT(i);} }
//配置PD端口为输出
//循环逐次显示每个LED二极管
实验心得体会:
通过学习,首先我了解了一些关于单片机的知识,包括单片机的分类,功能等,还有软硬件结合编程使用单片机,单片机的编程语言和EDA的使用,比如ICCAVR,AVR Studio 4等。
其次我了解了AVR单片机的一些基本知识,学会了控制端口的输入输出方向,和电平的高低的方法。同时,AVR单片机的C语言编程基本和标准C语言一致,它在C语言的基础上,添加了一些适合单片机的头文件。所以,在编程方面我遇到的障碍不是很大。
我觉得最大的收获是学会怎么看相关的技术文档,技术文档一般内容很多,并且都是以前没有学过的知识,所以快速的查阅到自己想看的内容,是一件很有学问的能力。
实验二:交通灯
实验原理图:
实验原理:
数码管有共阴和共阳两种,8段数码管由8段LED组成,共阴极数码管的8段LED的阴极相连,共用一个阴极;共阳极数码管的8段LED的阳极相连,共用一个阳极。
控制数码管的方式有两种。第一种为静态显示,这种方式的优点是原理简单,编写程序容易,而且二极管的亮度比较亮,缺点是占用的端口多,单片机上的I/O口资源很珍贵,所以这种方式一般不采用。第二种是动态控制显示二级管,这种方式的优点是节省端口资源,缺点是程序编写不容易,而且,二极管的亮度比较暗。
实验源程序:
1.静态实现:
#include #include
void delay(unsigned int ms){
int i,j;
for(i=0;i
for(j=0;j
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main(){
int i,j;DDRA=0XFF;
//LED
DDRB=0XFF;
//数码管DDRD=0XFF;
//数码管while(1){
for(i=2;i>=0;i--)
//绿灯
{
PORTA=0X01;
PORTB=table[i];
for(j=9;j>=0;j--)
{
PORTD=table[j];
delay(1000);
}
}
//黄灯
PORTA=0X02;
PORTB=table[0];
for(j=9;j>=0;j--)
{
PORTD=table[j];
delay(1000);
}
//红灯
for(i=2;i>=0;i--)
{
PORTA=0X04;
PORTB=table[i];
for(j=9;j>=0;j--)
{
PORTD=table[j];
delay(1000);
}
} } }
2.动态实现:
#include #include
void delay(unsigned int ms){
int i,j;
for(i=0;i
for(j=0;j
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main(){
int i,j,k;DDRD=0XFF;//位选
DDRB=0XFF;//段选
while(1){
//绿灯
for(i=2;i>=0;i--)
for(j=9;j>=0;j--)
for(k=1;k
{
PORTB=table[i];
PORTD=0b11111010;
}
delay(1);
PORTB=table[j];
PORTD=0b11111001;
delay(1);
} //黄灯
for(i=0;i>=0;i--)
for(j=9;j>=0;j--)
for(k=1;k
{
PORTB=table[i];
PORTD=0b11110110;
delay(1);
PORTB=table[j];
PORTD=0b11110101;
delay(1);
} //红灯
for(i=2;i>=0;i--)
for(j=9;j>=0;j--)
for(k=1;k
{
PORTB=table[i];
PORTD=0b11101110;
delay(1);
PORTB=table[j];
PORTD=0b11101101;
delay(1);
} }
实验心得:
通过学习,首先我学会了8段数码管的基本原理,以及共阴,共阳两种二极管的连接方式,还有二极管的两种控制方式:静态显示和动态显示。
其次,通过交通灯的程序编写,我进一步学习了单片机的C语言程序的编写,同时学会了在ICCAVR和AVR Studio中怎样软仿真调试程序和硬仿真调试,比如单步执行,设置断点,观察变量的地址和值的变化等。
实验三:蜂鸣器
实验原理图:
实验原理:
与AVR 单片机的I/O口相关的寄存器有3个,DDRx,PORTx,PINx.通过C语言中的条件控制语句if语句,判断端口的寄存器的值,可以实现检测开关是否按下,编写程序控制蜂鸣器,使其在按键开关按下的时候鸣响。当开关断开时不响。
实验源程序: #include #include int main(void){ DDRD &= ~(1
DDRA |=(1
while(1){
if(PIND &(1
{
PORTA &= ~(1
}
else
{
PORTA |=(1
} } }
实验心得:
通过学习,首先,我学会了蜂鸣器的电路原理以及在ATmega16最小系统下,将蜂鸣器接入电路的方式。
其次我学会了通过I/O的寄存器的值查询按键是否按下。编写程序,控制蜂鸣器的正极的电平的高低,使得在开关按下的时候,蜂鸣器正极为高电平,当开关断开时,蜂鸣器的正极为低电平。实验四:秒表计时器
实验原理图:
实验原理:
当计算机执行正常程序时,系统中会出现某些急需处理的异常情况和特殊请求,此时CPU会暂时中止执行程序,转去对随机发生的更为紧迫的事件进行处理,处理完毕后,CPU自动返回原来的程序继续执行,此过程就叫做中断。实现中断功能的硬件和软件统称为中断系统。
ATmega16单片机中有2个8位和1个16位定时/计数器。可以利用定时/计数器和中断来实现秒表的功能。实验源程序:
#include #include #define uchar unsigned char #define uint unsigned int uchar num=0;#pragma interrupt_handler miao:9
const table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(uint ms){
uint i,j;for(i=0;i
{
for(j=0;j
} }
void miao(){
if(num==60)
num=0;num++;TCNT1H=0X85;TCNT1L=0XED;} void main(){
TCCR1B=0X04;//控制寄存器,分频
TCNT1H=0X85;//计数器寄存器
TCNT1L=0XED;//
TIMSK|=BIT(2);//中断屏蔽寄存器
SREG|=BIT(7);//
DDRB=0XFF;DDRD=0XFF;
while(1){
PORTB=table[num/10];
} PORTD=table[num%10];}
实验心得:
通过这个实验,首先我了解了中断的含义。
其次,我了解了ATmega16单片机的内部中断源有哪些,中断的触发方式和中断函数的编写。
并且,我了解了ATmega16单片机内部的计数器的工作原理和分类。通过计数器和中断函数的编写,可以实现秒表的功能。
综合实验:闹钟的设计和实现
实验原理图:
实验原理:
使用ATmega16 单片机为控制系统,利用1602液晶显示器和4×4的键盘,DS1302时钟芯片组成一个闹钟系统。
我们在设计的时候对DS1302不是很了解,在具体做实验的时候,通过向老师的请教,了解到DS1302芯片使用时外接晶振,需要配置ATmega16的熔丝位,可能会锁死芯片。所以,在老师的建议下,我们采用软件模拟DS1302的功能,实现闹钟的功能。DS1302外接晶振,可以准确计时,我们通过函数仿真的形式,对时间的计时不是非常准确,但是原理与DS1302类似,而且误差比较小。
我们通过编写程序,闹钟实现的功能有 年-月-日-星期-时-分-秒 的计时(实现DS1302的功能,可以对闰年,平年,各个月份都适应),同时可以进行24/12小时进制的转换,AM/PM显示,可以设置闹钟的当前时间,设置闹钟时间,并且闹钟可中断。
实验源程序:
主程序文件:
#include
//包含型号头文件 #include
//包含“位”操作头文件 #define uchar unsigned char #define uint unsigned int
#define TRUE 1 #define FALSE 0 #include “YJ1602.C”
//包含1602液晶函数文件 #include “jianpan.c” //包含4×4键盘函数文件
uchar time_24[7]={0x50,0x58,0x23,0x01,0x09,0x07,0x11};//设置的秒,分,时,日,月,星期,年
uchar time_12[7]={0x50,0x58,0x23,0x01,0x09,0x07,0x11};//设置的秒,分,时,日,月,星期,年
uchar clock[7]={0x50,0x58,0x23,0x01,0x09,0x07,0x11};//设置闹钟的秒,分,时
uchar key;
//存储检测到的键盘值
void set_time(){
uchar i,j,tmp1,tmp2;uchar newtime[]={0x50,0x58,0x23,0x01,0x09,0x07,0x11};write_com(0x38);//设置显示
Delayms(5);write_com(0x01);//清屏
Delayms(5);write_com(0x80+0x05);write_com(0x0f);//显示光标
Delayms(5);write_com(0x06);//显示字符开关
Delayms(5);
//时
j=0;
while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x05);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x06);
write_dat(jianpan[key]);
tmp2=key;
j++;
} } newtime[2]=tmp1+tmp2;
write_com(0x80+0x07);write_dat(':');
//分
Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x08);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } j=0;Delayms(1000);while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x09);
write_dat(jianpan[key]);
tmp2=key;
j++;
} } newtime[1]=tmp1+tmp2;
write_com(0x80+0x0a);write_dat(':');
//秒
Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x0b);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x0c);
write_dat(jianpan[key]);
tmp2=key;
j++;
} } newtime[0]=tmp1+tmp2;
for(i=0;i
time_24[i]=newtime[i];} Disp_time(time_24);
}
void set_clock(uchar clock[]){
uchar i,j,tmp1,tmp2;write_com(0x38);//设置显示
Delayms(5);write_com(0x01);//清屏
Delayms(5);write_com(0x80+0x05);write_com(0x0f);//显示光标
Delayms(5);write_com(0x06);//显示字符开关
Delayms(5);
//时
j=0;
while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x05);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } Delayms(1000);j=0;
while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x06);
write_dat(jianpan[key]);
tmp2=key;
j++;
}
} clock[2]=tmp1+tmp2;
write_com(0x80+0x07);write_dat(':');
//分
Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x08);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } j=0;Delayms(1000);while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x09);
write_dat(jianpan[key]);
tmp2=key;
j++;
} } clock[1]=tmp1+tmp2;
write_com(0x80+0x0a);write_dat(':');
//秒
Delayms(1000);j=0;while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x0b);
write_dat(jianpan[key]);
tmp1=key*16;
j++;
} } Delayms(1000);j=0;
while(j
if(key_pre())
{
key=key_scan();
write_com(0x80+0x0c);
write_dat(jianpan[key]);
tmp2=key;
j++;
} } clock[0]=tmp1+tmp2;
for(i=3;i
clock[i]=time_24[i];} Disp_time(clock);write_com(0x0c);//光标不显示
Delayms(3000);}
/******************************************* 函数名称: add 功
能: 完成1302的功能,每1s自动加1 参
数: time当前时间 返 回 值: 无
/********************************************/ void add(uchar time[]){
uchar i,j,k,r,y,x,n;k=time[0]/16*10+time[0]%16;j=time[1]/16*10+time[1]%16;i=time[2]/16*10+time[2]%16;r=time[3]/16*10+time[3]%16;
y=time[4]/16*10+time[4]%16;x=time[5]/16*10+time[5]%16;n=time[6]/16*10+time[6]%16;if(k==59)
{ Delayms(1000);k=0;j++;
if(j==60){
j=0;
i++;
if(i==24)
{
i=0;
if(y==1|y==3|y==5|y==7|y==8|y==10|y==12)
{
if(r==31)
{
r=1;
x++;
if(x==8)
x=1;
y++;
if(y==13)
{
y=1;
n++;
}
}
else
{
r++;
x++;
if(x==8)
x=1;
}
}
if(y==4|y==6|y==9|y==11)
{
if(r==30)
{
r=1;
x++;
if(x==8)
x=1;
y++;
}
else
{
r++;
x++;
if(x==8)
x=1;
} }
if(y==2&(n%4!=0)){
if(r==28)
{
r=1;
x++;
if(x==8)
x=1;
y++;
}
else
{
r++;
x++;
if(x==8)
x=1;
} }
if(y==2&(n%4==0)){
if(r==29)
{
r=1;
x++;
if(x==8)
x=1;
y++;
}
else
{
r++;
x++;
if(x==8)
x=1;
}
}
}
}
}
else
{
Delayms(1000);
k++;
} time[0]=(k/10)*16+k%10;time[1]=(j/10)*16+j%10;time[2]=(i/10)*16+i%10;time[3]=r/10*16+r%10;time[4]=y/10*16+y%10;time[5]=x/10*16+x%10;time[6]=n/10*16+n%10;}
/******************************************* 函数名称: BCD_ASCII 功
能: 将压缩的BCD码转化为ASCII码 参
数: BCD—将要转化的压缩BCD码
ptasc—转化后的ASCII码数组指针
返 回 值: 无
/********************************************/ void BCD_ASCII(uchar BCD,uchar ptasc[]){
ptasc[0]=(BCD/0x10)|0x30;//0X58 35 38 //转化十位
ptasc[1]=BCD&0x0F|0x30;//转化个位 }
/******************************************* 函数名称: Disp_time 功
能: 在1602液晶上显示当前时间(第一行格式:年-月-日-星期;第二行格式:时-分-秒)
参
数: time[]—当前时间 返 回 值: 无
/********************************************/ void Disp_time(uchar time[]){ uchar i,asc[2];uchar line1[11]={0,0,'-',0,0,'-',0,0,' ',0,' '};//显示第一行的字符
uchar line2[9]={0,0,':',0,0,':',0,0,' '};
//显示第二行的字符数组
for(i=0;i
//为第二行的字符数组赋值 { BCD_ASCII(time[2-i],asc);line2[i*3]=asc[0];line2[i*3+1]=asc[1];}
BCD_ASCII(time[6],asc);
//为第一行的年复制 line1[0]=asc[0];line1[1]=asc[1];BCD_ASCII(time[4],asc);
//为第一行的月赋值 line1[3]=asc[0];line1[4]=asc[1];BCD_ASCII(time[3],asc);
//为第一行的日赋值 line1[6]=asc[0];line1[7]=asc[1];BCD_ASCII(time[5],asc);
//为第一行的星期赋值 line1[9]=asc[1];
while(LCD1602_readBF());LCD1602_gotoXY(1,2);
始显示
LCD1602_sendstr(“20”);2007
LCD1602_sendstr(line1);
while(LCD1602_readBF());
//第一行从第三个位置开
//将07年显示为
//第一行显示
LCD1602_gotoXY(2,4);
//第二行从第五个位置开始显示
LCD1602_sendstr(line2);
//第二行显示 }
/******************************************* 函数名称: main 功
能:1.在1602上显示当前时间 2.可以设置时间
参
数: 无 返 回
值: 无
/********************************************/ void main(void){
uchar i,j,k,tmp1,tmp2,tmp;
uchar dis_x,dis_y;
//存储1602光标的当前位置 uchar flag=0,c_flag=0;
//默认24小时显示,闹钟默认关 LCD1602_initial();//初始化1602
PORTD&=~BIT(PD0);//初始化闹钟,闹钟默认关 Disp_time(time_24);//显示当前时间
while(1)
//以下程序完成显示和设置时间 {
add(time_24);
for(i=0;i
{
time_12[i]=time_24[i];
}
if((time_24[2]/16*10+time_24[2]%16)>12)
{
tmp1=time_24[2]/16;
tmp2=time_24[2]%16;
tmp=tmp1*10+tmp2-12;
time_12[2]=tmp/10*16+tmp%10;
}
if(key_pre())
{
key=key_scan();
if(key==10)
//A设置显示方式
flag=~flag;
if(key==11)
//B设置当前是将
{
set_time();
}
if(key==12)
//C设置闹钟时间
{
Delayms(1000);
set_clock(clock);
}
if(key==13)
//D控制闹钟开关
c_flag=~c_flag;
} if(c_flag){
write_com(0x80+0x40);
write_dat('@');} else
{
PORTD&=~BIT(PD0);
write_com(0x80+0x40);
write_dat(0x20);
write_com(0x80+0x42);
write_dat(0x20);
}
if(flag)
Disp_time(time_12);
else
Disp_time(time_24);
if(time_24[2]
{
LCD1602_gotoXY(2,14);
LCD1602_sendstr(“AM”);
}
else
{
LCD1602_gotoXY(2,14);
LCD1602_sendstr(“PM”);
}
if((clock[0]==time_24[0])&(clock[1]==time_24[1])&(clock[2]==time_24[2]))
{
if(c_flag)
{
DDRD|=BIT(PD0);
PORTD|=BIT(PD0);
write_com(0x80+0x42);
write_dat(0x24);
write_com(0x0c);//光标不显示
}
} } } YJ1602.C和jianpan.c省略,在附件压缩包内 实验 过程&结果
实验心得:
通过这次AVR单片机的实验,我学习到了很多知识。
实验的第一天,我们听老师讲解了一些关于单片机的内容后,就开始看教学视频和相关的资料学习AVR单片机。在假期的时候,我预习了一下单片机的内容,从图书馆内借了几本关于51单片机的书。直到第一天上课,我才知道我们学习的是AVR单片机。于是我到图书馆里面又借了几本关于AVR的书。
从第二天开始,我和我的搭档领到实验板和实验器材后,就开始正式的学习。在接下来的4天时间里,我通过看视频教程和相关的技术文档,还有图书馆的书,比较全面地了解了一些AVR单片机的知识。从最基础的I/O的控制,到中断系统的使用,以及一些其他的原件的使用,比如蜂鸣器,按键开关,共阴极8段数码管等。通过学习,我们做了4个小实验,分别是流水灯,交通灯,蜂鸣器和秒表计数器。
在做这4个小实验的时候,由于我们一开始学习的知识不是很多,对开发板和其他原件的使用方法不够了解,出现了一些莫名其妙的问题,我们开始以为是自己的开发板出现故障,后来在老师的指导下,我学会了逐步检查电路的问题,按照一定的次序,我逐一检查,最后终于发现问题,并解决问题。在实验过程中,我遇到的问题可以分为两类:软件和硬件。在软件方面,我学习了两种编译器的使用,分别是ICCAVR和GCC编译器。在不同的编译器内,有不同的函数和定义,所以,在编译仿真的时候,我一开始遇到了一些软件方面的问题,比如编译失败,下载不到板子上等。后来,经过查阅书籍,我基本上掌握了他们的区别和联系,可以保证编译,下载不出问题。在硬件方面,我遇到的问题主要是连线问题和原件出故障。后来听老师讲解,发现是自己连接的时候没有限流导致故障。原件出故障后,换了一个新的以后问题也解决了。
综合实验,由于小车不够,我和同组的郭晋开始着手写计划和流程图。经过再三考虑我们决定做一个电子钟,因为这个涉及到了DS1302芯片的使用,需要查阅更多资料,而且在完成基本功能的同时,还可以添加其他附加的东西。由于对整个单片机的运行机制并不了解,所以在写流程图的时候,我们只用了最平实的框架描述,为后来的编程打了个草稿。可实现性我们写得比较详细,我觉得这个对我们后来的功能拓展帮助很大。
第二天我们开始编程,我负责液晶的初始化和显示。遇到了很多困难,首先就是不知道该从哪下手,因为我并没有在书上找到类似的例子,最后通过请教其他同学才知道应该多看教学视频,但是没太看懂,最后在参考了别人的程序后,我明白了液晶屏显示的原理,最后初始化和显示成功了。
之后我们很容易的完成了键盘和液晶连接,然后我们就开始着手DS1302的研究。手头只有一份英文的芯片说明,看了一天也只明白了个大概。晚上回寝室的时候,我上网查了很多资料,有中文的说明,也有其他语言编写的程序。第二天到机房继续研究,基本搞明白了芯片的读写原理,开始编程。编程的过程并不顺利,我们总是遇到一个个误区,困惑很长时间才明白过来,然后继续写。通过这次对DS1302芯片的研究,我认为当接触一个新的芯片时,首先要了解的就是芯片各个管脚的使用,哪些管脚是由单片机控制的,哪些管脚接高低电平;其次应该知道芯片的读写原理,是利用时钟的上升沿还是下降沿;编写好程序之后,最好采用硬件调测,观察芯片中数据的变化,是否和自己所了解的一样。因为判别哪些是芯片的功能,哪些是编程来实现的事在调测中不断发现的。
小学期后期的大部分时间都是在不断调测中度过的,不断编写、下载、检测„„正如老师所说的那样,一个困难摆在面前是巨大的,但当解决以后才发现也许只是一个小问题,但发现问题的过程却十分困难。在这次小学期的过程中,我觉得锻炼最大的就是发现问题的能力,有些问题能一直困扰我们好几天。比如上下午的翻转问题,我们研究了快四天,有时候实在没有思路,就先编写其他功能,然后再想这个问题。但克服了这个困难之后,我们的编程能力一下提高很多,思路开阔了不少,接下来的编程都十分的轻松。
另外,在写实验报告的时候,我们才开始真正理清了设计思路,或者说两个人的设计才更好的整合。我想如果当初在开始编程之前,对单片机的了解更透彻,设计好步骤,各个子程序,一定会大大提高我们的工作效率。我想在以后的学习中都是值得借鉴的一点。
最后我想说的是,两个人的协作问题。这次小学期,我和郭晋的合作十分愉快,既有独立工作的一面,也有共同协作的一面。刚开始的键盘和液晶是我们分开完成的,但开始入手DS1302的时候,遇到的问题大家便开始一起讨论,分析问题产生的原因。如果一方遇到了困难,就会告诉另一个人自己的设计思路,让他帮助查找错误。有时候我们遇到了问题,很长时间都没有结果,我们就静下心来休息一会,这之后往往会有答案。我想两人一组的实验,并不是要依靠谁强谁的工作量就大,而是大家都不断努力,始终保持同样的步伐。
三周的单片机小学期,我的收获很多,也发现了自己的更多潜能。在接下来的学习中,我会更加努力,善于思考,勇于创新。