本人刚不久参加了蓝桥杯电子赛嵌入式组,想要记录一下之前的学习成果,如有不正确的地方,欢迎大家交流与评论
目录
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
试题题目
试题完整代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/*总结
首先就是按键的配置以及按键的写法,一定不能出错,不然就会出现很多奇奇怪怪的错误
第二就是:PWM的配置一定不要忘记配参数以及开启PWM的定时器
第三就是:如何找出问题,一段一段注释找问题,
*/
#define DATA 0
#define SLEEPING 1
u8 LCD_Buffer[20];
u8 LCD_JM=DATA;
double TEMP=0;
u8 MODE=0; //当前控制模式0->auto,
u8 GEAR=1; //档位(GEAR)
u16 cnt_key_uart_5s=0;
_Bool Clear = 1;
u8 ucled=0;
uint32_t uwTick_LED4_point=0;
u8 rev_buf[2];
u8 res_buf[3];
u8 rx_index=0;
u8 uart_buf[50];
u8 uart_flag=0;
u8 key_value,key_down,key_up,key_old;
uint32_t uwTick_key_point=0;
void LED_Set(u8 ucled)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,ucled<<8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
//只能用这种写法
u8 Key_Scan(void)
{
u8 KEY_NUM=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0) KEY_NUM = 1;
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0) KEY_NUM =2;
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==0) KEY_NUM =3;
else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0) KEY_NUM =4;
return KEY_NUM;
}
double Get_ADC2(void)
{
u16 value=0;
HAL_ADC_Start(&hadc2);
value = HAL_ADC_GetValue(&hadc2);
return (value*3.3)/4095;
}
void SysTick_Handler(void)
{
HAL_IncTick();
if(LCD_JM==DATA)
{
cnt_key_uart_5s++;
}
}
//5s内按键无动作,或串口未下发命令,自动进入“睡眠界面”。
//当前控制模式(MODE):Auto表示自动控制模式;Manu表示手动控制模式;
void Temp_Proc()
{
double value;
value = Get_ADC2();
if(value<=1)
TEMP=20;
else if(value > 1 && value <3)
TEMP=10*(value+1);
else if(value >= 3)
TEMP=40;
}
void GEAR_Proc(void)
{
if(MODE==0)
{
if(TEMP < 25.00)
GEAR=1;
else if(TEMP >=25.00 && TEMP <=30.0)
GEAR=2;
else if(TEMP>=30.00)
GEAR=3;
}
}
void SLEEP_Proc(void)
{
if(cnt_key_uart_5s>5000)
{
LCD_JM=SLEEPING;
if(Clear==1)
{
LCD_Clear(Black);
Clear=0;
}
}
}
void LCD_Proc(void)
{
Temp_Proc();
GEAR_Proc();
SLEEP_Proc();
//测试
// sprintf((char*)LCD_Buffer,"cnt_5s: %d ",cnt_key_uart_5s);
// LCD_DisplayStringLine(Line9,(unsigned char *)LCD_Buffer);
// sprintf((char*)LCD_Buffer,"Clear: %d ",Clear);
// LCD_DisplayStringLine(Line8,(unsigned char *)LCD_Buffer);
if(LCD_JM==DATA)
{
sprintf((char*)LCD_Buffer," DATA ");
LCD_DisplayStringLine(Line1 ,(unsigned char *)LCD_Buffer);
sprintf((char*)LCD_Buffer," TEMP:%.1lf ",TEMP);
LCD_DisplayStringLine(Line3,(unsigned char *)LCD_Buffer);
if(MODE == 0)
{
sprintf((char*)LCD_Buffer," MODE:Auto ");
LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer);
}
else if(MODE==1)
{
sprintf((char*)LCD_Buffer," MODE:Manu ");
LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer);
}
sprintf((char*)LCD_Buffer," GEAR:%d ",GEAR);
LCD_DisplayStringLine(Line5 ,(unsigned char *)LCD_Buffer);
}
else if(LCD_JM==SLEEPING)
{
sprintf((char*)LCD_Buffer," SLEEPING ");
LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer);
sprintf((char*)LCD_Buffer," TEMP:%.1lf ",TEMP);
LCD_DisplayStringLine(Line5,(unsigned char *)LCD_Buffer);
}
}
void Key_Proc(void)
{
if( uwTick - uwTick_key_point < 20) return;
uwTick_key_point = uwTick;
key_value = Key_Scan();
key_down = key_value & (key_old ^ key_value);
key_up = ~key_value & (key_old ^ key_value);
key_old = key_value;
if(key_down == 1)
{
cnt_key_uart_5s=0;
if(LCD_JM==DATA)
{
MODE = (MODE + 1) % 2;
LCD_Clear(Black);
}
}
if(key_down==2) //定义为“档位加”按键,在“手动控制”模式下,按下B2按键,调整当前档位。切换顺序如图6所示。
{
cnt_key_uart_5s=0;
if(LCD_JM==DATA && MODE==1)
{
GEAR++;
if(GEAR>3)
GEAR=1;
}
}
if(key_down==3)//定义为“档位减”按键,在“手动控制”模式下,按下B3按键,调整当前档位。切换顺序如图6所示。
{
cnt_key_uart_5s=0;
if(LCD_JM==DATA && MODE==1)
{
GEAR--;
if(GEAR<1)
GEAR=3;
}
}
if(LCD_JM==SLEEPING)
{
if(key_down==1 || key_down == 2 || key_down==3)
{
cnt_key_uart_5s=0;
LCD_JM=DATA;
Clear=1;
}
}
}
void Rx_Proc(void)
{
if(rx_index==2)
{
uart_flag=1;
uwTick_LED4_point=uwTick;
if(LCD_JM==DATA)
{
if(res_buf[0] == 'B')
{
if(res_buf[1] == '1')
{
cnt_key_uart_5s=0;
LED_Set(0x40);
MODE = (MODE + 1) % 2;
//LCD_Clear(Black);
}
else if(res_buf[1]=='2')
{
cnt_key_uart_5s=0;
if(MODE==1)
{
GEAR++;
if(GEAR>3)
GEAR=1;
}
}
else if(res_buf[1]=='3')
{
cnt_key_uart_5s=0;
if(MODE==1)
{
GEAR--;
if(GEAR<1)
GEAR=3;
}
}
else{
sprintf((char*)uart_buf,"NULL");
HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50);
}
}
//串口发送其他非法字符,返回“NULL”
else{
sprintf((char*)uart_buf,"NULL");
HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50);
}
}
else if(LCD_JM==SLEEPING)
{
if(res_buf[0] == 'B' && (res_buf[1]=='1' || res_buf[1]=='2' || res_buf[1]=='3'))
{
LCD_JM=DATA;
//Clear=1;
cnt_key_uart_5s=0;
}
else{
sprintf((char*)uart_buf,"NULL");
HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50);
}
}
rx_index=0;
memset(res_buf,'\0',sizeof(res_buf));
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
res_buf[rx_index++]=rev_buf[0];
Rx_Proc();
HAL_UART_Receive_IT(&huart1,rev_buf,1);
}
//PWM功能
u8 duty=0;
void PWM_Proc(void)
{
if(GEAR == 1)
duty=10;
//TIM2->ARR = 500;
else if(GEAR==2)
duty=40;
else if(GEAR==3)
duty=80;
TIM2->CCR2 = (uint16_t)(500*(duty/100.0));
//TIM2->EGR = TIM_EGR_UG;
}
void LED_Proc(void)
{
if(MODE==0)
ucled |= 0x80;
else
ucled &=~0x80;
if(GEAR==1)
ucled |=0x01;
else
ucled &=~0x01;
if(GEAR==2)
ucled |=0x02;
else
ucled &=~0x02;
if(GEAR==3)
ucled |=0x04;
else
ucled &=~0x04;
if(uart_flag==1)
{
ucled |= 0x08;
if( uwTick - uwTick_LED4_point >=3000)
{
ucled&=~0x08;
uart_flag=0; //静下来思考,到底标志位应该放在哪里
}
}
LED_Set(ucled);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
HAL_UART_Receive_IT(&huart1,rev_buf,1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
while (1)
{
LCD_Proc();
Key_Proc();
PWM_Proc();
LED_Proc();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC12;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
代码之底层函数
void LED_Set(u8 ucled)
void LED_Set(u8 ucled) { HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOC,ucled<<8,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET); }
void KEY_Scan(void)
//只能用这种写法 u8 Key_Scan(void) { u8 KEY_NUM=0; if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0) KEY_NUM = 1; else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0) KEY_NUM =2; else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==0) KEY_NUM =3; else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0) KEY_NUM =4; return KEY_NUM; }
double Get_ADC2(void)
double Get_ADC2(void) { u16 value=0; HAL_ADC_Start(&hadc2); value = HAL_ADC_GetValue(&hadc2); return (value*3.3)/4095; }
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { res_buf[rx_index++]=rev_buf[0]; Rx_Proc(); HAL_UART_Receive_IT(&huart1,rev_buf,1); }
代码之基本功能函数
void LCD_Proc(void)
void LCD_Proc(void) { Temp_Proc(); GEAR_Proc(); SLEEP_Proc(); //测试 // sprintf((char*)LCD_Buffer,"cnt_5s: %d ",cnt_key_uart_5s); // LCD_DisplayStringLine(Line9,(unsigned char *)LCD_Buffer); // sprintf((char*)LCD_Buffer,"Clear: %d ",Clear); // LCD_DisplayStringLine(Line8,(unsigned char *)LCD_Buffer); if(LCD_JM==DATA) { sprintf((char*)LCD_Buffer," DATA "); LCD_DisplayStringLine(Line1 ,(unsigned char *)LCD_Buffer); sprintf((char*)LCD_Buffer," TEMP:%.1lf ",TEMP); LCD_DisplayStringLine(Line3,(unsigned char *)LCD_Buffer); if(MODE == 0) { sprintf((char*)LCD_Buffer," MODE:Auto "); LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer); } else if(MODE==1) { sprintf((char*)LCD_Buffer," MODE:Manu "); LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer); } sprintf((char*)LCD_Buffer," GEAR:%d ",GEAR); LCD_DisplayStringLine(Line5 ,(unsigned char *)LCD_Buffer); } else if(LCD_JM==SLEEPING) { sprintf((char*)LCD_Buffer," SLEEPING "); LCD_DisplayStringLine(Line4 ,(unsigned char *)LCD_Buffer); sprintf((char*)LCD_Buffer," TEMP:%.1lf ",TEMP); LCD_DisplayStringLine(Line5,(unsigned char *)LCD_Buffer); } }
void Key_Proc(void)
void Key_Proc(void) { if( uwTick - uwTick_key_point < 20) return; uwTick_key_point = uwTick; key_value = Key_Scan(); key_down = key_value & (key_old ^ key_value); key_up = ~key_value & (key_old ^ key_value); key_old = key_value; if(key_down == 1) { cnt_key_uart_5s=0; if(LCD_JM==DATA) { MODE = (MODE + 1) % 2; LCD_Clear(Black); } } if(key_down==2) //定义为“档位加”按键,在“手动控制”模式下,按下B2按键,调整当前档位。切换顺序如图6所示。 { cnt_key_uart_5s=0; if(LCD_JM==DATA && MODE==1) { GEAR++; if(GEAR>3) GEAR=1; } } if(key_down==3)//定义为“档位减”按键,在“手动控制”模式下,按下B3按键,调整当前档位。切换顺序如图6所示。 { cnt_key_uart_5s=0; if(LCD_JM==DATA && MODE==1) { GEAR--; if(GEAR<1) GEAR=3; } } if(LCD_JM==SLEEPING) { if(key_down==1 || key_down == 2 || key_down==3) { cnt_key_uart_5s=0; LCD_JM=DATA; Clear=1; } } }
void LED_Proc(void)
void LED_Proc(void) { if(MODE==0) ucled |= 0x80; else ucled &=~0x80; if(GEAR==1) ucled |=0x01; else ucled &=~0x01; if(GEAR==2) ucled |=0x02; else ucled &=~0x02; if(GEAR==3) ucled |=0x04; else ucled &=~0x04; if(uart_flag==1) { ucled |= 0x08; if( uwTick - uwTick_LED4_point >=3000) { ucled&=~0x08; uart_flag=0; //静下来思考,到底标志位应该放在哪里 } } LED_Set(ucled); }
代码之复杂功能函数
void SysTick_Handler(void)
void SysTick_Handler(void) { HAL_IncTick(); if(LCD_JM==DATA) { cnt_key_uart_5s++; } }
void Temp_Proc()
/5s内按键无动作,或串口未下发命令,自动进入“睡眠界面”。 //当前控制模式(MODE):Auto表示自动控制模式;Manu表示手动控制模式; void Temp_Proc() { double value; value = Get_ADC2(); if(value<=1) TEMP=20; else if(value > 1 && value <3) TEMP=10*(value+1); else if(value >= 3) TEMP=40; }
void GEAR_Proc(void)
void GEAR_Proc(void) { if(MODE==0) { if(TEMP < 25.00) GEAR=1; else if(TEMP >=25.00 && TEMP <=30.0) GEAR=2; else if(TEMP>=30.00) GEAR=3; } }
void SLEEP_Proc(void)
void SLEEP_Proc(void) { if(cnt_key_uart_5s>5000) { LCD_JM=SLEEPING; if(Clear==1) { LCD_Clear(Black); Clear=0; } } }
void RX_Proc(void)
void Rx_Proc(void) { if(rx_index==2) { uart_flag=1; uwTick_LED4_point=uwTick; if(LCD_JM==DATA) { if(res_buf[0] == 'B') { if(res_buf[1] == '1') { cnt_key_uart_5s=0; LED_Set(0x40); MODE = (MODE + 1) % 2; //LCD_Clear(Black); } else if(res_buf[1]=='2') { cnt_key_uart_5s=0; if(MODE==1) { GEAR++; if(GEAR>3) GEAR=1; } } else if(res_buf[1]=='3') { cnt_key_uart_5s=0; if(MODE==1) { GEAR--; if(GEAR<1) GEAR=3; } } else{ sprintf((char*)uart_buf,"NULL"); HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50); } } //串口发送其他非法字符,返回“NULL” else{ sprintf((char*)uart_buf,"NULL"); HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50); } } else if(LCD_JM==SLEEPING) { if(res_buf[0] == 'B' && (res_buf[1]=='1' || res_buf[1]=='2' || res_buf[1]=='3')) { LCD_JM=DATA; //Clear=1; cnt_key_uart_5s=0; } else{ sprintf((char*)uart_buf,"NULL"); HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50); } } rx_index=0; memset(res_buf,'\0',sizeof(res_buf)); } }
void PWM_Proc(void)
//PWM功能 u8 duty=0; void PWM_Proc(void) { if(GEAR == 1) duty=10; //TIM2->ARR = 500; else if(GEAR==2) duty=40; else if(GEAR==3) duty=80; TIM2->CCR2 = (uint16_t)(500*(duty/100.0)); //TIM2->EGR = TIM_EGR_UG; }
总结:本次试题注意的就是审题要清楚,小编刚开始的时候看到的是5秒内按下就执行某种操作,5秒后按下按下就执行另外一种操作,然后后面测试才发现有问题,题目不是这样描述的
然后这一次串口发送消息并没有重写printf函数,而是直接调用
sprintf((char*)uart_buf,"NULL"); HAL_UART_Transmit(&huart1, uart_buf,sizeof(uart_buf),50);