蓝桥杯单片机基本模块

锁存器

蓝桥杯这款单片机是用锁存器来实现引脚的复用的,所以代码写起来很麻烦,总是要开关锁存器

为了偷懒,可以用宏定义来定义每个锁存器打开的代码,也可以用函数来实现

用宏定义:

1
2
3
4
5
6
#define Y4 P2 = (P2&0x1f)|0x80;  //led
#define Y5 P2 = (P2&0x1f)|0xa0; //蜂鸣器和继电器
P0 = 0x40; //蜂鸣器
P0 = 0x10//继电器
#define Y6 P2 = (P2&0x1f)|0xc0; //数码管位选
#define Y7 P2 = (P2&0x1f)|0xe0; //数码管段选

用函数:

1
2
3
4
5
6
7
8
9
10
void select_channel(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; //数码管位选
case 7: P2 = P2&0x1f|0xe0; break; //数码管段选
}
}

数码管的显示问题

初学者一般都是用延时来实现动态数码管的,但是当要实现的功能多起来了,用延时来实现动态数码管,数码管很容易会闪烁,整体效果就很不好了。

另外一种方法可以是用定时器来扫描数码管,每隔一段时间就进入中断服务函数执行数码管的扫描,只要中断间隔的时间小于人眼的视觉暂留(大概是0.1~0.4s),就看不出来数码管会闪烁了。但是这个方法也有缺点,缺点是整个系统每隔这么短的时间就必须要进入这个中断服务函数,很容易会影响、打断其他程序的执行。现在也有解决方法就是在不能被中断打断的功能执行前关掉中断的开关,执行完之后再打开,显然这个解决方法也只是权宜之计,关掉中断的开关有的时候会影响这个计时器的计时,获得的时间就不是很准确,但是误差会很小吧,十行代码51单片机几毫秒甚至更短的时间就可以执行完。所以第二种方法算是比较好的一种方法了,相对于第一种方法来说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <reg52.h>

unsigned char smgd[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
unsigned char smgw[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
char smgbuf[8],smg_num = 0;

void select_channel(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; //数码管位选
case 7: P2 = P2&0x1f|0xe0; break; //数码管段选
}
}

void init() //总的初始化函数
{
char i;
for(i = 0;i < 8;i++)
smgbuf[i] = 10; //做初始化,上电数码管全部是熄灭的

P0 = 0xff; //关掉所有的LED
select_channel(4);
P2&= 0x1f;

P0 = 0x00; //关掉继电器和蜂鸣器
select_channel(5);
P2&= 0x1f;
}

void init_timer() //初始化计时器
{
TMOD = 0x01;
TH1 = 0xf8;
TL1 = 0x2f;//2ms
EA = 1;
ET1 = 1;
TR1 = 1;
}

void display() //数码管显示函数
{
smg_num++;
if(smg_num >= 8)
smg_num = 0; //从0-7循环扫描每一个数码管

P0 = 0xff;
select_channel(7);
P2&= 0x1f; //消影

P0 = 0x00;
select_channel(6);
P0 = smgw[smg_num];
P2&= 0x1f;

P0 = 0xff;
select_channel(7);
P0 = ~smgd[smgbuf[smg_num]];
P2&= 0x1f;
}

void main()
{
char i;
init();
init_timer();
while(1)
{
for(i=0;i<8;i++)
smgbuf[i] = i; //数码管一次显示0-7
}
}

void timer1() interrupt 3
{
display();
}

上面的代码是直接在Typora上面写的,没有编译,应该没有很大问题(手动滑稽)

这样写要改变数码管的值只要改变数组smgbuf[]中的值就行了0-9的数字是和编号一一对应的,其他的特殊符号可以自己手动加。