题目
在4t上测评78.2分,主要是频率的逐渐增加和减少有问题,我使用示波器测量发现没有问题,应该是测评的问题
CubeMX配置
引脚配置
ADC配置
查看产品手册可以知道要将PB15配置为ADC2_IN15
定时器配置
这题我用到的定时器比较多,TIM2为PWM输出,TIM3为输入捕获,TIM4为按键定时器,TIM6、TIM8、TIM16、TIM17为计时定时器
TIM2配置
这里PA1输出PWM,因此将PA1配置TIM2->CH2
TIM3配置
TIM4配置
其他定时器和TIM4一样配置就行,自己注意频率的设置
代码实现
中断回调函数
//中断回调函数
#include "interrupt.h"
extern int mode_flag;
unsigned int num=0;
int time1=0,time2=0,time3=0,time4=0;
int L_flag=0,H_flag=0;
struct keys key[4]={0,0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4)
{
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch(key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta==0)
{
key[i].judge_sta=1;
key[i].key_time=0;
}
}
break;
case 1:
{
if(key[i].key_sta==0)
{
key[i].judge_sta=2;
}
else
key[i].judge_sta=0;
}
break;
case 2:
{
if(key[i].key_sta==1)
{
key[i].judge_sta=0;
if(key[i].key_time<2000)
key[i].single_flag=1;//短按标志位
}
else
{
key[i].key_time++;
if(key[i].key_time>=2000)
key[i].long_flag=1;//长按标志位
}
}
break;
}
}
}
if(htim->Instance==TIM6){//5s无动作计时
time1++;
}
if(htim->Instance==TIM8){//低频最大速度2s计时
if(L_flag==1)
time2++;
else
time2=0;
}
if(htim->Instance==TIM17){//高低频切换计时
if(mode_flag==1||mode_flag==0)
time3++;
if(time3>100&&time3%250==0)//每250ms num值+1
num+=1;
}
if(htim->Instance==TIM16){//高频最大速度2s计时
if(H_flag==1)
time4++;
else
time4=0;
}
}
double ccr1=0;
int frq1=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2)//直接输入捕获
{
ccr1=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
__HAL_TIM_SetCounter(htim,0);
frq1=1000000/ccr1;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
}
}
}
主函数
我代码里面都写了注释,可以自己看看
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "interrupt.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern int time1,time2,time3,time4;
extern unsigned int num; //time3的标志位,用于逐渐增加频率
extern int L_flag,H_flag; //低频最大速度标志位和高频最大速度标志位
extern int frq1;
extern double ccr1;
extern struct keys key[4];
extern __IO uint32_t uwTick;;
char text[20];
int K=1,R=1,view=0;//参数K/R,界面
int choose=0,choose_num=0;//R/K切换标志,高低频切换计数
int mode_flag=0,knock=0,ld2_flag=0;//高低频模式标志位,锁定标志位,ld2闪烁标志位
double L_speed=0,H_speed=0; //低频最大速度和高频最大速度
double L_old=0,H_old=0;低频上次速度和高频上次速度
char mode='L';//高低频显示,初始为低频
double speed=0,duty=0;//速度参数和占空比显示
unsigned char led=0x00;
int pa1_duty=0;//PA1占空比设置
int mode_start;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 led_disp(unsigned char dsled){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,dsled<<8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
double getADC(ADC_HandleTypeDef *hadc)
{
double adc;
HAL_ADC_Start(hadc);
adc = HAL_ADC_GetValue(hadc);
return adc * 3.3 /4096;
}
void lcd_pro(void)
{
//数据界面
if(view==0)
{
LCD_DisplayStringLine(Line1, (unsigned char *)" DATA");
sprintf(text," M=%c ",mode);
LCD_DisplayStringLine(Line3, (unsigned char *)text);
sprintf(text," P=%2.f%% ",duty);
LCD_DisplayStringLine(Line4, (unsigned char *)text);
sprintf(text," V=%.1f ",speed);
LCD_DisplayStringLine(Line5, (unsigned char *)text);
}
//参数界面
if(view==1)
{
LCD_DisplayStringLine(Line1, (unsigned char *)" PARA");
sprintf(text," R=%d ",R);
LCD_DisplayStringLine(Line3, (unsigned char *)text);
sprintf(text," K=%d ",K);
LCD_DisplayStringLine(Line4, (unsigned char *)text);
}
//统计界面
if(view==2)
{
LCD_DisplayStringLine(Line1, (unsigned char *)" RECD");
sprintf(text," N=%d ",choose_num);
LCD_DisplayStringLine(Line3, (unsigned char *)text);
sprintf(text," MH=%.1f ",H_speed);
LCD_DisplayStringLine(Line4, (unsigned char *)text);
sprintf(text," ML=%.1f ",L_speed);
LCD_DisplayStringLine(Line5, (unsigned char *)text);
}
}
void key_pro(void)
{
//切换界面
if(key[0].single_flag==1)
{
LCD_Clear(Black);
view+=1;
//每次从数据界面进入参数界面,默认当前可调整的参数为R参数
choose=0;
key[0].single_flag=0;
if(view==3)
view=0;
}
//数据界面
if(view==0)
{
//长按B4进行锁定
if(key[3].long_flag==1)
{
knock=1;
key[3].long_flag=0;
}
//短按B4解锁
if(key[3].single_flag==1)
{
knock=0;
key[3].single_flag=0;
}
//选择按键(切换高低频)
if(mode=='H')
{
//5 秒内不可再次触发切换功能
if(key[1].single_flag==1&&uwTick<5000)
key[1].single_flag=0;
//切换为低频
if(key[1].single_flag==1&&uwTick>=5000)
{
num=0; //time3重新计时 num从0开始计次
uwTick=0;
mode_flag=0;//低频标志位
choose_num+=1;//切换次数+1
ld2_flag=1;//LD2标志位
key[1].single_flag=0;
}
}
if( mode=='L')
{
if(key[1].single_flag==1&&uwTick<5000)
key[1].single_flag=0;
//切换为高频
if(key[1].single_flag==1&&uwTick>=5000)
{
num=0; //time3重新计时 num从0开始计次
uwTick=0;
mode_start=1;//取消初始状态
mode_flag=1;//高频标志位
choose_num+=1;
ld2_flag=1;
key[1].single_flag=0;
}
}
//数据界面使B3标志位不生效
key[2].single_flag=0;
}
//参数界面
if(view==1)
{
if(key[1].single_flag==1)
{
choose+=1; //初始为0,按下B2加1,切换选择R、K
key[1].single_flag=0;
}
if(key[2].single_flag==1)
{
knock=0;
if(choose%2==0)//choos为偶数,按下B3,R加1
R+=1;
if(R>10)
R=1;
if(choose%2==1)//choos为奇数,按下B3,K加1
K+=1;
if(K>10)
K=1;
key[2].single_flag=0;
LCD_Clear(Black);
}
if(key[3].single_flag==1)
{
if(choose%2==0)//choos为偶数,按下B4,R减1
R-=1;
if(R<1)
R=10;
if(choose%2==1)//choos为偶数,按下B4,K减1
K-=1;
if(K<1)
K=10;
key[3].single_flag=0;
LCD_Clear(Black);
}
}
//记录界面
//使B2标志位失效,B4长短按标志位失效
if(view==2)
{
key[1].single_flag=0;
key[3].single_flag=0;
key[3].long_flag=0;
}
}
void speed_pro(void)
{
speed = frq1*2*3.14*R/100/K;//速度计算公式
if(mode == 'L')
{
//低频模式将高频最大速度清零
H_speed=0;
H_old=0;
//如果当前速度等于上一次速度L_old
//且当前速度大于低频最大速度
if(speed==L_old&&speed>=L_speed)
L_flag=1;//低频标志位置1,tim2开始计时
//如果当前速度小于最大速度
//或者当前速度比上次速度大1.0(因为频率捕获一直有0.几跳变,微小变化不停止计时)
if(speed-L_old>=1.0||speed<L_speed)
L_flag=0;//标志位清零,停止计时
//计时大于2s最大速度更新
if(time2>=2000)
{
L_speed = speed;
L_flag=0;
}
L_old = speed;
}
if(mode == 'H')
{
L_speed=0;
L_old=0;
if(speed==H_old&&speed>=H_speed)
H_flag=1;
if(speed-H_old>=1.0||speed<H_speed)
H_flag=0;
if(time4>=2000)
{
H_speed= speed;
H_flag=0;
}
H_old = speed;
}
}
void pwm_pro(void) //PWM
{
if(getADC(&hadc2)>1&&getADC(&hadc2)<3&&knock==0)
{
duty = 37.5*(getADC(&hadc2)-1)+10;
}
if(getADC(&hadc2)>=3&&knock==0)
{
duty = 85;
}
if(getADC(&hadc2)<=1&&knock==0)
{
duty = 10;
}
//锁定时占空比不变
if(knock==1)
{
duty = duty;
}
//高频标志位为1时,频率从4k在5s内加到8k
if(mode_flag==1)
{
htim2.Init.Period=(1000000/(4000+200*num))-1; //更改重装载值
HAL_TIM_Base_Init(&htim2);
pa1_duty=duty/100*TIM2->ARR;//保证占空比不变
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pa1_duty);//设置占空比
HAL_TIM_Base_Start_IT(&htim17);//time3开始计时
if(num>=20)//5s
{
mode = 'H';
time3=0;
HAL_TIM_Base_Stop_IT(&htim17);
}
}
//低频标志位为1时,频率从8k在5s内减到4k
if(mode_flag==0)
{
htim2.Init.Period=(1000000/(8000-200*num))-1;
HAL_TIM_Base_Init(&htim2);
pa1_duty=duty/100*TIM2->ARR;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pa1_duty);
HAL_TIM_Base_Start_IT(&htim17);
if(num>=20)
{
mode = 'L';
time3=0;
HAL_TIM_Base_Stop_IT(&htim17);
}
}
//初始频率为4k
if(mode_start==0)
{
htim2.Init.Period=250-1;
pa1_duty=duty/100*250;
HAL_TIM_Base_Init(&htim2);
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pa1_duty);
}
}
void led_pro(void)
{
if(view==0)
led |= 0x01;
else
led &= ~0x01;
if(knock==1)
led |= 0x04;
else
led &= ~0x04;
if(ld2_flag==1)//LD标志位为1时,LD2闪烁5s
{
HAL_TIM_Base_Start_IT(&htim6);//time1开始计时
if(time1%2==1)
led |= 0x02;
if(time1%2==0)
led &= ~0x02;
if(time1>=50)//5s停止闪烁
{
led &= ~0x02;
time1=0;
ld2_flag=0;
HAL_TIM_Base_Stop_IT(&htim6);//time1停止计时
}
}
led_disp(led);
}
/* 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_ADC2_Init();
MX_TIM3_Init();
MX_TIM4_Init();
MX_TIM6_Init();
MX_TIM2_Init();
MX_TIM8_Init();
MX_USART1_UART_Init();
MX_TIM17_Init();
MX_TIM16_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
led_disp(led);
uwTick=5000;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
//初始为低频
HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
HAL_TIM_Base_Start_IT(&htim4);
HAL_TIM_Base_Start_IT(&htim8);
HAL_TIM_Base_Start_IT(&htim16);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
speed_pro();
pwm_pro();
key_pro();
lcd_pro();
led_pro();
}
/* USER CODE END 3 */
}
PWM效果演示
蓝桥杯嵌入式第十四届省赛PWM效果演示