一、实验目的
1. 理解单片机定时器的工作原理。
2. 掌握定时器溢出中断实现定时的编程方法。
二、实验内容
1. 验证课堂例题
编译下载运行课堂例题——“T/C0溢出中断”(T0秒表),查看运行结果。理解程序的编程思想和程序执行过程。
2. 设计程序
参考上述例题的电路和编程思路,自行设计电路,包括六位数码管、2个按键,完成数码管显示和按键控制数码管数字累加速度。
具体要求如下:
(1)定时器溢出时间为20ms;
(2)上电复位后,数码管显示“000000”并保持,直到有按键按下;
(3)数码管后两位循环显示0-99;
(4)按下K1键后,数字以每0.5s加1的速度递增;按下K2键后,数字以每1s加1的速度递增。
在设计报告中,需进行总体设计思路描述,给出所涉及到的主程序、中断程序、关键功能子函数的流程图和设计代码。描述程序调试结果及出现的问题。
三、实验结果
1. 在下方贴出使用Proteus绘制的电路原理图。
图5-1 实验电路图
2. 描述所设计程序的总体设计思路
本程序在主函数中循环刷新数码管,来显示定时器的实时计数值。并编写一个20ms定时器中断函数,在定时器中断函数中设置了一个累加值,每次进入定时器中断中都判断累加值是否达到目标值,如果达到就做相应操作并将累加值清;零。
同时设置了两个按键中断,用于改变定时器中断中的累加值,以实现按键控制500ms,1000ms的递增速度。
3. 根据所设计的程序顶层结构,对主函数、中断函数、关键功能子函数的设计思路进行简单描述,并给出各函数的流程图。
本程序,设置了三个中断,分别为定时器溢出终端,以及两个按键中断。其中两个按键中断用于控制定时器溢出中断中的累加值,来达到500ms和1000ms定时的效果。并编写了一个数码管显示函数来实时显示定时器的计数值。
定时器中断中用于对累加值做处理,在到达了相应的定时条件之后对数码管显示的数组做相应的处理。
在主函数中只需要初始化好相关的外设再循环扫描显示数码管即可显示计数值。
//**************************************************************************************
//文件名:定时器
//功能描述:两位数码管循环显示0~59,进行秒计时
//系统时钟频率12MHz,TC0采用普通模式,定时器溢出时间为10ms,1024分频。
//硬件连接:单片机PD0~PD3接四个独立按键,PA3和PA4分别接两个74HC573锁存器,再接数码管。
//调试状态:正常运行,正常执行功能
//**************************************************************************************
//文件包含
#include <iom16v.h>
#include <macros.h>
//宏定义
#define uchar unsigned char
#define uint unsigned int
//全局变量定义
uchar const DuanXuan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //共阴级数码管显示0-9
uchar const WeiXuan[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; //调用第0-5位数码管亮
uchar LEDBuf[6]={0,0,0,0,0,0}; //存放数码管显示数据,0-9数字格式
uchar sencond_cnt=0; //用于1s计数
uchar number_model;
//函数声明
void delay(uint ms); //延时函数
void LEDshow(uchar LEDBuf[6]); //数码管显示函数
void IO_Init(); //IO初始化函数
void Timer0_Init(); //T/C0初始化函数
//中断函数
void Timer0_isr(void) ; //T/C0溢出中断服务函数
//通用功能子函数
//**************************************************************************************
//函数名:延时函数
//输入参数:ms
void delay(uint ms) //延时函数
{
uint p,q;
for(p=0;p<ms;p++)
{
for(q=0;q<1141;q++);
}
}
//数码管模块子函数
//**************************************************************************************
//函数名:数码管显示函数
//功能:在数码管上显示出对应的数字。0-5位数码管显示数据放在LEDBuf[]中,存放0-9数字格式
//输入参数:LEDBuf[]
void LEDshow(uchar LEDBuf[6])
{
uchar i;
for(i=0;i<6;i++) //循环扫描一次
{
//数码管位选程序
PORTB=WeiXuan[i]; //选择第i位数码管
PORTA|=BIT(PA4); //PA4输出高电平,位选端拉高
PORTA&=~BIT(PA4); //PA4输出低电平,位选端拉低,位选锁存
//数码管段选程序
PORTB=DuanXuan[LEDBuf[i]]; //输出段选
PORTA|=BIT(PA3); //PA3输出高电平,段选端拉高
PORTA&=~BIT(PA3); //PA3输出低电平,段选端拉低,段选锁存
delay(1);
}
}
//初始化子函数
//**************************************************************************************
//函数名:IO引脚初始化函数
//功能:数码管、锁存器设为输出状态
void IO_Init(void)
{
DDRA|=BIT(PA3); //PA3设置为输出状态
DDRA|=BIT(PA4); //PA4设置为输出状态
DDRB=0xFF; //PB口设置为输出状态
PORTD = 0XFF; //使能上拉电阻
MCUCR=0x0A; //下降沿INT0,下降沿INT1
GICR|=0b11000000; //允许INT0
}
//中断初始化函数
void Timer0_Init(void)
{
TCCR0=0x05; //普通模式,OC0不输出,1024分频
TCNT0=21; //初值为138,定时10ms
TIFR=0x01; //T/C0溢出标志
SREG=0x80;
}
//T/C0溢出中断服务函数
//**************************************************************************************
//功能:1s计数,到1s数码管数字个位加一
#pragma interrupt_handler Timer0_TOV_ISR:iv_TIM0_OVF
void Timer0_TOV_ISR(void)
{
TCNT0=50;
if(sencond_cnt<number_model)
{
sencond_cnt++;
}
else
{
sencond_cnt=0;
LEDBuf[5]++;
if(LEDBuf[5]==10)
{
LEDBuf[5]=0;
LEDBuf[4]++;
if(LEDBuf[4]==10)
{
LEDBuf[4]=0;
}
}
}
}
void main(void)
{
IO_Init(); //调用IO初始化函数
Timer0_Init(); //调用中断初始化函数
while(1)
{
LEDshow(LEDBuf);
}
}
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
TIMSK=0x01; //T/C0溢出中断使能
number_model=50;
}
#pragma interrupt_handler int1_isr:iv_INT1
void int1_isr(void)
{
TIMSK=0x01; //T/C0溢出中断使能
number_model=25;
}