蓝桥杯嵌入式15届省赛真题
·
一、题目展示

二、代码解析
1、头文件的相关定义与声明
#ifndef _code_h
#define _code_h
#include "stm32g4xx.h" // Device header
#include "stdio.h"
#include "string.h"
#include "stdint.h"
#include "main.h"
#include "gpio.h"
#include "lcd.h"
#include "tim.h"
void lcd_proc(void);
void key_proc(void);
void led_proc(u8 led_x,u8 led_mode);
void pwm_proc(void);
#endif
2、主函数的初始化
#include "code.h"
……
……
……
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
LCD_Init();
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
LCD_Clear(Black);
HAL_TIM_Base_Start(&htim3);
HAL_TIM_Base_Start(&htim4);
HAL_TIM_Base_Start(&htim6);
HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
extern u32 fre[2],f_min[2],f_max[2];
/*一开始是想解决上电后如果输入频率大于1000会发生一次突变问题,因为频率最小值和最大值初始化
*为0,在上电的前3s不可能有比0还小的频率,所以在前3s最小值只能为0,并且最大值又等于于此刻
*采集的频率,频率又大于1000,所以它一上电就会发生一次频率超限,这肯定是不对的,所以我想让
*它们上电的一瞬间都为此刻频率但用下面的方法还是不能解决,很怪,大家也可以思考一下,有好的
*方法可以在评论区告诉我,想学。
*/
for(u8 i=0;i<2;i++)
{
f_max[i]=f_min[i]=fre[i];
}
while (1)
{
lcd_proc();
key_proc();
pwm_proc();
}
3、各个模块的编写
#include "code.h"
u8 DATA_mode;//数据界面的模式?频率:周期
double fre[2];
/*---------------------------------lcd--------------------------------*/
char lcd_val[30];//lcd显示数组
u8 ui;//界面参数
char unit[4][4]={"Hz","uS","KHz","mS"};//存储显示单位
u8 A_unit,B_unit;//A,B通道是否需要发生进制
int a_unit,b_unit;//分别辅助A,B通道进制的显示
int PARA[3]={1000,5000,0},RECD[4];
void lcd_proc(void)
{
if(ui==0)
{
if(DATA_mode==0)//频率模式
{
//判断两个通道是否需要发生进位
A_unit=fre[0]>1000 ? 2:0;//发生进位需要两位小数
B_unit=fre[1]>1000 ? 2:0;
}
else//周期模式
{
A_unit=1/fre[0]*1000000>1000 ? 2:0;
B_unit=1/fre[1]*1000000>1000 ? 2:0;
}
a_unit=A_unit==2 ? 1000:1;//进制是以1000为步长
b_unit=B_unit==2 ? 1000:1;
sprintf(lcd_val," DATA ");
LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
/*第一个参数是小数点的位数(2或0),
*第二个是根据数据模式选择频率或者周期,同时进行进制转化,
*第三个参数是单位,根据是否发生进制而进行变化
*/
if(fre[0]>0&&fre[0]<80000)
sprintf(lcd_val," A=%.*f%s ",A_unit,DATA_mode==0 ? fre[0]/a_unit:1/fre[0]*1000000/a_unit,unit[DATA_mode+A_unit]);
else
sprintf(lcd_val," A=NULL ");
LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
if(fre[1]>0&&fre[1]<80000)
sprintf(lcd_val," B=%.*f%s ",B_unit,DATA_mode==0 ? fre[1]/b_unit:1/fre[1]*1000000/b_unit,unit[DATA_mode+B_unit]);
else
sprintf(lcd_val," B=NULL ");
LCD_DisplayStringLine(Line4,(u8 *)lcd_val);
}
else if(ui==1)
{
sprintf(lcd_val," PARA ");
LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
sprintf(lcd_val," PD=%dHz ",PARA[0]);
LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
sprintf(lcd_val," PH=%dHz ",PARA[1]);
LCD_DisplayStringLine(Line4,(u8 *)lcd_val);
sprintf(lcd_val," PX=%dHz ",PARA[2]);
LCD_DisplayStringLine(Line5,(u8 *)lcd_val);
}
else
{
sprintf(lcd_val," RECD ");
LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
sprintf(lcd_val," NDA=%d ",RECD[0]);
LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
sprintf(lcd_val," NDB=%d ",RECD[1]);
LCD_DisplayStringLine(Line4,(u8 *)lcd_val);
sprintf(lcd_val," NHA=%d ",RECD[2]);
LCD_DisplayStringLine(Line5,(u8 *)lcd_val);
sprintf(lcd_val," NHB=%d ",RECD[3]);
LCD_DisplayStringLine(Line6,(u8 *)lcd_val);
}
led_proc(1,!ui);
}
/*---------------------------------key--------------------------------*/
u8 key_val[4];
u8 key_old[4];
u8 key;
u8 PARA_x;
void key_proc(void)
{
for(u8 i=0;i<4;i++)
{
key_val[i] = HAL_GPIO_ReadPin(i<3?GPIOB:GPIOA,GPIO_PIN_0<<i%3);
if(key_val[i]==0&&key_old[i]==1)
{
HAL_Delay(20);
if(key_val[i]==0&&key_old[i]==1)
{
key=i+1;
}
}
key_old[i]=key_val[i];
}
switch(key)
{
case 1:
{
if(ui==1)
{
PARA[PARA_x]+=100;
if(PARA[0]>1000)PARA[0]=100;
if(PARA[1]>10000)PARA[1]=1000;
if(PARA[2]>1000)PARA[2]=-1000;
}
break;
}
case 2:
{
if(ui==1)
{
PARA[PARA_x]-=100;
if(PARA[0]<100)PARA[0]=1000;
if(PARA[1]<1000)PARA[1]=10000;
if(PARA[2]<-1000)PARA[2]=1000;
}
break;
}
case 3:
{
if(ui==1)
{
PARA_x++;
PARA_x%=3;
}
else if(ui==0)
{
DATA_mode=!DATA_mode;
}
else
{
TIM6->CNT=0;
}
break;
}
case 4:
{
ui++;
ui%=3;
LCD_Clear(Black);
PARA_x=0;
DATA_mode=0;
break;
}
}
key=0;
if(key_val[2]==0&&key_old[2]==0&&ui==2&&TIM6->CNT>10000)
{
for(u8 i=0;i<4;i++)
{
RECD[i]=0;
}
}
}
/*---------------------------------led--------------------------------*/
void led_proc(u8 led_x,u8 led_mode)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
if(led_mode)
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
/*---------------------------------tim--------------------------------*/
u32 Capture[2];
u8 PH_flag[2];//两个通道的超限标志位
u32 f_min[2],f_max[2];//两个通道的最大值和最小值
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM8)//A
{
Capture[0]=TIM8->CCR1;
TIM8->CNT=0;
}
else if(htim->Instance==TIM16)//B
{
Capture[1]=TIM16->CCR1;
TIM16->CNT=0;
}
}
void pwm_proc(void)
{
for(u8 i=0;i<2&&TIM3->CNT>1000;i++)//题目要求每秒采集10次,同时也避免fre在PH范围左右横跳
{
if(i)TIM3->CNT=0;//采集完两个通道再置零
fre[i]=80000000/(Capture[i]*80)+PARA[2];
if(TIM4->CNT>30000)
{
if(i)TIM4->CNT=0;//同上
if(f_max[i]-f_min[i]>PARA[0])RECD[i]++;//判断是否发生突变
f_max[i]=f_min[i]=fre[i];//复位
}
f_min[i]=f_min[i]>fre[i] ? fre[i]:f_min[i];
f_max[i]=f_max[i]<fre[i] ? fre[i]:f_max[i];
if(fre[i]>PARA[1]&&PH_flag[i]==0)//判断是否发生超限
{
RECD[2+i]++;
PH_flag[i]=1;
led_proc(2+i,1);
}
if(fre[i]<PARA[1])
{
PH_flag[i]=0;//复位超限标志位
led_proc(2+i,0);
}
if(RECD[0]>=3||RECD[1]>=3)led_proc(8,1);
else led_proc(8,0);
}
}
三、结语
这一套同样也是第二次写了,但写的依旧是依托答辩,连榜都没有上,写了22kB,而第一名的大佬只有16KB,太牛了,这一套主要还是lcd和pwm这两部分的编写,肯定还有非常大的优化空间。
更多推荐

所有评论(0)