关于蓝桥杯

CGC Lv4

基本原理

LED指示灯

基本原理


锁存器(M74HC573MIR)用io控制对应led,三八译码器控制y4(0)以控制y4c以控制锁存器使能

蜂鸣器与继电器

ULN2003达林顿管


输出为输入的非


通过三八译码器控制y5(低电平有效)控制y5c以控制锁存器使能,在通过锁存器及达林顿管(类非门)控制端口达到控制蜂鸣器及继电器作用

数码管

共阳数码管段位表

1
2
3
4
5
6
7
8
9
10
0	--	0xC0
1 -- 0xF9
2 -- 0xA4
3 -- 0xB0
4 -- 0x99
5 -- 0x92
6 -- 0x82
7 -- 0xF8
8 -- 0x80
9 -- 0x90

列表形式为

1
2
3
// 共阳
unsigned char smg_yang = [0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90] // 对应0-9
unsigned char smg_dot[10] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10}; // 带小数点 由不带小数点的段码减去0x80

共阴数码管段位表

1
2
3
4
5
6
7
8
9
10
0	--	0x3F
1 -- 0x06
2 -- 0x5B
3 -- 0x4F
4 -- 0x66
5 -- 0x6D
6 -- 0x7D
7 -- 0x07
8 -- 0x7F
9 -- 0x6F

列表形式为

1
2
// 共阴
unsigned char smg_yin = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F] // 对应0-9

按键


对于蓝桥板子 P37换为P44 P36换为P42

独立按键

需将J5的跳帽接到2~3引脚
0为按下

矩阵键盘

需将J5的跳帽接到1~2引脚

中断


需将J5的跳帽接到2~3引脚
即s5接到p32/int0 s4接到p33/int1

DB18B20


依据流程图 相关代码如下

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
void read_ds18b20()
{
unsigned char LSB, MSB;

init_ds18b20();
Write_DS18B20(0xcc); // 跳过rom操作
Write_DS18B20(0x44); // 开始读

delay_ds18b20(1000);
init_ds18b20();
Write_DS18B20(0xcc); // 跳过rom操作
Write_DS18B20(0xbe);

LSB = Read_DS18B20(); // 低八位
MSB = Read_DS18B20(); // 高八位

temp = MSB;
temp = (temp << 8) | LSB;
if(temp & 0xf800 == 0x0000) // 判断高五位(符号位)此处为判断正数
{
temp >>= 4;
temp = temp * 10;
temp = temp + (LSB & 0x0f) * 0.625;
}
}

DS1302

采用三线spi接口

日历时钟寄存器


备赛更新

HC138模块选择

版本1

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
void selete_hc138(u8 num)
{
switch (num)
{
case 0:
HC138_A = 0;
HC138_B = 0;
HC138_C = 0;
break;
case 4:
HC138_A = 0;
HC138_B = 0;
HC138_C = 1;
break;
case 5:
HC138_A = 1;
HC138_B = 0;
HC138_C = 1;
break;
case 6:
HC138_A = 0;
HC138_B = 1;
HC138_C = 1;
break;
case 7:
HC138_A = 1;
HC138_B = 1;
HC138_C = 1;
break;
}
}

其中
4 为LED
5 为继电器及蜂鸣器 0x10为继电器闭合 亮灯(L10)
6 为数码管位选
7 为数码管段选

版本2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void select_hc138(num)
{
switch (num)
{
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;
}
}

数码管显示

1
2
3
4
5
6
7
void fmq_display(u8 pos,u8 num)
{
selete_hc138(6);
P0 = (0X01 << pos) ;
selete_hc138(7);
P0 = num;
}

系统初始化

进行关灯等

1
2
3
4
5
6
7
void system_init()
{
selete_hc138(0);
P0 = 0x00;
selete_hc138(4);
P0 = 0xff;
}

温度模块-DS18B20

驱动文件修改 [2024更新] 最新的赛点资源包已经修复该问题


对于蓝桥杯的板子,由于其运行速度较快,官方给的驱动文件需要进行修改,将内部延时函数改为如下

1
2
3
4
5
void Delay_OneWire(unsigned int t)  
{
t *= 10;
while(t --);
}

即 将输入的延时时间放大十倍

温度读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
float temp_f;
u16 temp_i;
void rd_tempture()
{
u16 temp;
u8 high, low;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);

init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);

low = Read_DS18B20();
high = Read_DS18B20();

init_ds18b20();

temp = (high << 8) | low;
temp_f = temp * 0.0625;
temp_i = temp_f * 10;
}

其中temp_f为当前温度值,以float储存,在使用时根据所需进行放大并转为int储存在temp_i中便于数码管显示

内置日历时钟定时器-ds1302

寄存器表


注意
高四位及第四位以bcd码储存
以读秒为例子,取出81H地址中的值时,高八位储存的为十位,即time[0] / 16为十位,time[0] % 16为个位。

日历读取及使用

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
u8 code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; // 对应寄存器地址
u8 code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

u8 time[] = {0x50, 0x59, 0x20, 0x05, 0x03, 0x05, 0x23}; // 用于初始化
void ds1302_init() // 初始化
{
u8 i;
Write_Ds1302_Byte(0x8e, 0x00);
for(i = 0; i < 7; i++)
{
Write_Ds1302_Byte(WRITE_RTC_ADDR[i], time[i]);
}
Write_Ds1302_Byte(0x8e, 0x80);
}

void rd_ds1302() // 读取
{
u8 i;
for(i = 0; i < 7; i ++)
{
time[i] = Read_Ds1302_Byte(READ_RTC_ADDR[i]); // 储存于对应地址中
}
}

//以下为调用示例 输出小时及分钟数
void ds1302_display_1() // 时分
{
rd_ds1302();

fmq_display(0, 0xc1); // U
delay(200);
fmq_display(0, 0xff);

fmq_display(1, num_nodot[2]);
delay(200);
fmq_display(1, 0xff);

fmq_display(3, num_nodot[time[2] / 16]);
delay(200);
fmq_display(3, 0xff);

fmq_display(4, num_nodot[time[2] % 16]);
delay(200);
fmq_display(4, 0xff);

fmq_display(5, 0xbf);
delay(200);
fmq_display(5, 0xff);

fmq_display(6, num_nodot[time[1] / 16]);
delay(200);
fmq_display(6, 0xff);

fmq_display(7, num_nodot[time[1] % 16]);
delay(200);
fmq_display(7, 0xff);
}

PCF8591

关于IIC的使用

模数转换-ad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 驱动如下
unsigned char Ad_Read(unsigned char addr)
{
unsigned char temp;
IIC_Start();

IIC_SendByte(0x90);
IIC_WaitAck();

IIC_SendByte(addr);
IIC_WaitAck();

IIC_Start();

IIC_SendByte(0x91);
IIC_WaitAck();

temp = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();

return temp;
}

以下为使用该接口读取滑动变阻器的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void ad_display(u8 dat)
{
dat = Ad_Read(0x03); // 滑动变阻器的对应地址 光敏电阻为01
// dat = Ad_Read(0x01); // 光敏电阻
fmq_display(0, num_nodot[dat / 100]);
delay(500);
fmq_display(0, 0xff);
fmq_display(1, num_nodot[dat / 10 % 10]);
delay(500);
fmq_display(1, 0xff);
fmq_display(2, num_nodot[dat % 10]);
delay(500);
fmq_display(2, 0xff);
}

需要注意的是 读取的值均有稳定倍数关系 需要 * 5 / 255/ 51 即得到正常值

数模转换-da

输出值为板子D/A输出口的电压(有换算关系 为 *5 / 255)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Da_Write(unsigned char dat)
{
IIC_Start();

IIC_SendByte(0x90);
IIC_WaitAck();

IIC_SendByte(0x41);//使能
IIC_WaitAck();

IIC_SendByte(dat);
IIC_WaitAck();

IIC_Stop();
}

AT24C02

集成EEPROM

向EEPROM写入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void EEPROM_Write(unsigned char * string, unsigned char addr, unsigned char num)
{
IIC_Start();
IIC_SendByte(0xA0);
IIC_WaitAck();

IIC_SendByte(addr); // 标记为对应EEPROM地址
IIC_WaitAck();

while(num --)
{
IIC_SendByte(*string ++);
IIC_WaitAck();
IIC_Delay(200);
}
IIC_Stop();
}

调用即

1
EEPROM_Write(temp, 0x01, 2); // 0x01为对应地址

读取EEPROM数据

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
void EEPROM_Read(unsigned char* string, unsigned char addr, unsigned char num)
{
IIC_Start();

IIC_SendByte(0xA0);
IIC_WaitAck();

IIC_SendByte(addr);
IIC_WaitAck();

IIC_Start();

IIC_SendByte(0xA1);
IIC_WaitAck();

while(num --)
{
*string ++ = IIC_RecByte();
if(num)
{
IIC_SendAck(0);
}
else
{
IIC_SendAck(1);
}
}
IIC_Stop();
}

调用即

1
EEPROM_Read(date, 0x01, 2); // 从0x01地址中读取值存入date数组

NE555(频率计数)

需要两个计时器

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
u8 count = 0;
u8 count_i = 0;
u8 count_f = 0;

void ne555_timer_init()
{
TH0 = 0xff;
TL0 = 0xff;

TH1 = (65535 - 50000 + 1) / 256;
TL1 = (65535 - 50000 + 1) % 256;

TMOD = 0X16;

ET0 = 1;
ET1 = 1;

EA = 1;

TR0 = 1;
TR1 = 1;
}

void ne555_Timer0() interrupt 1
{
count_i += 1;
}

void ne555_Timer1() interrupt 3
{
TH1 = (65535 - 50000 + 1) / 256;
TL1 = (65535 - 50000 + 1) % 256;
count_f += 1;
if (count_f == 20)
{
count = count_i;
count_i = 0;
count_f = 0;
}
}

使用时例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void ne555_test()
{
display_smg(0, smg_nodot[count/100]);
delay(300);
display_smg(0, 0xff);
display_smg(1, smg_nodot[count/10%10]);
delay(300);
display_smg(1, 0xff);
display_smg(2, smg_nodot[count%10]);
delay(300);
display_smg(2, 0xff);
}

void main()
{
system_init();
ne555_timer_init();
while(1)
{
ne555_test();

}
}

注意!

  • init只在循环开始前执行一次
  • 在定时器1中需要重新声明
    1
    2
    TH1 = (65535 - 50000 + 1) / 256;
    TL1 = (65535 - 50000 + 1) % 256;
    使用ne555时候,需要用跳帽短接 signalP3^4

2023赛后更新

一点小牢骚

总的来说 尽力了
剩下一个ne555赌它不考来着。。。您猜怎么着?上来就给我来一手ne555
看到程序框图的第一反应人是傻的。。。

官方给的文件和原来手上的不一样也是想不到的
幸好 c语言没白学 头文件没忘记怎么写

_nop()_在哪个头文件里我忘记了…。
看着报错人也麻麻的
还是幸好 知道这个函数是干嘛用的 自己手写了一个延时函数大概能代替它了

幸好的幸好,除了用ne555做的湿度之外基本上都功能实现了 虽然有些地方好像写法很复杂

其实做完能做的之后还剩下一个小时的样子
看着ne555的手册和stc15的手册 本来想现学一手 想想 算了
于是又去检查前面的题目有没有问题了

这次比赛嘛 也不清楚到底比之前的难还是简单了
有幸运也有遗憾
我的建议是 尽力了 下次一定 如果有下次的话

2024赛前

一点准备注意事项

  • _nop()_ 对应头文件 intrins.h
  • 温度先读取低八位再读高八位
  • 要用Crome浏览器开所有东西 包括pdf(摄像头读取可能有问题)
  • 矩阵键盘延时设置为100
  • 延时函数形参为 u16
  • 在等待按键松开的while中加入paper_show 避免按下按键黑屏
  • 数码管位选前先段选赋 0XFF 消隐
  • 写其他模块时 ne555跳帽拔掉!
  • 涉及led和蜂鸣器,使用完毕关闭锁存器
  • P06为蜂鸣器
  • Title: 关于蓝桥杯
  • Author: CGC
  • Created at: 2023-03-14 21:45:28
  • Updated at: 2024-04-12 20:25:34
  • Link: https://redefine.ohevan.com/2023/03/14/关于蓝桥杯/
  • License: This work is licensed under CC BY-NC-SA 4.0.