stc15笔记

为了蓝桥杯单片机开发赛道。由于各种原因,一直没赶上培训,所以就自学。自学也不错,一两个小时下来的效率比听讲要高很多,还能集百家之长,还能随便写点东西出来。
实话说,我现在手上这些的芯片,其速度大都超越了上个世纪八十年代的所有芯片——而且存储空间很大,封装体积很小,随便就能吊打当时的任何超级计算机——如果有。

注意!

蓝桥杯比赛全程不能联网,不过会提供芯片资料,比赛时间为5个小时。我们应该对stc15开发板的各种性质足够熟悉——不需要记下来每个芯片的具体数据,但要熟悉流程,学会高效查阅数据手册,能够在合理的时间安排内把对应的数据填到对应的位置上去并实现功能。

官方会提供一些驱动代码,例如PCF的,不过有时候可能需要我们去补全部分缺失的代码。

头文件

  • STC15F2K60S2.h
  • intrins.h

下面是基础篇。

坑 & 注意

int的位数

STC15的int是16位的!!!
想要用32位还是得用long
2023年了,你甚至还可以遇到16位的上古int
建议手动typedefuint16_t之类的类型以方便使用。

P25、P26、P27

要注意这三个寄存器位的写入顺序,推荐的顺序是P27->P26->P25,这样似乎不容易误操作。

UART与时钟

UART会占用一个时钟,要使用UART调试的话你就只能用一个时钟了。

引脚

STC15的输出电平都是弱上拉,所以在矩阵按键里应该扫描低电平作为按键的标志。

点灯与简单按键

懒得截原理图了,直接上网找了一篇:
点灯与简单按键
抛个链接:蓝桥杯STC15单片机复习——IO口的使用,代码是我自己写的

由引脚图可以看出,STC15的外设资源与51单片机基本一致,常用的也是三组四组IO口(P0、P1、P2、P3),由于板子的电路设计,通过74LS138译码器进行P0的外挂模块的选择。

1
2
3
4
5
6
7
8
9
10
11
12
13

void LED_On(uint8_t index)
{
P25 = 0; P26 = 0; P27 = 1;
P0 |= 1 << index;
}

void LED_Off(uint8_t index)
{
P25 = 0; P26 = 0; P27 = 1;
P0 &= 0xFF ^ 1 << index;
}

矩阵按键

懒得截原理图了,直接上网找了一篇:
矩阵按键原理图
抛个链接:蓝桥杯STC15单片机复习——矩阵按键使用,代码是我自己写的

我的定义:以此图左上角按键为1,向右递增,然后按排数排列。也就是:

1 2 3 4
5 6 7 8

原理也很简单,懒得复述。

注意!

P3用来做矩阵按键,但有的板子在一些引脚上有所替换。例如此处是P42和P44取代了P36和P37。

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
// 如果无按键,返回0x00,否则返回按键编号(1-16)
uint8_t KeysMatrix_scan()
{
uint8_t res;
P3 = 0x0F; P42 = 0; P44 = 0;
if (P3 != 0x0F)
{
res = P3 & 0xFF;
P3 = 0x30; P42 = 1; P44 = 1;
res |= P3 | ((uint8_t)P42 << 6) | ((uint8_t)P44 << 7);
switch (res)
{
case 0x7E: return 1;
case 0xBE: return 2;
case 0xDE: return 3;
case 0xEE: return 4;
case 0x7D: return 5;
case 0xBD: return 6;
case 0xDD: return 7;
case 0xED: return 8;
case 0x7B: return 9;
case 0xBB: return 10;
case 0xDB: return 11;
case 0xEB: return 12;
case 0x77: return 13;
case 0xB7: return 14;
case 0xD7: return 15;
case 0xE7: return 16;
default: return 0;
}
}
return 0x00;
}

可以加个消抖之类的。

数码管显示

也懒得解释。
数码管原理图
抛个链接:蓝桥杯STC15单片机复习——数码管的使用,部分代码是改写的

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
#define SELECT(Z, Y, X) P27 = (Z); P26 = (Y); P25 = (X);
uint8_t NumberTubes_num[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; // 抄的,0x0~0xF
uint8_t NumberTubes_char[] = {0x00}; // 一些ascii字符的映射,懒得搞

// 抄的,关闭所有外设
void All_Stop(void)
{
P25 = 1;P26 = 0;P27 = 1;
P0 = 0x00;
P25 = 0;P26 = 1;P27 = 1;
P0 = 0x00;
P25 = 0;P26 = 0;P27 = 1;
P0 = 0xff;
}

void NumberTubes_ShowSingleNum(uint8_t pos, uint8_t dat)
{
SELECT(0, 0, 0);
P0 = 0; // 消影
SELECT(1, 1, 0);
P0 = pos;
SELECT(1, 1, 1);
P0 = NumberTubes_num[dat];
}

void NumberTubes_ShowNum(uint8_t pos, unsigned long dat)
{
unsigned long calculater = 1, dat_temp = dat / 10;
if (dat == 0)
{
NumberTubes_ShowSingleNum(pos, 0);
return;
}
while (dat_temp != 0)
{
dat_temp /= 10;
calculater *= 10;
}
while (calculater != 0 && pos != 0)
{
NumberTubes_ShowSingleNum(pos, dat / calculater);
dat -= dat / calculater * calculater;
calculater /= 10;
pos <<= 1;
delay_ms(2);
}
}

至于while(1)调用NumberTubes_ShowNum()的部分这里就不写了。建议到时候用时钟。

中断与计数器与时钟

摇滚与孤独与蓝色星球

外部中断

外部中断用得比较少

宁缺毋滥,去短板。

中断的位置

如上图所示,STC15的单片机的外部中断分别位于P32、P33(EX0、EX1),其中,外部中断0的中断号为0,外部中断1的中断号为2.

直接interrupt n就行。
完。

时钟与计数器

STC15上带有一个NE555,就让它输出的波形到计数器上去吧。

在定时器1的中断服务函数中,将采集到的脉冲数*2并显示出来,即可得到频率。
经过引文作者的测试,输出的频率确实为采集到的脉冲数的两倍。

Timer0对应中断1,Timer1对应中断3.timer初始化代码能直接用stc-isp获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Timer0Init(void)		//5毫秒@11.0592MHz 5ms
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0x04; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}

void Timer1Init(void) //5毫秒@11.0592MHz 5ms
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x00; //设置定时初始值
TH1 = 0x28; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}

注意!

记得写EA=1开启中断!!!

注意!

处理定时器与UART的冲突!!!

UART

直接代码。
UartInit()代码能直接用stc-isp获取。

注意!

下面所示的UART与Timer1冲突。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

char putchar(char c)
{
TI = 0; //清空发送完中断请求标志位
SBUF = c; //将数据放入寄存器发送
while(TI == 0);//等待发送完毕,发送完毕 TI == 1
TI = 0; //清空发送完中断请求标志位
return c;
}


void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR &= 0xBF; //定时器时钟12T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xE8; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
}

温度检测

蓝桥杯STC15单片机复习——DS18B20

DS18B20寄存器定义

如上图数据手册所示,DS18B20在进行温度转换以后,得到的是16位的数据,即高八位high,低八位low。其中,高八位的前五位代表符号位,当温度为正值时,这五位都为0,反之都为1;高八位的后三位与低八位的前四位共同组成了整数位。
因此,在只显示整数时,我们只需要将高八位左移四位,随后或上低八位的前四位,即可得到整数的温度值;
对于小数部分,我们只需要定义一个十六位数据,保留高八位的的后四位(&0x0f),随后拼上低八位并乘以0.0625(最小精度),即可得到小数部分的数值。

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
uint8_t DS18B20_Get()
{
uint8_t low,high,temp;

init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(200);

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

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

temp = high<<4;
temp |= low>>4;

return temp;
}

float DS18B20_Getfloat()
{
float temp2;
unsigned int temp;
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
Delay_OneWire(200);

init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE);
Delay_OneWire(200);

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

temp = high&0x0f;
temp = temp<<8|low;
temp2 = temp*0.0625;

return temp2;
}

DS1302

它是个时钟芯片。DS1302有什么用呢?它就相当于,当你给电脑关机后,你的电脑仍然能够进行计时,当你再次开机时,你的电脑能够不联网地准确获取当前时间。
DS1302的作用是“掉电”存储功能,当你关闭开关,它将继续工作——除非你拔掉了USB,或者是进行物理破坏(误)

DS1302寄存器定义

抛个链接:蓝桥杯STC15单片机复习——DS1302

下面的代码就是链接里的改写。
time_dat是直接读取到的时间,需要注意进制上的写法与实际显示上的写法的转换。(如从0x48->48)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void DS1302_Write(unsigned char *time_dat)
{
int i;
unsigned char addr = 0x80;
Write_Ds1302_Byte(0x8E,0x00);
for(i=2;i>=0;i--)
{
Write_Ds1302_Byte(addr,time_dat[i]);
addr+=2;
}
Write_Ds1302_Byte(0x8E,0x80);
}

void DS1302_Read(unsigned char *time_dat)
{
int i;
unsigned char addr = 0x81;
Write_Ds1302_Byte(0x8E,0x80);
for(i=2;i>=0;i--)
{
time_dat[i] = Read_Ds1302_Byte(addr);
addr+=2;
}
}

注意!

由于官方提供的底层驱动的写入与读取都是基于十六进制进行的,而我们定义时间变量与显示常常使用的是十进制的方式,因此,我们在进行设定的时候需要对其数据进行处理,在写入时应将十进制转换为十六进制,在读取时应将十六进制转换为十进制。

我一开始没明白这句话是什么意思,直到我再看了一眼寄存器定义,我发现它和汇编中断获取当前时间的数据格式几乎一致。于是秒懂:

简单解释一下:假定此时秒数为58,那么它在寄存器里会直接给你写成0x58,而不是58所对应的0x3A,直接读取和使用会产生错误——你读取到的是0x58,也就是十进制下的88。

具体地,以获取Seconds为例:

在DS1302的寄存器中,

  • 高四位存储的数值=十位上的数字
  • 低四位存储的数值=个位上的数字

秒的取值范围是00~59,在读取时,我们读取寄存器的值,将高四位的数值搁在十位上,将低四位的数值搁在个位上,于是有

1
2
3
4
uint8_t seconds_in_register = 0x58;
uint8_t seconds_in_register_low_4_bit = seconds_in_register & 0x0F;
uint8_t seconds_in_register_high_4_bit = (seconds_in_register & 0xF0) >> 4;
uint8_t seconds = seconds_in_register_low_4_bit * 1 + seconds_in_register_high_4_bit * 10;

上述过程写出了详细步骤,具体代码可以化简,反过来就是写入的转化过程。

DA/AD

抛个链接:蓝桥杯电子类单片机组模块——DAC
另外:见下面的PCF部分。

在蓝桥杯电子类单片机组历年的省赛以及国赛中,DAC模块常常被考察到。而组委会为减轻考生负担,提前给出了关于DAC模块的代码,剩下的便需要我们自己去编写(以第十届为例)。

可能……考试时我需要补全一些“第三方库”中的不完整代码?

在模块C文件里:

1
2
3
4
5
6
7
8
9
10
11
12
13
void write_dac(unsigned char add)
{
EA=0;
IIC_Start();
IIC_SendByte(0X90);
IIC_WaitAck();
IIC_SendByte(0X40);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
EA=1;
}

在Header文件里

1
2
void write_adc(unsigned char add);
unsigned char read_adc(unsigned char add);

然后就可以正常使用了。
在main里可以直接运用ADC模块。

AT24C02

AT24C02是一种能掉电(真正意义上的)存储的芯片,存储介质为EEPROM,I2C通信。
关于I2C通信如何实现,自己搞一块OLED0.96inc的屏幕,然后对着其他人的轮子敲一遍驱动程序就能完全理解。
抛个链接:AT24C02详解(蓝桥杯单片机模块(IIC总线))。比赛方提供IIC的文件。因为STC15开发板采用了单总线的设计,所以直接拿过来用就可以了。

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
#include <IIC.h>
//写函数(2byte)
void v_AtW(uint8_t addr, uint16_t dat)
{
IIC_Start();
IIC_SendByte(SlaveAddrW);
IIC_WaitAck();
IIC_SendByte(addr*2);
IIC_WaitAck();
IIC_SendByte(dat >> 8);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
//读函数(2byte)
uint16_t u_AtR(uint8_t addr)
{
uint16_t _data;
IIC_Start();
IIC_SendByte(SlaveAddrW);
IIC_WaitAck();
IIC_SendByte(addr*2);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(SlaveAddrR);
IIC_WaitAck();
_data = IIC_RecByte();
IIC_SendAck(0);
_data = _data << 8 | IIC_RecByte();
IIC_Stop();
return _data;
}

只要不发送停止信号,EEPROM就会顺着地址一直读/写下去。这里就是利用了这个特性读取和写入了2byte字节。
关于从机地址、读写规则请阅读上面的文章。

PCF8591

抛个链接:PCF8591详解(蓝桥杯单片机模块(IIC总线)),过。

赛题

十二届赛题

竞赛板配置要求

  1. 将 IAP15F2K61S2 单片机内部振荡器频率设定为 12MHz。
  2. 键盘工作模式跳线 J5 配置为 KBD 键盘模式。
  3. 扩展方式跳线 J13 配置为 IO 模式。
  4. 请注意:选手需严格按照以上要求配置竞赛板,编写和调试程序,不符合以上配置要求的作品将被评为零分或者被酌情扣分。

功能概述

  1. 通过获取 DS18B20 温度传感器的温度数据,完成温度测量功能。
  2. 通过 PCF8591 AD/DA 芯片完成 DAC 输出功能。
  3. 通过数码管完成题目要求的数据显示功能。
  4. 通过按键完成题目要求的显示界面切换和设置功能。
  5. 通过 LED 指示灯完成题目要求的指示功能。

性能要求

  1. 温度数据刷新时间:≤1 秒。
  2. DAC 输出电压刷新时间:≤0.5 秒。
  3. 按键动作响应时间:≤0.2 秒。

显示功能

  1. 温度显示界面
    温度数据界面如图 2 所示,显示内容包括标识符 C 和温度数据,温度数据保留小数点后 2 位有效数字,单位为摄氏度。
C 8 8 8 2 4. 2 5
标识 熄灭 熄灭 熄灭 温度:24.25℃ 温度:24.25℃ 温度:24.25℃ 温度:24.25℃
图 2 温度显示界面
  1. 参数设置界面
    参数设置界面如图 3 所示,显示内容包括标识符 P 和温度参数,温度参数为整数,单位为摄氏度。
C 8 8 8 8 8 2 5
标识 熄灭 熄灭 熄灭 熄灭 熄灭 参数:25℃ 参数:25℃
图 3 参数设置界面
  1. DAC 输出界面
    DAC 输出界面如图 4 所示,显示内容包括标识符 A 和当前 DAC 输出的电压值,电压数据保留小数点后 2 位有效数字。
C 8 8 8 8 3. 2 5
标识 熄灭 熄灭 熄灭 熄灭 VDAC = 3.25V VDAC = 3.25V 温VDAC = 3.25V
图 4 DAC 输出界面

按键功能

功能说明

  • S4:定义为“界面”按键,按下 S4 按键,切换温度显示界面、参数设置界面和 DAC 输出界面,按键 S4 切换模式如图 5 所示:
    S4

图 5 通过 S4 按键切换界面

  • S8:定义为“减”按键
    在参数界面下按下 S8 按键,温度参数减 1。
  • S9:定义为“加”按键
    在参数界面下按下 S9 按键,温度参数加 1。
  • S5:定义为“模式”切换按键。

图 6 通过 S5 切换模式

模式 1:DAC 输出电压与温度相关。
通过 DS18B20 采集到的实时温度小于温度参数时,DAC 输出 0V,否则,DAC 输出 5V。
模式 2:DAC 按照图 7 给出的关系输出电压。

图 7 模式 2 下 DAC 输出电压

其它要求

  • 按键应做好消抖处理,避免出现一次按键动作导致功能多次触发等问题。
  • 按键动作不影响数码管显示和数据采集过程。
  • S8、S9 按键仅在参数设置界面有效。
  • 设定的温度参数在退出参数设置界面时生效。

LED 指示灯功能

  1. 当前处于 模式 1 状态,指示灯 L1 点亮,否则熄灭。
  2. 当前处于温度显示界面,指示灯 L2 点亮,否则熄灭。
  3. 当前处于参数设置界面,指示灯 L3 点亮,否则熄灭。
  4. 当前处于 DAC 输出界面,指示灯 L4 点亮,否则熄灭。

初始状态说明

请严格按照以下要求设计作品的上电初始状态。

  1. 处于温度显示界面。
  2. 处于模式 1。
  3. 温度参数为 25℃。

代码

一下是我实现的一个思路。

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
#include <STC15F2K60S2.h>
#include <intrins.h>
#include <stdio.h>
#include "onewire.h"
#include "iic.h"

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

#define BLANK 16
#define SYMBOL_C 0xC
#define SYMBOL_P 17
#define SYMBOL_A 18

#define SYMBOL_H 19
#define SYMBOL_I 0x1

#define REFRESH_DISCOUNT 50

#define select(Z, Y, X, dat) P25 = (X); P27 = (Z); P26 = (Y); P0 = (dat); // used by LED
#define choose(Z, Y, X, dat) P26 = (Y); P25 = (X); P27 = (Z); P0 = (dat); // used by NumberTubes

#define LED_On(index) led_statue &= 0xFF ^ (1 << index);
#define LED_Off(index) led_statue |= 1 << index;
#define LED_Update() select(1, 0, 0, led_statue);

code uint8_t NumberTubes_code[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,
0xFF, 0x8C, 0x88, 0x89, 0xC7};
uint8_t NumberTubes_buffer[8] = {BLANK, BLANK, BLANK, BLANK, BLANK, BLANK, SYMBOL_H, SYMBOL_I};
uint8_t NumberTubes_dot_pos;

uint8_t refresh_count;
uint8_t led_statue;
uint8_t key_enable;
uint8_t led_upd_flag = 1;

float arg_temperature = 25.0;

typedef enum
{
TEMPERATURE,
ARGUMENT,
DAC_OUTPUT
}MODULE_SELECT;

typedef enum
{
MODE1,
MODE2
}OUTPUT_MODE;

MODULE_SELECT interface = TEMPERATURE;
OUTPUT_MODE mode = MODE1;

void ad_write(uint8_t addr)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x43); // 允许DA输出
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Stop();
}

uint8_t ad_read(uint8_t addr)
{
uint8_t res;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
res = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return res;
}

///////////////////////////////////////////////

void NumberTubes_ShowSingle(uint8_t pos, uint8_t dat)
{
choose(1, 1, 0, 1 << pos);
choose(1, 1, 1, NumberTubes_code[dat]);
}

void NumberTubes_ShowSingle_Dot(uint8_t pos, uint8_t dat)
{
choose(1, 1, 0, 1 << pos);
choose(1, 1, 1, NumberTubes_code[dat] & 0x80 ^ NumberTubes_code[dat]);
}

void NumberTubes_SetF(float dat)
{
char translate[8];
uint8_t i;
uint8_t siz = sprintf(translate, "%.2f", dat);
for (i = 0; i < siz && translate[i] != '.'; i++)
{
NumberTubes_buffer[9 - siz + i] = translate[i] - '0';
}
NumberTubes_dot_pos = 8 - siz + i;
i++;
for (; i < siz; i++)
{
NumberTubes_buffer[8 - siz + i] = translate[i] - '0';
}
for (i = 1; i <= 8 - siz; ++i)
{
NumberTubes_buffer[i] = BLANK;
}
}

// 矩阵按键扫描
uint8_t MatrixKey_Scan()
{
uint8_t temp = 0;
P3 = 0x30;
P42 = 1;
P44 = 1;
if (P3 != 0x0C || P42 != 0 || P44 != 0)
{
temp = P3 | ((uint8_t)P42 << 6) | ((uint8_t)P44 << 7);
P3 = 0x0F;
P42 = 0;
P44 = 0;
temp |= P3;
switch(temp)
{
case 0x7E: return 1;
case 0xBE: return 2;
case 0xDE: return 3;
case 0xEE: return 4;
case 0x7D: return 5;
case 0xBD: return 6;
case 0xDD: return 7;
case 0xED: return 8;
case 0x7B: return 9;
case 0xBB: return 10;
case 0xDB: return 11;
case 0xEB: return 12;
case 0x77: return 13;
case 0xB7: return 14;
case 0xD7: return 15;
case 0xE7: return 16;
default: return 0;
}
}
return 0;
}

///////////////////////////////////////////////

void Timer1_Init() // 500us
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xE8; //设置定时初始值
TH1 = 0xEA; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}

void update(uint8_t key)
{
if (key == 13) // S4
{
interface++;
interface %= 3;
led_upd_flag = 1;

if (interface == TEMPERATURE)
{
LED_On(TEMPERATURE + 1);
}
else
{
LED_Off(TEMPERATURE + 1);
}
if (interface == ARGUMENT)
{
LED_On(ARGUMENT + 1);
}
else
{
LED_Off(ARGUMENT + 1);
}
if (interface == DAC_OUTPUT)
{
LED_On(DAC_OUTPUT + 1);
}
else
{
LED_Off(DAC_OUTPUT + 1);
}

}
if (key == 14 && interface == ARGUMENT && arg_temperature != 0) // S8
{
arg_temperature -= 1;
}
if (key == 10 && interface == ARGUMENT) // S9
{
arg_temperature += 1;
}
if (key == 9) // S5
{
switch(mode)
{
case MODE1:
mode = MODE2;
break;
case MODE2:
mode = MODE1;
break;
}
if (mode == MODE1)
{
LED_On(0);
}
else
{
LED_Off(0);
}
led_upd_flag = 1;
}
}

void Timer1_Int() interrupt 3
{
static uint8_t index = 8;

if (index == 0)
{
index = 8;
}
index--;

if (led_upd_flag)
{
led_upd_flag = 0;
LED_Update();
choose(0, 0, 0, 0xFF);
}
else
{
P0 = 0xFF;
}

if (index == NumberTubes_dot_pos)
{
NumberTubes_ShowSingle_Dot(index, NumberTubes_buffer[index]);
}
else
{
NumberTubes_ShowSingle(index, NumberTubes_buffer[index]);
}
}

void GenshinImpact()
{
static uint8_t key = 0;
static uint8_t key_flag = 0;
key = MatrixKey_Scan();
if (key != 0 && key_flag != key && !key_enable)
{
update(key);
key_enable = 1;
}
key_flag = key;
}

void abaaba()
{
float current_temperature;
float dac_voltage;

if (++refresh_count <= REFRESH_DISCOUNT)
{
return;
}
refresh_count = 0;

key_enable = 0;

// Temperature
current_temperature = rd_temperature();
start_convert_ds18b20();

// DAC
if (mode == MODE1)
{
if (current_temperature < arg_temperature)
{
dac_voltage = 0;
ad_write(0);
}
else
{
dac_voltage = 5;
ad_write(255);
}
}
if (mode == MODE2)
{
if (current_temperature <= 20)
{
ad_write(51);
dac_voltage = 1;
}
else if (current_temperature >= 40)
{
ad_write(204);
dac_voltage = 4;
}
else
{
dac_voltage = current_temperature * 0.15 - 2;
ad_write(dac_voltage / 5 * 255);
}
}

// NumberTubes_buffer
if (interface == TEMPERATURE)
{
if (current_temperature == 85.0)
{
return; // 暴力return扫除一切障碍
}
NumberTubes_buffer[0] = SYMBOL_C;
NumberTubes_SetF(current_temperature);
}
if (interface == ARGUMENT)
{
NumberTubes_buffer[0] = SYMBOL_P;
NumberTubes_SetF(arg_temperature);
}
if (interface == DAC_OUTPUT)
{
NumberTubes_buffer[0] = SYMBOL_A;
NumberTubes_SetF(dac_voltage);
}
}

void Init()
{
// All_Stop
select(1, 0, 1, 0);
select(0, 1, 1, 0);
select(0, 0, 1, 0);

Timer1_Init();
start_convert_ds18b20();

interface = TEMPERATURE;
mode = MODE1;
arg_temperature = 25;
led_statue = 0xFF;
NumberTubes_dot_pos = 8;
led_upd_flag = 1;
LED_On(TEMPERATURE + 1);
LED_On(0);

EA = 1;
}

void main()
{
Init();
for ( ; ; )
{
abaaba();
GenshinImpact();
}
}

代码已经过运行。

UPD: 消影( LED 不总是需要更新,只在状态发生改变之后去修改一下即可),解决数码管闪烁问题(因为之前忘记了更新N umberTubes_SetF() 中的 NumberTubes_buffer[]=BLANK 的先后顺序了)
UPD:去除了手写的strlen(忘记sprintf会返回这个数了)

除此之外,还有在文件中补全的部分代码为:

onewire.h

删除了 char rd_remperature(void);

1
2
float rd_temperature(void);
void start_convert_ds18b20(void);

onewire.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void start_convert_ds18b20(void)
{
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
}

float rd_temperature(void)
{
unsigned char low, high;
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);

init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE);

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

return ((high << 8) | low) / 16.0;
}

十一届赛题

题目

见这个:https://blog.csdn.net/qq_53960242/article/details/123997096

代码

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
#include <STC15F2K60S2.h>
#include <intrins.h>
#include <stdio.h>
#include "onewire.h"
#include "ds1302.h"
#include "iic.h"

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

#define select(Z, Y, X) P25 = (X); P26 = (Y); P27 = (Z); // led
#define choose(Z, Y, X) P26 = (Y); P25 = (X); P27 = (Z); // tubes

#define LED_On(index) led_statue ^= led_statue & (1 << (index));
#define LED_Off(index) led_statue |= 1 << (index);
#define LED_Update() select(1, 0, 0); P0 = led_statue;

#define BLANK 10
#define LINE 11
#define SYMBOL_C 12
#define SYMBOL_P 13
#define SYMBOL_E 14

#define REFRESH_DISCOUNT 500

code uint8_t tubes_code[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90,
0xFF, 0xbf, 0xC6, 0x8C, 0x86};
uint8_t tubes_buffer[8] = {BLANK, BLANK, BLANK, BLANK, BLANK, BLANK, BLANK, BLANK};
uint8_t tubes_dot = 8;
uint8_t led_statue = 0xFF;

uint8_t arg_time = 17;
uint8_t arg_temperature = 25;
uint8_t arg_led = 4;

bit interface = 0; // data or arg
uint8_t led3_action = 0;
uint8_t mode = 0;

uint16_t refresh_count = REFRESH_DISCOUNT;
uint32_t timer1_count;

float light;

void tubes_show(uint8_t pos, uint8_t dat)
{
choose(1, 1, 1);
P0 = 0xFF;
choose(1, 1, 0);
P0 = 1 << pos;
choose(1, 1, 1);
P0 = tubes_code[dat];
}

void tubes_show_dot(uint8_t pos, uint8_t dat)
{
choose(1, 1, 1);
P0 = 0xFF;
choose(1, 1, 0);
P0 = 1 << pos;
choose(1, 1, 1);
P0 = tubes_code[dat] ^ 0x80;
}

void tubes_setf(float dat)
{
char translate[8];
uint8_t siz, i;
siz = sprintf(translate, "%.1f", dat);
for (i = 0; i < siz && translate[i] != '.'; ++i)
{
tubes_buffer[9 - siz + i] = translate[i] - '0';
}
tubes_dot = 8 - siz + i;
i++;
for (; i < siz; ++i)
{
tubes_buffer[8 - siz + i] = translate[i] - '0';
}
for (i = 1; i <= 8 - siz; ++i)
{
tubes_buffer[i] = BLANK;
}
}

void tubes_clear()
{
uint8_t i = 0;
for (i = 0; i < 8; ++i)
{
tubes_buffer[i] = BLANK;
}
}

uint8_t adc_r()
{
uint8_t res = 0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x41);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
res = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return res;
}

void Timer0_Int() interrupt 1
{
static uint8_t index = 8;
if (index == 0)
{
index = 8;
}
--index;
LED_Update();
if (tubes_dot == index)
{
tubes_show_dot(index, tubes_buffer[index]);
}
else
{
tubes_show(index, tubes_buffer[index]);
}
}

void Timer1_Int() interrupt 3
{
if (timer1_count <= 3000)
{
++timer1_count;
return;
}
timer1_count = 0;
if (led3_action)
{
LED_On(2);
}
else
{
LED_Off(2);
}
}

void Timer0_Init(void) //500微秒@12.0000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x90; //设置定时初始值
TH0 = 0xE8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}

void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}

uint8_t Keys_Scan()
{
uint8_t temp = 0;
P3 = 0x30;
P42 = 1;
P44 = 1;
if (P3 != 0x0C || P42 != 0 || P44 != 0)
{
temp = P3 | ((uint8_t)P42 << 6) | ((uint8_t)P44 << 7);
P3 = 0x0F;
P42 = 0;
P44 = 0;
temp |= P3;
switch(temp)
{
case 0x7E: return 1;
case 0xBE: return 2;
case 0xDE: return 3;
case 0xEE: return 4;
case 0x7D: return 5;
case 0xBD: return 6;
case 0xDD: return 7;
case 0xED: return 8;
case 0x7B: return 9;
case 0xBB: return 10;
case 0xDB: return 11;
case 0xEB: return 12;
case 0x77: return 13;
case 0xB7: return 14;
case 0xD7: return 15;
case 0xE7: return 16;
default: return 0;
}
}
return 0;
}

void update()
{
char translate[8];
float temperature;
uint8_t i, j, k;
float tmp;

if (++refresh_count < REFRESH_DISCOUNT)
{
return;
}
refresh_count = 0;

temperature = rd_temperature();
i = GetHour();
j = GetMinute();
k = GetSecond();
tmp = adc_r();
tmp = tmp / 255.0 * 5.0;

if ((arg_time > 8 && (i < 8 || i >= arg_time)) ||
(arg_time < 8 && i >= arg_time && i < 8))
{
LED_On(0);
}
else
{
LED_Off(0);
}

if (temperature < arg_temperature)
{
LED_On(1);
}
else
{
LED_Off(1);
}

if (tmp < 1.0)
{
if (led3_action == 0)
{
timer1_count = 0;
led3_action = 1;
}
}
else
{
if (led3_action == 1)
{
timer1_count = 0;
led3_action = 0;
}
}

if (tmp < 1.0)
{
led_statue = led_statue & 0x07 | (0xF8 ^ (1 << (arg_led - 1)));
}
else
{
LED_Off(arg_led - 1);
}

if (interface == 0)
{
switch (mode)
{
case 0:
tubes_buffer[0] = i / 10;
tubes_buffer[1] = i % 10;
tubes_buffer[2] = LINE;
tubes_buffer[3] = j / 10;
tubes_buffer[4] = j % 10;
tubes_buffer[5] = LINE;
tubes_buffer[6] = k / 10;
tubes_buffer[7] = k % 10;
break;
case 1:
tubes_buffer[0] = SYMBOL_C;
tubes_setf(temperature);
start_convert_ds18b20();
break;
case 2:
tubes_buffer[0] = SYMBOL_E;
sprintf(translate, "%.2f", tmp);
tubes_buffer[2] = translate[0] - '0';
tubes_dot = 2;
tubes_buffer[3] = translate[2] - '0';
tubes_buffer[4] = translate[3] - '0';
if (tmp < 1.0)
{
tubes_buffer[7] = 1;
}
else
{
tubes_buffer[7] = 0;
}
break;
}
}
else
{
switch(mode)
{
case 0:
tubes_buffer[0] = SYMBOL_P;
tubes_buffer[1] = 1;
tubes_buffer[6] = arg_time / 10;
tubes_buffer[7] = arg_time % 10;
break;
case 1:
tubes_buffer[0] = SYMBOL_P;
tubes_buffer[1] = 2;
tubes_buffer[6] = arg_temperature / 10;
tubes_buffer[7] = arg_temperature % 10;
break;
case 2:
tubes_buffer[0] = SYMBOL_P;
tubes_buffer[1] = 3;
tubes_buffer[7] = arg_led;
break;
}
}
}

void keys_process()
{
static uint8_t key_flag = 0;
uint8_t key = Keys_Scan();
if (key != 0 && key != key_flag)
{
switch(key)
{
case 13: // S4
interface = ~interface;
mode = 0;
tubes_clear();
break;
case 9: // S5
mode++;
mode %= 3;
tubes_clear();
break;
case 14: // S8
if (interface)
{
switch(mode)
{
case 0:
if (arg_time > 0)
arg_time--;
break;
case 1:
if (arg_temperature > 0)
arg_temperature--;
break;
case 2:
if (arg_led > 4)
arg_led--;
break;
}
}
break;
case 10: // S9
if (interface)
{
switch(mode)
{
case 0:
if (arg_time < 23)
arg_time++;
break;
case 1:
if (arg_temperature < 99)
arg_temperature++;
break;
case 2:
if (arg_led < 8)
arg_led++;
break;
}
}
break;
}
}
key_flag = key;
}

void Init()
{
select(1, 0, 1); P0 = 0;
select(0, 1, 1); P0 = 0;
select(0, 0, 1); P0 = 0;

Timer0_Init();
Timer1_Init();
Init_Ds1302(16, 59, 50);
update();
EA = 1;
}

void main()
{
Init();
while (1)
{
update();
keys_process();
}
}

十届赛题

题目


这个题用Timer0的8位非自动填充实现了一个频率计。

代码

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#include <STC15F104E.H>
#include <intrins.h>
#include <stdio.h>
#include "onewire.h"
#include "iic.h"

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

#define BLANK 10
#define SYMBOL_LINE 11
#define SYMBOL_F 12
#define SYMBOL_U 13

#define choose(Z, Y, X) P26 = (Y); P25 = (X); P27 = (Z); // tube
#define select(Z, Y, X) P25 = (X); P26 = (Y); P27 = (Z); // led

#define led_on(index) led_statue &= 0xFF ^ (1 << (index)); led_upd_flag = 1;
#define led_off(index) led_statue |= 1 << (index); led_upd_flag = 1;
#define led_update() select(1, 0, 0); P0 = led_statue;

code uint8_t tube_code[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0xFF, 0xBF, 0x8E, 0xC1};
uint8_t tube_buf[8] = {BLANK,BLANK,BLANK,BLANK,BLANK,BLANK,BLANK,BLANK};
uint8_t tube_dot[8] = {0,0,0,0,0,0,0,0};

uint8_t led_statue = 0xFF;
bit led_upd_flag = 1;

uint32_t freq_timer_count;
uint32_t freq_count;
uint32_t freq;

uint16_t key_count;

bit interface = 0; // 0 freq 1 voltage
bit adc_mode = 0;
bit led_disp = 1;
bit tube_disp = 1;
bit key_enable = 1;

float temperature;
float voltage;

void tube_show(uint8_t pos, uint8_t dat)
{
choose(1, 1, 1);
P0 = 0xFF;
choose(1, 1, 0);
P0 = 1 << pos;
choose(1, 1, 1);
P0 = tube_code[dat];
}

void tube_show_dot(uint8_t pos, uint8_t dat)
{
choose(1, 1, 1);
P0 = 0xFF;
choose(1, 1, 0);
P0 = 1 << pos;
choose(1, 1, 1);
P0 = tube_code[dat] ^ 0x80;
}

void tube_setn(uint32_t dat)
{
uint8_t i = 7;
do{
tube_buf[i] = dat % 10;
tube_dot[i] = 0;
dat /= 10;
i--;
} while(dat != 0);
for (; i > 0; i--)
{
tube_buf[i] = BLANK;
tube_dot[i] = 0;
}
}

void timer1_init()
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x90; //设置定时初始值
TH1 = 0xE8; //设置定时初始值
TF1 = 0; //清除TF0标志
TR1 = 1; //定时器0开始计时
ET1 = 1;
}

void freq_init()
{
TMOD |= 0x06;
TH0 = 0xFF;
TL0 = 0xFF;
TR0 = 1;
PT0 = 0;
ET0 = 1;
}

uint8_t key_scan()
{
uint8_t tmp = 0;
P3 = 0x0F;
P42 = 0;
P44 = 0;
if (P30 != 1 || P31 != 1 || P32 != 1 || P33 != 1)
{
tmp = P3;
P3 = 0x30;
P42 = 1;
P44 = 1;
tmp |= P3 | ((uint8_t)P42 << 6) | ((uint8_t)P44 << 7);
switch(tmp)
{
case 0x7E: return 0 + 1;
case 0xBE: return 0 + 2;
case 0xDE: return 0 + 3;
case 0xEE: return 0 + 4;
case 0x7D: return 4 + 1;
case 0xBD: return 4 + 2;
case 0xDD: return 4 + 3;
case 0xED: return 4 + 4;
case 0x7B: return 8 + 1;
case 0xBB: return 8 + 2;
case 0xDB: return 8 + 3;
case 0xEB: return 8 + 4;
case 0x77: return 12 + 1;
case 0xB7: return 12 + 2;
case 0xD7: return 12 + 3;
case 0xE7: return 12 + 4;
default: return 0;
}
}
return 0;
}

void transfer()
{
if (interface)
{
tube_buf[0] = SYMBOL_U;
tube_buf[7] = (uint8_t)(voltage * 100) % 10;
tube_buf[6] = (uint8_t)(voltage * 10) % 10;
tube_buf[5] = (uint8_t)voltage % 10;
tube_dot[5] = 1;

led_on(0);
led_off(1);
}
else
{
tube_buf[0] = SYMBOL_F;
tube_setn(freq);

led_off(0);
led_on(1);
}

if (voltage < 1.5)
{
led_off(2);
}
else if (voltage < 2.5 && voltage >= 1.5)
{
led_on(2);
}
else if (voltage < 3.5 && voltage >= 2.5)
{
led_off(2);
}
else
{
led_on(2);
}

if (freq < 1000)
{
led_off(3);
}
else if (freq < 5000 && freq >= 1000)
{
led_on(3);
}
else if (freq < 10000 && freq >= 5000)
{
led_off(3);
}
else
{
led_on(3);
}

if (adc_mode)
{
led_on(4);
}
else
{
led_off(4);
}
}

void key_process()
{
static uint8_t key_flag = 0;
uint8_t key = key_scan();

if (key != 0)
{
if (key_flag == 0)
{
key_flag = key;
switch (key)
{
case 13: // S4
interface = ~interface;
break;
case 9: // S5
adc_mode = ~adc_mode;
break;
case 10: // S6
led_disp = ~led_disp;
led_upd_flag = 1;
break;
case 14: // S8
tube_disp = ~tube_disp;
break;
}
}
}
else if (key_count >= 500)
{
key_flag = 0;
}
if (key_flag == 0)
{
key_count = 0;
}
}

void update()
{
voltage = ad_read(0x43) * 5.0 / 255.0;

if (adc_mode)
{
ad_write(voltage / 5.0 * 255.0);
}
else
{
ad_write(82);
}

if (freq_timer_count >= 1000)
{
freq = freq_count * 2000 / freq_timer_count;
freq_timer_count = 0;
freq_count = 0;
}

temperature = rd_temperature();
}

void freq_int() interrupt 1
{
freq_count++;
}

void timer1_Int() interrupt 3
{
static uint8_t index = 8;

++freq_timer_count;
++key_count;

if (index == 0)
{
index = 8;
key_enable = 1;
}
--index;

if (led_upd_flag)
{
if (!led_disp)
{
select(1, 0, 0);
P0 = 0xFF;
led_upd_flag = 0;
}
else
{
led_update();
led_upd_flag = 0;
}
}

if (!tube_disp)
{
tube_show(index, BLANK);
}

else if (tube_dot[index])
{
tube_show_dot(index, tube_buf[index]);
}
else
{
tube_show(index, tube_buf[index]);
}
}

void init()
{
select(1, 0, 1); P0 = 0x00;
select(0, 1, 1); P0 = 0x00;
select(0, 0, 1); P0 = 0x00;

timer1_init();
freq_init();

update();
transfer();
EA = 1;
}

void main()
{
init();
for (; ;)
{
update();
transfer();
key_process();
}
}

大吉大利,四月吃鸡

加油

加油

加油

加油

加油

加油

更新说明

  • 2023.6.16:自定义标签适应新的博客主题Icarus。
作者

勇敢梧桐树

发布于

2023-03-19

更新于

2023-07-05

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×