一、题目
解析:这届题目用到的是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; }
相关文章
发表评论