目录
2.5 修改占空比函数解释(box.c中的Personal_SetCompare)
题解思路:
- 使用STM32 CubeMX配置时钟80MHz、GPIO(包括PC8~PC15(LED)、PD2(锁存器), PA1(PWM), PA7(输入捕获以测量频率和占空比),PA0、PB0~2(按键) ,PB15(ADC采集R37上电压)
- 用三行按键法区分长短按,用枚举定义高低频模式、界面模式、参数选择、锁定或解锁状态等,定义多个函数以实现和区分子功能。
- 修改频率时要同时修改ARR和CCR的值,以实现占空比不变;修改占空比只需使用函数HAL_SetCompare()。
- 注意功能要求,不同界面下的按键有不同功能,同时有时间限制(LCD_Clear()等会有延时)。
详细内容:
一、系统初始化CubeMX配置
1.1 引脚配置
这里展示的是除LED、按键之外的引脚设置(在十三届蓝桥杯省赛内容分享中有介绍)。
1.2 ADC2配置
PB15引脚为ADC2通道15,使用单端输入模式,不使用外部中断触发。
使用异步时钟二分频 ,使能规则转化组(会出现Rank,不过只使用一个通道,不过以后可以使用多个),采样周期这里可以选择最大640.5周期(采样频率低一些),其余可以忽略(默认间断模式)。
1.3 TIM配置
1.3.1 TIM2&PWM
PWM输出可以按上图配置就行,默认低频模式(装载值ARR为250-1),CCR后续还会修改。
1.3.2 TIM3&IC
TIM3用于PWM输入捕获,即A7脚测量频率(占空比可以顺便测量,因为题目只说明要实时占空比,可以是实时输出也可以是实时测量的),通道2(IC2)与A7脚连接,则作为主通道,捕获上升沿,同时触发内部通道1(即通道1作为从通道,被间接触发),TIM3计数器(CCR1和CCR2)清零,当下降沿来临时计数器捕获到CCR1中,下个上升沿来临时触发到CCR2,具体可以参考大佬文章http://t.csdnimg.cn/bQ9E4。最后还要注意NVIC定时器(TIM3_IT)中断开启。
二、 代码文件
2.1 按键配置
按键需要区分长短按,先判断是否按下,是否是长按,再判断是否是短按,采用三行按键法,具体可以看十三届蓝桥杯省赛内容分享 ,详细代码如下。
key.c/h
#include "key.h"
#include "box.h"
#include "lcd.h"
/* USER CODE BEGIN 0 */
unsigned char ucTrg1=0;
unsigned char ucCont=0;
unsigned char ucRead=0;
unsigned char uckey_num=0;
uint16_t uckey_times=0;
int B1_pressTime=-5000;
uint32_t pressTime=0;
/* USER CODE END 0 */
/* 参数初始化 */
uint8_t R=1,K=1;
uint8_t N=0;
//判断是否发生转化的标志
extern uint8_t startFlag;
//各种定义的模式或状态
extern enum Mode mode;
extern enum Freq freq;
extern enum Para para;
extern enum State state;
/* USER CODE END 1 */
/** CubeMX生成gpio.c中的初始化函数 进行重命名 **/
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB1 PB2 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/** 按键扫描 **/
void key_scan()
{
ucRead=(KEYPORT)^0xff;
ucTrg1=ucRead&(ucRead^ucCont);
ucCont=ucRead;
}
/** 短按+长按 **/
void key_Press()
{
if(uwTick-pressTime<20)return;
key_scan();
//判断哪个按键被触发
switch(ucCont)
{
//B1
case 0x01:uckey_num=1;uckey_times++;
if(uwTick-B1_pressTime<5000)return;
if(mode==DataMode)mode=ParaMode;
else if(mode==ParaMode)mode=RecdMode;
else if(mode==RecdMode)mode=DataMode;
LCD_Clear(Black);
B1_pressTime=uwTick;
break;
//B2
case 0x02:uckey_num=2;uckey_times++;
break;
//B3
case 0x04:uckey_num=3;uckey_times++;
break;
//B4长按需要
case 0x08:uckey_times++;uckey_num=4;
if(uckey_times>50)
if(mode==DataMode)
if(state==Unlock)state=Lock; //长按锁定(50*20ms)
break;
}
/*** 长按时不会执行下列语句,但是短按必定执行 ***/
if(ucTrg1==0x00 && ucCont == 0x00)
{
if(uckey_times>0 && uckey_times<50)
{
switch(uckey_num)
{
/*** 执行语句写入 ***/
case 1:break;
case 2:if(mode==DataMode)
{
startFlag=1; // 开始频率转换
N++; // PWM模式切换次数加1
}
else if(mode==ParaMode)
{
if(para==P_R)para=P_K;
else para=P_R;
}
break;
case 3:if(mode==ParaMode)
{
if(para==P_R)
{
R++;
if(R>=11)
{
R=1;
LCD_ClearLine(Line3);
}
}
else if(para==P_K)
{
K++;
if(K>=11)
{
K=1;
LCD_ClearLine(Line4);
}
}
}
break;
case 4:if(mode==ParaMode) //参数界面
{
if(para==P_R)
{
R--;
if(R==0)
{
R=10;
}
LCD_ClearLine(Line3);
}
else if(para==P_K)
{
K--;
if(K==0)
{
K=10;
}
LCD_ClearLine(Line4);
}
}
else if(mode==DataMode) //数据界面
{
if(state==Lock)state=Unlock; //短按解锁
}
break;
}
}
uckey_times=0;uckey_num=0;
}
pressTime=uwTick;
}
#ifndef __KEY_H__
#define __KEY_H__
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#define KEY1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KEY2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KEY4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
/** 将每个按键的状态放到低四位,组合成新的字节数据 **/
#define KEYPORT KEY1|(KEY2 << 1)|(KEY3 << 2)|(KEY4 <<3)|0xf0
/*** 参数初始化 ***/
void KEY_Init(void);
void KEY_Input();
void key_scan();
void key_Press();
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#endif
2.2 封装各类函数
由于题目功能要求比较复杂,要保证互不影响需要的子程序很多,可以直接在一个代码文件里面定义和调用其它的板载驱动程序(如led.h、lcd.h)以及需要的PWM输出和输入捕获(tim.h)和ADC采集(adc.h)。封装的函数包含界面显示、切换,频率改变,占空比改变,最大速度统计等,写入box.c中。
box.c/h
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "adc.h"
#include "box.h"
#include "tim.h"
#include "stdio.h"
uint8_t startFlag=0;
float D_Set=0.1,D_Get=0.1,v;
float MH,ML;
float frequency,Voltage;//调试观察频率
uint8_t Freq1_Tick=0,tempFlag=1;
u16 tempCount=249;
unsigned char P[20]="null",V[20]="null";
unsigned char Rstr[20]="null",Kstr[20]="null";
unsigned char Nstr[20]="null",MHstr[20]="null",MLstr[20]="null";
enum Mode mode=DataMode;
enum Freq freq=Low;
enum Para para=P_R;
enum State state=Unlock;
extern u8 R,K,N;
void LCD_Display()
{
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
v=frequency*2*3.14*R/(100*K);
if(mode==DataMode)
{
sprintf((char*)P," P=%d%%",(int)(D_Get*100+0.5));
sprintf((char*)V," V=%.1f",v);
LCD_DisplayStringLine(Line1,(u8*)" DATA");
/** 显示 M **/
if(freq==Low)LCD_DisplayStringLine(Line3,(u8*)" M=L");
else if(freq==High)LCD_DisplayStringLine(Line3,(u8*)" M=H");
/** 显示 P **/
LCD_DisplayStringLine(Line4,(u8*)P);
/** 显示 V **/
LCD_DisplayStringLine(Line5,(u8*)V);
}
else if(mode==ParaMode)
{
sprintf((char*)Rstr," R=%d",R);
sprintf((char*)Kstr," K=%d",K);
LCD_DisplayStringLine(Line1,(u8*)" PARA");
/** 显示 R **/
LCD_DisplayStringLine(Line3,(u8*)Rstr);
/** 显示 K **/
LCD_DisplayStringLine(Line4,(u8*)Kstr);
displayCursor();
}
else if(mode==RecdMode)
{
sprintf((char*)Nstr," N=%d",N);
sprintf((char*)MHstr," MH=%.1f",MH);
sprintf((char*)MLstr," ML=%.1f",ML);
LCD_DisplayStringLine(Line1,(u8*)" RECD");
/** 显示 N **/
LCD_DisplayStringLine(Line3,(u8*)Nstr);
/** 显示 MH **/
LCD_DisplayStringLine(Line4,(u8*)MHstr);
/** 显示 ML **/
LCD_DisplayStringLine(Line5,(u8*)MLstr);
}
Freq1_Tick=uwTick;
}
/* 显示当前所选R还是K,方便调试 */
void displayCursor()
{
LCD_SetBackColor(Black);
LCD_SetTextColor(Cyan);
if(para==P_R)
{
LCD_DisplayChar(Line3,100,'<');
LCD_DisplayChar(Line4,100,' ');
}
else if(para==P_K)
{
LCD_DisplayChar(Line4,100,'<');
LCD_DisplayChar(Line3,100,' ');
}
}
/*** 频率变换 ***/
void PWM_Freq_Change()
{
/*** 如果是从高频变为低频 ARR(124->249),或从低频变为高频 ARR(249->124) **/
if(uwTick-Freq1_Tick<40)return;
if(mode == DataMode && freq==High && startFlag==1)
{
//修改频率(因为要保持占空比D不变,但ARR发生改变了,所以也要改变CCR)
++tempCount;
__HAL_TIM_SetAutoreload(&htim2,tempCount);
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,(int)((D_Set*(tempCount+1))+0.5));
HAL_TIM_GenerateEvent(&htim2,TIM_EVENTSOURCE_UPDATE);
//如果已经变为4000HZ,则认为是低频且停止转换
if(tempCount>=249)
{
freq=Low;
startFlag=0;
}
}
else if(mode == DataMode && freq==Low && startFlag==1)
{
//修改频率(因为要保持占空比D不变,但ARR发生改变了,所以也要改变CCR)
--tempCount;
__HAL_TIM_SetAutoreload(&htim2,tempCount);
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,(int)((D_Set*(tempCount+1))+0.5));
HAL_TIM_GenerateEvent(&htim2,TIM_EVENTSOURCE_UPDATE);
//如果已经变为8000HZ,则认为是高频且停止转换
if(tempCount<=124)
{
freq=High;
startFlag=0;
}
}
Freq1_Tick=uwTick;
}
/**** 获取R37上电压值 **/
float getVoltage()
{
float voltage=0,getV=0;
HAL_ADC_Start(&hadc2);
getV=HAL_ADC_GetValue(&hadc2);
voltage=getV*3.3/4095;
return voltage;
}
/*** 根据电压值修改占空比 **/
void Personal_SetCompare()
{
float voltage=getVoltage();
if(voltage>=0 && voltage<1)D_Set=0.1;
else if(voltage>=1 && voltage <=3)D_Set=0.375*voltage-0.275; //直线方程
else if(voltage>3)D_Set=0.85;
//修改输出比较值CCR,其中CCR=D*(ARR+1),再经过类型转换四舍五入
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,(int)(D_Set*(htim2.Init.Period+1)+0.5));
HAL_TIM_GenerateEvent(&htim2,TIM_EVENTSOURCE_UPDATE);
}
/*** 测量PWM频率重写回调函数 ***/
//上升沿和下降沿捕获值
u32 riseVal,fallVal,tick=0;
unsigned char tempString[20];
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2 && htim==&htim3)
{
if(uwTick-tick>100)
{
riseVal=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
fallVal=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
if(riseVal >1)
{
frequency=1000000.0/(riseVal);
D_Get=((float)fallVal)/(riseVal);
}
tick=uwTick;
}
}
}
u32 record_Tick;
/*** 找最大值需要考虑采样率、是否纳入统计 ***/
float maxV,tempV[100],record_v,record_flag=1;
u8 count=0;
void record()
{
if(uwTick-record_Tick<20)return;
tempV[count]=v;
if(tempV[count]!=tempV[0])
{
count=0;
record_Tick=uwTick;
}
else count++;
if(count==100)
{
count=0;
record_v=tempV[0]; //纳入统计
}
record_Tick=uwTick;
}
void findMAXv()
{
if(record_v>maxV)maxV=record_v;
if(freq==High)
{
MH=maxV;
ML=maxV/2;
}
else
{
ML=maxV;
MH=2*maxV;
}
}
#ifndef _BOX_H
#define _BOX_H
/*** 三种界面 **/
enum Mode{
DataMode,
ParaMode,
RecdMode
};
/** 判断高低频 **/
enum Freq{
High,
Low
};
/** 选择R或K **/
enum Para{
P_R,
P_K
};
/** 是否解锁 **/
enum State{
Lock,
Unlock
};
void LCD_Display();
void displayCursor();
void PWM_Freq_Change();
float getVoltage();
void Personal_SetCompare();
void record();
void findMAXv();
#endif
2.3 lcd.c文件修改
由于lcd中部分引脚和led引脚共用,lcd.c中写寄存器会对PC引脚产生影响,使得混乱,需要修改一下竞赛给的lcd.c的三个函数,恢复寄存器的值。参考大佬文章http://t.csdnimg.cn/S5rNT。
lcd.c
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
uint16_t temp=GPIOC->ODR; //补充
GPIOB->BRR |= GPIO_PIN_9;
GPIOB->BRR |= GPIO_PIN_8;
GPIOB->BSRR |= GPIO_PIN_5;
GPIOC->ODR = LCD_Reg;
GPIOB->BRR |= GPIO_PIN_5;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_5;
GPIOB->BSRR |= GPIO_PIN_8;
GPIOC->ODR = LCD_RegValue;
GPIOB->BRR |= GPIO_PIN_5;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_5;
GPIOB->BSRR |= GPIO_PIN_8;
GPIOC->ODR=temp; //补充
}
/*******************************************************************************
* Function Name : LCD_WriteRAM_Prepare
* Description : Prepare to write to the LCD RAM.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
uint16_t temp=GPIOC->ODR; //补充
GPIOB->BRR |= GPIO_PIN_9;
GPIOB->BRR |= GPIO_PIN_8;
GPIOB->BSRR |= GPIO_PIN_5;
GPIOC->ODR = R34;
GPIOB->BRR |= GPIO_PIN_5;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_5;
GPIOB->BSRR |= GPIO_PIN_8;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_9;
GPIOC->ODR=temp; //补充
}
/*******************************************************************************
* Function Name : LCD_WriteRAM
* Description : Writes to the LCD RAM.
* Input : - RGB_Code: the pixel color in RGB mode (5-6-5).
* Output : None
* Return : None
*******************************************************************************/
void LCD_WriteRAM(u16 RGB_Code)
{
uint16_t temp=GPIOC->ODR; //补充
GPIOB->BRR |= GPIO_PIN_9;
GPIOB->BSRR |= GPIO_PIN_8;
GPIOB->BSRR |= GPIO_PIN_5;
GPIOC->ODR = RGB_Code;
GPIOB->BRR |= GPIO_PIN_5;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_5;
GPIOB->BSRR |= GPIO_PIN_8;
__nop();
__nop();
__nop();
GPIOB->BSRR |= GPIO_PIN_9;
GPIOC->ODR=temp; //补充
}
2.4 led灯功能实现
CubeMX生成的初始化函数和个人编写的锁定(LD3)、闪烁(LD2)、Data界面(LD3) ,同时还可在LED_Control()解锁状态下调用Personal_SetCompare()修改占空比。
led.c/h
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "box.h"
#define LED1 GPIOC,GPIO_PIN_8
#define LED2 GPIOC,GPIO_PIN_9
#define LED3 GPIOC,GPIO_PIN_10
#define LOCK GPIOD,GPIO_PIN_2
/* USER CODE BEGIN 0 */
extern uint8_t startFlag;
extern enum Mode mode;
extern enum State state;
/********* CubeMX 生成 gpio.c修改 ***/
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
/*Configure GPIO pins : PC13 PC14 PC15 PC8
PC9 PC10 PC11 PC12 */
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PD2 */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
uint8_t LED_Tick=0;
void LED_Control()
{
/*** Data模式界面下灯的状态改变 ***/
if(mode==DataMode)
{
HAL_GPIO_WritePin(LED1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(LED1,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
}
/*** 判断是否是锁状态 ***/
if(state==Lock)
{
HAL_GPIO_WritePin(LED3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
}
else if(state==Unlock)
{
HAL_GPIO_WritePin(LED3,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
Personal_SetCompare();
}
if(startFlag==1)
{
if(uwTick-LED_Tick<100)return;
if(HAL_GPIO_ReadPin(LED2)==SET)HAL_GPIO_WritePin(LED2,GPIO_PIN_RESET);
else HAL_GPIO_WritePin(LED2,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
LED_Tick=uwTick;
}
else
{
HAL_GPIO_WritePin(LED2,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_SET);
HAL_GPIO_WritePin(LOCK,GPIO_PIN_RESET);
}
}
#ifndef __LED_H__
#define __LED_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
void LED_Init(void);
void LED_Control();
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */
2.5 修改占空比函数解释(box.c中的Personal_SetCompare)
根据折线图可以看出占空比D函数关系与ADC采集电压U的关系,如下:
2.6 TIM3中断回调函数重写(box.c中)
PWM输入模式下(即TI2FP2)需要捕获下一个上升沿(计算频率)和上一个下降沿(计算占空比),需要重写捕获中断回调函数void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)其中1000000.0是TIM3计数器经过分频后的计数频率(80M/80=1MHz)。
/*** 测量PWM频率重写回调函数 ***/
//上升沿和下降沿捕获值
u32 riseVal,fallVal,tick=0;
unsigned char tempString[20];
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2 && htim==&htim3)
{
if(uwTick-tick>100)
{
riseVal=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
fallVal=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
if(riseVal >1)
{
frequency=1000000.0/(riseVal);
D_Get=((float)fallVal)/(riseVal);
}
tick=uwTick;
}
}
}
2.7 main函数内容
开启PWM需要使用HAL_TIM_PWM_Start(),开启PWM输入捕获需要开启时基中断HAL_TIM_Base_Start_IT(),输入捕获中断HAL_TIM_IC_Start() ,时钟配置程序在MX中自动生成。
main.c
/* USER CODE BEGIN Header */
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "box.h"
unsigned char temp[20];
extern float frequency;
extern enum State state;
void SystemClock_Config(void);
void System_Init();
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
int main(void)
{
HAL_Init();
SystemClock_Config();
/* USER CODE BEGIN SysInit */
System_Init();
/* USER CODE END SysInit */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
LCD_Display();
key_Press();
LED_Control();
PWM_Freq_Change();
record();
findMAXv();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void System_Init()
{
MX_ADC2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
LCD_Init();
KEY_Init();
LED_Init();
LCD_Clear(Black);
//开启PWM输出
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
//开启中断,tim3用于捕获,即测量频率和占空比
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
}
三、 开发板调试展示
十四届蓝桥嵌入式省赛调试
四、 补充
程序存在部分Bug,如占空比测得100%会使LCD上多出一个%符号,可以用if语句完善,由于刷新界面频繁,会造成一些延时;由于使用枚举,代码看起来更加冗杂,但是思路会清晰一些 。像key.c和led.c已经在十三届蓝桥杯省赛内容分享说明过,可以方便在工程中移植,如果在同样的开发板下建立不同工程,制作可移植代码文件是很方便的。希望文章对读者有所帮助。