一、题目

解析:这届题目用到的是LCD、LED、按键、ADC、PWM输出和脉冲捕获,其中按键还包括了短按键和长按键,首先让我们来进行CubeMX的配置。

二、CubeMX配置

基础配置

1、RCC配置:

2、时钟树的配置:

3、SYS配置:

模块配置

1、GPIO配置:

2、定时器配置:

3、ADC配置:

当全部配置完成后就是这样

三、题目分析

先把整个题目看一遍,了解大概要用到什么知识,特别是硬件框图,直接确定了本题所用到的模块,当大致了解以后就可以去配置CubeMX。一些模块的初始状态很重要,编写代码时要根据题目要求来确定模块的初始状态,然后再根据题目要求一点一点的去实现题目的要求。

1、LCD

分三个不同界面,分别是数据界面、参数界面、统计界面,不同界面实现不同功能,可以设置三个不同的条件来决定进入哪个界面。同时LCD初始状态也要配置正确。

2、按键

B1按键用来切换界面,在数据界面时,B2按键用于切换输出模式,B4按键长按,锁定输出信号占空比,短按解锁。在参数界面时,B2按键用于选择参数R和K,B3按键定义为“加”,B4按键定义为“减”。

3、LED

在数据界面下,LED灯1一直亮起,当B2按键按下,LED灯2闪烁,闪烁五秒后熄灭,输出模式切换。当B4长按时,锁定输出信号占空比,LED灯3亮起,B4短按后解锁,LED灯3熄灭

四、代码实现

1、主函数基础设置

int view=0,n=0,lock=0;    //界面,模式切换次数,状态
int R=1,K=1;        //参数
int plv_pa1=200;    //频率
int flag_view1;        //选择标志位
uchar PA1_duty;        //占空比
float Vs,Vmax_H,Vmax_L;    //实时速度,最大速度,最小速度

    LED_Disp(0x01);//设置LED初始状态
    LCD_Init ();//LCD初始化
    
    LCD_Clear(Black  );
    LCD_SetBackColor(Black );
    LCD_SetTextColor(White);        //设置LCD背景
    
    HAL_TIM_Base_Start_IT (&htim3 );    //开启定时器3
    HAL_TIM_Base_Start_IT (&htim4 );    //开启定时器4


    HAL_TIM_PWM_Start (&htim2 ,TIM_CHANNEL_2 );//PWM输出打开
    
    HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1 );//脉冲捕获定时器开启

2、LCD显示部分

void disp_proc(void )    //LCD模块
{
 
    Vs = (frq*2*3.14*R)/(100*K);        //实时速度V
    
    if(getADC (&hadc2 )<1 && lock==0)        //如果电压小于1V且位于解锁状态
    {
        PA1_duty =10;
    }
    else if(getADC (&hadc2 )>3 && lock==0)        //如果电压大于3V且位于解锁状态
    {
        PA1_duty =85;
    }
    else if(lock ==0)                            //位于1V~3V之间
    PA1_duty =37.5*getADC (&hadc2 )-27.5;    //实时占空比P    
    
    if(plv_pa1 >=200)        //高频模式下最大速度
    {
        if(Vs>Vmax_H)
        {
            Vmax_H=Vs;
        }
    }
    else if(plv_pa1 <105)        //低频模式下最大速度
    {
        if(Vs>Vmax_L)
        {
            Vmax_L=Vs;
        }
    }
    
    if(view ==0)        //数据界面
    {             
        char text[30];
        sprintf (text ,"         DATA                ");
        LCD_DisplayStringLine(Line2, (uint8_t *)text );
        if(plv_pa1==200)
        {
            sprintf (text ,"    M=L                      ");
            LCD_DisplayStringLine(Line4, (uint8_t *)text );
        }
        else if(plv_pa1==100)
        {
            sprintf (text ,"    M=H                     ");
            LCD_DisplayStringLine(Line4, (uint8_t *)text );
        }
        sprintf (text ,"    P=%d%%               ",PA1_duty );
        LCD_DisplayStringLine(Line5, (uint8_t *)text );
        sprintf (text ,"    V=%.1f              ",Vs);
        LCD_DisplayStringLine(Line6, (uint8_t *)text );
    }
    else if(view ==1)        //参数界面
    {
      char text[30];
      sprintf (text ,"         PARA                ");
      LCD_DisplayStringLine(Line2, (uint8_t *)text );
      sprintf (text ,"    R=%d                       ",R);
      LCD_DisplayStringLine(Line4, (uint8_t *)text );
      sprintf (text ,"    K=%d                       ",K);
      LCD_DisplayStringLine(Line5, (uint8_t *)text );

    }
    else if(view==2)            //    统计界面
    {      
      char text[30];  
      sprintf (text ,"         RECD               ");
      LCD_DisplayStringLine(Line2, (uint8_t *)text );
      sprintf (text ,"    N=%d                  ",n);
      LCD_DisplayStringLine(Line4, (uint8_t *)text );
      sprintf (text ,"    MH=%.1f          ",Vmax_H);
      LCD_DisplayStringLine(Line5, (uint8_t *)text );
      sprintf (text ,"    ML=%.1f          ",Vmax_L);
      LCD_DisplayStringLine(Line6, (uint8_t *)text );
    }
}

3、按键实现

void key_proc(void )        //按键模块
{

    if(key[0].single_flag ==1)             //当按键B1按下
    {
        LCD_Clear(Black );
        view++;            //界面切换
        if(view ==3)    {view=0;}
        
        if(view==0)        //如果在view0界面下
        {
            LED_Disp(0x01);        //led灯1亮
        }
        else LED_Disp(0x00);        //否则全熄灭
        
        if(view==1)        
        {
            flag_view1=0;//每次进入view1界面,默认可调整参数为R
        }

        key[0].single_flag=0;
    }    
    
    if(key[1].single_flag ==1)    //当按键B2按下
    {
        if(view==0)        //view0界面下
        {
            n++;        //高低频率模式切换次数            
            flag_5s =1;//跳转到中断函数
        }            
        if(view ==1)        //view1界面下
        {
            flag_view1++;        //R,K参数选择
            if(flag_view1==2)
            {
                flag_view1=0;
            }
        
        }
        key[1].single_flag =0;
    }
    
    if(key[2].single_flag ==1)        //按键B3按下
    {
        if(view ==1)        //view1界面下
        {
            if(flag_view1==0)        //处于R参数位置下
            {
                R++;
                if(R==11)
                {
                    R=1;
                }
            }
            else            //处于K位置下
            {
                K++;
                if(K==11)
                {
                    K=1;
                }
            }        
        }
            key[2].single_flag =0;
    }
    
    if(key[3].single_flag==1)        //按键B4按下
    {
        
        if(view==0)
        {
            lock =0;
            LED_Disp(0x01);
        }                        //用于解锁
        
        if(view==1)        //位于view1界面下
        {
            if(flag_view1==0)        //处于R位置
            {
                R--;
                if(R==0)
                {
                    R=10;
                }
            }
            if(flag_view1==1)        //处于K位置
            {
                K--;
                if(K==0)
                {
                    K=10;
                }
            }
        }
        key[3].single_flag=0;
    }
    
        if(key[3].long_flag==1)        //当按键B4长按
        {    
            lock=1;
            LED_Disp(0x05);        //led灯1和led灯3亮起
            key[3].long_flag=0;
        }

}

4、中断函数interrupt.c

#include "interrupt.h"
#include "led.h"

extern int plv_pa1;
int deng,flag_5s,Num=0;
bool led_flag;
struct keys key[4]={0,0,0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
定时器3控制按键//
    if(htim ->Instance ==TIM3 )
    {
        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 <200)
                        {
                            key[i].single_flag =1;
                        }
                    }
                    else
                    {
                        key[i].key_time ++;
                        if(key[i].key_time >200)
                            key[i].long_flag =1;
                    }
                }
                break;
            }
        }    
    }
定时器控制LED灯///
    if(htim ->Instance== TIM4)
    {    
        if(flag_5s==1)
        {
            led_flag =!led_flag ;
            if(led_flag )
            {
                LED_Disp (0x03);
            }
            else
            {
                LED_Disp (0x01);

            }
            Num++;
            if(Num>=100)        //闪烁100次
            {
                flag_5s =0;
                Num=0;
                if(plv_pa1 ==200)//如果处于低频模式
                {
                    plv_pa1 =100;//高频模式
                }
                else if(plv_pa1 ==100)//如果处于高频模式
                {
                    plv_pa1 =200;//低频模式
                }
            }
        }
    }
    
}
//脉冲捕获模块
uint  ccr1_val=0,frq=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
        if(htim ->Channel ==HAL_TIM_ACTIVE_CHANNEL_1 )
        {
            ccr1_val=HAL_TIM_ReadCapturedValue (htim,TIM_CHANNEL_1 );//获取计数器1的值
            __HAL_TIM_SetCounter (htim ,0);//计数器归0
            frq=(80000000/80)/ccr1_val;//计算频率frq
            HAL_TIM_IC_Start (htim ,TIM_CHANNEL_1 );//开启定时器
        }
        
        if(plv_pa1 ==200)        //如果处于低频模式
        {
            __HAL_TIM_SetAutoreload (&htim2,1000);// 80 000 000\(20*1000)
        }
        else if(plv_pa1 ==100)        //如果处于高频模式
        {
            __HAL_TIM_SetAutoreload (&htim2,500);//80 000 000\(20*500)
        }
}

5、led设置

#include "led.h"

void LED_Disp(uchar dsLED)
{
    HAL_GPIO_WritePin (GPIOC ,GPIO_PIN_All ,GPIO_PIN_SET );//所有led置高电平,led熄灭
    HAL_GPIO_WritePin (GPIOC ,dsLED <<8,GPIO_PIN_RESET );//led置低电平,led亮起
    HAL_GPIO_WritePin (GPIOD ,GPIO_PIN_2 ,GPIO_PIN_SET );//打开锁存器
    HAL_GPIO_WritePin (GPIOD ,GPIO_PIN_2 ,GPIO_PIN_RESET );
}

6、AD模块

#include "badc.h"

double getADC(ADC_HandleTypeDef *pin)
{
    uint adc;
    HAL_ADC_Start (pin);
    adc=HAL_ADC_GetValue (pin);
    return adc*3.3/4096;
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐