蓝桥杯单片机
(〇)注意事项
- 运行程序时注意调整J13为IO模式 / MM模式
- 运行程序时注意调整J5为BTN独立按键 / KBD矩阵键盘
- Keil创建工程文件选择AT89C52
- Keil编译完后要勾选Creat HEX File
- STC-ISP要选择相应的单片机型号和串口号
- 串口助手中注意波特率调整 与文本、HEX模式的切换
- 注意区别unsigned char 与 unsigned int 类型
- DS18B20中onewire.c中调用的所有延时函数的参数都要扩大10倍
(一)LED闪烁
01 LED全部同时闪烁
#include <reg52.h>
//74HC138译码器定义管脚
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
void Delay(unsigned int t) //延时函数
{
while(t--);
while(t--);
}
void LEDRunning() //LED闪烁函数
{
HC138_C = 1; //CBA=100即38译码器Y4输出低电平(有效)
HC138_B = 0;
HC138_A = 0;
P0 = 0x00; //全亮,根据原理图:低电平有效
Delay(60000);
Delay(60000);
P0 = 0xff; //全灭
Delay(60000);
Delay(60000);
}
void main() //主函数
{
while(1)
{
LEDRunning();
}
}
02 LED闪烁三次后依次亮灭
#include <reg52.h>
//74HC138译码器定义管脚
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
//延时函数
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void LEDRunning()
{
unsigned char i;
HC138_C = 1;
HC138_B = 0;
HC138_A = 0;
for(i=0;i<3;i++)
{
P0 = 0x00;
Delay(60000);
Delay(60000);
P0 = 0xff;
Delay(60000);
Delay(60000);
}
for(i=1;i<=8;i++) //i从1开始,使第一次也亮
{
P0 = 0xff << i; //全1,左移补0
Delay(60000);
Delay(60000);
}
for(i=1;i<=8;i++)
{
P0 = ~(0xff << i); //相当于全0,左移补1
Delay(60000);
Delay(60000);
}
}
void main()
{
while(1)
{
LEDRunning();
}
}
*03 补充关闭外设的代码
void InitSystem() //关闭外设(蜂鸣器与继电器)
{
HC138_C = 1; //Y5输出,连接U9锁存器与达林顿管
HC138_B = 0;
HC138_A = 1;
P0 = 0x00; //达林顿管中为非门,输出1关闭蜂鸣器与继电器
}
04 LED闪烁并控制蜂鸣器与继电器
#include <reg52.h>
//74HC138译码器定义管脚
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
//延时函数
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void LEDRunning()
{
unsigned char i;
HC138_C = 1; //Y4输出
HC138_B = 0;
HC138_A = 0;
for(i=0;i<3;i++)
{
P0 = 0x00;
Delay(60000);
Delay(60000);
P0 = 0xff;
Delay(60000);
Delay(60000);
}
HC138_C = 1; //Y5输出
HC138_B = 0;
HC138_A = 1;
P0 = 0x10; //继电器吸合,其LED亮
Delay(60000);
Delay(60000);
P0 = 0x00; //继电器关闭,其LED灭
HC138_C = 1; //Y4输出,切换到控制8个LED
HC138_B = 0;
HC138_A = 0;
for(i=1;i<=8;i++) //i从1开始,使第一次也亮
{
P0 = 0xff << i; //全1,左移补0
Delay(60000);
Delay(60000);
}
for(i=1;i<=8;i++)
{
P0 = ~(0xff << i); //相当于全0,左移补1
Delay(60000);
Delay(60000);
}
HC138_C = 1; //Y5输出
HC138_B = 0;
HC138_A = 1;
P0 = 0x40; //蜂鸣器响,其LED亮
Delay(60000);
Delay(60000);
P0 = 0x00; //蜂鸣器关闭,其LED灭
}
void InitSystem() //关闭外设(蜂鸣器与继电器)
{
HC138_C = 1; //Y5输出,连接U9锁存器与达林顿管
HC138_B = 0;
HC138_A = 1;
P0 = 0x00; //达林顿管中为非门,输出1关闭蜂鸣器与继电器
}
void main()
{
InitSystem(); //关闭外设
while(1)
{
LEDRunning();
}
}
04 简化整体程序设计
#include <reg52.h>
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void InitHC138(unsigned char n) //控制74HC138输出
{
switch(n)
{
case 4: P2 = P2 & 0x1F | 0x80; break;
case 5: P2 = P2 & 0x1F | 0xa0; break;
case 6: P2 = P2 & 0x1F | 0xc0; break;
case 7: P2 = P2 & 0x1F | 0xe0; break;
}
}
void LEDRunning() //控制LED闪烁
{
unsigned char i;
InitHC138(4);
for(i=0;i<3;i++)
{
P0 = 0x00;
Delay(60000);
Delay(60000);
P0 = 0xff;
Delay(60000);
Delay(60000);
}
InitHC138(5); //控制继电器
P0 = 0x10;
Delay(60000);
Delay(60000);
P0 = 0x00;
InitHC138(4);
for(i=1;i<=8;i++)
{
P0 = 0xff << i;
Delay(60000);
Delay(60000);
}
for(i=1;i<=8;i++)
{
P0 = ~(0xff << i);
Delay(60000);
Delay(60000);
}
InitHC138(5); //控制蜂鸣器
P0 = 0x40;
Delay(60000);
Delay(60000);
P0 = 0x00;
}
void InitSystem() //关闭外设(蜂鸣器与继电器)
{
InitHC138(5);
P0 = 0x00;
}
void main()
{
InitSystem(); //关闭外设
while(1)
{
LEDRunning();
}
}
(二)数码管显示
01 数码管静态显示
(数码管分别单独显示0 ~ 9,然后同时显示0 ~ F)
#include <reg52.h>
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
//建立数组:数码管段码表,即单个数码管上显示的内容
unsigned char SMG_duanma[18]=
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, // 0~9
0x88,0x80,0xc6,0xc0,0x86,0x8e, // A~F
0xbf,0x7f}; // -与.
void InitHC138(unsigned char n) //选择输出端口连接相应功能的锁存器
{
switch(n)
{
case 4:
P2 = P2 & 0x1F | 0x80;
break;
case 5:
P2 = P2 & 0x1F | 0xA0;
break;
case 6:
P2 = P2 & 0x1F | 0xC0;
break;
case 7:
P2 = P2 & 0x1F | 0xE0;
break;
}
}
void show_SMG(unsigned char dat, unsigned int pos) //单个数码管显示
{
InitHC138(7); //单个数码管显示的内容
P0 = dat;
InitHC138(6); //单个数码管显示的位置
P0 = 0x01 << pos;
/*从左边第一个数码管开始,到右边最后一个数码管为止 由于高位在前,低位在后,代码编写时为左移符号*/
}
void SMG_Static() //数码管分别单独显示0~9
{
unsigned char i,j;
for(i = 0;i < 8; i++) //控制显示位置
{
for(j = 0;j < 10; j++) //控制显示内容
{
show_SMG(SMG_duanma[j],i);
Delay(60000);
Delay(60000);
}
}
for(j = 0;j < 16; j++)
{
InitHC138(7); //控制显示内容,段码端,接0有效
P0 = SMG_duanma[j];
InitHC138(6); //控制显示位置,共阳com端,接1有效
P0 = 0xff;
Delay(60000); //容易忘记延时函数!!!
Delay(60000);
}
}
void InitSystem() //初始化,关闭蜂鸣器、继电器、LED
{
InitHC138(5);
P0 = 0x00;
InitHC138(4);
P0 = 0xff;
}
void main()
{
InitSystem(); //关闭外设
while(1)
{
SMG_Static(); //数码管显示函数
}
}
02 数码管动态显示
(前四位为2023,中二位为- -分隔符,后两位为月份递增)
#include <reg52.h>
unsigned char month = 12; //月份上限
unsigned char SMG_duanma[18]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, // 0~9
0x88,0x80,0xc6,0xc0,0x86,0x8e, // A~F
0xbf,0x7f}; // -与.
void SelectHC573(unsigned char channel) //74HC138输出端连接的相应信道的HC573
{
switch(channel)
{
case(4):
P2 = P2 & 0x1f | 0x80;
break;
case(5):
P2 = P2 & 0x1f | 0xa0;
break;
case(6):
P2 = P2 & 0x1f | 0xc0;
break;
case(7):
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void SMG_bit(unsigned char dat, unsigned char pos) //单个数码管的显示内容、显示位置
{
SelectHC573(7);
P0 = dat;
SelectHC573(6);
P0 = 0x01 << pos;
}
void SMG_Dlelay(unsigned int t) //单个数码管显示的延时函数
{
while(t--);
}
void SMG_display()
{
SMG_bit(SMG_duanma[2],0);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[0],1);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[2],2);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[3],3);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[16],4);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[16],5);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[month/10],6);
SMG_Dlelay(500);
SMG_bit(SMG_duanma[month%10],7);
SMG_Dlelay(500);
}
void Delay(unsigned int t) //控制月份递增的延时函数
{
while(t--)
{
SMG_display();
}
}
void InitSystem() //关闭外设
{
SelectHC573(5);
P0 = 0x00;
}
void main()
{
InitSystem();
while(1)
{
SMG_display();
month++;
if(month>12)
month = 1;
Delay(100);
}
}
(三)独立按键
01 独立按键的基本操作
S7 ~ S4 控制 L1 ~ L4亮灭
#include <reg52.h>
sbit S7 = P3^0; //定义按键引脚
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit L1 = P0^0; //定义LED引脚
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;
sbit L7 = P0^6;
sbit L8 = P0^7;
void SelectHC573(unsigned char channel) //选择HC138输出的HC573锁存器
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void KEY_Delay(unsigned char t) //按键延时
{
while(t--);
}
void KEY_Alone()
{
SelectHC573(4); //选通LED锁存器
if(S7 == 0) //判断按键是否按下
{
KEY_Delay(100); //延时去抖动(消抖)
/*实现按键消抖 一个简单的消抖办法是检测到按键按下,则等待一定时常之后,再次检测是否在按下状态,如果是按下的状态,那么才确定是在按下状态。*/
if(S7 ==0) //按键持续按下
{
L1 = 0; //L1亮
while(S7 ==0); //如果按键为按下状态,则L1保持亮状态,不执行下面语句
L1 = 1; //如果按键松开,即跳出while循环,则L1灭
}
}
if(S6 == 0)
{
KEY_Delay(100);
if(S6 ==0)
{
L2 = 0;
while(S6 ==0);
L2 = 1;
}
}
if(S5 == 0)
{
KEY_Delay(100);
if(S5 ==0)
{
L3 = 0;
while(S5 ==0);
L3 = 1;
}
}
if(S4 == 0)
{
KEY_Delay(100);
if(S4 ==0)
{
L4 = 0;
while(S4 ==0);
L4 = 1;
}
}
}
void InitSystem() //关闭外设,LED上电后为全灭状态
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xFF;
}
void main()
{
InitSystem();
while(1)
{
KEY_Alone();
}
}
02 独立按键的扩展应用
S7、S6为两个状态,相互独立,
S7按下时,S6不能操作;S6按下时,S7不能操作
S7、S6都能够控制S5、S4
当S7、S6都未按下时,S5、S4都不能操作
S7控制S5使L3亮灭;S7控制S4使L4亮灭
S6控制S5使L5亮灭;S6控制S4使L6亮灭
#include <reg52.h>
sbit S7 = P3^0; //定义按键引脚
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit L1 = P0^0; //定义LED引脚
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;
sbit L7 = P0^6;
sbit L8 = P0^7;
void SelectHC573(unsigned char channel) //选择HC138输出的HC573锁存器
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void KEY_Delay(unsigned char t) //按键延时
{
while(t--);
}
unsigned char stat = 0; //定义一个状态变量
void KEY_Alone()
{
SelectHC573(4); //选通LED锁存器
if(S7 == 0) //判断按键是否按下
{
KEY_Delay(100); //延时去抖动
if(S7 ==0) //按键持续按下
{
if(stat == 0) //按键按下后,判断当前状态
{
L1 = 0;
stat = 1; //占用状态,设置为状态1
}
else if(stat == 1) //按键按下后,判断当前状态
{
L1 = 1;
stat = 0; //释放状态
}
while(S7 ==0); //循环当前状态,避免跳变
}
}
if(S6 == 0)
{
KEY_Delay(100);
if(S6 ==0)
{
if(stat == 0)
{
L2 = 0;
stat = 2; //占用状态,设置为状态2
}
else if(stat == 2)
{
L2 = 1;
stat = 0; //释放状态
}
while(S6 ==0); //循环当前状态,避免跳变
}
}
if(S5 == 0)
{
KEY_Delay(100);
if(S5 ==0)
{
if(stat == 1) //状态1,受S7控制
{
L3 = 0;
while(S5 == 0);
L3 =1;
}
else if(stat ==2) //状态2,受S6控制
{
L5 = 0;
while(S5 == 0);
L5 =1;
}
}
}
if(S4 == 0)
{
KEY_Delay(100);
if(S4 ==0)
{
if(stat == 1)
{
L4 = 0;
while(S4 == 0);
L4 =1;
}
else if(stat ==2)
{
L6 = 0;
while(S4 == 0);
L6 =1;
}
}
}
}
void InitSystem() //关闭外设,LED上电后为全灭状态
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xFF;
}
void main()
{
InitSystem();
while(1)
{
KEY_Alone();
}
}
(四)矩阵键盘
01 矩阵键盘的基本应用
矩阵键盘扫描,按键控制数码管第一位显示
#include <reg52.h>
/*打开头文件后发现没有对C3、C4的引脚P4的定义 需要自己添加,头文件中P3为0xb0,所以可以定一P4为0xc0*/
sfr P4 = 0xc0;
sbit R1 = P3^0;
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;
sbit C1 = P4^4;
sbit C2 = P4^2;
sbit C3 = P3^5;
sbit C4 = P3^4;
unsigned char SMG_duanma[18]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void Delay(unsigned char t)
{
while(t--);
}
void SMG_Display(unsigned char dat)
{
SelectHC573(6); //只在第一位显示
P0 = 0x01;
SelectHC573(7);
P0 = dat;
}
unsigned char Key_Num;
void ScanKey_DisplayNum()
{
//扫描第一行
R1 = 0;
R2 = R3 = R4 =1;
C1 = C2 = C3 = C4 =1;
if(C1 == 0)
{
Delay(100); //按键延时消抖
if(C1 == 0)
{
while(C1 == 0);
Key_Num = 0;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C2 == 0)
{
Delay(100); //按键延时消抖
if(C2 == 0)
{
while(C2 == 0);
Key_Num = 1;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C3 == 0)
{
Delay(100); //按键延时消抖
if(C3 == 0)
{
while(C3 == 0);
Key_Num = 2;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C4 == 0)
{
Delay(100); //按键延时消抖
if(C4 == 0)
{
while(C4 == 0);
Key_Num = 3;
SMG_Display(SMG_duanma[Key_Num]);
}
}
//扫描第二行
R2 = 0;
R1 = R3 = R4 =1;
C1 = C2 = C3 = C4 =1;
if(C1 == 0)
{
Delay(100); //按键延时消抖
if(C1 == 0)
{
while(C1 == 0);
Key_Num = 4;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C2 == 0)
{
Delay(100); //按键延时消抖
if(C2 == 0)
{
while(C2 == 0);
Key_Num = 5;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C3 == 0)
{
Delay(100); //按键延时消抖
if(C3 == 0)
{
while(C3 == 0);
Key_Num = 6;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C4 == 0)
{
Delay(100); //按键延时消抖
if(C4 == 0)
{
while(C4 == 0);
Key_Num = 7;
SMG_Display(SMG_duanma[Key_Num]);
}
}
//扫描第三行
R3 = 0;
R1 = R2 = R4 =1;
C1 = C2 = C3 = C4 =1;
if(C1 == 0)
{
Delay(100); //按键延时消抖
if(C1 == 0)
{
while(C1 == 0);
Key_Num = 8;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C2 == 0)
{
Delay(100); //按键延时消抖
if(C2 == 0)
{
while(C2 == 0);
Key_Num = 9;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C3 == 0)
{
Delay(100); //按键延时消抖
if(C3 == 0)
{
while(C3 == 0);
Key_Num = 10;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C4 == 0)
{
Delay(100); //按键延时消抖
if(C4 == 0)
{
while(C4 == 0);
Key_Num = 11;
SMG_Display(SMG_duanma[Key_Num]);
}
}
//扫描第四行
R4 = 0;
R1 = R2 = R3 =1;
C1 = C2 = C3 = C4 =1;
if(C1 == 0)
{
Delay(100); //按键延时消抖
if(C1 == 0)
{
while(C1 == 0);
Key_Num = 12;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C2 == 0)
{
Delay(100); //按键延时消抖
if(C2 == 0)
{
while(C2 == 0);
Key_Num = 13;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C3 == 0)
{
Delay(100); //按键延时消抖
if(C3 == 0)
{
while(C3 == 0);
Key_Num = 14;
SMG_Display(SMG_duanma[Key_Num]);
}
}
else if(C4 == 0)
{
Delay(100); //按键延时消抖
if(C4 == 0)
{
while(C4 == 0);
Key_Num = 15;
SMG_Display(SMG_duanma[Key_Num]);
}
}
}
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
}
void main()
{
InitSystem(); //关闭外设
while(1)
{
ScanKey_DisplayNum(); //矩阵键盘扫描,数码管显示相应数字
}
}
(五)中断系统与外部中断
01 外部中断基本操作
主程序:L1闪烁
中断服务函数:L8亮一段时间
方法1
#include <reg52.h>
sbit L1 = P0^0;
sbit L8 = P0^7;
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void working()
{
SelectHC573(4);
L1 = 0;
Delay(60000);
L1 = 1;
Delay(60000);
}
//=============================
void Init_INT0() //中断函数初始化
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
void Service_INT0() interrupt 0 //中断服务函数
{
L8 = 0;
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
L8 = 1;
}
//================================
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
}
void main()
{
InitSystem();
Init_INT0();
while(1)
{
working();
}
}
方法2
简化中断服务函数(中断函数要快进快出)
注意!!!
注意!!!
注意!!!
方法2并没有实现符合要求的中断,中断里仅仅对L8状态赋值,然而while中依旧遵循在执行完working()以后,才会执行控制L8相关函数(即必须在L1灭的状态之后才可以控制L8)
方法1才是符合要求的中断,实现了在中断中就直接对L8进行控制(即在L1灭或亮的状态下都可以控制L8)
注意!!!
注意!!!
注意!!!
#include <reg52.h>
sbit L1 = P0^0;
sbit L8 = P0^7;
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void working()
{
SelectHC573(4);
L1 = 0;
Delay(60000);
L1 = 1;
Delay(60000);
}
//=============================
void Init_INT0()
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
unsigned char stat = 0;
void Service_INT0() interrupt 0
{
stat = 1;
}
void LEDINT()
{
if(stat == 1)
{
L8 = 0;
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
Delay(60000);
L8 = 1;
stat = 0;
}
}
//================================
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
}
void main()
{
InitSystem();
Init_INT0();
while(1)
{
working();
LEDINT();
}
}
(六)定时器
01 定时器的基本原理与应用
定时器T0的模式1,实现以下功能
每隔1s,L1闪烁1次,即亮0.5s,灭0.5s
每隔10s,L8闪烁1次,即亮5s,灭5s
#include <reg52.h>
sbit L1 = P0^0;
sbit L8 = P0^7;
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
//================================
void Init_Time0()
{
TMOD = 0x01; //模式1,16位无自动重装
/* TMOD只能高四位控制T1,此处不需要,所以全部置0 低四位控制T0,且使用模式1*/
TH0 = (65535-50000) / 256; //高8位
TL0 = (65535-50000) % 256; //低8位
ET0 = 1; //T0的中断允许
EA = 1; //总中断
TR0 =1; //定时器0运行控制
}
unsigned char count = 0;
unsigned char count1 = 0;
void Service_Time0() interrupt 1
{
Select_HC573(4);
TH0 = (65535-50000) / 256; //模式1无自动重装,中断服务函数需重新赋初始值
TL0 = (65535-50000) % 256;
count++;
count1++;
if(count == 10)
{
L1 = ~L1;
count = 0;
}
if(count1 == 100)
{
L8 = ~L8;
count1 = 0;
}
}
//=================================
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_Time0();
Init_System();
while(1)
{
}
}
02 定时器的进阶综合案例
分、秒、毫秒显示
00-00-00
#include <reg52.h>
sbit S4 = P3^3;
sbit S5 = P3^2;
unsigned char SMG_duanma[12]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0xbf,0x7f};
unsigned char min;
unsigned char sec;
unsigned char msec;
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
void SMG_bit(unsigned char pos,unsigned char dat)
{
Select_HC573(6);
P0 = 0x01 << pos;
Select_HC573(7);
P0 = dat;
}
void SMG_Delay(unsigned int t)
{
while(t--);
}
void SMG_Display()
{
SMG_bit(7,SMG_duanma[msec%10]);
SMG_Delay(500);
SMG_bit(6,SMG_duanma[msec/10]);
SMG_Delay(500);
SMG_bit(5,SMG_duanma[10]);
SMG_Delay(500);
SMG_bit(4,SMG_duanma[sec%10]);
SMG_Delay(500);
SMG_bit(3,SMG_duanma[sec/10]);
SMG_Delay(500);
SMG_bit(2,SMG_duanma[10]);
SMG_Delay(500);
SMG_bit(1,SMG_duanma[min%10]);
SMG_Delay(500);
SMG_bit(0,SMG_duanma[min/10]);
SMG_Delay(500);
}
//==========定时器相关函数================
void Init_Time0()
{
TMOD = 0x01; //模式1,16位无自动重装
TH0 = (65535-50000) / 256; //高8位
TL0 = (65535-50000) % 256; //低8位
ET0 = 1; //T0的中断允许
EA = 1; //总中断
TR0 =1; //定时器0运行控制
}
/*可以用烧录软件生成蓝桥杯规定的12MHz下的定时器配置, 再自己添加定时器中断使能和总中断。 void Init_Time0() //50毫秒@12.000MHz { AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0xB0; //设置定时初始值 TH0 = 0x3C; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; EA = 1; } */
void Service_Time0() interrupt 1
{
TH0 = (65535-50000) / 256;
TL0 = (65535-50000) % 256;
msec++;
if(msec == 20)
{
sec++;
msec = 0;
if(sec == 60)
{
min++;
sec = 0;
}
if(min == 99)
min = 0;
}
}
//=================================
void Key_Delay(unsigned int t)
{
while(t--);
}
void Key_fun()
{
if(S4 == 0)
{
Key_Delay(100); //延时消抖
if(S4 == 0)
{
TR0 = ~TR0; //暂停或启动
while(S4 == 0) //松手检测,数码管仍动态显示
{
SMG_Display();
}
}
}
if(S5 == 0)
{
Key_Delay(100); //延时消抖
if(S5 == 0)
{
min = sec = msec = 0; //复位
while(S5 == 0)
{
SMG_Display();
}
}
}
}
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_Time0();
Init_System();
while(1)
{
SMG_Display();
Key_fun();
}
}
(七)脉冲宽度调制(PWM)
01 脉宽调制信号的发生与控制
S7控制L1调节三种亮度,10%、40%、90%
脉宽信号频率为100Hz(即信号周期为10ms=10 000us,将一个周期分为100份,每份100us)
#include <reg52.h>
sbit L1 = P0^0;
sbit S7 = P3^0;
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
//============定时器相关函数==============
void Init_Time0()
{
TMOD = 0x00; //模式0,16位自动重装,中断服务函数中不用再重写了
TH0 = (65535-100) / 256;
TL0 = (65535-100) % 256;
ET0 = 1;
EA = 1;
//TR0定时器0控制位放在按键函数中
}
unsigned char count = 0;
unsigned char pwm_duty = 0;
void Service_Time0() interrupt 1
{
count++;
if(count == pwm_duty)
{
L1 = 1;
}
else if(count == 100)
{
L1 = 0;
count = 0;
}
}
//========================================
void Key_Delay(unsigned char t)
{
while(t--);
}
unsigned char stat = 0; //状态变量
void Key_Fun()
{
Select_HC573(4);
if(S7 == 0)
{
Key_Delay(100); //延时消抖
if(S7 == 0)
{
switch(stat)
{
case 0:
L1 = 0;
TR0 = 1; //开启定时器0运行控制位
pwm_duty = 10;
stat = 10;
break;
case 10:
pwm_duty = 40;
stat = 40;
break;
case 40:
pwm_duty = 90;
stat = 90;
break;
case 90:
L1 = 1;
TR0 = 0; //关闭定时器0运行控制位
stat = 0;
break;
}
while(S7 == 0); //检测松手
}
}
}
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_System();
Init_Time0();
while(1)
{
Key_Fun();
}
}
(八)串口通信
01 串口通信基本原理应用
- Send_Byte()函数需要重新上电才能执行
- 串口中断,串口接收完完整的一帧数据自身产生的中断,配置使能该中断后,串口会判断总线上一个字节的时间间隔内有没有再次接收到数据(即if(RI == 1)),如果没有则当前一帧数据接收完成,产生中断。
#include <reg52.h>
sfr AUXR = 0x8e; //定义辅助寄存器
void Send_Byte(unsigned char dat);
//声明数据发送函数(因数据接收函数在发送函数之前要调用发送函数)
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = P2 & 0x1f | 0x80;
break;
case 5:
P2 = P2 & 0x1f | 0xa0;
break;
case 6:
P2 = P2 & 0x1f | 0xc0;
break;
case 7:
P2 = P2 & 0x1f | 0xe0;
break;
}
}
//============中断接收函数===============
void Init_Uart()
{
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
SCON = 0x50;
AUXR = 0x00;
ES = 1;
EA = 1;
}
unsigned char urdat;
void Service_Uart() interrupt 4 //数据接收(中断方式)
{
if(RI == 1)
{
RI = 0; //软件复位
urdat = SBUF;
Send_Byte(urdat + 1);
}
}
//===================================
void Send_Byte(unsigned char dat) //数据发送(轮询方式)
{
SBUF = dat; //SBUF 串口数据缓冲寄存器
while(TI == 0); //如果数据已发送则TI为1,跳出此循环
TI = 0;
}
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_System();
Init_Uart();
Send_Byte(0x5a);
Send_Byte(0xa5);
while(1);
}
02 串口通信的进阶应用
开关反转
在原理图中LED亮为0,灭为1
但若是题目要求亮为1,灭为0
以ax为例
改变低4位,保留高4位
0 | any = any
1 | any = 1
0 & any = 0
1 & any = any
- 一般由于程序初始化设置,LED上电后为灭状态,即P0 = 0xff(1111 1111)
- P0 | 0x0f ——>
高4位不变
,低4位为1(1111 1111)- ~command | 0xf0 ——>command按位取反,再使高4位为1,
低4位不变
(1111 xxxx)- P0 = (P0 | 0x0f) & (~command | 0xf0) ——>两式相与(1111 xxxx)
#include <reg52.h>
sfr AUXR = 0x8e; //定义辅助寄存器
void Select_HC573(unsigned char channel) //锁存器选择函数
{
switch(channel)
{
case 4: P2 = P2 & 0x1f | 0x80; break; //控制LED
case 5: P2 = P2 & 0x1f | 0xa0; break; //控制蜂鸣器、继电器
case 6: P2 = P2 & 0x1f | 0xc0; break; //数码管com共阳公共端
case 7: P2 = P2 & 0x1f | 0xe0; break; //数码管段码端
}
}
//==============串口数据接收中断===================
void Init_Uart() //中断初始化函数
{
TMOD = 0x20; //定时器1
TH1 = 0xfd; //设置波特率为9600
TL1 = 0xfd; //11.0592M或12M的12分频
SCON = 0X50; //串口参数为模式1且允许接收
AUXR = 0x00; //bit7=1:定时器1不分频,0则12分频
TR1 = 1; //启动定时器1
ES = 1; //使能串口中断
EA = 1; //打开总中断
}
unsigned char command = 0x00; //注意赋初值为16进制
void Service_Uart() interrupt 4 //中断服务函数
{
if(RI == 1) //收到一个完整字节
{
command = SBUF; //将SBUF缓冲器中数据赋值给command
RI = 0; //人工清零
}
}
//=================================================
void SendByte(unsigned char dat) //发送数据函数
{
SBUF = dat; //将数据放入SBUF缓冲器
while(TI == 0); //如果成功发送数据,则TI为1跳出此循环
TI = 0; //人工清零
}
void SendString(unsigned char *str) //发送字符串函数
{
while(*str != '\0') //判断指针是否指向字符串结束符
{
SendByte(*str++); //先执行SendByte(*str),赋值完成后,指针++移向下一位
}
}
void Working()
{
Select_HC573(4); //控制LED
if(command != 0x00)
{
switch(command & 0xf0) //高4位不变,低4位清零
{
case 0xa0:
P0 = (P0 | 0x0f) & (~command | 0xf0);
command = 0x00; //避免重复执行working函数
break;
case 0xb0:
P0 = (P0 | 0xf0) & ((~command << 4)| 0x0f);
command = 0x00;
break;
case 0xc0:
SendString("The System is Working Normally...");
command = 0x00;
break;
}
}
}
void Init_System() //程序初始化
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_Uart();
Init_System();
SendString("Welcome to the System...\r\n");
while(1)
{
Working();
}
}
(九)IO / 存储扩展
IO扩展(J13接2~3脚 IO模式)
#include <reg52.h>
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4: P2 = P2 & 0x1f | 0x80; break;
case 5: P2 = P2 & 0x1f | 0xa0; break;
case 6: P2 = P2 & 0x1f | 0xc0; break;
case 7: P2 = P2 & 0x1f | 0xe0; break;
}
}
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void LED_Display()
{
Select_HC573(4);
P0 = 0x0f;
Delay(60000);
Delay(60000);
P0 = 0xf0;
Delay(60000);
Delay(60000);
P0 = 0xff;
Delay(60000);
Delay(60000);
}
void SMG_Display()
{
unsigned char i;
for(i = 0;i < 8; i++)
{
Select_HC573(6);
P0 = 0x01 << i;
Select_HC573(7);
P0 = 0x00;
Delay(60000);
Delay(60000);
}
P0 = 0xff;
Delay(60000);
Delay(60000);
}
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_System();
while(1)
{
LED_Display();
SMG_Display();
}
}
存储扩展(J13接1~2脚 MM模式)
#include <absacc.h>
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void LED_Display()
{
XBYTE[0x8000] = 0x0f;
Delay(60000);
Delay(60000);
XBYTE[0x8000] = 0xf0;
Delay(60000);
Delay(60000);
XBYTE[0x8000] = 0xff;
Delay(60000);
Delay(60000);
}
void SMG_Display()
{
unsigned char i;
for(i = 0;i < 8; i++)
{
XBYTE[0xc000] = 0x01 << i;
XBYTE[0xe000] = 0x00;
Delay(60000);
Delay(60000);
}
XBYTE[0xe000] = 0xff;
Delay(60000);
Delay(60000);
}
void Init_System()
{
XBYTE[0xa000] = 0x00;
XBYTE[0x8000] = 0xff;
}
void main()
{
Init_System();
while(1)
{
LED_Display();
SMG_Display();
}
}
今天的文章蓝桥杯单片机按键程序_单片机项目设计案例[通俗易懂]分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/79421.html