蓝桥杯单片机第五届国赛题目-多功能事件记录器
Posted _WILLPOWER_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯单片机第五届国赛题目-多功能事件记录器相关的知识,希望对你有一定的参考价值。
前言
功能全部实现,实话说,这届国赛题的串口和eeprom还是很有挑战的,关于这部分需要多加练习和注意;对于常见的一些操作要多加总结,才能够在比赛的时候拿出来就用。在保存信息的时候,一定不要用保存字符串的方式!直接采用保存变量的方式(uchar)即可。我就想提几个需要注意的地方吧。
- 第一个是要注意strcpy和memcpy的区别,一个是字符串的复制,一个是内存的复制。字符串的复制不能用于数组的复制,因为一旦数组中出现了0,那么就会被识别的空字符!
- 注意数组的大小是否能够装的下格式化后的字符串!
- 第二个是eeprom的处理,eeprom分为32页,一页有8Byte,因此可以采用页写的方式来保存。比如你起始地址为0即为第一页,起始位置为8则为第二页,我发现采用页写的方式后,写和读都还是有点问题,因此采用了特殊的方式来进行处理。这部分可以看程序来理解
- 串口数据的接收和判断不要写死了,比如我发送的数据不一定是6位,如果数据宽度不一样,写死的程序势必会造成错误。这个也可以看我串口的处理部分来理解一下。
- 题目我就不发了,网上都有。
效果
说了这么多,看一下效果吧。
注意声音有点大,不好意思录进去了
蓝桥杯单片机第五届国赛题目-多功能事件记录器演示
视频链接
代码树
init.c
#include "init.h"
extern uchar bf[8];
void SL(uchar _dev, uchar _data)
{
P0 = _data; SEL(_dev);
}
void Timer1Init(void) //2毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x40; //设置定时初值
TH1 = 0xA2; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
EA = 1;
}
uchar GetKey()
{
if(K3 == 0) return 5;
if(K4 == 0) return 4;
return 0;
}
void TimeRun(t_delay* time)
{
if(time->cnt++ < time->max);
else
{
time->cnt = 0;
time->ok = 1;
}
}
uchar FR(float _data, uchar _dig)
{
uint i = 1;
while(_dig--)
{
i = i*10;
}
return((uint)_data/i%10);
}
void Bf(uchar _0, uchar _1, uchar _2, uchar _3,
uchar _4, uchar _5, uchar _6, uchar _7)
{
bf[0] = _0; bf[1] = _1; bf[2] = _2; bf[3] = _3;
bf[4] = _4; bf[5] = _5; bf[6] = _6; bf[7] = _7;
}
void UartInit(void) //1200bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0x3C; //设定定时初值
T2H = 0xF6; //设定定时初值
AUXR |= 0x10; //启动定时器2
ES = 1;
}
void print(uchar* string)
{
ES = 0; TI = 1;
printf("%s", string);
TI = 0; ES = 1;
}
uchar LedChange(uchar _data, uchar _dig, uchar _state)
{
//LED的状态是反着来的
if(!_state)
{
_data |= 1 << _dig;
}
else
{
_data &= ~(1 << _dig);
}
SL(4, _data);
return _data;
}
main.c
#include "init.h"
enum{LED=4, EXT, SEL, CODE};
code uchar CA[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99,
0x92, 0x82, 0xf8, 0x80, 0x90,
0xff, 0xc6, 0x89, 0xbf};
uchar bf[] = {1, 2, 3, 4, 5, 6, 7, 8};
uchar curDig = 0;
uchar enprint = 0;
uchar key, tmpKey, keyCnt;
enum{KS_GT, KS_AS, KS_WA};keyState=KS_GT;
t_delay delay_200 = {200, 0, 0};
t_delay tx_delay = {50, 0, 0};
t_delay cnt_65535 = {65535, 0, 0};
uchar index = 0;
uchar xdata rxBuf[20] = "0";
//发送缓冲不能小了,要避免出现其他异常情况将发送缓冲装溢出了
uchar xdata txBuf[30] = "0";
uchar revCorrect = 0;
uchar time[3];
uchar jieJin = 0;
uchar Second = 255;
//事件接近的时间
uchar timeCnt = 0;
//模式
enum{S_AUTOT, S_AUTOR}gloSta = S_AUTOT;
//显示模式
enum{DIS_WSD, DIS_TIME, DIS_ITEM}disMode = DIS_WSD;
uchar ledData = 0xfe;
float adcVal, adc1Val;
uchar storeData[5][7] = {0};
//调试使用
//uchar storeData1[5][6] = {{1,2,3, 4 ,5 ,25},
// {1,2,3, 4 ,5 ,25},
// {1,2,3, 4 ,5 ,25},
// {1,2,3, 4 ,5 ,25},
// {1,2,3, 4 ,5 ,25}};
void Timer1Hanle() interrupt 3
{
SL(CODE, 0xff);SL(SEL, 1 << curDig); SL(CODE, CA[bf[curDig]]);
curDig = (curDig + 1)%8;
switch(keyState)
{
case KS_GT:
keyCnt = 0; tmpKey =GetKey(); keyState = KS_AS;
break;
case KS_AS:
if(keyCnt++ < 10);
else if(tmpKey == GetKey())
{
if(tmpKey != key)
{
key = tmpKey;keyState = KS_WA;
}
else
{
keyState = KS_GT;
}
}
else
{
keyState = KS_GT;
}
break;
}
TimeRun(&delay_200);
if(tx_delay.ok == 2)
TimeRun(&tx_delay);
//如果允许计算时间
if(cnt_65535.ok == 2)
TimeRun(&cnt_65535);
}
void Sensor()
{
if(delay_200.ok == 1)
{
delay_200.ok = 0;
Temp_Read();
adcVal = ADC_Read(0x43, 0);
adc1Val = ADC_Read(0x41, 0);
if(adc1Val < 50)
{
jieJin = 1;
ledData = LedChange(ledData, 2, 1);
//如果计时没有开始,那么让计时开始
if(cnt_65535.cnt == 0)
cnt_65535.ok = 2;
}
else
{
jieJin = 0;
ledData = LedChange(ledData, 2, 0);
//如果已经开始计时,那么停止
if(cnt_65535.cnt != 0)
{
uchar tmpString[7];
cnt_65535.ok = 0;
timeCnt = cnt_65535.cnt*2/1000;
tmpString[0] = (uint)tempVal/100;
tmpString[1] = (uint)adcVal;
tmpString[2] = time[2];
tmpString[3] = time[1];
tmpString[4] = time[0];
tmpString[5] = timeCnt;
stack(tmpString);
cnt_65535.cnt = 0;
}
}
DS1302_Read();
}
}
void UartHandle() interrupt 4
{
if(TI) TI = 0;
if(RI)
{
RI = 0;
//如果进来的时候是第一次,因此开启计时
if(tx_delay.ok == 0)
tx_delay.ok = 2;
//进来是因为串口接收中断
if(index < 20)
{
rxBuf[index++] = SBUF;
}
}
}
void UartProcess()
{
//如果接收超时,触发检查事件
//如果进来的时候是因为计时结束
if(tx_delay.ok == 1)
{
//结束标志清零
tx_delay.ok = 0;
//如果接收的数据是6位
if(index == 6)
{
//如果口令正确
if(strncmp(rxBuf, "AAASSS", 6) == 0)
{
enprint = 1;
}
}
//如果口令不是正确的,那么就是错误的
else
{
enprint = 2;
}
//不管哪种情况,都需要将index清空
index = 0;
}
//如果口令正确
if(enprint == 1)
{
uchar i;
enprint = 0;
//根据状态来选择串口的输出
switch(gloSta)
{
case S_AUTOT:
//开启串口输出
revCorrect = 1;
break;
case S_AUTOR:
for(i = 0; i < 5; i++)
{
uchar temp[25] = {0};
sprintf(temp, "{%bu-%bu%%}-{%bu-%bu-%bu}{%bu}\\r\\n",
storeData[i][0], storeData[i][1], storeData[i][2], storeData[i][3], storeData[i][4], storeData[i][5]);
print(temp);
//很重要,不然会联结
Delay8ms();
}
break;
}
//如果口令不正确关闭输出
}
else if(enprint == 2)
{
enprint = 0;
revCorrect = 0;
}
}
void EventProcess()
{
if(revCorrect)
{
//如果一秒到了
if(Second != time[0])
{
//发送相应命令
Second = time[0];
sprintf(txBuf, "{%.0f-%.0f%%}-{%bu-%bu-%bu}{%bu}\\r\\n",
tempVal/100.0, adcVal, time[2], time[1], time[0], jieJin);
print(txBuf);
}
}
}
//按键处理
void keyProcess()
{
switch(key)
{
case 4:
gloSta = (gloSta == S_AUTOT)?S_AUTOR:S_AUTOT;
//互锁的先关闭所有,再根据条件开启响应的led
ledData = LedChange(ledData, 1, 0);
ledData = LedChange(ledData, 0, 0);
if(gloSta == S_AUTOR)
{
revCorrect = 0;
ledData = LedChange(ledData, 1, 1);
}
else
{
ledData = LedChange(ledData, 0, 1);
}
break;
case 5:
if(disMode == DIS_WSD)
disMode = DIS_TIME;
else if(disMode == DIS_TIME)
disMode = DIS_ITEM;
else
disMode = DIS_WSD;
break;
}
}
void DisProcess()
{
switch(disMode)
{
case DIS_WSD:
Bf(FR(tempVal, 3), FR(tempVal, 2), F_CC, F_C, F_C, FR(adcVal, 1), FR(adcVal, 0), F_H);
break;
case DIS_TIME:
Bf(FR(time[2], 1), FR(time[2], 0), F_SEP,
FR(time[1], 1), FR(time[1], 0), F_SEP,
FR(time[0], 1), FR(time[0], 0));
break;
case DIS_ITEM:
Bf(F_C, F_C, F_C,
F_SEP, FR(timeCnt, 3), FR(timeCnt, 2),
FR(timeCnt, 1), FR(timeCnt, 0));
break;
}
}
//非常重要
void Delay8ms() //@12.000MHz
{
unsigned char i, j;
i = 94;
j = 95;
do
{
while (--j);
} while (--i);
}
void stack(uchar* string)
{
uchar i = 0;
for(; i < 4; i++)
{
memcpy(storeData[i], storeData[i+1], 6);
}
memcpy(storeData[i], string, 6);
for(i = 0; i < 5; i++)
{
EEPROM_Write(i*8, storeData[i], 6);
EEPROM_Write(i*8, storeData[i], 6);
EEPROM_Write(i*8, storeData[i], 6);
}
}
void StoreInit()
{
uchar i = 0;
//调试使用
// for(i = 0; i < 5; i++)
// {
// EEPROM_Write(i*8, storeData1[i], 7);
// EEPROM_Write(i*8, storeData1[i], 7);
// EEPROM_Write(i*8, storeData1[i], 7);
// }
for(i = 0; i < 5; i++)
{
uchar tmpData[6];
EEPROM_Read(i*8, 6, storeData[i]);
EEPROM_Read(i*以上是关于蓝桥杯单片机第五届国赛题目-多功能事件记录器的主要内容,如果未能解决你的问题,请参考以下文章