一、基本要求
使用大赛组委会提供的嵌入式竞赛实训平台(基于STM32G431RBT6微控制器设计),完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的hex文件。
hex文件是唯一成绩评测依据,不符合以上文件提交要求的作品将被评为零分或者被酌情扣分。
二、硬件框图
图1 系统硬件框图
三、功能描述
3.1 基本功能
1)通过微控制器的ADC功能,检测电位器R37上输出的模拟电压信号。
2)通过PA1引脚输出频率、占空比可调节的脉冲信号。
3)通过串口实现远程控制功能。
4)根据试题要求,通过LED和LCD完成数据显示和报警功能。
5)根据试题要求,通过按键实现切换界面和控制等功能。
3.2 显示功能
1)数据界面
数据界面如图2所示,显示要素包括界面名称(DATA)、温度值(TEMP)、当前控制模式(MODE)和档位(GEAR)。
图2 数据界面
2)睡眠界面
睡眠界面如图3所示,显示要素包括界面名称(SLEEPING)和温度值(TEMP)。
图3 睡眠界面
5s内按键无动作,或串口未下发命令,自动进入“睡眠界面”。
备注:
温度值(TEMP)单位为℃,保留小数点后1位有效数字;
当前控制模式(MODE):Auto表示自动控制模式;Manu表示手动控制模式;
自动控制模式:
温度值 < 25℃时,档位为1档。
25℃ ≤ 温度值 ≤ 30℃,档位为2档。
温度值 > 30℃时,档位为3档。
显示说明
(1)显示背景颜色(BackColor):黑色。
(2)显示字体颜色(TextColor):白色。
(3)请严格按照图示要求设计各个信息项的名称(区分字母大小写)和相对行列位置。
3.3 模拟功能
通过检测电位器R37输出的模拟电压信号VR37模拟温度,VR37和与温度的关系如图4所示。
图4 VR37和温度关系图
3.3 按键功能
1)B1:定义为“模式”按键,在数据界面下,按下B1按键,切换自动控制模式和手动控制模式。切换顺序如图5所示。
图5 模式切换
2)B2:定义为“档位加”按键,在“手动控制”模式下,按下B2按键,调整当前档位。切换顺序如图6所示。
图5 档位加顺序
3)B3:定义为“档位减”按键,在“手动控制”模式下,按下B3按键,调整当前档位。切换顺序如图6所示。
图5 档位减顺序
注意:
(1)按键B2和B3仅在“手动控制”模式下有效。
(2)按键应进行有效的防抖处理,避免出现一次按键动作触发多次功能等情形。
(3)按键动作不应影响数据采集过程和屏幕显示效果。
(4)在“睡眠界面”下,按下按键B1、B2或B3切换到“数据界面”,且当前按键动作仅作唤醒“数据界面”使用,不触发按键功能。
3.5 串口功能
串口作远程遥控使用,串口功能如下:
串口发送‘B1’定义为按键B1,实现按键B1切换模式功能;
串口发送‘B2’,定义为按键B2,实现B2“档位加”功能;
串口发送‘B3’,定义为按键B3,实现B3“档位减”功能;
串口发送其他非法字符,返回“NULL”。
注意:
串口通信波特率9600;
除命令‘B1’、‘B2’和‘B3’外,其他字符均为非法字符。
在“睡眠界面”下,发送命令‘B1’、‘B2’和‘B3’界面切换到“数据界面”,且当前命令仅作唤醒“数据界面”使用,不触发功能。
3.6 PWM功能
通过PA1输出2kHz,占空比连续可调的频率信号,占空比和档位关系:
档位为1,占空比10%;
档位为2,占空比40%;
档位为3,占空比80%。
3.7 LED指示灯功能
1)在自动控制模式下,指示灯LD8点亮,否则熄灭;
2)档位为1时,指示灯LD1点亮,否则熄灭;
3)档位为2时,指示灯LD2点亮,否则熄灭;
4)档位为3时,指示灯LD3点亮,否则熄灭;
5)串口发送命令,同时指示灯LD4点亮,3秒后熄灭;
5)指示灯LD5~LD7始终处于熄灭状态。
3.8 初始状态说明
设备上电后,初始状态如下:
1)自动控制模式;
2)处于数据界面。
备注:请严格按照此初始状态设计功能。
具体代码如下:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2024 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"
#include "led.h"
#include "myadc.h"
#include "lcd.h"
#include "interrupt.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern struct key_t key[4];
extern struct adc2_t adc2;
extern struct interface_t interface;
extern struct uart1_t uart1;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void lcd_process(void)
{
char buf[30];
if(interface.flg == 0)//DATA
{
if(interface.clean_flg)
{
LCD_Clear(Black);
interface.clean_flg = 0;
}
sprintf(buf," DATA");
LCD_DisplayStringLine(Line1,(uint8_t*)buf);
sprintf(buf," TEMP:%.1f",adc2.temp);
LCD_DisplayStringLine(Line3,(uint8_t*)buf);
if(interface.mode == 0)
{
sprintf(buf," MODE:Auto");
}
else if(interface.mode == 1)
{
sprintf(buf," MODE:Manu");
}
LCD_DisplayStringLine(Line4,(uint8_t*)buf);
sprintf(buf," GEAR:%d",interface.gears);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
if(interface.flg == 1)//sleep
{
if(interface.sleep_clean)
{
LCD_Clear(Black);
interface.sleep_clean = 0;
}
sprintf(buf," SLEEPING");
LCD_DisplayStringLine(Line4,(uint8_t*)buf);
sprintf(buf," TEMP:%.1f",adc2.temp);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
}
void key_process(void)
{
//B1
if(key[0].short_flg == 1 && interface.flg == 0)
{
interface.sleep_time = 500;
interface.mode++;
if(interface.mode > 1)
{
interface.mode = 0;
}
key[0].short_flg = 0;
}
if(key[0].short_flg == 1 && interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
key[0].short_flg = 0;
}
//B2
if(key[1].short_flg == 1 && interface.mode == 1 && interface.flg == 0)
{
interface.sleep_time = 500;
interface.gears++;
if(interface.gears >= 3)
{
interface.gears = 3;
}
key[1].short_flg = 0;
}
if(key[1].short_flg == 1&& interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
key[1].short_flg = 0;
}
if(key[1].short_flg == 1&& interface.flg == 0)
{
interface.sleep_time = 500;
key[1].short_flg = 0;
}
//B3
if(key[2].short_flg == 1 && interface.mode == 1&& interface.flg == 0)
{
interface.sleep_time = 500;
interface.gears--;
if(interface.gears <= 1)
{
interface.gears = 1;
}
key[2].short_flg = 0;
}
if(key[2].short_flg == 1 && interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
key[2].short_flg = 0;
}
if(key[2].short_flg == 1 && interface.flg == 0)
{
interface.sleep_time = 500;
key[2].short_flg = 0;
}
}
void adc_process(void)
{
adc2.vol = get_adc();
if(adc2.vol <= 1.0f)
{
adc2.temp = 20.0f;
}
else if(adc2.vol >= 3.0f)
{
adc2.temp = 40.0f;
}
else
{
adc2.temp = 10.f*adc2.vol +10;
}
if(interface.mode == 0)
{
if(adc2.temp < 25)
{
interface.gears = 1;
}
else if(adc2.temp <= 30)
{
interface.gears = 2;
}
else
{
interface.gears = 3;
}
}
}
void pwm_process(void)
{
if(interface.gears == 1)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,10);
}
else if(interface.gears == 2)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,40);
}
else if(interface.gears == 3)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,80);
}
}
void myprintf(uint8_t *buf)
{
while(*buf != 0)
{
HAL_UART_Transmit(&huart1,buf++,1,0xffff);
}
}
void uart_process(void)
{
uint8_t str[10];
if(uart1.place > 0)
{
uart1.lenght = uart1.place;
HAL_Delay(1);
if(uart1.lenght == uart1.place)
{
uart1.led_flg = 1;
if(uart1.place == 4)
{
sscanf((char*)uart1.buf,"%2s",str);
if(!strcmp((char*)str,"B1"))
{
//B1
if(interface.flg == 0)
{
interface.sleep_time = 500;
interface.mode++;
if(interface.mode > 1)
{
interface.mode = 0;
}
}
else if(interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
}
else if(interface.flg == 0)
{
interface.sleep_time = 500;
}
}
else if (!strcmp((char*)str,"B2"))
{
//B1
if(interface.flg == 0 && interface.mode== 1)
{
interface.sleep_time = 500;
interface.gears++;
if(interface.gears >= 3)
{
interface.gears = 3;
}
}
else if(interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
}
else if(interface.flg == 0)
{
interface.sleep_time = 500;
}
}
else if (!strcmp((char*)str,"B3"))
{
//B1
if(interface.flg == 0 && interface.mode== 1)
{
interface.sleep_time = 500;
interface.gears--;
if(interface.gears <= 1)
{
interface.gears = 1;
}
}
else if(interface.flg == 1)
{
interface.clean_flg = 1;
interface.sleep_time = 500;
}
else if(interface.flg == 0)
{
interface.sleep_time = 500;
}
}
else
{
myprintf((uint8_t*)"NULL\r\n");
}
}
else
{
myprintf((uint8_t*)"NULL\r\n");
}
uart1.place = 0;
memset(uart1.buf,0,sizeof(uart1.buf));
}
}
}
void led_process(void)
{
uint8_t mode = 0;
if(interface.mode == 0)
{
mode |= 0x80;
}
else
{
mode &= 0x7f;
}
if(interface.gears == 1)
{
mode |= 0x01;
}
else
{
mode &= 0xfe;
}
if(interface.gears == 2)
{
mode |= 0x02;
}
else
{
mode &= 0xfd;
}
if(interface.gears == 3)
{
mode |= 0x04;
}
else
{
mode &= 0xfb;
}
if(uart1.led_flg)
{
mode |= 0x08;
}
else
{
mode &= 0xf7;
}
LED_Disp(mode);
}
/* 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 */
/* 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_TIM2_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
interface.sleep_time = 500;
interface.mode = 0;
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
HAL_UART_Receive_IT(&huart1,&uart1.data,1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
lcd_process();
key_process();
uart_process();
adc_process();
pwm_process();
led_process();
}
/* 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****/