【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛

文章目录

  • 前言
  • 一、题目
  • 二、模块初始化以及功能分析
    • 1.模块的初始化
    • 2.模块功能分析
  • 三、函数实现
      • 1.void Display(void);
      • 2.uint8_t KEY_Scan(uint8_t mode);
      • 3.void KEY_Handle(uint8_t key);
      • 4.uint16_t Get_ADC(void);
      • 5.void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);
      • 6.int main(void);
        • 初始化;
        • while(1);
  • 总结


前言

为了减少篇幅,各模块的初始化均在模块配置中,可以随时去翻看博客,还有function里面的函数,将不再罗列出来,只是截图展示。

一、题目

【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第1张图片
【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第2张图片
【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第3张图片
此处少了参数页面的模板,大概就是两个占空比的输出。(题目来于转载)
【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第4张图片
【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第5张图片

二、模块初始化以及功能分析

1.模块的初始化

需要用的模块:LCD、四个按键、LED、ADC(PB15)、TIM3。
(TIM3CH1、CH2输出比较模式,请参考
【STM32G4】备战蓝桥杯嵌入式—模块配置—TIM_Output_Compare
【STM32G4】备战蓝桥杯嵌入式—模块配置—TIM_Output_Compare(2))
为了配置这个模式才写的,里面有一些细节,本文只会略提,不懂的参考上文

2.模块功能分析

LCD:显示-----》Display();
按键:对参数进行调整-----》KEY_Handle();KEY_Scan();
LED:提示作用-----》LED();
ADC: 采集电压值-----》Get_ADC();

三、函数实现

1.void Display(void);

Page是表示数据页面Or参数页面
mode

void Display(void)
{
	if(Page == 0)
	{
		LCD_DisplayStringLine(Line1, "      Data    ");
		
		sprintf((char *)ass,"    V: %.2f", Volt);
		LCD_DisplayStringLine(Line3, ass);
	}
	else
	{
		LCD_DisplayStringLine(Line1, "      Parameter    ");
		
		sprintf((char *)ass,"    PA6_Duty: %d%%", PA6_Duty);
		LCD_DisplayStringLine(Line3, ass);
		sprintf((char *)ass,"    PA7_Duty: %d%%", PA7_Duty);
		LCD_DisplayStringLine(Line4, ass);
	}
	if(mode == 0)
		sprintf((char *)ass, "    Mode:AUTO");
	else
		sprintf((char *)ass, "    Mode:MANU");
	
	LCD_DisplayStringLine(Line5, ass);
}

2.uint8_t KEY_Scan(uint8_t mode);

uint8_t KEY_Scan(uint8_t mode)
{
	static uint8_t flag=1;
	if(mode)	flag = 1;
	if(flag &&(KEY_B1 == 0 || KEY_B2	== 0 || KEY_B3 == 0 ||	KEY_B4== 0 ))
	{
		HAL_Delay(10);
		flag = 0;
		if (KEY_B1 == 0)	return B1_Press;
		else if (KEY_B2 == 0) return B2_Press;
		else if (KEY_B3 == 0) return B3_Press;
		else if (KEY_B4 == 0) return B4_Press;
	}else if(KEY_B1 == KEY_B2 == KEY_B3 == KEY_B4 == 1)	flag = 1;
	return 0;
}

3.void KEY_Handle(uint8_t key);

按键处理注意一下更改占空比后,重置一下计数器的值。(逻辑上成立,实际上可以不需要)

void KEY_Handle(uint8_t key)
{
	if(key == B1_Press)
	{
		Page = !Page;
		LCD_Clear(White);
	}
	else if(key == B2_Press && Page == 1)
	{
		PA6_Duty += 10;
		TIM3->CNT = 0;
		if(PA6_Duty >= 90)	PA6_Duty = 10;
	}
	else if(key == B3_Press && Page == 1)
	{
		PA7_Duty += 10;
		TIM3->CNT = 0;
		if(PA7_Duty >= 90)	PA7_Duty = 10;
	}
	else if(key == B4_Press)
	{
		mode = !mode;
	}
}

4.uint16_t Get_ADC(void);

读取电压值,电压值为Get_ADC()*3.3/4096;

uint16_t Get_ADC(void)
{
	uint16_t temp = 0 ;
	HAL_ADC_Start(&hadc2);
	temp = HAL_ADC_GetValue(&hadc2);
	HAL_ADC_Stop(&hadc2);
	
	return temp;
}

5.void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);

编写中断服务函数。切记到tim.c 的IRQN总中断函数,删除CC1和CC2清除中断标志位的代码。(具体原因参考上文)
中断服务函数,在上文已经讲过,再此需要注意测试的时候是用串口输出,(有示波器的小伙伴可以直接看波形),由于串口打印使得在终端里面停留时间过长,所以会使页面显示迟钝和按键没作用。所以,最后是要注释串口打印的代码哦。

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
	if((TIM3->DIER & (0x1 << 1)) && (TIM3->DIER & (0x1 << 2)))
	{
		HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_1);
		HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_2);
		if(__HAL_TIM_GET_FLAG(htim, TIM_IT_CC1))//(TIM3->SR & (0x1 << 1))
		{
//			sprintf((char *)arr, "CNT: %d, CCR1: %d\r\n", TIM3->CNT,TIM3->CCR1);
//			HAL_UART_Transmit(&huart1, arr,sizeof(arr),50);
			if(state1)
			{
				TIM3->CCR1 = TIM3->CCR1 + (uint8_t)(T1*(double)PA6_Duty/100);
				state1 = 0;
			}
			else 
			{
				TIM3->CCR1 = TIM3->CCR1 + T1 - (uint8_t)(T1*(double)PA6_Duty/100);
				state1 = 1;
			}
			TIM3->CCR1 = TIM3->CCR1 % TIM3_Period;
			__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
		}
		
		if(__HAL_TIM_GET_FLAG(htim, TIM_IT_CC2))//(TIM3->SR & (0x1 << 2))
		{
//			sprintf((char *)arr, "CNT: %d,           CCR2: %d \r\n", TIM3->CNT,TIM3->CCR2);
//			HAL_UART_Transmit(&huart1, arr,sizeof(arr),50);
			if(state2)
			{
				TIM3->CCR2 = TIM3->CCR2 + (uint8_t)(T2*(double)PA7_Duty/100);
				state2 = 0;
			}
			else
			{
				TIM3->CCR2 = TIM3->CCR2 + T2 - (uint8_t)(T2*(double)PA7_Duty/100);
				state2 = 1;
			}
			TIM3->CCR2 = TIM3->CCR2 % TIM3_Period;
			__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
		}
	}
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
}

6.int main(void);

初始化;

这次把参数定义拿出来看一下咯。
【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第6张图片

【STM32G4】备战蓝桥杯嵌入式---实战---第十一届嵌入式省赛_第7张图片

	LCD_Init();
	LCD_Clear(White);
	LCD_SetTextColor(Red);
	
	mode = 0;
	Page = 0;//0,数据界面,1,参数界面
	PA6_Duty = PA7_Duty = 10;//参数初始化
	
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
	TIM3->CCR1 = PA6_Duty;
	TIM3->CCR2 = PA7_Duty;
	TIM3->CNT = 0;

while(1);

	Display();
		key = KEY_Scan(0);
		KEY_Handle(key);
		Volt = Get_ADC()*3.3/4096;
		if(mode == 0 && (PA6_Duty != (uint8_t)((double)Volt * 100 / 3.3)) && (PA7_Duty != (uint8_t)((double)Volt * 100 / 3.3)))//自动模式
		{
			PA6_Duty = PA7_Duty = (uint8_t)((double)Volt * 100 / 3.3);
			TIM3->CNT = 0;
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(mode == 0)
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
		else
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
		
		if(Page == 0)
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
		else
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
		
		HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);

主函数就平平无奇了,看过我之前的文章的都应该懂这些套路了。


总结

以上就是本次赛题的程序设计部分(变量定义部分,本人没有罗列出来嗷),总的来说,十一届考的这定时器模式确实有点wu~yu,定时器这个功能本人基本没用过,为了配置也花了大量时间查手册,也另外写了文章介绍。
如果喜欢的话,支持一下,点个赞,评论一下再走吧

你可能感兴趣的:(嵌入式,stm32)