试用定时/计数器T1对外部事件计数。要求每计数100,就将T1改成定时方式,控制P1.7输出 一个脉宽为10ms的正脉冲,然后又转为计数方式,如此反复循环。设晶振频率为12MHz。
时间: 2023-08-01 08:11:07 浏览: 169
MCS-51定时/计数器PPT
4星 · 用户满意度95%
这是一道典型的单片机应用题,需要用到定时器/计数器 T1,以及外部中断。下面是具体实现步骤:
1. 配置 T1 为计数模式,并启动 T1 计数器。
2. 配置外部中断 INT0 为上升沿触发,并启用外部中断。
3. 编写外部中断服务程序,每触发一次外部中断,就将 T1 的计数值加 1。
4. 在主程序中,不断检查 T1 的计数值是否达到 100,如果达到则执行以下操作:
a. 停止 T1 计数器,将 T1 配置为定时模式,并设置计时器初值,使得 T1 计时 10ms。
b. 等待 T1 计时完成,即 T1 中断标志位被置位。
c. 清除 T1 中断标志位,将 T1 配置为计数模式,将计数器初值清零,重新启动 T1 计数器。
d. 控制 P1.7 输出一个脉宽为 10ms 的正脉冲。
5. 回到主程序,继续执行循环。
下面是具体的程序实现(使用 keil C51 编译器):
```c
#include <reg52.h>
#define FREQ_OSC 12000000UL // 晶振频率
sbit LED = P1^7; // 控制 LED 的 IO 口
unsigned int cnt = 0; // 外部事件计数器
bit flag = 0; // 定时/计数模式标志位
void init_timer1()
{
TMOD |= 0x10; // T1 为 16 位计数器,工作在模式 1(M1=0,M0=1)
TH1 = 0; // 计数器初值高位清零
TL1 = 0; // 计数器初值低位清零
TR1 = 1; // 启动 T1 计数器
}
void init_ext_int0()
{
IT0 = 1; // 外部中断 INT0 触发方式为上升沿
EX0 = 1; // 允许外部中断 INT0
EA = 1; // 允许所有中断
}
void timer1_isr() interrupt 3
{
TF1 = 0; // 清除 T1 中断标志位
if (flag) {
flag = 0;
TH1 = (65536UL - (FREQ_OSC / 100UL / 12UL)) / 256;
TL1 = (65536UL - (FREQ_OSC / 100UL / 12UL)) % 256;
TR1 = 1; // 启动 T1 定时器
LED = 1; // 输出正脉冲
}
}
void ext_int0_isr() interrupt 0
{
cnt++; // 外部事件计数器加 1
}
void main()
{
init_timer1();
init_ext_int0();
while (1) {
if (cnt >= 100) { // 达到计数阈值
cnt = 0;
flag = 1; // 标记为定时模式
while (!TF1); // 等待 T1 定时完成
LED = 0; // 停止输出正脉冲
TR1 = 0; // 停止 T1 定时器
TH1 = 0; // 计数器初值高位清零
TL1 = 0; // 计数器初值低位清零
TF1 = 0; // 清除 T1 中断标志位
init_timer1(); // 重新配置 T1 为计数模式
}
}
}
```
需要注意的是,上述程序中的计时器初值是根据晶振频率和计时时间计算得出的,具体计算方法可以参考《51单片机原理与应用》等相关资料。同时,由于晶振频率可能存在一定的误差,因此实际输出的脉冲宽度可能会略微偏差。
阅读全文