文章目录
前言
相关说明:
开发板:CT117E-M4(STM32G431RB 蓝桥杯嵌入式比赛板)
开发环境: CubeMX+Keil5
涉及题目:第十一届蓝桥杯嵌入式省赛
题目难点:相对容易,较少难点
(本次项目编写运用了模块化编程,更有利于代码阅读与理解。)
CubeMX配置、主要函数代码及说明:
一、CubeMX配置(第十一届模拟题完整版)
1.使能外部高速时钟:
2.配置时钟树:
3.GPIO:
4.TIM3、TIM17(PWM):
5.TIM6(0.5s中断):
6.ADC(获取R37电压值):
7.NVIC(使能TIM6中断):
二、代码相关定义、声明
1.函数声明
main.c
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef * htim);//定时器中断函数
void LCD_Init_Show(void); //LCD初始化界面
void LCD_Refresh(uint8_t page); //LCD更新函数
void Data_change(uint8_t dat); //数据改变函数
void LED_Refresh(void); //LED更新函数
void Mode_Change(void); //模式改变函数
tim.h
void PWM_OutPut(uint16_t PA6_pulse,uint16_t PA7_pulse); //PWM输出配置
gpio.h
void KEY_Scan(void); //按键扫描
void LED_AllClose(uint8_t *LED_close); //LED关闭
adc.h
double ADC_GetValue(void); //获取R37电压值
2.宏定义
gpio.h
#define LED_GPIO_PORT GPIOC
#define LED1_GPIO_PIN GPIO_PIN_8
#define LED2_GPIO_PIN GPIO_PIN_9
#define LED3_GPIO_PIN GPIO_PIN_10
#define LED4_GPIO_PIN GPIO_PIN_11
#define LED5_GPIO_PIN GPIO_PIN_12
#define LED6_GPIO_PIN GPIO_PIN_13
#define LED7_GPIO_PIN GPIO_PIN_14
#define LED8_GPIO_PIN GPIO_PIN_15
#define ON GPIO_PIN_RESET
#define OFF GPIO_PIN_SET
#define LED1(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED1_GPIO_PIN,a)
#define LED2(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED2_GPIO_PIN,a)
#define LED3(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED3_GPIO_PIN,a)
#define LED4(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED4_GPIO_PIN,a)
#define LED5(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED5_GPIO_PIN,a)
#define LED6(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED6_GPIO_PIN,a)
#define LED7(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED7_GPIO_PIN,a)
#define LED8(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED8_GPIO_PIN,a)
#define KEY1_GPIO_PORT GPIOB
#define KEY1_GPIO_PIN GPIO_PIN_0
#define KEY2_GPIO_PORT GPIOB
#define KEY2_GPIO_PIN GPIO_PIN_1
#define KEY3_GPIO_PORT GPIOB
#define KEY3_GPIO_PIN GPIO_PIN_2
#define KEY4_GPIO_PORT GPIOA
#define KEY4_GPIO_PI GPIO_PIN_0
main.h
#define PA6 1
#define PA7 2
3.变量定义
main.c
double v_value; //R37的电压值
char *pwm_mode="AUTO"; //PWM占空比控制模式
uint8_t PA6_air=10; //PA6输出PWM的占空比 (10即10%)
uint8_t PA7_air=10; //PA7输出PWM的占空比
uint8_t air_step=10; //占空比每次改变值
uint8_t air_max=90; //最大占空比
uint8_t air_min=10; //最小占空比
uint8_t page_now=1; //LCD显示页(1为数据页/2为配置页)
uint8_t PWM_refresh_flag=0; //PWM更新标志位(每0.5s更新一次)
uint8_t LED_close[3]={0,0,0}; //LED关闭数组(为1则下标对应LED关闭)
char str[30]; //组合字符串
tim.c
TIM_OC_InitTypeDef sConfigOC = {0};//重新配置后需要删除下面函数中的这个语句
三、主要函数
1.按键相关
key.c
/* KEY */
void Setting_Mode()//配置模式
{
while(1)
{
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET);
LCD_Refresh(1);//LCD更新显示
break;//退出循环
}
}
else if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET)//PA6++
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET);
Data_change(PA6);//PA6数据改变
LCD_Refresh(2);//LCD更新显示
}
}
else if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET)//PA7++
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET);
Data_change(PA7);//PA7数据改变
LCD_Refresh(2);//LCD更新显示
}
}
LED_Refresh();
}
}
void KEY_Scan()//按键扫描
{
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET);
LCD_Refresh(2);
Setting_Mode();
}
}
else if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET);
Mode_Change();
}
}
}
2.数据更改
main.c
void Data_change(uint8_t dat)//数据更改
{
switch(dat)
{
case PA6:
PA6_air+=air_step;
if(PA6_air>air_max)
PA6_air=air_min;
break;
case PA7:
PA7_air+=air_step;
if(PA7_air>air_max)
PA7_air=air_min;
break;
}
}
3.LCD更新显示
main.c
void LCD_Refresh(uint8_t page)//LCD更新显示
{
if(page==1)//数据界面
{
page_now=1;
LED_close[2]=0;
LCD_DisplayStringLine(Line0,(unsigned char*)" Data ");
sprintf(str," V:%.2fV ",v_value);
LCD_DisplayStringLine(Line2,(unsigned char*)str);
sprintf(str," Mode:%s ",pwm_mode);
LCD_DisplayStringLine(Line4,(unsigned char*)str);
}
else if(page==2)//参数界面
{
page_now=2;
LED_close[2]=1;
LCD_DisplayStringLine(Line0,(unsigned char*)" Para ");
sprintf(str," PA6:%d%% ",PA6_air);
LCD_DisplayStringLine(Line2,(unsigned char*)str);
sprintf(str," PA7:%d%% ",PA7_air);
LCD_DisplayStringLine(Line4,(unsigned char*)str);
}
}
4.模式更改
main.c
void Mode_Change()//模式更改
{
if(strcmp(pwm_mode,"AUTO")==0)
{
pwm_mode="MANU";
LED_close[1]=1;
}
else
{
pwm_mode="AUTO";
LED_close[1]=0;
}
}
5.LED状态更新
main.c
/* LED */
void LED_Refresh()//LCD状态更新
{
LED_AllClose(LED_close);
if(strcmp(pwm_mode,"AUTO")==0)
{
LED1(ON);
}
if(page_now==1)
{
LED2(ON);
}
}
6.PWM输出
TIM_OC_InitTypeDef sConfigOC = {0};这个结构体在这定义为全局变量,MX重新配置后需要删除tim.c生成函数中的这个语句。
tim.c
void PWM_OutPut(uint16_t PA6_pulse,uint16_t PA7_pulse)//PWM输出函数
{
sConfigOC.Pulse=PA6_pulse;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) ;
HAL_TIM_PWM_Init(&htim3);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
sConfigOC.Pulse=PA7_pulse;
HAL_TIM_PWM_ConfigChannel(&htim17, &sConfigOC, TIM_CHANNEL_1) ;
HAL_TIM_PWM_Init(&htim17);
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
}
7.Main函数
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_TIM17_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
LCD_Init();//LCD初始化
TIM6->SR=0;//定时器更新标志位清零
TIM6->CNT=0;//定时器计数值清零
HAL_TIM_Base_Start_IT(&htim6);//定时器开始计时
v_value=ADC_GetValue();//获取ADC的值
PWM_OutPut(v_value/3.3*(9999+1),v_value/3.3*(4999+1));//初始为AUTO模式
LCD_Init_Show();//LCD初始化显示
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
KEY_Scan();//按键扫描
v_value=ADC_GetValue();//获取ADC的值
LCD_Refresh(1);//LCD更新显示
LED_Refresh();//LED更新显示
if(PWM_refresh_flag==1)//每0.5S更新一次PWM
{
PWM_refresh_flag=0;
if(strcmp(pwm_mode,"AUTO")==0)//如果为AUTO模式
{
PWM_OutPut(v_value/3.3*(9999+1),v_value/3.3*(4999+1));
}
else //如果为Menu模式
{
PWM_OutPut(PA6_air*1.0/100*(9999+1),PA7_air*1.0/100*(4999+1));
}
}
HAL_Delay(50);//LCD更新延时,减少冲突
}
/* USER CODE END 3 */
}
四、实验结果
五、源码(转载请注明出处)
总结
以上就是全部内容,如有错误请批评指正。