【蓝桥杯】单片机设计与开发指南:模板V1.1详解
#include<STC15.H> // STC15系列单片机头文件
#include<intrins.H> // 包含内部函数,如_crol_等
#define uchar unsigned char
#define uint unsigned int
// LED控制相关定义
unsigned char LED_Bit=0XFF; // LED状态位,初始全灭(1表示灭,0表示亮)
unsigned char Actuator_Bit=0X00; // 执行器(蜂鸣器/继电器)状态位
// LED控制宏定义
#define LEDx_ON(n) { LED_Bit&=_crol_(0XFE,n-1); P0=LED_Bit; P2|=0X80; P2&=0X9F; P2&=0X1F;} // 打开第n个LED
#define LEDx_OFF(n) { LED_Bit|=_crol_(0X01,n-1); P0=LED_Bit; P2|=0X80; P2&=0X9F; P2&=0X1F;} // 关闭第n个LED
// 蜂鸣器和继电器控制宏定义
#define Buzzer_ON Actuator_Bit|=0x40; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F; // 打开蜂鸣器
#define Buzzer_OFF Actuator_Bit&=0XBF; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F; // 关闭蜂鸣器
#define Relay_ON Actuator_Bit|=0x10; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F; // 打开继电器
#define Relay_OFF Actuator_Bit&=0XEF; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F; // 关闭继电器
// 数码管相关定义
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; // 共阳数码管段码表(0-9,-,全灭)
unsigned char KEY_Value = 0 ; // 存储按键值
unsigned char DigCom=0; // 数码管位选计数器
unsigned char DigBuf[8] = {10,10,10,10,10,10,10,10}; // 数码管显示缓冲区(初始显示"-")
// LED流水灯相关变量
unsigned char LED = 1 ; // 当前点亮的LED编号(1-8)
unsigned int LED_tt =0; // LED计时计数器
bit LED_Ref = 0 ; // LED刷新标志
// 数码管倒计时相关变量
unsigned int SEG_tt =0; // 数码管计时计数器
bit SEG_Ref = 0 ; // 数码管刷新标志
bit SEG_Run = 0 ; // 数码管倒计时运行标志
unsigned int Num = 999 ; // 倒计时初始值999
// 其他功能预留变量
unsigned int XXX_tt =0; // 预留计时器
bit XXX_Ref =0; // 预留刷新标志
// 函数声明
void ALL_Init(void); // 初始化所有外设
void Delay_MS(unsigned int MS); // 毫秒级延时
void KeyScan(void); // 独立按键扫描
void ArrKeyScan(void); // 矩阵按键扫描(未使用)
void Timer0Init(void); // 定时器0初始化(1毫秒@11.0592MHz)
// 主函数
void main(void)
{
ALL_Init(); // 初始化所有外设
Timer0Init(); // 初始化定时器0
EA=1;ET0=1; // 开启总中断和定时器0中断
while(1) // 主循环
{
KeyScan(); // 扫描按键
// ArrKeyScan(); // 矩阵按键扫描(注释掉未使用)
// 按键处理
if(KEY_Value==7){KEY_Value=0;SEG_Run = 1 ;} // 按键7:启动倒计时
if(KEY_Value==6){KEY_Value=0;SEG_Run = 0 ;} // 按键6:停止倒计时
if(KEY_Value==5){KEY_Value=0;LEDx_ON(1);Buzzer_ON;} // 按键5:打开LED1和蜂鸣器
if(KEY_Value==4){KEY_Value=0;LEDx_OFF(1);Buzzer_OFF;} // 按键4:关闭LED1和蜂鸣器
// LED流水灯控制
if(LED_Ref == 1) // 每999ms刷新一次LED
{
LED_Ref = 0 ; // 清除刷新标志
LEDx_OFF(LED-1); // 关闭上一个LED
LEDx_ON(LED); // 点亮当前LED
if (++LED == 9) LED = 1 ; // LED编号循环1-8
}
// 数码管倒计时处理
if(SEG_Ref==1) // 每1000ms刷新一次
{
SEG_Ref=0; // 清除刷新标志
Num=Num-1; // 倒计时减1
}
// 数码管显示处理
if(SEG_Run==1) // 倒计时运行状态下更新显示
{
// 高5位数码管显示空白(11对应tab中的全灭)
DigBuf[3]=11;DigBuf[4]=11;DigBuf[5]=11;DigBuf[6]=11;DigBuf[7]=11;
// 低3位数码管显示倒计时数值(百位、十位、个位)
DigBuf[0]=Num/100;DigBuf[1]=Num%100/10;DigBuf[2]=Num%10;
}
// if(XXX_Ref==1) // 预留功能处理
// {
// XXX_Ref=0;
// XXX;
// DigBuf[0]=XXX/100;DigBuf[1]=XXX%100/10;DigBuf[2]=XXX%10;
// }
}
}
// 独立按键扫描函数
void KeyScan(void)
{
if(P30==0) // 检测P3.0按键
{
Delay_MS(10); // 消抖延时
if(P30==0)KEY_Value = 7 ; // 确认按键按下,赋值7
while(!P30); // 等待按键释放
}
else if(P31==0) // 检测P3.1按键
{
Delay_MS(10);
if(P31==0)KEY_Value = 6 ;
while(!P31);
}
else if(P32==0) // 检测P3.2按键
{
Delay_MS(10);
if(P32==0)KEY_Value = 5 ;
while(!P32);
}
else if(P33==0) // 检测P3.3按键
{
Delay_MS(10);
if(P33==0)KEY_Value = 4 ;
while(!P33);
}
}
// 定时器0中断服务函数(1ms中断一次)
void Timer0(void) interrupt 1
{
// 数码管动态显示处理
P0=0X00; // 先关闭所有段选
P2|=0XC0; // 打开段选锁存器
P2&=0XDF;
P2&=0X1F; // 关闭所有锁存器
P0=tab[DigBuf[DigCom]]; // 根据显示缓冲区设置当前数码管段选
P2|=0XE0; // 打开段选锁存器
P2&=0XFF;
P2&=0X1F; // 关闭所有锁存器
P0=(0X01<<DigCom); // 设置当前数码管位选(1-8)
P2|=0XC0; // 打开位选锁存器
P2&=0XDF;
P2&=0X1F; // 关闭所有锁存器
if(++DigCom == 8)DigCom = 0 ; // 数码管位选循环0-7
// LED流水灯计时
LED_tt++;
if(LED_tt == 999) {LED_tt = 0 ; LED_Ref = 1 ;} // 每999ms设置LED刷新标志
// 数码管倒计时计时
if(++SEG_tt==1000){SEG_tt=0;SEG_Ref=1;} // 每1000ms设置倒计时刷新标志
// 预留功能计时
// XXX_tt++;
// if(++XXX_tt==NNN){XXX_tt=0;XXX_Ref=1;}
}
// 定时器0初始化函数(1毫秒@11.0592MHz)
void Timer0Init(void)
{
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0xCD; // 设置定时初始值
TH0 = 0xD4; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
}
// 毫秒级延时函数
void Delay_MS(unsigned int MS)
{
unsigned i,j;
for(i=0;i<MS;i++)
for(j=853;j>0;j--); // STC15单片机设置为853; STC8H单片机修改为1109;STC32G单片机修改为427;
}
// 外设初始化函数
void ALL_Init(void)
{
// 初始化蜂鸣器和继电器(关闭)
P2=0XA0; // 打开控制蜂鸣器继电器的74HC573锁存器
P0=0X00; // 关闭蜂鸣器继电器
// 初始化LED(全部关闭)
P2=0X80; // 打开控制LED灯74HC573锁存器
P0=0XFF; // 关闭所有的LED
// 初始化数码管(全部关闭)
P2=0XC0; // 打开控制数码管位选的锁存器
P0=0XFF; // 选中所有的数码管
P2=0XE0; // 打开控制数码管段选的锁存器
P0=0XFF; // 关闭所有的数码管
P2=0XC0; // 打开控制数码管位选的锁存器
P0=0X00; // 不选中所有的数码管
}
// 矩阵按键扫描函数(代码中有定义但未在主循环中使用)
void ArrKeyScan(void)
{
unsigned char temp; //定义局部变量用来存储从P3口读出的数值?
P44=0; P42=1; P3=0X7F; // //0111 1111 扫描第一列
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
Delay_MS(5);
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
temp = P3 ;
switch(temp) //1110 1101 1011 0111
{
case 0X7E: KEY_Value = 7 ; break;
case 0X7D: KEY_Value = 6 ; break;
case 0X7B: KEY_Value = 5 ; break;
case 0X77: KEY_Value = 4 ; break;
default : break;
}
while(temp != 0X0F)
{
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
}
}
}
P44=1; P42=0; P3=0XBF; // //0111 1111 扫描第一列
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
Delay_MS(5);
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
temp = P3 ;
switch(temp) //1110 1101 1011 0111
{
case 0XBE: KEY_Value = 11 ; break;
case 0XBD: KEY_Value = 10 ; break;
case 0XBB: KEY_Value = 9 ; break;
case 0XB7: KEY_Value = 8 ; break;
default : break;
}
while(temp != 0X0F)
{
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
}
}
}
P44=1; P42=1; P3=0XDF; // //1101 1111 扫描第一列
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
Delay_MS(5);
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
temp = P3 ;
switch(temp) //1110 1101 1011 0111
{
case 0XDE: KEY_Value = 15 ; break;
case 0XDD: KEY_Value = 14 ; break;
case 0XDB: KEY_Value = 13 ; break;
case 0XD7: KEY_Value = 12 ; break;
default : break;
}
while(temp != 0X0F)
{
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
}
}
}
P44=1; P42=1; P3=0XEF; // //0111 1111 扫描第一列
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
Delay_MS(5);
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
if(temp != 0X0F)
{
temp = P3 ;
switch(temp) //1110 1101 1011 0111
{
case 0XEE: KEY_Value = 19 ; break;
case 0XED: KEY_Value = 18 ; break;
case 0XEB: KEY_Value = 17; break;
case 0XE7: KEY_Value = 16; break;
default : break;
}
while(temp != 0X0F)
{
temp = P3 ; //将P3口读出的数字赋值给temp
temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX
}
}
}
}
作者:三歪爱三玖