单片机 AT89C52
利用定时器/计数器T/C1进行0~199次的计数设计,要求用计数器T/C1控制,对外部按键的输入进行计数,使用三位数码管进行计数值的动态显示;开始时,显示“000”,按下按键S1|后开始增计数(正向计数);计数至200次时,计数值归0。
每段程序有注释
定时器计数器
可参考
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit S1 = P1^0; // 定义按键S1,连接到P1.0口
sbit COM1 = P2^0; // 定义数码管第一位,连接到P2.0口
sbit COM2 = P2^1; // 定义数码管第二位,连接到P2.1口
sbit COM3 = P2^2; // 定义数码管第三位,连接到P2.2口
uchar code table[] = { // 数码管显示表,0~9的编码值
0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7d, 0x07, 0x7f, 0x6f
};
uchar cnt = 0; // 计数器变量,初始值为0
uchar i, j; // 循环计数变量
bit flag; // 按键标志位,初始值为0,表示按键未按下
// 数码管动态显示函数
void display(uchar num) {
COM1 = 0; COM2 = 1; COM3 = 1; // 第一位数码管选通,二、三位不选通
P0 = table[num / 100]; // 显示百位数
for (i = 0; i < 2; i++) { // 延时一段时间,使数码管显示更清晰
for (j = 0; j < 100; j++);
}
COM1 = 1; COM2 = 0; COM3 = 1; // 第二位数码管选通,一、三位不选通
P0 = table[(num % 100) / 10]; // 显示十位数
for (i = 0; i < 2; i++) { // 延时一段时间,使数码管显示更清晰
for (j = 0; j < 100; j++);
}
COM1 = 1; COM2 = 1; COM3 = 0; // 第三位数码管选通,一、二位不选通
P0 = table[num % 10]; // 显示个位数
for (i = 0; i < 2; i++) { // 延时一段时间,使数码管显示更清晰
for (j = 0; j < 100; j++);
}
}
// 主函数
void main() {
TMOD = 0x10; // 定时器/计数器T/C1工作在模式1,16位定时器
TH1 = 0x3c; // 定时器初值,每1ms中断一次
TL1 = 0xb0;
TR1 = 1; // 启动定时器/计数器T/C1
while (1) {
if (!S1) { // 如果按键S1被按下
while (!S1); // 等待按键S1松开
flag = !flag; // 按键标志位取反,表示按键状态
}
if (flag == 1) { // 如果按键被按下
cnt++; // 计数器变量加1
if (cnt >= 200) { // 如果计数器变量达到200
cnt = 0; // 计数器变量归0
}
}
display(cnt); // 数码管动态显示计数器变量
}
}
好的,以下是AT89C52的计数器T/C1设计程序,已添加注释。
#include <reg52.h> // 引入AT89C52的头文件
sbit S1 = P3^0; // 定义外部按键S1
sbit DIO = P2^0; // 定义74HC595数据引脚DIO(串行数据输入)
sbit RCLK = P2^1; // 定义74HC595锁存时钟引脚RCLK(移位寄存器锁存时钟输入)
sbit SRCLK = P2^2; // 定义74HC595移位时钟引脚SRCLK(移位寄存器时钟输入)
unsigned int count = 0; // 初始化计数值为0
void Timer1_Init(void) {
TMOD |= 0x10; // 配置定时器/计数器T/C1为16位定时器模式
TH1 = 0xFC; // 计时器初值设置为0xFC67,定时1ms
TL1 = 0x67;
TR1 = 1; // 启动定时器/计数器T/C1
ET1 = 1; // 允许定时器/计数器T/C1中断
EA = 1; // 全局中断使能
}
void Delay(unsigned int t) { // 延时函数
unsigned int i, j;
for(i=0;i<t;i++)
for(j=0;j<110;j++);
}
void Display(unsigned char dat) { // 数码管动态显示函数
unsigned char i;
for(i=0;i<8;i++) {
SRCLK = 0; // 移位寄存器时钟引脚SRCLK置低电平
DIO = dat & 0x80; // 将dat的最高位传输到74HC595串行数据输入引脚DIO上
dat <<= 1; // 左移一位
SRCLK = 1; // 移位寄存器时钟引脚SRCLK置高电平,将上一位数据存储到移位寄存器中
}
RCLK = 1; // 移位寄存器锁存时钟引脚RCLK置高电平,将移位寄存器中的数据输出到三位数码管上显示
Delay(1); // 延时一段时间保持显示稳定
RCLK = 0; // 移位寄存器锁存时钟引脚RCLK置低电平
}
void main() {
Timer1_Init(); // 初始化定时器/计数器T/C1
while(1) { // 进入主循环
if(S1 == 0) { // 当按键S1被按下时
Delay(20); // 延时20ms消除抖动
if(S1 == 0) {
count++; // 计数值加1
if(count >= 200) // 当计数值大于等于200时,归0
count = 0;
}
}
Display(count); // 显示当前计数值
}
}
void Timer1_Isr() interrupt 3 { // 定时器/计数器T/C1中断服务程序
TH1 = 0xFC; // 计时器初值重置为0xFC67
TL1 = 0x67;
}
注意:以上代码是基于74HC595移位寄存器驱动三位共阳数码管进行动态显示的,在实际使用时需要将P2口连接至74HC595芯片的对应引脚。
参考上面的,不多说了
答案参考ChatGPT Plus版,整理汇总。希望能帮助你解决问题以下是使用单片机AT89C52和定时器/计数器T/C1实现0~199次计数的设计示例程序:
ORG 0H ; 程序的起始地址
MOV P1, #00000000 ; 设置P1口为输出,用于驱动三位数码管
MOV P3, #00000010 ; 设置P3.1为输入,用于接收按键S1输入
MOV TMOD, #00100001 ; 设置定时器/计数器T0为模式1,用于延时
MOV TH0, #0FDH ; 设置T0初值
MOV TL0, #0FDH
MOV TMOD, #00100001 ; 设置定时器/计数器T1为模式1,用于计数
MOV TH1, #0 ; 设置T1初值
MOV TL1, #0
SETB EA ; 允许中断
SETB ET1 ; 允许T1中断
START: ; 主程序入口
MOV A, #0 ; 清零计数器
MOV R1, #0 ; 清零显示计数值
LOOP: ; 主循环
JNB P3.1, LOOP ; 等待按键S1按下
CLR P3.1 ; 清除按键S1的输入标志
INC A ; 计数器递增
CPL A ; 取反计数器的值,用于动态显示
MOV P1, A ; 将计数器的值输出到P1口驱动数码管
MOV R0, #10 ; 设置延时值为10(可根据需要调整)
DELAY: ; 延时循环
DJNZ R0, DELAY
CJNE A, #200, LOOP ; 判断计数器是否达到200,若未达到则继续循环
CLR A ; 计数器归零
MOV P1, A ; 清空数码管显示
SJMP START ; 重新开始计数
END ; 程序结束
上述程序使用定时器/计数器T1进行计数操作,计数值通过P1口驱动连接的三位数码管进行动态显示。按下按键S1后开始增计数,当计数器达到200时,计数值归零并重新开始计数。
请注意,以上程序是汇编语言示例,需要使用汇编器将其转换为可执行的机器码,然后将其下载到AT89C52单片机中运行。