概述
实验3-单片机定时器中断实验
之前做的一次实验,51单片机定时器中断实验。如有问题欢迎指正。
实验目标:
通过定时1s(方式2)和5s(方式1),分别让对应的led灯闪烁一次。通过外部信号发生器,计数外部下降沿,并计算频率应用数码管显示,与信号发生器的频率进行比对。
实现效果:
Proteus原理图
选择元器件:
DEVICES | 说明 |
---|---|
7SEG-MPX8-CC-BLUE | 八位共阴极数码管 |
AT89C51 | MCU |
BUTTON | 按键 |
CAP | 普通电容 |
CAP-ELEC | 电解电容 |
CRYSTAL | 晶振 |
LED-BLUE | 蓝色LED灯 |
RES | 电阻 |
RESPACK-8 | 排阻 |
51单片机的P0口做IO口使用时是漏极开路输出,其引脚一般需要在片外接一定阻值的上拉电阻,此时端口不存在高阻抗的悬浮状态,因此它是一个准双向口。同时,P0口每一位的驱动能力是P1~P3口的两倍,每位可以驱动8个LSTTL(Low-power Schottky TTL,即低功耗肖特基TTL)输入,89C51等单片机任何一个端口想要获得较大的驱动能力,必须采用低电平输出。
时钟晶体振荡频率为
f
o
s
c
=
12
M
H
Z
f_{osc}=12MHZ
fosc=12MHZ
时钟周期相当于
T
o
s
c
=
1
f
o
s
c
≈
83.33
n
s
T_{osc}=frac{1}{f_{osc}} approx 83.33ns
Tosc=fosc1≈83.33ns
复位电路的话通过给89C51等单片机的复位引脚RST加上大于2个机器周期的高电平(即24个时钟振荡周期)就可以使单片机复位。
KEIL工程:
1.我按照要求,使用定时器t0的方式2去控制LED灯,间隔1秒闪烁;
2.使用定时器t1的方式1,去控制LED灯,间隔5秒闪烁;
3.为了计数频率,我使用外部中断0来计数下降沿,为了使计数准确,我设置外部中断0为高优先级。同时使用晶振12MHZ,计数下降沿需要2个机器周期,那么理论最高计数频率为,12M/24=50KHZ。考虑到LED定时精准,不影响t0和t1,计数频率我使用t2计时器。每隔200毫秒统计一次下降沿(精度:5HZ,可以调整),故理论最低计数频率为5HZ。
4.考虑到使用了太多中断,当外部中断0频繁中断,即频率过高时,主函数的数码管显示会受影响。
注意:计数高频率时,数码管会闪烁,原因是中断太频繁。如果在定时器t0或者t1里面,每隔一段时间计数下降沿频率,会对LED闪烁时间有相当大的的影响。如果不对外部中断0设置高优先级,会导致计数丢失。
BUG:当测频过高由于中断太多会闪屏,待改进。
头文件宏定义等:
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define Datadula P0 /*数码管段码和位码端口*/
#define Datawela P2
#define LedPort P1
#define TIME 1000 /*延时常量(ms)*/
#define T0_INIT_VALUE 256-250 /*定时器T0的方式2 初值250us=0.25ms*/
#define T1_INIT_VALUE 50000 /*定时器T1的方式1 初值50000us=50ms*/
#define T2_INIT_VALUE 50000
#define SHAKING_TIME 10 /*消抖时间(ms)*/
//#define Screen_Change 800 /*频率数值刷新0.25*800=200ms 即最低可测5HZ*/
sbit LED_1s=P1^0;
sbit LED_5s=P1^2;
uchar code Duanma[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};/*0123456789-*/
uchar code Weima []= {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; /*自左向右*/
uchar TempData[8]; /*存储显示值的全局变量*/
uint num1,num2,num3,ctemp=1;
unsigned long int Show_freq,count;
主函数:
void main(void)
{
Init();//定时器初始化
while(1)
{
//先显示,防止断帧
Display(0,8);
if(num1==4000)
{
num1=0;
LED_1s=~LED_1s; //亮1s,灭1s
}
if(num2==100) //亮5s,灭5s
{
num2=0;
LED_5s=~LED_5s;
}
}
}
显示函数:
void Display(uchar FirstBit,uchar Num)
{
static uchar i=0;
Datadula=0x00;//段码消隐
Datawela=0xff;//位码消隐
Datawela=Weima[i+FirstBit];//位码数据,从数码管从左到右的第一位开始对应
Datadula=TempData[i]; //段码数据
i++;
if(i==Num)
i=0;
}
定时器初始化及中断子函数:
void Init()/*使用定时器T0的方式2定时1s,使用定时器T1的方式1定时5s*/
{
TMOD=0x12; /*使用定时器0的方式2,8位自动重载定时器定时器/计数器
和 定时器1的方式1,16位定时器/计数器,
或运算是为了在给相应位赋值时不会影响无关位 */
CP_RL2=0;EXEN2=0; //设置定时器T2为16位自动重装载定时器工作方式
TH0=T0_INIT_VALUE; //定时器T0的方式2装入初值(256-250),250us
TL0=T0_INIT_VALUE;
TH1=(65536-T1_INIT_VALUE)/256; //定时器T1的方式1装入初值,50ms
TL1=(65536-T1_INIT_VALUE)%256;
TH2=RCAP2H=(65536-T2_INIT_VALUE)/256; //定时器T2的方式1装入初值,10ms
TL2=RCAP2L=(65536-T2_INIT_VALUE)%256;
PX0=1; //设置外部中断为高优先级。关键!否则会在T2计数器装TempData[]显示值时漏检测下降沿
//PT0=1; //将定时器0中断设为高优先级
//PT1=1;
EA=1; //开总中断
ET0=1; //开中断允许寄存器IE,允许定时器T0溢出中断
ET1=1; //开中断允许寄存器IE,允许定时器T1溢出中断
ET2=1; //开中断允许寄存器IE,允许定时器T2溢出中断
TR2=1; //启动定时器2-在后面
TR0=1; //启动定时器0
TR1=1; //启动定时器1
EX0=1; //外部中断0开
IT0=1; //边沿触发
LedPort=0xff;
TempData[0]=0x71;
TempData[1]=0x48;/*固定字符F=*/
}
void T0_time() interrupt 1 //定时器T0的方式2 基础0.25ms
{
//相比方式0,这里不需要加入重装初值
num1++;
}
void T1_time() interrupt 3 //定时器T1的方式1
{
TH1=(65536-T1_INIT_VALUE)/256; //定时器T1的方式1重装入初值,50ms
TL1=(65536-T1_INIT_VALUE)%256;
num2++;
}
void T2_time(void) interrupt 5
{
TF2=0;//用软件清溢出中断标志位T2
num3++;
if(num3==4)//200ms
{
Show_freq=5*count;
count=0;
num3=0;
TempData[2]=Duanma[Show_freq /100000]; //十万
TempData[3]=Duanma[Show_freq /10000%10];//万
TempData[4]=Duanma[Show_freq /1000%10]; //千
TempData[5]=Duanma[Show_freq /100%10]; //百
TempData[6]=Duanma[Show_freq /10%10]; //十
TempData[7]=Duanma[Show_freq %10]; //个
}
Display(0,8);
}
void ISR_Key(void) interrupt 0 using 1
{
count++;
if(count==100000)
count=0;
//晶振12MHZ,理论最高计数频率为12M/24=50KHZ,即50 0000
}
参考文献
1.《单片机原理与接口技术》张毅刚
资源
返回目录
最后
以上就是舒心小丸子为你收集整理的51单片机Proteus仿真+Keil工程-实验3-开启4个中断-频率计实验3-单片机定时器中断实验的全部内容,希望文章能够帮你解决51单片机Proteus仿真+Keil工程-实验3-开启4个中断-频率计实验3-单片机定时器中断实验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复