单片机 AVR 流水灯 闹钟等_单片机流水灯实验步骤

2020-02-27 其他范文 下载本文

单片机 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的时候,遇到的问题大家便开始一起讨论,分析问题产生的原因。如果一方遇到了困难,就会告诉另一个人自己的设计思路,让他帮助查找错误。有时候我们遇到了问题,很长时间都没有结果,我们就静下心来休息一会,这之后往往会有答案。我想两人一组的实验,并不是要依靠谁强谁的工作量就大,而是大家都不断努力,始终保持同样的步伐。

三周的单片机小学期,我的收获很多,也发现了自己的更多潜能。在接下来的学习中,我会更加努力,善于思考,勇于创新。

《单片机 AVR 流水灯 闹钟等.docx》
将本文的Word文档下载,方便收藏和打印
推荐度:
单片机 AVR 流水灯 闹钟等
点击下载文档
相关专题 单片机流水灯实验步骤 单片机 闹钟 流水 单片机流水灯实验步骤 单片机 闹钟 流水
[其他范文]相关推荐
    [其他范文]热门文章
      下载全文