当前位置: 首页 > wzjs >正文

梧州百度网络推广关键词优化公司

梧州百度,网络推广关键词优化公司,政府网站建设工作总结报告,小说网站设计模板个人吐槽 #因为最近蓝桥杯快要开始了,我舍不得米白费了,所以就认真刷刷模拟题,但是我感觉真题会更好,所以就看了一下上届的真题。不过它是真的长,我看着就头晕,但是还是把几个模块认真分析了一下就还是很容…

个人吐槽

#因为最近蓝桥杯快要开始了,我舍不得米白费了,所以就认真刷刷模拟题,但是我感觉真题会更好,所以就看了一下上届的真题。不过它是真的长,我看着就头晕,但是还是把几个模块认真分析了一下就还是很容易写的。

#分析的话,频率超限和频率突变,这位博主就写的很好,所以我就直接使用他的来了,很清晰,所以这里更多的是以我的视角一起来分析一下想法。题目的话,就不截取了。第十五届蓝桥杯嵌入式组省赛题目分析及代码_蓝桥杯嵌入式15届赛题-CSDN博客

个人心得部分

对于题目来说,每一个题目的要求都是有用的。 写题目的时候一定要注意。 比如说性能要求那里,频率的测量范围,真的会影响到后面的测评结果。所以一定要大致的扫描完题目后,细致地针对题目要求来进行代码编写。 

STM32CUBEMX 配置部分

所用到的外设有

  1. LED1-7   默认配置 LD1-LD7  
  2. 四个按键 B1,B2,B3,B4 --- 这个后续会在我的代码里出现的,注意
  3. 这里我用到了差不多4个Timer 四个定时器  

Timer2,Timer16 都是通道1,配置为输入捕获,且时钟源为内部时钟。 psc为80 - 1其他保持默认。

Timer6 我是用于按键状态机   定时器中断处理 按键状态机 它的频率为100hz 。 psc,arr你怎么给取决于自己。只要保证定时器为100hz即可。其他默认

Timer4 我是用于处理频率数据 10hz,psc,arr由你决定。只要保证为10hz即可。其他保持默认。

模块分割(先从简单的部分开始)

1.变量部分

/*
主要的变量是以下部分,之前我写过按键状态机,
那个变量的话,我单独拿出来讲。由于是第一次写这个省赛题目, 我会标出这个代码所在文件main.c
*/
typedef enum
{LCD_SHOW_DATA_PAGE_FREQUENCE,     /* 数据界面(频率) */LCD_SHOW_DATA_PAGE_TIMES    ,      /* 数据界面(周期) */LCD_SHOW_PARA_PAGE          ,     /* 参数界面*/LCD_SHOW_COUNT_PAGE         ,     /* 统计界面*/
}LCD_Page;typedef enum
{PARA_NONE = 0,PARA_PD,PARA_PH,PARA_PX,
}Para; //参数/* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
char       text[20]                       ;
int        ccl_value_1 = 0, ccl_value_2 = 0;   // 获取输入捕获值/* 对于频率部分 fA / fB = FA / FB + PX  */
int        fA = 0,fB = 0;                   // 频率值
int PD = 1000,PH = 5000,PX = 0;               
float      fre_A = 0,fre_B = 0;         
float      A_times = 0,B_times = 0;int   NDA = 0,NDB = 0;   /*  A/B通道频率突变次数 */
int   NHA = 0,NHB = 0;   /*  A/B通道频率超限次数 */
int   PHA[2],PHB[2];
uint16_t A_us = 0,B_us = 0;   /* A,B的时间 (us)*/
float    A_ms = 0, B_ms = 0;  /* A,B的时间 (ms)*/
LCD_Page   mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;   /* 初始化为 数据界面(频率)*/  
LCD_Page   Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;
Para       mypara = PARA_NONE;  //用于参数选择/* --- 频率突变部分 --- */
int PDA[30] = {0},PDB[30] = {0};
int Max_A,Max_B,Min_A,Min_B;
uint16_t timerA = 0,timerB = 0; // 3s的时间窗口标志位/* --- 最终频率--- */
int FreA = 0,FreB = 0;

 上面是main.c 函数中运用到的变量值

/*fun.h
*/#ifndef _fun_h
#define _fun_h
#include "headfile.h"#define   KEY_NUM          4
#define   DEBOUNCE_CNT     2
#define   LONG_PRESS_THRESH  900  // 长按判断阈值(ms)#define LED_CloseAll()				do{GPIOC->ODR = 0xFFFFU;}while(0)/*   枚举按键状态类型  */
typedef enum 
{KEY_STATE_IDLE,KEY_STATE_DEBOUNCE,KEY_STATE_PRESSED,
//	KEY_STATE_RELEASE_DEBOUNCE	
}KeyState;typedef enum
{ KEY_EVT_NONE,       //没有按下? KEY_EVT_PRESS,      //按下事件KEY_EVT_RELEASE,    //释放事件KEY_EVT_LONG_PRESS  // 长按事件
}KeyEventType;typedef struct
{KeyEventType type;uint32_t duration;   //事件持续时间(ms)}KeyEvent;// 增强按键结构体
typedef struct {GPIO_TypeDef* GPIOx;uint16_t GPIO_Pin;KeyState state;uint32_t pressStart;    // 按下开始时间uint32_t pressDuration; // 当前按压持续时间uint8_t eventFlag;      // 事件标志KeyEvent event;         // 事件详情
} KeyHandle;void Keys_StateMachine_Handler(void);/*   获取当前按压持续时间   */
uint32_t Get_KeyPressDuration(uint8_t KeyID);// 事件轮询函数
KeyEvent Poll_KeyEvent(uint8_t keyID);/* 获取按键事件 */
uint8_t Get_Key(uint8_t KeyID);void LED_Ctrl(uint8_t num,uint8_t mode);
void LED_CLOSEALL(void);
#endif

这里是我自己定义的fun.h文件 里面包括我自己定义的按键状态机 + LED灯控制。

/*headfile.h
*/#ifndef _headfile_h
#define _headfile_h#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "stm32g4xx.h"                  // Device header#include "string.h"
#include "stdint.h"
#include "main.h"
#include "gpio.h"
#include "TIM.h"#include "fun.h"
#include "lcd.h"#endif

这个是headfile.h文件 里面集成了大部分所要用到的头文件,就无需我们总是在不同的头文件中重复引入相同的头文件。

1.5 频率捕获部分

/*
main.c输入捕获部分
*/// 变量部分
int        ccl_value_1 = 0, ccl_value_2 = 0;   // 获取输入捕获值/* 对于频率部分 fA / fB = FA / FB + PX  */
int        fA = 0,fB = 0;                   // 频率值
int PD = 1000,PH = 5000,PX = 0;               
float      fre_A = 0,fre_B = 0;       
////代码部分/*    频率获取部分
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{/*      r40 输出捕获   通道 A */if(htim->Instance == TIM2){fA = 1000000 / (TIM2->CCR1+1);TIM2->CNT = 0;// 这里我们根据 性能要求部分推出if(fA > 20000) fA = 20000;else if(fA < 400) fA = 400;FreA = fA + PX;ccl_value_1 = 1000000 / FreA;/*这里我根据测评出的结果 推出来,它其实周期的计算是根据最终的频率来计算的而不是我最先测出的fA来进行计算。*/}/*      R39 输出捕获  通道 B  */if(htim->Instance == TIM16){fB = 1000000 / (TIM16->CCR1+1);TIM16->CNT = 0;if(fB > 20000) fB = 20000;else if(fB < 400) fB = 400;FreB = fB + PX;ccl_value_2 = 1000000 / FreB;}
}

为什么我们在输入捕获那里 还写一个if..else。 因为我们可以具体去看性能要求部分。

400 hz --- 20000hz 

// 这里我们根据 性能要求部分推出
       if(fA > 20000) fA = 20000;
       else if(fA < 400) fA = 400;

2.按键部分

按键部分的话,我就不细说了,它在我写的博客里,就是最近的博客。直接上代码了。 头文件是fun.h 就是上面那个代码。

/*此为 fun.c 里面包括了
1.按键状态机 + 状态轮询函数(我进行封装了)
2.LED控制
*/
#include "fun.h"// 初始化 按键
static KeyHandle Keys[KEY_NUM] = 
{{B1_GPIO_Port,B1_Pin,KEY_STATE_IDLE,0,0,0,{KEY_EVT_PRESS, 0}},{B2_GPIO_Port,B2_Pin,KEY_STATE_IDLE,0,0,0,{KEY_EVT_PRESS, 0}},{B3_GPIO_Port,B3_Pin,KEY_STATE_IDLE,0,0,0,{KEY_EVT_PRESS, 0}},{B4_GPIO_Port,B4_Pin,KEY_STATE_IDLE,0,0,0,{KEY_EVT_PRESS, 0}},
};void Keys_StateMachine_Handler(void)
{static uint8_t debounceCnt[KEY_NUM] = {0};uint32_t now  = HAL_GetTick();   // 获取tick时间uint8_t i;for(i = 0;i<KEY_NUM;i++){uint8_t pinState = HAL_GPIO_ReadPin(Keys[i].GPIOx,Keys[i].GPIO_Pin);   //读取按键状态switch(Keys[i].state){case KEY_STATE_IDLE://如果按下if(pinState == GPIO_PIN_RESET){Keys[i].state = KEY_STATE_DEBOUNCE; //第一次按下的时侯debounceCnt[i] = 0;Keys[i].pressStart = now;   //记录下初始按下时间}break;case KEY_STATE_DEBOUNCE:if (pinState == GPIO_PIN_RESET) { // 持续检测按下状态if (++debounceCnt[i] >= DEBOUNCE_CNT) {Keys[i].state = KEY_STATE_PRESSED;Keys[i].event.type = KEY_EVT_PRESS;Keys[i].event.duration = 0;Keys[i].eventFlag = 1;debounceCnt[i] = 0;}} else { // 中途释放则回到IDLEKeys[i].state = KEY_STATE_IDLE;debounceCnt[i] = 0;}break;				case KEY_STATE_PRESSED:/*  持续更新按压时间 */Keys[i].pressDuration = now - Keys[i].pressStart;  // now 不断在更新if(Keys[i].pressDuration >= LONG_PRESS_THRESH){Keys[i].event.type = KEY_EVT_LONG_PRESS;Keys[i].event.duration = Keys[i].pressDuration; //获取按下时间Keys[i].eventFlag = 1;Keys[i].pressStart = now;  // 重置计时避免重复触发}if(pinState == GPIO_PIN_SET){Keys[i].state = KEY_STATE_IDLE;Keys[i].event.type = KEY_EVT_RELEASE;Keys[i].event.duration = now - Keys[i].pressDuration;Keys[i].eventFlag = 1;}break;}	}
}/*   获取当前按压持续时间   */
uint32_t Get_KeyPressDuration(uint8_t KeyID)
{if(KeyID >= KEY_NUM) return 0;  // 超出范围return Keys[KeyID].pressDuration;  // 返回持续时间
}// 事件轮询函数
KeyEvent Poll_KeyEvent(uint8_t keyID)
{KeyEvent evt = {KEY_EVT_NONE, 0};if(keyID >= KEY_NUM) return evt;if(Keys[keyID].eventFlag){evt = Keys[keyID].event;Keys[keyID].eventFlag = 0;// 重置持续时间(释放事件后)if(evt.type == KEY_EVT_RELEASE){Keys[keyID].pressDuration = 0;}}return evt;
}/* 获取按键事件    B1 --- KeyID -  0 */
uint8_t Get_Key(uint8_t KeyID)
{if(KeyID >= KEY_NUM ) return 0;if(Keys[KeyID].eventFlag){Keys[KeyID].eventFlag = 0;return 1;}else{return 0;}
}/*led亮灭控制*/
void LED_Ctrl(uint8_t num,uint8_t mode)
{HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << (num - 1),mode ? GPIO_PIN_RESET:GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);}void LED_CLOSEALL(void)
{HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);}

接下来就是直接放到定时器里面,每10ms触发一次检测,通过定时器来消除抖动。

/*
main.c 部分
*/
/*      TIM定时器处理部分     */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/*    处理按键   100hz */if(htim->Instance == TIM6){Keys_StateMachine_Handler();   //此处每10ms进入一次按键状态机}
}

3.按键轮询

/*main.c
前言,在前面,我们已经完成了按键状态机,所以现在可以正式
开启,按键检测(按键轮询 都可以) 
*/// 所用到的变量 (这里是我进行再一次重复拿出来,加深你的印象)
typedef enum
{LCD_SHOW_DATA_PAGE_FREQUENCE,     /* 数据界面(频率) */LCD_SHOW_DATA_PAGE_TIMES    ,      /* 数据界面(周期) */LCD_SHOW_PARA_PAGE          ,     /* 参数界面*/LCD_SHOW_COUNT_PAGE         ,     /* 统计界面*/
}LCD_Page;typedef enum
{PARA_NONE = 0,PARA_PD,PARA_PH,PARA_PX,
}Para; //参数 针对于参数界面,我用的是switch + enumint        ccl_value_1 = 0, ccl_value_2 = 0;   // 获取输入捕获值
int        fA = 0,fB = 0;                   // 频率值
int PD = 1000,PH = 5000,PX = 0;               
float      fre_A = 0,fre_B = 0;            //转换为float值
float      A_times = 0,B_times = 0;       // 周期值转为float值LCD_Page   mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;   /* 初始化为 数据界面(频率)*/  
LCD_Page   Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;
Para       mypara = PARA_NONE;  //用于参数选择int FreA = 0,FreB = 0; //最终频率
//// 代码部分/* 按键轮询处理及逻辑优化 */
void Key_While()
{/*------ 页面控制变量 ------*/static uint8_t DataSubPage = 0;          // 数据子页面 0-频率 1-次数static uint8_t ChoosePara = 0;           // 参数选择 0-PD 1-PH 2-PXstatic uint8_t ChoosePage = 0;           // 页面选择 0-数据 1-参数 2-统计/*------ 按键事件处理 ------*/KeyEvent KEYS[4];for(uint8_t i = 0; i < 4; i++) {KEYS[i] = Poll_KeyEvent(i);}/*------ 按键1: 参数加 ------*/if(KEYS[0].type == KEY_EVT_PRESS) {LCD_Clear(Black);if(mypage == LCD_SHOW_PARA_PAGE) // 加入了页面限制{switch(mypara) {case PARA_PD: PD = (PD >= 1000) ? 1000 : (PD + 100); break;case PARA_PH: PH = (PH >= 10000) ? 10000 : (PH + 100); break;case PARA_PX: PX = (PX >= 1000) ? 1000 : (PX + 100); break;}}}/*------ 按键2: 参数减 ------*/else if(KEYS[1].type == KEY_EVT_PRESS) {LCD_Clear(Black);if(mypage == LCD_SHOW_PARA_PAGE) //将按键只在参数界面才可以作用{switch(mypara) {case PARA_PD: PD = (PD <= 100) ? 100 : (PD - 100); break;case PARA_PH: PH = (PH <= 1000) ? 1000 : (PH - 100); break;case PARA_PX: PX = (PX <= -1000) ? -1000 : (PX - 100); break;}}}/*------ 按键3: 参数切换/子页面切换 ------*/else if(KEYS[2].type == KEY_EVT_PRESS) {LCD_Clear(Black);switch(Key3page) {/* 参数页切换 */case LCD_SHOW_PARA_PAGE:ChoosePara = (ChoosePara + 1) % 3;  // 优化为循环切换switch(ChoosePara) {case 0: mypara = PARA_PD; break;case 1: mypara = PARA_PH; break;case 2: mypara = PARA_PX; break;break;}break;/* 数据页子页面切换 */case LCD_SHOW_DATA_PAGE_FREQUENCE:case LCD_SHOW_DATA_PAGE_TIMES:DataSubPage = (DataSubPage + 1) % 2;  // 使用常量更佳LCD_Clear(Black);Key3page = (DataSubPage == 0) ? LCD_SHOW_DATA_PAGE_FREQUENCE : LCD_SHOW_DATA_PAGE_TIMES;mypage = Key3page;  // 保持页面同步break;}}/*------ 按键3: 参数切换/子页面切换/统计页长按清零 ------*/else if(KEYS[2].type == KEY_EVT_LONG_PRESS) {  // 新增长按处理if(Key3page == LCD_SHOW_COUNT_PAGE) {NDA = NDB = NHA = NHB = 0;LCD_Clear(Black);// 可以添加统计页刷新函数}}/*------ 按键4: 主页面切换 ------*/else if(KEYS[3].type == KEY_EVT_PRESS) {ChoosePage = (ChoosePage + 1) % 3;  // 循环切换LCD_Clear(Black);switch(ChoosePage) {case 0:  // 数据页DataSubPage = 0;Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;break;case 1:  // 参数页ChoosePara = 0;  // 重置参数选择Key3page = LCD_SHOW_PARA_PAGE;mypage = LCD_SHOW_PARA_PAGE;mypara = PARA_PD;  // 默认选中PDbreak;case 2:  // 统计页Key3page = LCD_SHOW_COUNT_PAGE;mypage = LCD_SHOW_COUNT_PAGE;break;}}
}

对于按键3部分的处理,其实我处理的很粗超,其实用if...else if...反而更快,更方便。 对于那个数据子页面的转换,我是以一种互斥量的想法编写的,我拿了这个值,那你就不能拿。对于这个转换也是 所以 key3page 是用来控制现在是哪个页面 ---> 对于按键来说。  mypage是用来决定lcd显示的。  其他的就比较清晰了。

4.LCD显示

/*main.c
这里是LCD显示部分
*/// 需要的变量  这个只是用于提示各位接下来会出现的变量,这些之前已经定义过了
/* USER CODE BEGIN PM */
typedef enum
{LCD_SHOW_DATA_PAGE_FREQUENCE,     /* 数据界面(频率) */LCD_SHOW_DATA_PAGE_TIMES    ,      /* 数据界面(周期) */LCD_SHOW_PARA_PAGE          ,     /* 参数界面*/LCD_SHOW_COUNT_PAGE         ,     /* 统计界面*/
}LCD_Page;typedef enum
{PARA_NONE = 0,PARA_PD,PARA_PH,PARA_PX,
}Para; //参数int        ccl_value_1 = 0, ccl_value_2 = 0;   // 获取输入捕获值/* 对于频率部分 fA / fB = FA / FB + PX  */
int        fA = 0,fB = 0;                   // 频率值
int PD = 1000,PH = 5000,PX = 0;               
float      fre_A = 0,fre_B = 0;         
float      A_times = 0,B_times = 0;int   NDA = 0,NDB = 0;   /*  A/B通道频率突变次数 */
int   NHA = 0,NHB = 0;   /*  A/B通道频率超限次数 */
int   PHA[2],PHB[2];
uint16_t A_us = 0,B_us = 0;   /* A,B的时间 (us)*/
float    A_ms = 0, B_ms = 0;  /* A,B的时间 (ms)*/
LCD_Page   mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;   /* 初始化为 数据界面(频率)*/  
LCD_Page   Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;
Para       mypara = PARA_NONE;  //用于参数选择
////代码部分
void LCD_SHOWPAGE(void)
{switch(mypage){case LCD_SHOW_DATA_PAGE_FREQUENCE:LCD_DisplayStringLine(Line1,(uint8_t * )"        DATA   ");if(FreA<0){LCD_DisplayStringLine(Line3,(uint8_t *)"     A=NULL  ");}else if(FreA > 1000){fre_A = (float)FreA / 1000.0f;sprintf(text,"     A=%.2fKHz   ",fre_A);LCD_DisplayStringLine(Line3,(uint8_t *)text);}else{sprintf(text,"     A=%dHz      ",FreA);LCD_DisplayStringLine(Line3,(uint8_t *)text);		}if(FreB < 0){LCD_DisplayStringLine(Line4,(uint8_t *)"     B=NULL");}else if(FreB > 1000){fre_B = (float)FreB / 1000.0f;sprintf(text,"     B=%.2fKHz   ",fre_B);LCD_DisplayStringLine(Line4,(uint8_t *)text);				}else{sprintf(text,"     B=%dHz     ",FreB);LCD_DisplayStringLine(Line4,(uint8_t *)text);				}break;case LCD_SHOW_DATA_PAGE_TIMES:LCD_DisplayStringLine(Line1,(uint8_t * )"        DATA   ");		/*		对于通道A	这里我进行了修改 通过判断频率是否为负,进而判断是否为NULL	*/if(FreA < 0){LCD_DisplayStringLine(Line3,(uint8_t *)"     A=NULL");}else if(ccl_value_1 > 1000){A_times = (float)ccl_value_1 / 1000.0f;sprintf(text,"     A=%.2fmS   ",A_times);LCD_DisplayStringLine(Line3,(uint8_t *)text);}else{sprintf(text,"     A=%duS  ",ccl_value_1);LCD_DisplayStringLine(Line3,(uint8_t *)text);}// 这里我进行了修改 通过判断频率是否为负,进而判断是否为NULLif(FreB < 0){LCD_DisplayStringLine(Line4,(uint8_t *)"     B=NULL");}else if(ccl_value_2 > 1000){B_times = (float)ccl_value_2 / 1000.0f;sprintf(text,"     B=%.2fmS  ",B_times);LCD_DisplayStringLine(Line4,(uint8_t *)text);}else{sprintf(text,"     B=%duS  ",ccl_value_2);LCD_DisplayStringLine(Line4,(uint8_t *)text);}break;case LCD_SHOW_PARA_PAGE:LED_Ctrl(1,0);LCD_DisplayStringLine(Line1,(uint8_t *)"       PARA    ");sprintf(text,"     PD=%dHz   ",PD);LCD_DisplayStringLine(Line3,(uint8_t *)text);sprintf(text,"     PH=%dHz   ",PH);LCD_DisplayStringLine(Line4,(uint8_t *)text);sprintf(text,"     PX=%dHz   ",PX);LCD_DisplayStringLine(Line5,(uint8_t *)text);		break;case LCD_SHOW_COUNT_PAGE:LED_Ctrl(1,0);LCD_DisplayStringLine(Line1,(uint8_t *)"        RECD   ");sprintf(text,"     NDA=%d    ",NDA);LCD_DisplayStringLine(Line3,(uint8_t *)text);sprintf(text,"     NDB=%d    ",NDB);LCD_DisplayStringLine(Line4,(uint8_t *)text);sprintf(text,"     NHA=%d    ",NHA);LCD_DisplayStringLine(Line5,(uint8_t *)text);sprintf(text,"     NHB=%d    ",NHB);LCD_DisplayStringLine(Line6,(uint8_t *)text);break;default:break;}if(NDA >= 3 || NDB >= 3) {LED_Ctrl(8,1);}else{LED_Ctrl(8,0);}if(mypage == LCD_SHOW_DATA_PAGE_FREQUENCE || mypage == LCD_SHOW_DATA_PAGE_TIMES){LED_Ctrl(1,1);}else{LED_Ctrl(1,0);}
}

5.频率处理部分

5.1频率超限部分 

/*main.c处理频率超限
*/
//变量部分
int   NDA = 0,NDB = 0;   /*  A/B通道频率突变次数 */
int   NHA = 0,NHB = 0;   /*  A/B通道频率超限次数 */
int   PHA[2],PHB[2]; // 为什么是数组,PHA[0] --- 上一次的值  PHA[1] --- 这一次的值//代码部分
void PH_Beyond(void)
{/*获取最新的值*/PHA[1] = FreA;PHB[1] = FreB;if(PHA[1] > PH && PHA[0] < PH){NHA++;}if(PHB[1] > PH && PHB[0] < PH){NHB++;}if(PHA[1] > PH) {LED_Ctrl(2,1);}else{LED_Ctrl(2,0);}if(PHB[1] > PH){LED_Ctrl(3,1);}else{LED_Ctrl(3,0);}PHA[0] = PHA[1];PHB[0] = PHB[1];
}

5.2频率突变部分

/*main.c  频率突变部分  用到TIM4定时器 频率为10hz
*///变量部分int PDA[30] = {0},PDB[30] = {0};
int Max_A,Max_B,Min_A,Min_B;//
/*      TIM定时器处理部分     */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/*    处理按键   100hz */if(htim->Instance == TIM6){Keys_StateMachine_Handler();   }/*     处理获取的频率数据  10hz  */if(htim->Instance == TIM4){if(timerA == 0){Max_A = FreA;Min_A = FreA;}else{if(Max_A < FreA){Max_A = FreA;}if(Min_A > FreA){Min_A = FreA;}}timerA++;if(timerA >= 30){timerA = 0;if((Max_A - Min_A) > PD){NDA++;}}if(timerB == 0){Max_B = FreB;Min_B = FreB;}else{if(Max_B < FreB){Max_B = FreB;}if(Min_B > FreB){Min_B = FreB;}}timerB++;if(timerB >= 30){timerB = 0;if((Max_B - Min_B) > PD){NDB++;}}}
}

这里的原理就类似于时间窗口,一个大小为3s的时间窗口,不断检测进入窗口的值,一边进入,一边释放,类似于队列的效果。这样就可以实时的测出最大值,最小值。注意最小值的初始状态一定要和最大值相同。不然就会一直保持那个值(无法达到检测最小值的效果了)

总体逻辑部分

/*main.c
*//* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
typedef enum
{LCD_SHOW_DATA_PAGE_FREQUENCE,     /* 数据界面(频率) */LCD_SHOW_DATA_PAGE_TIMES    ,      /* 数据界面(周期) */LCD_SHOW_PARA_PAGE          ,     /* 参数界面*/LCD_SHOW_COUNT_PAGE         ,     /* 统计界面*/
}LCD_Page;typedef enum
{PARA_NONE = 0,PARA_PD,PARA_PH,PARA_PX,
}Para; //参数/* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
char       text[20]                       ;
int        ccl_value_1 = 0, ccl_value_2 = 0;   // 获取输入捕获值/* 对于频率部分 fA / fB = FA / FB + PX  */
int        fA = 0,fB = 0;                   // 频率值
int PD = 1000,PH = 5000,PX = 0;               
float      fre_A = 0,fre_B = 0;         
float      A_times = 0,B_times = 0;int   NDA = 0,NDB = 0;   /*  A/B通道频率突变次数 */
int   NHA = 0,NHB = 0;   /*  A/B通道频率超限次数 */
int   PHA[2],PHB[2];
uint16_t A_us = 0,B_us = 0;   /* A,B的时间 (us)*/
float    A_ms = 0, B_ms = 0;  /* A,B的时间 (ms)*/
LCD_Page   mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;   /* 初始化为 数据界面(频率)*/  
LCD_Page   Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;
Para       mypara = PARA_NONE;  //用于参数选择int PDA[30] = {0},PDB[30] = {0};
//uint8_t i;
int Max_A,Max_B,Min_A,Min_B;int FreA = 0,FreB = 0;
uint16_t timerA = 0,timerB = 0;
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//*    频率获取部分
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{/*      r40 输出捕获   通道 A */if(htim->Instance == TIM2){fA = 1000000 / (TIM2->CCR1+1);TIM2->CNT = 0;if(fA > 20000) fA = 20000;else if(fA < 400) fA = 400;FreA = fA + PX;ccl_value_1 = 1000000 / FreA;/*这里我根据测评出的结果 推出来,它其实周期的计算是根据最终的频率来计算的而不是我最先测出的fA来进行计算。*/}/*      R39 输出捕获  通道 B  */if(htim->Instance == TIM16){fB = 1000000 / (TIM16->CCR1+1);TIM16->CNT = 0;if(fB > 20000) fB = 20000;else if(fB < 400) fB = 400;FreB = fB + PX;ccl_value_2 = 1000000 / FreB;}
}/*      TIM定时器处理部分     */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/*    处理按键   100hz */if(htim->Instance == TIM6){Keys_StateMachine_Handler();   }/*     处理获取的频率数据  10hz  */if(htim->Instance == TIM4){if(timerA == 0){Max_A = FreA;Min_A = FreA;}else{if(Max_A < FreA){Max_A = FreA;}if(Min_A > FreA){Min_A = FreA;}}timerA++;if(timerA >= 30){timerA = 0;if((Max_A - Min_A) > PD){NDA++;}}if(timerB == 0){Max_B = FreB;Min_B = FreB;}else{if(Max_B < FreB){Max_B = FreB;}if(Min_B > FreB){Min_B = FreB;}}timerB++;if(timerB >= 30){timerB = 0;if((Max_B - Min_B) > PD){NDB++;}}}
}/* 按键轮询处理及逻辑优化 */
void Key_While()
{/*------ 页面控制变量 ------*/static uint8_t DataSubPage = 0;          // 数据子页面 0-频率 1-次数static uint8_t ChoosePara = 0;           // 参数选择 0-PD 1-PH 2-PXstatic uint8_t ChoosePage = 0;           // 页面选择 0-数据 1-参数 2-统计/*------ 按键事件处理 ------*/KeyEvent KEYS[4];for(uint8_t i = 0; i < 4; i++) {KEYS[i] = Poll_KeyEvent(i);}/*------ 按键1: 参数加 ------*/if(KEYS[0].type == KEY_EVT_PRESS) {LCD_Clear(Black);if(mypage == LCD_SHOW_PARA_PAGE) // 加入了页面限制{switch(mypara) {case PARA_PD: PD = (PD >= 1000) ? 1000 : (PD + 100); break;case PARA_PH: PH = (PH >= 10000) ? 10000 : (PH + 100); break;case PARA_PX: PX = (PX >= 1000) ? 1000 : (PX + 100); break;}}}/*------ 按键2: 参数减 ------*/else if(KEYS[1].type == KEY_EVT_PRESS) {LCD_Clear(Black);if(mypage == LCD_SHOW_PARA_PAGE){switch(mypara) {case PARA_PD: PD = (PD <= 100) ? 100 : (PD - 100); break;case PARA_PH: PH = (PH <= 1000) ? 1000 : (PH - 100); break;case PARA_PX: PX = (PX <= -1000) ? -1000 : (PX - 100); break;}}}/*------ 按键3: 参数切换/子页面切换 ------*/else if(KEYS[2].type == KEY_EVT_PRESS) {LCD_Clear(Black);switch(Key3page) {/* 参数页切换 */case LCD_SHOW_PARA_PAGE:ChoosePara = (ChoosePara + 1) % 3;  // 优化为循环切换switch(ChoosePara) {case 0: mypara = PARA_PD; break;case 1: mypara = PARA_PH; break;case 2: mypara = PARA_PX; break;break;}break;/* 数据页子页面切换 */case LCD_SHOW_DATA_PAGE_FREQUENCE:case LCD_SHOW_DATA_PAGE_TIMES:DataSubPage = (DataSubPage + 1) % 2;  // 使用常量更佳LCD_Clear(Black);Key3page = (DataSubPage == 0) ? LCD_SHOW_DATA_PAGE_FREQUENCE : LCD_SHOW_DATA_PAGE_TIMES;mypage = Key3page;  // 保持页面同步break;}}/*------ 按键3: 参数切换/子页面切换/统计页长按清零 ------*/else if(KEYS[2].type == KEY_EVT_LONG_PRESS) {  // 新增长按处理if(Key3page == LCD_SHOW_COUNT_PAGE) {NDA = NDB = NHA = NHB = 0;LCD_Clear(Black);// 可以添加统计页刷新函数}}/*------ 按键4: 主页面切换 ------*/else if(KEYS[3].type == KEY_EVT_PRESS) {ChoosePage = (ChoosePage + 1) % 3;  // 循环切换LCD_Clear(Black);switch(ChoosePage) {case 0:  // 数据页DataSubPage = 0;Key3page = LCD_SHOW_DATA_PAGE_FREQUENCE;mypage = LCD_SHOW_DATA_PAGE_FREQUENCE;break;case 1:  // 参数页ChoosePara = 0;  // 重置参数选择Key3page = LCD_SHOW_PARA_PAGE;mypage = LCD_SHOW_PARA_PAGE;mypara = PARA_PD;  // 默认选中PDbreak;case 2:  // 统计页Key3page = LCD_SHOW_COUNT_PAGE;mypage = LCD_SHOW_COUNT_PAGE;break;}}
}/* 
Log: 显示部分 数据的频率和周期显示会有冲突*/
void LCD_SHOWPAGE(void)
{switch(mypage){case LCD_SHOW_DATA_PAGE_FREQUENCE:LCD_DisplayStringLine(Line1,(uint8_t * )"        DATA   ");if(FreA<0){LCD_DisplayStringLine(Line3,(uint8_t *)"     A=NULL  ");}else if(FreA > 1000){fre_A = (float)FreA / 1000.0f;sprintf(text,"     A=%.2fKHz   ",fre_A);LCD_DisplayStringLine(Line3,(uint8_t *)text);}else{sprintf(text,"     A=%dHz      ",FreA);LCD_DisplayStringLine(Line3,(uint8_t *)text);		}if(FreB < 0){LCD_DisplayStringLine(Line4,(uint8_t *)"     B=NULL");}else if(FreB > 1000){fre_B = (float)FreB / 1000.0f;sprintf(text,"     B=%.2fKHz   ",fre_B);LCD_DisplayStringLine(Line4,(uint8_t *)text);				}else{sprintf(text,"     B=%dHz     ",FreB);LCD_DisplayStringLine(Line4,(uint8_t *)text);				}break;case LCD_SHOW_DATA_PAGE_TIMES:LCD_DisplayStringLine(Line1,(uint8_t * )"        DATA   ");		/*		对于通道A	这里我进行了修改 通过判断频率是否为负,进而判断是否为NULL	*/if(FreA < 0){LCD_DisplayStringLine(Line3,(uint8_t *)"     A=NULL");}else if(ccl_value_1 > 1000){A_times = (float)ccl_value_1 / 1000.0f;sprintf(text,"     A=%.2fmS   ",A_times);LCD_DisplayStringLine(Line3,(uint8_t *)text);}else{sprintf(text,"     A=%duS  ",ccl_value_1);LCD_DisplayStringLine(Line3,(uint8_t *)text);}// 这里我进行了修改 通过判断频率是否为负,进而判断是否为NULLif(FreB < 0){LCD_DisplayStringLine(Line4,(uint8_t *)"     B=NULL");}else if(ccl_value_2 > 1000){B_times = (float)ccl_value_2 / 1000.0f;sprintf(text,"     B=%.2fmS  ",B_times);LCD_DisplayStringLine(Line4,(uint8_t *)text);}else{sprintf(text,"     B=%duS  ",ccl_value_2);LCD_DisplayStringLine(Line4,(uint8_t *)text);}break;case LCD_SHOW_PARA_PAGE:LED_Ctrl(1,0);LCD_DisplayStringLine(Line1,(uint8_t *)"       PARA    ");sprintf(text,"     PD=%dHz   ",PD);LCD_DisplayStringLine(Line3,(uint8_t *)text);sprintf(text,"     PH=%dHz   ",PH);LCD_DisplayStringLine(Line4,(uint8_t *)text);sprintf(text,"     PX=%dHz   ",PX);LCD_DisplayStringLine(Line5,(uint8_t *)text);		break;case LCD_SHOW_COUNT_PAGE:LED_Ctrl(1,0);LCD_DisplayStringLine(Line1,(uint8_t *)"        RECD   ");sprintf(text,"     NDA=%d    ",NDA);LCD_DisplayStringLine(Line3,(uint8_t *)text);sprintf(text,"     NDB=%d    ",NDB);LCD_DisplayStringLine(Line4,(uint8_t *)text);sprintf(text,"     NHA=%d    ",NHA);LCD_DisplayStringLine(Line5,(uint8_t *)text);sprintf(text,"     NHB=%d    ",NHB);LCD_DisplayStringLine(Line6,(uint8_t *)text);break;default:break;}if(NDA >= 3 || NDB >= 3) {LED_Ctrl(8,1);}else{LED_Ctrl(8,0);}if(mypage == LCD_SHOW_DATA_PAGE_FREQUENCE || mypage == LCD_SHOW_DATA_PAGE_TIMES){LED_Ctrl(1,1);}else{LED_Ctrl(1,0);}
}void PH_Beyond(void)
{/*获取最新的值*/PHA[1] = FreA;PHB[1] = FreB;if(PHA[1] > PH && PHA[0] < PH){NHA++;}if(PHB[1] > PH && PHB[0] < PH){NHB++;}if(PHA[1] > PH) {LED_Ctrl(2,1);}else{LED_Ctrl(2,0);}if(PHB[1] > PH){LED_Ctrl(3,1);}else{LED_Ctrl(3,0);}PHA[0] = PHA[1];PHB[0] = PHB[1];
}/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_TIM4_Init();MX_TIM6_Init();MX_TIM3_Init();MX_TIM8_Init();MX_TIM16_Init();/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);HAL_TIM_Base_Start_IT(&htim6);HAL_TIM_Base_Start_IT(&htim4);HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);LED_CLOSEALL();   /* 关闭所有的LED	*//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){Key_While();LCD_SHOWPAGE();PH_Beyond();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

以上就是我的全部内容了,若有疑问请评论区提出。 

我写的比较潦草,最近要去刷一下题了,所以大体写的很快。 

http://www.dtcms.com/wzjs/136388.html

相关文章:

  • 福州做网站公司网络营销是什么工作主要干啥
  • 做双语网站用什么cms系统好武汉竞价托管公司
  • 电子商务网站开发进什么科目友情链接交易平台源码
  • 新乡做网站优化电工培训
  • 优秀的个人博客网站项目推广方式有哪些
  • 网站转载代码百度关键词推广条件
  • 网站优化 检测响应速度优化技术
  • wordpress限制站点使用时间互联网营销师培训课程免费
  • 可以做彩页的网站运营推广是做什么的
  • 如何登陆wordpress后台湖北网站seo设计
  • 公司建设网站的案例分析app推广30元一单
  • 短网址缩短暴风seo论坛
  • wordpress文章列表全文seo技术培训海南
  • 做网站的费用计入哪个科目温州seo按天扣费
  • 自己做网站可以上传软件营销型网站建设套餐
  • 找别人做网站需要注意什么环球网最新消息
  • 做网站的微信号汕头网站建设方案外包
  • 郑州app制作公司上海好的seo公司
  • 怎么做自己的网站弄商城佣金西安网站制作建设
  • 域名除了做网站还能做什么网站seo优化公司
  • 大连b2c网站建设设计公司网站设计
  • 四川党的建设杂志社网站广告软文范例200字
  • 怎样建设文章网站网络营销外包推广定制公司
  • 房产公司网站建设微博推广方式
  • 商场网站 策划泉州seo外包
  • wordpress获取内容限制字数排名优化公司
  • 六年级做的网站的软件下载百度推广400电话
  • 佛山营销网站建设谷歌seo服务商
  • 餐饮行业做网站的好处常州网络推广平台
  • 如何做网站域名备案seox