仿真图:
芯片/模块的特点:
AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。
AT89C52的主要特点如下:
内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。
RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。
外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。
通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。
定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0
串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。
低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。
宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。
主程序:
#include <reg52.h> //调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
#define uint unsigned int //无符号整型 宏定义 变量范围0~65535
#include <intrins.h>
//数码管段选定义 0 1 2 3 4 5 6 7 8 9
uchar code smg_du[] = {0x28, 0xEE, 0x32, 0xA2, 0xE4, 0xA1, 0x21, 0xEA, 0x20, 0xA0,
0x60, 0x25, 0x39, 0x26, 0x31, 0x71, 0xff}; //断码
//管脚声明
sbit SMG_S1 = P3^4; //数码管位选定义
sbit SMG_S2 = P3^5;
sbit SMG_S3 = P3^6;
sbit SMG_S4 = P3^7;
sbit BUZZER = P3^2;
sbit KEY_SET = P2^0;
sbit KEY_ADD = P2^1;
sbit KEY_SUB = P2^2;
sbit KEY_START = P2^3;
uchar dis_smg[8] = {0x90, 0xf5, 0x1c, 0x34, 0x71, 0x32, 0x12, 0xf4}; //显示内容
uchar dis_smg_buf[8] = 0; //显示内容
bit flag_500ms = 1;
uchar a_a;
uchar g_setLocation; //设置参数用
uchar minute = 0; // 倒计时数
uchar second = 0; // 倒计时数
uchar mSec = 0; // 倒计时数
uchar numValue; // 用做中间的变量
bit startFlag; // 倒计时器开始计时使能标志位
uchar setMinute = 30; // 设置倒计时数的启始值
uchar setSecond = 0; // 设置倒计时数的启始值
/***********************1ms延时函数*****************************/
void DelayMs(uint q)
{
uint i, j;
for (i = 0; i < q; i++)
for (j = 0; j < 120; j++)
;
}
/***********************数码位选函数*****************************/
void smg_we_switch(uchar i) //选择i位单独显示
{
switch (i)
{
case 0:
SMG_S1 = 0;
SMG_S2 = 1;
SMG_S3 = 1;
SMG_S4 = 1;
break;
case 1:
SMG_S1 = 1;
SMG_S2 = 0;
SMG_S3 = 1;
SMG_S4 = 1;
break;
case 2:
SMG_S1 = 1;
SMG_S2 = 1;
SMG_S3 = 0;
SMG_S4 = 1;
break;
case 3:
SMG_S1 = 1;
SMG_S2 = 1;
SMG_S3 = 1;
SMG_S4 = 0;
break;
}
}
/*************定时器0初始化程序***************/
void Timer_Init()
{
EA = 1; //开总中断
TMOD = 0X01; //定时器0、工作方式1
ET0 = 1; //开定时器0中断
TR0 = 1; //允许定时器0定时
}
/***********************数码显示函数*****************************/
void Display()
{
uchar i;
for (i = 0; i < 4; i++)
{
P1 = 0xff; //消隐
smg_we_switch(i); //位选
P1 = dis_smg[i]; //段选
DelayMs(1);
}
}
/********************独立按键程序*****************/
uchar key_can; //按键值
void key() //独立按键程序
{
static uchar key_new;
key_can = 20; //按键值还原
if ((P2 & 0x0F) != 0x0F) //按键按下
{
DelayMs(1); //按键消抖动
if (((P2 & 0x0F) != 0x0F) && (key_new == 1))
{ //确认是按键按下
key_new = 0;
switch (P2 & 0x0F)
{
case 0x0E:
key_can = 1;
break; //得到k2键值
case 0x0D:
key_can = 2;
break; //得到k3键值
case 0x0B:
key_can = 3;
break; //得到k4键值
case 0x07:
key_can = 4;
break; //得到k5键值
}
}
}
else
key_new = 1;
}
/****************按键处理数码管显示函数***************/
void key_with()
{
if (key_can == 1)
{
g_setLocation++;
if (g_setLocation >= 3) //确定设置
{
g_setLocation = 0;
minute = setMinute;
second = setSecond;
}
}
if (g_setLocation == 0) //倒计时器按键操作开始 暂停
{
if (key_can == 4) //开始键
{
startFlag = ~startFlag;
BUZZER = 0; //打开蜂鸣器
DelayMs(30);
BUZZER = 1; //关闭蜂鸣器
}
}
if (g_setLocation == 1) //设置倒计时器开始数
{
if (key_can == 2)
{
setSecond++; // 设置数加
if (setSecond >= 60)
setSecond = 0; //最大加到99
dis_smg[0] = smg_du[setSecond % 10]; //取个数显示
dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
}
if (key_can == 3)
{
if (setSecond == 0)
setSecond = 60;
setSecond--; // 设置数减
dis_smg[0] = smg_du[setSecond % 10]; //取个数显示
dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
}
}
if (g_setLocation == 2) //设置倒计时器开始数
{
if (key_can == 2)
{
setMinute++; // 设置数加
if (setMinute > 99)
setMinute = 0; //最大加到99
dis_smg[2] = smg_du[setMinute % 10]; //取个数显示
dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
}
if (key_can == 3)
{
if (setMinute == 0)
setMinute = 100;
setMinute--; // 设置数减
dis_smg[2] = smg_du[setMinute % 10]; //取个数显示
dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
}
}
}
/******************主程序**********************/
void main()
{
BUZZER = 0; //开机蜂鸣器叫一声
DelayMs(100);
P0 = P1 = P2 = P3 = 0xff; //初始化IO口
Timer_Init();
second = setSecond; //开机显示设置数
minute = setMinute; //开机显示设置数
while (1)
{
key();
if (key_can < 10)
{
key_with(); //按键执行函数
}
if (g_setLocation == 0) //扫描显示倒计时数
{
dis_smg[0] = smg_du[second % 10];
dis_smg[1] = smg_du[second / 10 % 10];
dis_smg[2] = smg_du[minute % 10] & 0xdf;
dis_smg[3] = smg_du[minute / 10 % 10];
if (flag_500ms == 1)
{
flag_500ms = 0;
if ((second <= 5) && (minute == 0)) //计时到小于等于5s 蜂鸣器报警
BUZZER = ~BUZZER;
}
if ((minute == 0) && (second == 0))
{
BUZZER = 1; //关闭蜂鸣器
second = setSecond; //让显示最大数
minute = setMinute; //让显示最大数
startFlag = 0;
mSec = 1;
}
}
if (g_setLocation == 1) //在设置的时候十位数闪烁
{
if (flag_500ms == 1)
{
dis_smg[0] = smg_du[setSecond % 10]; //取个位显示
dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
}
else
{
dis_smg[0] = 0xff; //取个位显示
dis_smg[1] = 0xff; //取十位显示
dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
}
}
if (g_setLocation == 2) //在设置的时候十位数闪烁
{
if (flag_500ms == 1)
{
dis_smg[0] = smg_du[setSecond % 10]; //取个位显示
dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
}
else
{
dis_smg[0] = smg_du[setSecond % 10]; //取个位显示
dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
dis_smg[2] = 0xff; //取个数显示
dis_smg[3] = 0xff; //取十位显示
}
}
Display(); //数码管显示函数
}
}
/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{
static uint cnt = 0;
TH0 = (65536 - 9216) / 256;
TL0 = (65536 - 9216) % 256; // 10ms
cnt++;
if (cnt >= 50) //每次10ms 定时到50次也就是500ms
{
cnt = 0;
flag_500ms = ~flag_500ms; //标志置位
}
if (startFlag == 1) //显示标志
{
numValue = 0;
if (mSec == 0) //显示秒位
{
mSec = 100;
if (second == 0)
{
second = 60; //重置s单位
if (minute != 0) //如果分不为0
minute--;
}
}
mSec--;
}
}
设计文件: