几乎每届蓝桥杯单片机组比赛都会考到led模块;特别是对于近几年的省赛来讲,led模块的使用显得更为灵活;即便led比较之简单,但是编写程序时还是很有可能出现错误。
现在来给大家介绍动态数码管的使用方法
1、对led模块进行操作,无需改变跳帽的位置。
2、led模块相关原理图如下
- 在这里我只展示了led显示模块的主要部分。其他是一些门电路,大家可以参照官方给定的PDF。
- 注意CT017D开发版上的led模块共Vcc。
- 打开led有关锁存器的代码位P2=0X80;打开led有关锁存器的代码位P2=0X00;
- led显示代码的编写同样利用到了状态机的思想,为了防止led模块对应的锁存器频繁开关,我们可以定义一个led_flag标志位对其进行控制。
- led显示模块的一般操作:一、将操作led点亮的数码管代码送入锁存器。二、打开led有关锁存器。三、关闭led有关锁存器。
Q:为啥led的操作是先送数据再操作锁存器呢?
A:在执行点亮led点亮的代码时,P0口可能会随时发生改变;若此时先打开锁存器再发送数据,那么P0就有可能被多次赋值,从而导致led模块可能出现微亮现象。因此,为了杜绝此类事情发生,我们必须先送数据再操作相应锁存器。
总而言之,在编写代码的时候必须避开这两个坑
-
l
ed模块微亮
-
循环不间断访问led模块
3、如下,附上led显示代码块。
#include "STC15F2K60S2.h"
#define u8 unsigned char
#define KEY_STATE0 0
#define KEY_STATE1 1
#define KEY_STATE2 2
#define led_0 0x00
#define led_1 ((0x01)<<(1-1))
#define led_2 ((0x01)<<(2-1))
#define led_3 ((0x01)<<(3-1))
#define led_4 ((0x01)<<(4-1))
#define led_5 ((0x01)<<(5-1))
#define led_6 ((0x01)<<(6-1))
#define led_7 ((0x01)<<(7-1))
#define led_8 ((0x01)<<(8-1))
//上述代码简单粗暴
void Timer0Init(void) //配置定时器0,1ms中断
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0xCD;
TH0 = 0xD4;
TF0 = 0;
TR0 = 1;
ET0=1;
EA=1;
}
unsigned char key_scan()
{
static char KEY_STATE=KEY_STATE0;
u8 KEY=0;
u8 key_value=0;
P30=1;P31=1;P32=1;P33=1;
if(P30==0) KEY=7;
if(P31==0) KEY=6;
if(P32==0) KEY=5;
if(P33==0) KEY=4;
if((P30==1)&&(P31==1)&&(P32==1)&&(P33==1)) KEY=0;
switch(KEY_STATE)
{
case KEY_STATE0:
if(KEY!=0)
{
KEY_STATE=KEY_STATE1;
}
break;
case KEY_STATE1:
switch(KEY)
{
case 4: key_value=4; break;
case 5: key_value=5; break;
case 6: key_value=6; break;
case 7: key_value=7; break;
}
KEY_STATE=KEY_STATE2;
break;
case KEY_STATE2:
if(KEY==0)
{
KEY_STATE=KEY_STATE0;
}
break;
}
return key_value;
}
bit key_flag;
u8 key_val;
bit led_flag;
u8 led_COM[10]={led_0,led_1,led_2,led_3,led_4,led_5,led_6,led_7,led_8};//led显示数组
static char led_choose1=0; //若每次只需要对于一个led进行操作
//static char led_choose2=0; //每次需要对两个以上的led进行操作,可另外添加led_choosex
void main()
{
P0=~0X00;P2=0X80;P2=0X00;
P2=0XA0;P0=0X00;P2=0X00;
Timer0Init();
while(1)
{
if(led_flag)
{
led_flag=0;//状态置0,防止一直进行led模块的操作。
P0=~(led_COM[led_choose1]/*|led_COM[led_choose2]*/);P2=0X80;P2=0X00;
//特别注意,若需要操作多个led灯,则每个代码之间需相或。
}
if(key_flag)
{
key_flag=0;
key_val=key_scan();
switch(key_val)
{
case 4: led_flag=1;led_choose1=1; /*led_choose2=8;*/ break;
case 5: led_flag=1;led_choose1=2; /*led_choose2=7;*/ break;
case 6: led_flag=1;led_choose1=3; /*led_choose2=6;*/ break;
case 7: led_flag=1;led_choose1=4; /*led_choose2=5;*/ break;
//注意:不管键值如何,只要需对led进行操作,就必须使“led_flag”置1。
}
}
}
}
void Timer0() interrupt 1 //定时器0中断
{
static int key_count=0;
key_count++;
if(key_count==10)
{
key_count=0;
key_flag=1;
}
}
-
为了方便看到led显示的效果,本文中还用到了独立按键模块;如需要深入了解独立按键模块的运行,请点击下面的链接:
https://blog.csdn.net/qq_44629819/article/details/104486419
4、这只是led模块最基本的操作,led流水灯等内容以后会提到。
版权声明:本文为qq_44629819原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。