电路介绍
![](https://i-blog.csdnimg.cn/blog_migrate/ae0b9f42affb23de439e07c1a784165b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b5b1a0aaa6d2cac19b24a282915eac23.png)
与蜂鸣器、继电器电路原理一模一样,只是使用的锁存器(U6)和选通锁存器的管脚(Y4C)不一样。
蓝桥杯板上一个使用的8个LED组成灯组,并且是共阳极连接的,也就是所有LED的阳极全部连接在一起接上电源VCC,所以要想让LED点亮,就需要给它输入低电平,也就是相应管教置0就点亮,置1就熄灭。
与蜂鸣器继电器一样,首先P0相应的管脚置0,再将Y4C置1,选通U6锁存器(P2=0x80),人后将Y4C置0,关闭锁存器,就可以对相应的LED进行点亮。
点亮指定的LED
虽然板子上的LED是L1~L8这样子排列的,但是在给P0赋值时是从高位开始的(P7~P0),所以在进行写代码进行进制转换时,要按照L8~L1这样来思考。考试的时候是可以直接用计算器来进行进制转换之类的计算的,但是考试一般使用的是win7系统,所以建议大家下载一个win7计算器来使用,以便于适应考试时的电脑。
/*
上电默认关闭继电器、蜂鸣器,并点亮指定的LED灯
1.点亮L1 L3 L7 L8四个LED,其余熄灭
2.点亮L1 L3 L5 L7四个LED,其余熄灭
*/
#include "STC15F2K60S2.h"
#include "intrins.h"
unsigned char buzzer_ctrl; //定义全局变量buzzer_ctrl来控制蜂鸣器
unsigned char relay_ctrl; //定义全局relay_ctrl变量来控制继电器
void Delay1000ms() /* 延时1s@12.000MHz,用STC-ISP软件生成 */
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 46;
j = 153;
k = 245;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Divice_Ctrl(unsigned char p2data,unsigned char p0data) //继电器、蜂鸣器控制函数
{
P0=p0data;
P2=p2data;
P2=0;
}
void System_Init() //系统初始化函数,将继电器、蜂鸣器关闭
{
buzzer_ctrl=0;
relay_ctrl=0;
Divice_Ctrl(0xa0,((buzzer_ctrl<<6)|(relay_ctrl<<4)));
}
void main()
{
System_Init();
Divice_Ctrl(0x80,0x3a); //0x3a就是0011 1010的16进制
Delay1000ms();
Divice_Ctrl(0x80,0xaa); //0xaa就是1010 1010的16进制
Delay1000ms();
}
变量位操作LED
上面的代码是整个P0口进行赋值来点亮LED,用变量位来进行点亮LED,就可以单独操作一个P
0的位,且不影响其他的位。也就是控制单个LED且不影响其他LED的控制。
/**数组进行变量位控制**/
/*点亮L1 L3 L7 L8四个LED*/
#include "STC15F2K60S2.h"
#include "intrins.h"
unsigned char led_ctrl[9];
void Divice_Ctrl(unsigned char p2data,unsigned char p0data) //继电器、蜂鸣器控制函数
{
P0=p0data;
P2=p2data;
P2=0;
}
void System_Init() //系统初始化函数,将继电器、蜂鸣器关闭
{
Divice_Ctrl(0xa0,0);
}
void main()
{
System_Init();
led_ctrl[1]=1;
led_ctrl[3]=1;
led_ctrl[7]=1;
led_ctrl[8]=1;
Divice_Ctrl(0x80,~(led_ctrl[1] | led_ctrl[3]<<2 | led_ctrl[7]<<6 | led_ctrl[8]<<7));
while(1)
{
}
}
以上代码与前面的继电器、蜂鸣器十分形似,都采用全局变量来进行相应控制,并且该代码使用了取反运算符(~),这样就可以记忆成相应管脚置1点亮LED,可以更好的与继电器、蜂鸣器一起进行记忆。
以上代码采用了数组中相应的元素进行赋值,并移位的操作来控制LED,当需要单独控制某一个LED时,就可以直接对数组中的元素进行操作,此方法使用起来方便,不需要进行进制转换,并且容易记,所以相较于上面的对整个P0口进行赋值操作的方法,更推荐该种方法。
注:为什么不使用sbit来定义管脚,直接进行位控制,而是要用变量的方式来进行控制
使用sbit对单独的位进行操作时,如果前面有对蜂鸣器、继电器操作后留下的数据,在打开锁 存器进行LED控制时,前面遗留下的数据,可能会对LED的控制产生影响。所以为了避免这种 情况,在进行控制时,要对整个P0口一起控制。
流水灯
/*流水灯*/
/*L1~L8从左往右依次点亮,间隔为1s*/
/*L8~L1从右往左依次点亮,间隔为1s*/
/*L2 L4 L6 L8从左往右依次点亮,间隔为1s*/
#include "STC15F2K60S2.h"
#include "intrins.h"
unsigned char led_ctrl[9];
void Divice_Ctrl(unsigned char p2data,unsigned char p0data) //继电器、蜂鸣器控制函数
{
P0=p0data;
P2=p2data;
P2=0;
}
void Delay1000ms() /* 延时1s@12.000MHz,用STC-ISP软件生成 */
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 46;
j = 153;
k = 245;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void System_Init() //系统初始化函数,将继电器、蜂鸣器关闭
{
Divice_Ctrl(0xa0,0);
}
void led_flash_L1_L8()
{
static unsigned char led_shift=0;
Divice_Ctrl(0x80,~(0x01 << led_shift));
led_shift++;
if(led_shift==8)
led_shift=0;
}
void led_flash_L8_L1()
{
static unsigned char led_shift=0;
Divice_Ctrl(0x80,~(0x80 >> led_shift));
led_shift++;
if(led_shift==8)
led_shift=0;
}
void led_flash_L2_L4_L6_L8()
{
static unsigned char led_shift=0;
Divice_Ctrl(0x80,~(0x02 << led_shift));
led_shift=led_shift+2;
if(led_shift==8)
led_shift=0;
}
void main()
{
Divice_Ctrl(0xa0,0);
while(1){
//led_flash_L1_L8();
//led_flash_L8_L1();
led_flash_L2_L4_L6_L8();
Delay1000ms();
}
}
以上代码需要注意的是,控制移位操作的变量需要定义为static静态变量,不然在while循环中,每次执行该函数,都会将led_shift赋值为0,灯也就不会进行流水点亮,会只点亮一个灯。当然如果不像上面一样进行函数封装,直接在while循环中实现流水灯代码,也就不需要定义为静态变量了。
利用共用体实现字节赋值和位赋值
这种方式可以既能字节赋值也能位赋值,需要用到结构体、共用体、位域等知识。
/*************************************************
File name: 【LED】利用共用体实现字节赋值和位赋值
Description:
1. 定义一个叫bits的结构体数据类型! 用bits b; 变量b就是结构体变量!
2. 定义一个叫HexTobin的共用体数据类型! 用 HexToBin led_ctrl; 变量led_ctrl就是个共用体变量!
3. 对led_ctrl.hex赋值一个字节的数据,对应的led_ctrl.b.b0 到 led_ctrl.b.b7会对应变化!
4. 对led_ctrl.b.b0进行位赋值,对应led_ctrl.hex也会对应变化!
Attention:
1. 熟悉typedef用法,结构体struct用法,共用体union用法!
Copyright (c) 电子设计工坊 dianshe.taobao.com
All rights reserved
*************************************************/
#include <STC15F2K60S2.H>
#include <intrins.h>
#include "Delay.h"
#include "Device.h"
/* 用typedef定义一个叫bits的结构体“数据类型”, 从而可以用 bits b; 定义b为结构体的“变量”*/
typedef struct
{
unsigned char b0 : 1;
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
}bits;
/* 用typedef定义一个叫HexToBin的共用体“数据类型”, 从而可以用 HexToBin led_ctrl; 定义led_ctrl为共用体的“变量”*/
typedef union
{
unsigned char hex;
bits b;
}HexToBin;
HexToBin led_ctrl,buzzer_ctrl;
/**
* @brief 系统初始化函数:关闭继电器、蜂鸣器
* @param None
* @retval None
* @author dianshe.taobao.com
*/
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /* 关闭蜂鸣器、继电器*/
}
void main(void)
{
vSystem_Init();
led_ctrl.hex = 0x55; /* 对led_ctrl进行“字节赋值”,希望L2 L4 L6 L8点亮 */
vDevice_Ctrl(0x80,led_ctrl.hex); /* 选通Y4C锁存器,并在P0口输出一个字节数据,完成点亮L2 L4 L6 L8操作 */
buzzer_ctrl.b.b4 = 1; /* 对buzzer_crtl进行“位赋值”,希望吸合继电器 */
vDevice_Ctrl(0xa0,buzzer_ctrl.hex); /* 选通Y5C锁存器,并在P0口输出一个字节数据,完成吸合继电器操作 */
while(1)
{
led_ctrl.b.b1 = 1; /* led_ctrl进行“位赋值”,希望熄灭L2 */
vDevice_Ctrl(0x80,led_ctrl.hex); /* 选通Y4C锁存器,并在P0口输出一个字节数据,完成熄灭L2操作 */
buzzer_ctrl.b.b4 = 1; /* 对buzzer_crtl进行“位赋值”,希望吸合继电器 */
vDevice_Ctrl(0xa0,buzzer_ctrl.hex); /* 选通Y5C锁存器,并在P0口输出一个字节数据,完成吸合继电器操作 */
vDelay_Ms(200); /* 仅作练习用,在while(1)不要使用大于20ms的延时!会造成CPU资源浪费!学完定时器,即可把长时间Delay给优化掉! */
led_ctrl.b.b1 = 0; /* led_ctrl进行“位赋值”,希望点亮L2 */
vDevice_Ctrl(0x80,led_ctrl.hex); /* 选通Y4C锁存器,并在P0口输出一个字节数据,完成点亮L2操作 */
buzzer_ctrl.b.b4 = 0; /* 对buzzer_crtl进行“位赋值”,希望关闭继电器 */
vDevice_Ctrl(0xa0,buzzer_ctrl.hex); /* 选通Y5C锁存器,并在P0口输出一个字节数据,完成关闭继电器操作 */
vDelay_Ms(200);
}
}