一、题目
解析:这届题目用到的是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;
}