_delay_ms(250);
}
}
(二)LED指示灯循环显示程序设计实验
1、实验目的
(1).熟悉LED指示灯电路原理图;
(2).学会单片机C语言I/O端口编程控制方法;
(3).学会外部显示部件LED灯的软件编程使用方法;
(4).进一步熟悉单片机实验开发系统的使用。
2、实验设计电路原理
LED指示灯的硬件电路连接如图2-1所示。
图2-1LED指示灯的硬件连接图
注:
LED_CS与ATmega128的PC5相连。
在图2-1所示的LED模块接口电路中,8个LED指示灯阳极通过限流电阻与电源连接,当锁存器的输出端(Q0~Q7)引脚Qn(0≤n≤7)输出低电平时,将点亮编号为DS20X(X=n+1)的LED灯;反之,则将熄灭LED灯。
一次基本的LED操作应按照如图2-2所示的LED灯基本操作流程进行。
图2-2LED灯基本操作流程
第一步端口初始化,在这个步骤中,驱动程序将与锁存器数据输入端(D0~D7)相连的MCU的8条引脚所对应的端口PB初始化为输出模式;并且将与锁存器的锁存使能端(LE)相连的MCU引脚PC5(LED_CS)初始化为输出模式。
然后通过PORTB口输出显示状态码,低电平的LED位灯亮,高电平的LED位灯灭。
PC5(LED_CS)高电平有效使能端。
3、实验内容
设计程序能够实现变换五种不同的显示方式,并能循环显示。
4、程序源代码
#include
#include
#include"led.h"
voidLED_Init()
{
PORTB=PB_MASK;
DDRB=PB_MASK;
PORTC|=_BV(LED_CS);
DDRC|=_BV(LED_CS);
}
intmain()
{
inti;
uint8_tled_sel;
LED_Init();
while
(1){
i=0;
led_sel=0x01;
while(i<3){
PORTB=~led_sel;
_delay_ms(300);
if(led_sel==0x80){
led_sel=0x01;
++i;
}
else
led_sel*=2;
}
i=0;
led_sel=0x80;
while(i<3){
PORTB=~led_sel;
_delay_ms(300);
if(led_sel==0x01){
led_sel=0x80;
++i;
}
else
led_sel/=2;
}
for(i=0;i<3;++i){
PORTB|=PB_MASK;
_delay_ms(500);
PORTB&=~PB_MASK;
_delay_ms(500);
}
led_sel=0x01;
i=0;
while(i<3){
PORTB=~led_sel;
_delay_ms(300);
if(led_sel==0x40){
led_sel=0x01;
i++;
}
else
led_sel*=4;
}
led_sel=0x02;
i=0;
while(i<3){
PORTB=~led_sel;
_delay_ms(300);
if(led_sel==0x80){
led_sel=0x02;
i++;
}
else
led_sel*=4;
}
}
return0;
}
Led.h
#ifndefLED_H
#defineLED_H
#defineLED_CSPC5
#definePB_MASK0xFF
voidLED_Init();
#endif
(三)数码管动态显示程序设计
1、实验目的
(1).熟悉单片机数码管电路结构原理;
(2).学会单片机C语言I/O端口编程控制方法;
(3).学会外部显示部件LED灯的软件编程使用方法;
(4).学会单片机开发系统的软件调试方法。
2、实验设计电路原理
数码管硬件电路连接如图3-1所示。
图3-1数码管硬件电路连接图
注:
DIG_CS1、DIG_CS2分别与ATmega128的PG3、PG4相连。
数码管的编程基本操作包括两个步骤:
一是位码操作;二是段码操作。
所谓“位码操作”,是指选定将要进行显示的某一位数码管;所谓“段码操作”,是指输出欲显示的字符的段码。
本模块中,有两个四位数码管拼接而成了八位数码管,所以位码共有8种选择。
对于共阳极数码管的基本段码表详见附录1中的共阳极数码管基本段码表,自定义扩充的段码表详见附录1中的共阳极数码管自定义扩充段码表。
一次基本的数码管操作应按照如图2所示的数码管编程基本操作流程进行。
图3-2数码管编程基本操作流程
第一步:
端口初始化。
在这个步骤中,驱动程序将与锁存器数据输入端(D0~D7)相连的MCU的8条引脚所对应的端口PB初始化为输出模式;并且将与位码锁存器的锁存使能端(LE)相连的MCU引脚(DIG_CS1)和与段码锁存器的锁存使能端(LE)相连的MCU引脚(DIG_CS2)初始化为输出模式。
第二步:
关闭段码锁存器,使能位码锁存器。
此时MCU通过对段码锁存器的锁存使能端(LE)输出低电平,即可关闭段码锁存器;MCU通过对位码锁存器的锁存使能端(LE)输出高电平,即可使能位码锁存器。
第三步:
送数码管位码。
MCU通过端口PB输出数码管位码,指定将要进行显示的某位数码管。
当MCU引脚PBn(0≤n≤7)输出为高电平时,从右至左编号为第n+1位的数码管将被用于显示;当MCU引脚PBn(0≤n≤7)输出为低电平时,则从右至左编号为第n+1位的数码管未被选中。
例如,若输出PB=0x81将选中编号(从右至左编号)为第8位和第1位的数码管,其余6位数码管则未被选中。
注意:
在送数码管位码期间,应确保段码锁存器处于关闭状态,而位码锁存器处于使能状态。
第四步:
关闭位码锁存器,使能段码锁存器。
此时MCU通过对位码锁存器的锁存使能端(LE)输出低电平,即可关闭位码锁存器;MCU通过对段码锁存器的锁存使能端(LE)输出高电平,即可使能段码锁存器。
第五:
送数码管段码。
MCU通过端口PB输出数码管共阳极段码,用于在指定的某位数码管上显示特定的字符。
例如,根据附录1中给出的共阳极数码管基本段码表,此时若输出PB=0xc0,则被选中的某位数码管将显示数字字符“0”。
注意:
在送数码管段码期间,应确保位码锁存器处于关闭状态,而段锁存器处于使能状态。
第六步:
关闭段码锁存器。
此时MCU通过对段码锁存器的锁存使能端(LE)输出低电平,即可关闭段码锁存器。
当位码锁存器和段码锁存器同时处于关闭状态时,数码管的显示状态将不再受MCU端口PB输出的影响。
表附录3-1共阳极数码管基本段码表
字符
h
g
f
e
d
c
b
a
共阳极段码
0
0
0
1
1
1
1
1
1
0xc0
1
0
0
0
0
0
1
1
0
0cf9
2
0
1
0
1
1
0
1
1
0xa4
3
0
1
0
0
1
1
1
1
0xb0
4
0
1
1
0
0
1
1
0
0x99
5
0
1
1
0
1
1
0
1
0x92
6
0
1
1
1
1
1
0
1
0x82
7
0
0
0
0
0
1
1
1
0xf8
8
0
1
1
1
1
1
1
1
0x80
9
0
1
1
0
1
1
1
1
0x90
A
0
1
1
1
0
1
1
1
0x88
b
0
1
1
1
1
1
0
0
0x83
C
0
0
1
1
1
0
0
1
0xc6
d
0
1
0
1
1
1
1
0
0xa1
E
0
1
1
1
1
0
0
1
0x86
F
0
1
1
1
0
0
0
1
0x8e
表附录1-2共阳极数码管自定义扩充段码表
字符
h
g
f
e
d
c
b
a
共阳极段码
-
0
1
0
0
0
0
0
0
0xbf
.
1
0
0
0
0
0
0
0
0x7f
全亮
1
1
1
1
1
1
1
1
0x00
全灭
0
0
0
0
0
0
0
0
0xff
3、实验内容
设计实现8位数码管能够自动进位计数显示的功能程序,并在实验系统平台完成编译、调试、下载验证,运行结果正确。
4、程序源代码
//**文件名:
digitron.c
//**功能:
8位数码管依次循环显示
//**说明:
数码管共阳极连接
#include
#include
//#include"digitron.h"
#ifndefDIGITRON_H
#defineDIGITRON_H
#defineDIG_CS1PG3
#defineDIG_CS2PG4
#definePB_MASK0xFF
voidDIG_Init();
#endif
uint8_tcode[16]={0xC0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
voidDIG_Init()
{
PORTB=~PB_MASK;
DDRB=PB_MASK;
PORTG&=0x00;
DDRG|=_BV(DIG_CS1)|_BV(DIG_CS2);
}
intmain()
{
inti=0;
intj=0;
intcom=1;
//intb=1;
DIG_Init();
inta[8]={0};
while
(1){
for(j=0;j<50;j++){
for(i=0;i<8;++i){
PORTG|=_BV(DIG_CS2);
PORTG&=~_BV(DIG_CS1);
PORTB=code[a[7-i]];
PORTG|=_BV(DIG_CS1);
PORTG&=~_BV(DIG_CS2);
PORTB=com;
com*=2;
PORTG&=~_BV(DIG_CS1);
PORTG&=~_BV(DIG_CS2);
_delay_ms
(1);
if(com>128)
com=1;
}
}
a[0]++;
for(i=0;i<8;i++)
{
if(a[i]>15)
{
a[i]-=16;
a[i+1]++;
//b++;
}
}
}
return0;
}
(四)定时/计数器中断应用程序设计
1、实验目的
(1)熟悉单片机内部定时/计数器的工作原理;
(2)了解单片机中断机制工作原理;
(3)掌握单片机中断服务程序的设计方法;
(4)了解定时计数器的功能及应用。
2、实验设计电路原理
单片机的中断分为软中断(内部中断)和硬中断(外部中断)两种。
所谓软中断指软件中断,例如定时器定时中断,这类中断是程序员根据需要设置的,是可以预测的中断。
而所谓硬中断是另一类不可预测的中断类型,例如单片机的端口输入中断。
这一类中断程序员事先并不能预测何时发生。
中断的重要意义在于其能够及时响应对应的事件,当某种紧急事件发生时,使用中断功
能,CPU能够立刻暂停当前的程序运行,转而执行中断服务程序,在中断服务程序执行完毕
后再返回原来的程序继续运行,以保证对紧急事件的实时响应。
ATmega128单片机有2个具有独立预分频器和比较器功能的8位定时器/计数器——
T/C0、T/C2,以及有2个具有独立预分频器、比较器功能和捕获功能的16位定时器/计数
器——T/C1、T/C3。
程序设计相关寄存器说明:
1.16位T/C1数据寄存器——TCNT1H和TCNT1L,组成16位计数单元。
2.16位T/C1输出比较寄存器——OCR1AH和OCR1AL,存放16位比较数值。
3.16位T/C1控制寄存器——TCCR1A,设置通道比较输出模式;
——TCCR1B,时钟分频设置。
4.定时器/计数器中断屏蔽寄存器——TIMSK,中断使能设置。
3、实验内容
修改示例程序中断服务程序的功能,自己设计实现用8位数码管显示的电子钟功能程序,并在实验系统平台完成编译、调试、下载验证,运行结果正确。
4、程序源代码
/*------------------------------------------------------------
文件名称:
TIMERl_INT.C
功能:
16位定时器/计数器1,中断方式使用,控制蜂鸣器发声
说明:
定时器/计数器1,8MHz下,时钟256分频,定时时间0.5s
--------------------------------------------------------------*/
#include
#include
#include"digitron.h"
#include
/********************************************
函数名称:
SIGNAL(SIG_OUTPUT_COMPARE1A)
功能:
定时器/计数器1比较匹配中断的中断服务程序
说明:
重置计数初值,并对PE3端口取反,开/关声响
入口参数:
无
返回值:
无
*********************************************/
inta[6]={1,2,2,2,1,2};
uint8_tcode[16]={0xC0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
//intb[2]={0};
voidDIG_Init()
{
PORTB=~PB_MASK;
DDRB=PB_MASK;
PORTG&=0x00;
DDRG|=_BV(DIG_CS1)|_BV(DIG_CS2);
}
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
TCNT1H=0x00;//T/C1计数值清零
TCNT1L=0x00;
//对PE3取反,0.5秒改变一次
/*if(PORTE&_BV(PE3))
PORTE&=~_BV(PE3);//输出低电平
else
PORTE|=(1</*inti=0;
intj=0;
intcom=1;
for(j=0;j<50;j++){
for(i=0;i<4;++i){
PORTG|=_BV(DIG_CS2);
PORTG&=~_BV(DIG_CS1);
PORTB=code[a[i]];
PORTG|=_BV(DIG_CS1);
PORTG&=~_BV(DIG_CS2);
PORTB=com;
com*=2;
PORTG&=~_BV(DIG_CS1);
PORTG&=~_BV(DIG_CS2);
_delay_ms
(1);
if(com>8)
com=1;
}
}*/
a[0]++;
if(a[0]>9){
a[0]=0;
a[1]++;
}
if(a[1]>5){
a[1]=0;
a[2]++;
}
if(a[2]>9){
a[2]=0;
a[3]++;
}
if(a[3]>5){
a[3]=0;
a[4]++;
}
if(a[4]>9){
a[4]=0;
a[5]++;
}
if(a[5]==2&&a[4]==4){
a[4]=0;
a[5]=0;
}
}
//主程序
voidmain(void)
{
//DDRE=_BV(PE3);//初始化端口PE3为输出模式
//PORTE&=_BV(PE3);//输出高电平,蜂鸣器禁止发声
TCCR1B=0x00;//中断控制寄存器清零,停止T/Cl计数
OCR1AH=0x7A;//设置8MHz、256分频、定时0.5s的比较值,
OCR1AL=0x12;//与TCNTl的计数值进行比较,若匹配产生中断
TCCR1A=0x00;//T/C1普通端口模式
TCCR1B=0x04;//启动定时器T/C1,256分频
TIMSK|=0x10;//使能C/Tl比较匹配中断
sei();
inti=0;
intj=0;
intcom=128;
DIG_Init();//允许全局中断
while
(1){
for(i=0;i<6;++i){
PORTG|=_BV(DIG_CS2);
PORTG&=~_BV(DIG_CS1);
PORTB=code[a[i]];
PORTG|=_BV(DIG_CS1);
PORTG&=~_BV(DIG_CS2);
PORTB=com;
if(i==0||i==2||i==4||i==5)
com/