温馨提示:
真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程,我打算先自己做一遍,把遇到的问题和不同之处记录到演练篇,然后再返回来仔细研究一下,找到最佳的解题方法记录到研究篇。
解题记录:
草稿:
功能分析:
主要流程和全局变量:
功能函数分析:
过程中遇到的问题:
- 很明显第一个问题就是草稿太乱,需要规范化一下。
- 之前没想过需要获取定时器状态或定时时间,以实现长按、判断时长等功能。
- 根据题目,要把PCB设置为80MHz会更方便,在自己开发的时候我习惯设置为100MHz。
- 准确的毫秒级延时,由于预分频系数不可以大于65535,所以只能填7999,这样计数10000时就是1s。
- 忘记打开中断,设置优先级。
- 还是会漏掉某些变量的设置。
- 写草稿没有清谁是谁,重新查找浪费时间。
源代码:
main.c
/* USER CODE BEGIN PV */
uint8_t B1_key=1;
uint8_t PWMOut_MOde=1;//1:µÍƵ
uint32_t PWMOut_Pluse=10;
uint32_t PWMIn_f=0;
uint8_t PARA_mode=1;
uint16_t PARA_R=1;
uint16_t PARA_K=1;
uint8_t changeMode=1;
uint32_t changeNum=0;
uint8_t PWM_C=1;
uint32_t volt=0;
char LCD_str[20];
uint16_t PWMChangeTim=0;
uint32_t Period=200;
float Data_V=0.0;//(uint32_t)((PWMIn_f*6.28*PARA_R)/(100*PARA_K));
uint8_t V_change=1;
float V_Hmax=0.0;
float V_Lmax=0.0;
/* USER CODE END PV */
//LED函数
void LED_Switch(uint16_t GPIO_Pin,GPIO_PinState PinState)
{
HAL_GPIO_WritePin(GPIOC,GPIO_Pin,PinState);
HAL_GPIO_WritePin(GPIOD,LED_LE_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,LED_LE_Pin,GPIO_PIN_RESET);
}
//PWM渐变函数
void PWM_Change()
{
for(uint16_t i=0;i<50;i++)
{
HAL_TIM_Base_Start(&htim7);
}
}
//读ADC并改变占空比
void Read_ADC()
{
if(PWM_C==1)
{
volt=(3300*HAL_ADC_GetValue(&hadc2))>>12;
if(volt<=1000)
PWMOut_Pluse=10;
else if(volt>=3000)
PWMOut_Pluse=85;
else
PWMOut_Pluse=(volt-1000)/(27*100);
if(PWMOut_MOde==1)
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,PWMOut_Pluse*2);
else
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,PWMOut_Pluse);
}
}
//计算速度
void Set_V()
{
if(V_change==0)
{
HAL_TIM_Base_Stop(&htim4);
V_change=1;
}
PWMIn_f=80000000/__HAL_TIM_GetCompare(&htim3,TIM_CHANNEL_1);
Data_V=(PWMIn_f*6.28*PARA_R)/(100*PARA_K);
HAL_TIM_Base_Start(&htim4);
V_change=0;
}
//按键1功能函数
void B1Fun()
{
B1_key++;
if(B1_key>3)
B1_key=1;
}
//按键2功能函数
void B2Fun()
{
if(B1_key==1&&changeMode==1)
{
changeNum++;
changeMode=0;
PWM_Change();
}
else if(B1_key==2)
{
if(PARA_mode==1)
PARA_mode=0;
else
PARA_mode=1;
}
}
//按键3功能函数
void B3Fun()
{
if(B1_key==2)
{
if(PARA_mode==1)
PARA_R++;
else
PARA_K++;
}
}
///按键4功能函数
void B4Fun()
{
if(B1_key==2)
{
if(PARA_mode==1)
PARA_R--;
else
PARA_K--;
}
else if(B1_key==3)
{
if(PWM_C==1)//³¤°´
{
HAL_TIM_Base_Start(&htim6);
while(HAL_TIM_Base_GetState(&htim6)==HAL_TIM_STATE_BUSY)
{
if(HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin)==GPIO_PIN_SET)
{
HAL_TIM_Base_Stop(&htim6);
return;
}
}
}
else
{
PWM_C=1;
}
}
}
//按键扫描函数
void KeyScan()
{
if(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)==GPIO_PIN_RESET)
{
B1Fun();
}
}
if(HAL_GPIO_ReadPin(B2_GPIO_Port,B2_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(B2_GPIO_Port,B2_Pin)==GPIO_PIN_RESET)
{
B2Fun();
}
}
if(HAL_GPIO_ReadPin(B3_GPIO_Port,B3_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(B3_GPIO_Port,B3_Pin)==GPIO_PIN_RESET)
{
B3Fun();
}
}
if(HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin)==GPIO_PIN_RESET)
{
B4Fun();
}
}
}
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
LCD_Init();
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
LCD_Clear(Black);
/* 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_ADC2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM6_Init();
MX_TIM7_Init();
MX_TIM15_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LED_Switch(LED1_Pin|LED2_Pin|LED3_Pin|LED4_Pin|LED5_Pin|LED6_Pin|LED7_Pin|LED8_Pin,GPIO_PIN_SET);
Set_V();
while (1)
{
KeyScan();
Read_ADC();
if(B1_key==1)
{
LCD_Clear(Black);
LED_Switch(LED1_Pin,GPIO_PIN_RESET);
LCD_DisplayStringLine(Line2," DATA");
if(PWMOut_MOde==1)
LCD_DisplayStringLine(Line4," M=L");
else
LCD_DisplayStringLine(Line4," M=H");
sprintf(LCD_str," P=%d%",PWMOut_Pluse);
LCD_DisplayStringLine(Line5,LCD_str);
sprintf(LCD_str," V=%.1f",Data_V);
LCD_DisplayStringLine(Line6,LCD_str);
LED_Switch(LED1_Pin,GPIO_PIN_SET);
}
else if(B1_key==2)
{
LCD_Clear(Black);
LCD_DisplayStringLine(Line2," PARA");
sprintf(LCD_str," R=%d",PARA_R);
LCD_DisplayStringLine(Line4,LCD_str);
sprintf(LCD_str," K=%d",PARA_K);
LCD_DisplayStringLine(Line5,LCD_str);
}
else if(B1_key==3)
{
Set_V();
LCD_Clear(Black);
LCD_DisplayStringLine(Line2," RECD");
sprintf(LCD_str," N=%d",changeNum);
LCD_DisplayStringLine(Line4,LCD_str);
sprintf(LCD_str," MH=%.1f",V_Hmax);
LCD_DisplayStringLine(Line5,LCD_str);
sprintf(LCD_str," MH=%.1f",V_Lmax);
LCD_DisplayStringLine(Line6,LCD_str);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
//省略
main.h
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include <stdio.h>
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define LED6_Pin GPIO_PIN_13
#define LED6_GPIO_Port GPIOC
#define LED7_Pin GPIO_PIN_14
#define LED7_GPIO_Port GPIOC
#define LED8_Pin GPIO_PIN_15
#define LED8_GPIO_Port GPIOC
#define B4_Pin GPIO_PIN_0
#define B4_GPIO_Port GPIOA
#define B1_Pin GPIO_PIN_0
#define B1_GPIO_Port GPIOB
#define B2_Pin GPIO_PIN_1
#define B2_GPIO_Port GPIOB
#define B3_Pin GPIO_PIN_2
#define B3_GPIO_Port GPIOB
#define LED1_Pin GPIO_PIN_8
#define LED1_GPIO_Port GPIOC
#define LED2_Pin GPIO_PIN_9
#define LED2_GPIO_Port GPIOC
#define LED3_Pin GPIO_PIN_10
#define LED3_GPIO_Port GPIOC
#define LED4_Pin GPIO_PIN_11
#define LED4_GPIO_Port GPIOC
#define LED5_Pin GPIO_PIN_12
#define LED5_GPIO_Port GPIOC
#define LED_LE_Pin GPIO_PIN_2
#define LED_LE_GPIO_Port GPIOD
/* USER CODE BEGIN Private defines */
extern uint8_t B1_key;
extern uint8_t PWMOut_MOde;
extern uint32_t PWMOut_Pluse;
extern uint32_t PWMIn_f;
extern uint8_t PARA_mode;
extern uint16_t PARA_R;
extern uint16_t PARA_K;
extern float Data_V;//(uint32_t)((PWMIn_f*6.28*PARA_R)/(100*PARA_K));
extern uint8_t changeMode;
extern uint32_t changeNum;
extern uint8_t PWM_C;
extern char LCD_str[];
extern uint16_t PWMChangeTim;
extern uint32_t Period;
extern uint8_t V_change;
extern float V_Hmax;
extern float V_Lmax;
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
stm32g4xx_it.c
//前面的内容省略
/******************************************************************************/
/* STM32G4xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32g4xx.s). */
/******************************************************************************/
/**
* @brief This function handles ADC1 and ADC2 global interrupt.
*/
void ADC1_2_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_2_IRQn 0 */
/* USER CODE END ADC1_2_IRQn 0 */
HAL_ADC_IRQHandler(&hadc2);
/* USER CODE BEGIN ADC1_2_IRQn 1 */
/* USER CODE END ADC1_2_IRQn 1 */
}
/**
* @brief This function handles TIM1 break interrupt and TIM15 global interrupt.
*/
void TIM1_BRK_TIM15_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_BRK_TIM15_IRQn 0 */
/* USER CODE END TIM1_BRK_TIM15_IRQn 0 */
HAL_TIM_IRQHandler(&htim15);
/* USER CODE BEGIN TIM1_BRK_TIM15_IRQn 1 */
/* USER CODE END TIM1_BRK_TIM15_IRQn 1 */
}
/**
* @brief This function handles TIM2 global interrupt.
*/
void TIM2_IRQHandler(void)
{
/* USER CODE BEGIN TIM2_IRQn 0 */
/* USER CODE END TIM2_IRQn 0 */
HAL_TIM_IRQHandler(&htim2);
/* USER CODE BEGIN TIM2_IRQn 1 */
/* USER CODE END TIM2_IRQn 1 */
}
/**
* @brief This function handles TIM3 global interrupt.
*/
void TIM3_IRQHandler(void)
{
/* USER CODE BEGIN TIM3_IRQn 0 */
/* USER CODE END TIM3_IRQn 0 */
HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */
/* USER CODE END TIM3_IRQn 1 */
}
/**
* @brief This function handles TIM4 global interrupt.
*/
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
/* USER CODE BEGIN TIM4_IRQn 1 */
V_change=1;
if(PWMOut_MOde==1)
{
if(Data_V>V_Lmax)
V_Lmax=Data_V;
}
else
{
if(Data_V>V_Hmax)
V_Hmax=Data_V;
}
/* USER CODE END TIM4_IRQn 1 */
}
/**
* @brief This function handles TIM6 global interrupt, DAC1 and DAC3 channel underrun error interrupts.
*/
void TIM6_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */
/* USER CODE END TIM6_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */
/* USER CODE END TIM6_DAC_IRQn 1 */
}
/**
* @brief This function handles TIM7 global interrupt.
*/
void TIM7_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_IRQn 0 */
/* USER CODE END TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_IRQn 1 */
PWMChangeTim++;
if(PWMChangeTim==50)
{
PWMChangeTim=0;
if(PWMOut_MOde==1)
__HAL_TIM_SetAutoreload(&htim2,100);
else
__HAL_TIM_SetAutoreload(&htim2,200);
HAL_TIM_Base_Stop(&htim7);
}
else
{
if(PWMOut_MOde==1)
Period=200-PWMChangeTim*2;
else
Period=100+PWMChangeTim*2;
__HAL_TIM_SetAutoreload(&htim2,Period);
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,(uint32_t)(Period/PWMOut_Pluse));
HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
HAL_GPIO_WritePin(GPIOD,LED_LE_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,LED_LE_Pin,GPIO_PIN_RESET);
}
/* USER CODE END TIM7_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
更新:24-3-29
下载后,发现如下问题:(应该简单在草稿上列出,这样可以理清思路)
- 屏幕一直闪,原因是LCD驱动函数响应较慢,所以不能总是清屏,应该改成在按下B1后清屏;
- LED灯全亮,之前只在进入循环前关LED,这样是不行的,因为操作LCD会改变引脚的状态,所以进入每次都要关LED。而且不可以离点亮LED灯的位置太远,不然会闪;
- 没有打印‘%’,将语句改为如下代码:
sprintf(LCD_str," P=%d%c",PWMOut_Pluse,'%');
- 按键有粘滞现象,修改后反应时间又过长,再次下载后粘滞消失,说明硬件不稳定,按键延时就设置为50就行,不快也不慢;
- PARA模式下R和K等于0还可以减小,从十位数减到个位数没有清行,在减小值的位置添加清屏。
- 没有仔细读题。
- R和K的范围是1到10
- 而且B4的长按是在数据界面,我一直以为是统计界面,太粗心。幸好我模块化做的可以,需要改动的代码比较少。
- 计算要从简:计算速度,频率不是8k就是4k,只要判断模式即可,不用计算频率。
- 关于时间的操作可以在TIM中断服务函数中进行的,就不要拿出来,比如PWM频率转换,和长按。
- 长按后,要等待按键松开:
if(PWM_C==1)//³¤°´ { HAL_TIM_Base_Start_IT(&htim6); //等待定时器到2s,若中途松开,就关闭定时器 while(HAL_TIM_Base_GetState(&htim6)==HAL_TIM_STATE_BUSY) { if(HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin)==GPIO_PIN_SET) { HAL_TIM_Base_Stop_IT(&htim6); HAL_Delay(50); return; } } //等待按键松开 while(HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin)==GPIO_PIN_RESET); }
- 看来最后的问题就是PWM的读取和输出了。
- 基础,但是致命的错误:
- 要使用定时器中断服务函数,就必须用中断方式打开或关闭定时器!
- PWM输出的定时器需要打开对应定时器、打开PWM输出!
- PWM输入的定时器也需要打开,还有对应的两个通道!
/* USER CODE BEGIN WHILE */ HAL_TIM_Base_Start(&htim2); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); HAL_TIM_Base_Start(&htim3); HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1); HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2); while (1)
- 修改后发现计算占空比有问题,修改如下:
PWMOut_Pluse=(volt-1000)/27+10;
- 还有时间的话就先保存一份,然后优化代码,消除所有警告,如LCD显示里,把强制类型转换加上。
未解决的问题:
按键长按的实现没有成功,要学习一下。
反思总结
我们自己学习的时候使用的都是高性能的芯片和开发板,比赛用的设备没有那么好,所以需要我们适应这种设备。而且,实际应用中一般为了降低成本,也需要我们使用较低性能的设备。
- 不能总是清屏,应该改成在按下B1后清屏;
- 每次都要关LED。而且不可以离点亮LED灯的位置太远,不然会闪;
- 按键延时就设置为50就行,不快也不慢;如果开发板反复无常,就是硬件有问题,要求更换!
- 减小值的位置添加清屏。或者在写显示函数的时候格式化数字的位数。
- 计算要从简
- 关于时间的操作可以在TIM中断服务函数中进行的,就不要拿出来
- 要使用定时器中断服务函数,就必须用中断方式打开或关闭定时器!
- PWM输出的定时器需要打开对应定时器、打开PWM输出!
- PWM输入的定时器也需要打开,还有对应的两个通道!
之前没有记住的函数:
- 改变周期的函数
__HAL_TIM_SetAutoreload