一、题目展示

二、代码解析

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这两部分的编写,肯定还有非常大的优化空间。

 

更多推荐