蓝桥杯嵌入式第十四届省赛真题

题目

在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>&copy; 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效果演示

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值