终于拿满分了
接下来步入正题
一、基本要求
使用大赛组委会提供的嵌入式竞赛实训平台(基于STM32G431RBT6微控制器设计),完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的hex文件。
hex文件是唯一成绩评测依据,不符合以上文件提交要求的作品将被评为零分或者被酌情扣分。
二、硬件框图
图1 系统硬件框图
三、功能描述
3.1 基本功能
1)通过微控制器的ADC功能,检测电位器R37和R38上输出的模拟电压信号,分别模拟某工厂生产的R37和R38两类产品。
2)通过串口完成数据查询功能。
3)根据试题要求,通过按键实现界面切换、产品检测标准调整等功能。
4)根据试题要求,通过LED和LCD完成数据显示和报警功能。
3.2 显示功能
1)产品参数界面
产品参数如图2所示,显示要素包括界面名称(GOODS)、R37产品(R37)、R38产品(R38)。
图2 产品参数界面
备注:
采集的电压值保留小数点后两位,单位为V。
2)标准设置界面
标准设置界面图3所示,显示内容包括界面名称(STANDARD),R37产品检测标准(SR37)和R38产品检测标准(SR38)。
图3 标准设置界面
3)合格率界面
合格率界面如图4所示,显示内容包括界面名称(PASS),R37产品合格率(PR37)和R38产品合格率(PR38)
图4 合格率界面
产品合格标准:
产品检测标准下限≤产品电压值≤产品检测标准上限
合格率计算公式:
合格率保留小数点后一位。
显示说明
(1)显示背景颜色(BackColor):黑色。
(2)显示字体颜色(TextColor):白色。
(3)请严格按照图示要求设计各个信息项的名称(区分字母大小写)和相对行列位置。
3.3 按键功能
1)B1:定义为“切换”按键,按下按键B1,切换“产品参数界面”、“标准设置界面”和“合格率界面”,切换顺序如图5所示。
图5 界面切换顺序
2)B2:
① 在“产品参数界面”下,定义为“R37检测”按键,按下按键B2,检测产品R37是否合格。
② 在“标准设置界面”下,定义为“选择”按键,选择需要调整产品R37、产品R38的检测标准上限或下限,选择顺序如图6所示。
图6 选择顺序
3)B3:
① 在“产品参数界面”下,定义为“R38检测”按键,按下按键B3,检测产品R38是否合格。
② 在“标准设置界面”下,定义为“加”按键,按下按键B3,选择的产品标准上限或下限加0.2,产品标准上限加顺序如图7.1所示。
图7.1 产品标准上限加顺序
产品标准下限加顺序如图7.2所示。
图7.2 产品标准下限加顺序
3)B4:
① 在“合格率界面”下,定义为“清零”按键,按下按键B4,清零当前得出的产品R37和产品R38的合格率。
② 在“标准设置界面”下,定义为“减”按键,按下按键B4,选择的产品标准上限或下限减0.2,产品标准上限减顺序如图8.1所示。
图8.1 产品标准上限减顺序
产品标准下限减顺序如图8.2所示。
图8.2 产品标准下限减顺序
注意:
-
- 注意若某一产品标准改变,对应产品的合格率清零;
- 当前界面下无功能的按键按下,不触发其它界面的功能;
- 按键应进行有效的防抖处理,避免出现一次按键动作触发多次功能等情形;
- 按键动作不应影响数据采集过程和屏幕显示效果。
3.4 串口功能
1)使用竞赛平台上的USB转串口完成相关功能设计。
2)串口通信波特率设置为9600bps。
3)串口接收到字符“R37”或“R38”后,向PC端返回对应产品的名称、当前总检测数、合格数及合格率。返回格式如下:
产品名称:总检测数,合格数,合格率
例如:
串口接收到字符:R37
串口向PC端返回:R37:23,20,87.0%
注意:
合格率保留小数点后一位。
串口接收到非法字符,不作返回。除字符“R37”和“RS8”外的字符均为非法字符。
3.5 LED指示灯功能
1)LD1:产品R37检测通过时,LD1点亮1s后熄灭;
2)LD2:产品R38检测通过时,LD2点亮1s后熄灭;
5)LD3:“产品参数界面”下,LD3点亮,否则熄灭;
6)LD4:“标准设置界面”下,LD4点亮,否则熄灭;
7)LD5:“合格率界面”下,LD5点亮,否则熄灭;
6)指示灯LD6~LD8始终处于熄灭状态。
3.6 初始状态说明
设备上电后,初始状态如下:
1)产品参数界面;
2)选择调整参数R37;
3)产品R37标准:1.2-2.2;
4)产品R38标准:1.4-3.0;
备注:请严格按照此初始状态设计功能。
相关代码如下:
/* 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 "interrupt.h"
#include "myadc.h"
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern struct key_t key[4];
extern struct uart1_t uart1;
extern struct myadc_t myadc;
extern struct interface_t interface;
extern struct data_t data;
extern struct led_t led;
/* 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[50];
if(interface.flg == 0) //产品参数界面
{
sprintf(buf," GOODS");
LCD_DisplayStringLine(Line1,(uint8_t*)buf);
sprintf(buf," R37:%.2fV",myadc.r37);
LCD_DisplayStringLine(Line3,(uint8_t*)buf);
sprintf(buf," R38:%.2fV",myadc.r38);
LCD_DisplayStringLine(Line4,(uint8_t*)buf);
}
else if(interface.flg == 1)//标准设置界面
{
sprintf(buf," STANDARD");
LCD_DisplayStringLine(Line1,(uint8_t*)buf);
sprintf(buf," SR37:%.1f-%.1f",data.r37_l,data.r37_h);
LCD_DisplayStringLine(Line3,(uint8_t*)buf);
sprintf(buf," SR38:%.1f-%.1f",data.r38_l,data.r38_h);
LCD_DisplayStringLine(Line4,(uint8_t*)buf);
}
else if(interface.flg == 2)//合格率界面
{
sprintf(buf," PASS");
LCD_DisplayStringLine(Line1,(uint8_t*)buf);
sprintf(buf," PR37:%.1f%c ",data.r37_rate,'%');
LCD_DisplayStringLine(Line3,(uint8_t*)buf);
sprintf(buf," PR38:%.1f%c ",data.r38_rate,'%');
LCD_DisplayStringLine(Line4,(uint8_t*)buf);
}
}
void key_process(void)
{
//B1
if(key[0].short_flg == 1)
{
LCD_Clear(Black);
interface.flg++;
if(interface.flg > 2)
{
interface.flg = 0;
}
key[0].short_flg = 0;
}
//B2
if(key[1].short_flg == 1 && interface.flg == 0)//检测R37
{
data.r37_flg = 1;
key[1].short_flg = 0;
}
if(key[1].short_flg == 1 && interface.flg == 1)//选择R38 r37
{
interface.place++;
if(interface.place > 3)
{
interface.place = 0;
}
key[1].short_flg = 0;
}
//B3
if(key[2].short_flg == 1 && interface.flg == 0)//检测R38
{
data.r38_flg = 1;
key[2].short_flg = 0;
}
if(key[2].short_flg == 1 && interface.flg == 1)//加R38 r37
{
data.r38_sun = 0;
data.r37_sun = 0;
data.r37 = 0;
data.r38 = 0;
data.r37_rate = 0;
data.r38_rate = 0;
if(interface.place == 0)//r37上线加
{
data.r37_h+=0.2f;
if(data.r37_h >= 3.2f)
{
data.r37_h = 2.2f;
}
}
else if(interface.place == 1)
{
data.r37_l+=0.2f;
if(data.r37_l >= 2.2f)
{
data.r37_l = 1.2f;
}
}
else if(interface.place == 2)
{
data.r38_h+=0.2f;
if(data.r38_h >= 3.2f)
{
data.r38_h = 2.2f;
}
}
else if(interface.place == 3)
{
data.r38_l+=0.2f;
if(data.r38_l >= 2.2f)
{
data.r38_l = 1.2f;
}
}
key[2].short_flg = 0;
}
//B4
if(key[3].short_flg == 1 && interface.flg == 1)//减R38 r37
{
data.r38_sun = 0;
data.r37_sun = 0;
data.r37 = 0;
data.r38 = 0;
data.r37_rate = 0;
data.r38_rate = 0;
if(interface.place == 0)//r37上限减
{
data.r37_h-=0.2f;
if(data.r37_h <= 2.0f)
{
data.r37_h = 3.0f;
}
}
else if(interface.place == 1)
{
data.r37_l-=0.2f;
if(data.r37_l <= 1.0f)
{
data.r37_l = 2.0f;
}
}
else if(interface.place == 2)
{
data.r38_h-=0.2f;
if(data.r38_h <= 2.0f)
{
data.r38_h = 3.0f;
}
}
else if(interface.place == 3)
{
data.r38_l-=0.2f;
if(data.r38_l <= 1.0f)
{
data.r38_l = 2.0f;
}
}
key[3].short_flg = 0;
}
if(key[3].short_flg == 1 && interface.flg == 2)//合格率清0
{
data.r38_sun = 0;
data.r37_sun = 0;
data.r37 = 0;
data.r38 = 0;
data.r37_rate = 0;
data.r38_rate = 0;
key[3].short_flg = 0;
}
}
void adc_process(void)
{
myadc.r37 = get_adec(&hadc2);
myadc.r38 = get_adec(&hadc1);
}
void datetion_process(void)
{
//r38检测
if(data.r38_flg)
{
data.r38_sun++;//检测一次总数加1
if(myadc.r38 >= data.r38_l && myadc.r38 <= data.r38_h)//检测通过
{
led.r38 = 1;
data.r38++;
}
data.r38_rate = (data.r38*1.0f/data.r38_sun*1.0f)*100.0f;
data.r38_flg = 0;
}
//r37检测
if(data.r37_flg)
{
data.r37_sun++;//检测一次总数加1
if(myadc.r37 >= data.r37_l && myadc.r37 <= data.r37_h)//检测通过
{
led.r37 = 1;
data.r37++;
}
data.r37_rate = (data.r37*1.0f/data.r37_sun*1.0f)*100.0f;
data.r37_flg = 0;
}
}
void myprintf(uint8_t *buf)
{
while(*buf != 0)
{
HAL_UART_Transmit(&huart1,buf++,1,0xffff);
}
}
void uart_process(void)
{
uint8_t str[5];
char buf[40];
if(uart1.place > 0)
{
uart1.lenght = uart1.place;
HAL_Delay(1);
if(uart1.place == uart1.lenght)
{
if(uart1.place == 3)
{
sscanf((char*)uart1.buf,"%3s",str);
if(!strcmp((char*)str,"R37"))
{
sprintf(buf,"%s:%d,%d,%.1f%c",str,data.r37_sun,data.r37,data.r37_rate,'%');
myprintf((uint8_t*)buf);
}
else if(!strcmp((char*)str,"R38"))
{
sprintf(buf,"%s:%d,%d,%.1f%c",str,data.r38_sun,data.r38,data.r38_rate,'%');
myprintf((uint8_t*)buf);
}
}
uart1.place = 0;
memset(uart1.buf,0,sizeof(uart1.buf));
}
}
}
void led_process(void)
{
uint8_t mode = 0;
if(interface.flg == 0)
{
mode |= 0x04;
}
else
{
mode &= 0xfb;
}
if(interface.flg == 1)
{
mode |= 0x08;
}
else
{
mode &= 0xf7;
}
if(interface.flg == 2)
{
mode |= 0x10;
}
else
{
mode &= 0xef;
}
if(led.r37)
{
mode |= 0x01;
}
else
{
mode &= 0xfe;
}
if(led.r38)
{
mode |= 0x02;
}
else
{
mode &= 0xfd;
}
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_ADC1_Init();
MX_ADC2_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
data.r37_l = 1.2f;
data.r37_h = 2.2f;
data.r38_l = 1.4f;
data.r38_h = 3.0f;
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4);
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();
adc_process();
datetion_process();
uart_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****/