文章目录
- 1.题目解析
- 1.1 分而治之,藕断丝连
- 1.2 模块化思维导图
- 1.3 模块解析
- 1.3.1 KEY模块
- 1.3.2 ADC模块
- 1.3.3 IIC模块
- 1.3.4 UART模块
- 1.3.5 LCD模块
- 1.3.6 LED模块
- 1.3.7 TIM模块
- 2.源码
- 3.第七届题目
前言:STM32G431RBT6实现嵌入式组第七届题目解析+源码,本文默认读者具备基础的stm32知识。文章末尾有第七届题目。
1.题目解析
1.1 分而治之,藕断丝连
还是那句话,将不同模块进行封装,通过变量进行模块间的合作。
1.2 模块化思维导图
下图根据题目梳理。第六届没有写这么详细(主要是懒😀)。
1.3 模块解析
整合模块,逻辑思维。
1.3.1 KEY模块
B1:界面1,2之间切换,方法:计数;0:表示界面1,1:表示界面2。
B2:三种阈值位之间切换,方法:计数;0:表示T1,1:表示T2,2:表示T3。
B3:每次加5,上限95(各阈值之间还应该T1<T2<T3, 但是我没写😅)。
B4:每次减5,下限5。
//B1,B4,B3都是同样的格式
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
{
if(HAL_GetTick() - tick > KEY_REDUCTION){ //按键消抖
tick = HAL_GetTick();
keyS->bits.B1 ^= 1;
// keyS->bits.B1++;
// if(keyS->bits.B1 == 2) keyS->bits.B1 = 0;
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET); //实现按下一次只计数一次
}
}
//B2多了一种状态
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) //B2
{
if(HAL_GetTick() - tick > KEY_REDUCTION){
tick = HAL_GetTick();
keyS->bits.B2++;
if(keyS->bits.B2 == 3) keyS->bits.B2 = 0;
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET);
}
}
1.3.2 ADC模块
采集可调电位器电压。默认10次为一组进行一次滤波。
假如使用0.2s时基来开启adc采集,采集10次需2s响应太慢,放在systick中断中,程序写到后面时间1ms显短,我就多使用了一个tim产生0.5s时基,不用白不用。也可使用一个0.5的就行,累计4次就执行一次需0.2s时基模块。也可使用dma采集。
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(adc_smp_flag < (FILTER_LEN+1))
{
adc_smp_flag++;
adc_smp_vtg.smp_val[adc_smp_flag] = HAL_ADC_GetValue(hadc);
if(adc_smp_flag == (FILTER_LEN+1))
{
adc_smp_flag =0;
filter_process(&adc_smp_vtg); //累加相除
}
}
}
typedef struct{
uint32_t smp_val[FILTER_LEN];
uint32_t filter_val;
} adc_smp_t;
1.3.3 IIC模块
完成eeprom中数据的读写。开发板的PB6和PB7设置为开漏输出,使用软件模拟实现单字节数据的读写。注意:魔术棒->c\c+±>optimization选项要设置成-O0,要不然代码执行后得不到想要的结果。
具体实现看第二部分源码。
/* 软件模拟实现at24c02单字节写入 */
void at24c02_write(uint8_t addr, uint8_t data){
...
}
/* 软件模拟实现at24c02单字节读取 */
uint8_t at24c02_read(uint8_t addr){
...
}
/* i2c向eeprom写入data */
void iic_write()
{
...
}
...
1.3.4 UART模块
UART接收PC端查询码’C’, ‘S’,做出相应的回应。
具体实现看第二部分源码。
//中断触发回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
...
}
//定时上报数据
void uart_inform_PC()
{
...
}
1.3.5 LCD模块
将涉及到的数据显示到lcd屏幕上,份界面1和界面2。
具体实现看第二部分源码。
void lcd_process()
{
if
{
//1:if 界面1,2切换清屏
//2:LCD显示数据
//3:if设置阈值成功后切换到界面1,将set_thros写入eeprom
}
else
{
//1:if 界面1,2切换清屏
//2:if 显示thros1为绿色+设置该阈值
//3:else if 显示thros2为绿色+设置该阈值
//4:else if 显示thros3为绿色+设置该阈值
}
}
1.3.6 LED模块
这届题目我感觉难度就在led的处理上面,看着题目要求非常简单,正常思路当事件发生的时候,使用HAL_GPIO_TogglePin()翻转led对应引脚电平就行,但是我们使用到了lcd屏幕,lcd屏幕也使用到PC8-PC15这些引脚,所以我们每次写入led状态的时候对其他led引脚也得考虑。我就被绕进去了,整了我2个多小时。还是因为逻辑思维不够强,代码写少了😶。
三种事件相互之间保持独立。我们分析一下三个事件之间的关系:
LD1:每隔1s亮灭闪烁,事件周期性触发。
LD2:0.2s间隔闪烁5次,但是事件触发没有周期性,液位等级变化触发一次。
LD3:0.2s间隔闪烁5次,但是事件触发没有周期性,接收到查询指令触发一次。
所以三事件相互独立,可能同时触发,可以一次触发其中的随机两个,也可能是一个,也可能是都没发生。所以这样就构成了8种情况。
我们假设一个uint8_t temp变量,LD1代表第1位(事件1),LD2代表第2位(事件2),LD3代表第3位(事件3),对应位置1表示该事件发生,需执行该事件。这样我就得到了8种情况:
111:代表三种事件同时发生;
110:代表事件3,事件2发生;
依此类推…
000:代表都不发生。
最后根据这八种情况写入对应的电平状态就可以了。
void led_process()
{
uint8_t temp = 0;
uint8_t new_liq_level = liq_level_process(iic_liq_thros);
ld1_tim_flag++;
if(ld1_tim_flag == 5){
temp |= 1;
ld1_state_flag ^= 1;
}
if(old_liq_level != new_liq_level)
{
temp |= 2;
ld2_tim_flag++;
ld2_state_flag ^= 1;
if(ld2_tim_flag == 1) uart_inform_PC(new_liq_level);
}
if(uart_rec_flag == 1)
{
temp |= 4;
ld3_tim_flag++;
ld3_state_flag ^= 1;
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
if(temp == 0) GPIOC->ODR = 0xff00;
else if(temp == 1)
{
GPIOC->ODR = 0xfe00 ^ (ld1_state_flag << 8);
}
else if(temp == 2)
{
GPIOC->ODR = 0xfd00 ^ (ld2_state_flag << 9);
}
else if(temp == 3)
{
GPIOC->ODR = 0xfc00 ^ ((ld1_state_flag + (ld2_state_flag << 1)) << 8);
}
else if(temp == 4)
{
GPIOC->ODR = 0xfb00 ^ (ld3_state_flag << 10);
}
else if(temp == 5)
{
GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld3_state_flag << 2)) << 8);
}
else if(temp == 6)
{
GPIOC->ODR = 0xfa00 ^ (((ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
}
else if(temp == 7)
{
GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
//事件完成之后结束设置对应标志位。
if(ld1_tim_flag == 5){
ld1_tim_flag = 0;
}
if(ld2_tim_flag == 10)
{
old_liq_level = new_liq_level;
ld2_tim_flag = 0;
}
if(ld3_tim_flag == 10)
{
uart_rec_flag = 0;
ld3_tim_flag = 0;
}
}
1.3.7 TIM模块
170MHz的频率,预分频值填写16,重装载寄存器填写1999999实现0.2s时基;
预分频值填写16,重装载寄存器填写499999实现0.05s时基。
0.2s的时基,用在led模块。
0.05s的时基用在uart,adc上。
具体实现看第二部分源码。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint8_t test_val = 0;
if(htim == &htim2) //tim2
{
led_process(); //led处理函数
}
else{ //tim3
HAL_ADC_Start_IT(&hadc2);
HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
}
}
2.源码
我所有的实现都在main.c文件中。
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* 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 "i2c_hal.h"
#include "lcd.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define FILTER_LEN 10
#define KEY_REDUCTION 20
/* 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 */
typedef struct{
uint32_t smp_val[FILTER_LEN];
uint32_t filter_val;
} adc_smp_t;
adc_smp_t adc_smp_vtg = {0}; //将ADC采集的数据收集FILTER_LEN个,之后会进行均值滤波
typedef union{
uint8_t keys;
struct{
uint8_t B1:2;
uint8_t B2:2;
uint8_t B3:2;
uint8_t B4:2;
}bits;
}key_state_t;
key_state_t key_state = {0}; //表示按键状态
/*
adc_smp_flag:保证采集FILTER_LEN个数据之后进行滤波
key_add_sub_flag, b3_b4_flag:控制按键B3,B4加减操作。
lcd_clear_flag:在界面1和界面2之间切换时候的清屏标志位。
set_thros_flag:B1按下返回界面1后,设置阈值成功,将设置阈值写入eeprom
uart_rec_flag:接收到pc查询指令后,控制ld3标志
old_liq_level:记住上一次的level值,通知pc端时知道是U还是D,还有配合控制ld2
*/
uint8_t adc_smp_flag = 0, key_add_sub_flag = 100, b3_b4_flag = 100,
lcd_clear_flag = 0, set_thros_flag = 0, uart_rec_flag = 0, old_liq_level = 0;
/* 在lcd上显示数据,配合sprinf使用 */
char lcd_HOR[30] = {0}, lcd_thros[30] = {0}, uart_resp[30] = {0};
/*
iic_liq_thros:实时值
set_thros:更改阈值时做中间值
*/
uint8_t iic_liq_thros[3] = {30, 50, 70}, set_thros[3] = {0};
/*
ldi_tim_flag:0.2s加一,控制ldi闪烁次数
ldi_state_flag:改变对应ldi的状态标志,对应周期等间隔1010...交替变化
*/
uint16_t ld1_tim_flag = 0, ld2_tim_flag = 0, ld3_tim_flag = 0,
ld1_state_flag = 0, ld2_state_flag = 0, ld3_state_flag = 0;
/* 接收pc端发来的查询信号 */
uint8_t uart_rec_char;
void filter_process(adc_smp_t *adcSmp);
void lcd_process();
void at24c02_write(uint8_t addr, uint8_t data);
uint8_t at24c02_read(uint8_t addr);
void iic_write(uint8_t* data);
void iic_read(uint8_t* data);
void key_process(key_state_t *keyS);
void set_thros_process(uint8_t *des, uint8_t index);
void led_process();
uint8_t cmp_thros(uint8_t *a);
uint32_t liq_level_process(uint8_t* liq_thros);
void iic1_process();
void uart_inform_PC(uint8_t level);
/* 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 */
LCD_Init();
LCD_Clear(Black);
/* 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_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2); //tim2产生200ms时基
HAL_TIM_Base_Start_IT(&htim3); //tim3产生50ms时基
HAL_ADC_Start_IT(&hadc2);
HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
//检查eeprom对应数据内存中数据是否符合要求,应对第一次在板子下载该程序,eeprom对应内存位置数据不正确的问题
iic_read(set_thros);
if(cmp_thros(set_thros))
{
iic_write(iic_liq_thros);
}else{
iic_read(iic_liq_thros);
}
for(int i=0;i<3;i++)
{
set_thros[i] = iic_liq_thros[i];
}
old_liq_level = liq_level_process(iic_liq_thros);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key_process(&key_state);
lcd_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};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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_DIV6;
RCC_OscInitStruct.PLL.PLLN = 85;
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 buses 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_4) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/*
void lcd_process()
{
if
{
1:if 界面1,2切换清屏
2:LCD显示数据
3:if设置阈值成功后切换到界面1,将set_thros写入eeprom
}
else
{
1:if 界面1,2切换清屏
2:if 显示thros1为绿色+设置该阈值
3:else if 显示thros2为绿色+设置该阈值
4:else if 显示thros3为绿色+设置该阈值
}
}
*/
void lcd_process()
{
if(key_state.bits.B1 == 0)
{
if(lcd_clear_flag == 0)
{
LCD_Clear(Black);
lcd_clear_flag = 1;
}
LCD_DisplayStringLine(Line1, " Liquid Level");
sprintf(lcd_HOR, " Height:%dcm", adc_smp_vtg.filter_val*100/4096);
LCD_DisplayStringLine(Line2, (uint8_t*)lcd_HOR);
sprintf(lcd_HOR, " ADC:%.2fV", adc_smp_vtg.filter_val*3.3/4096);
LCD_DisplayStringLine(Line3, (uint8_t*)lcd_HOR);
sprintf(lcd_HOR, " Level: %d", liq_level_process(iic_liq_thros));
LCD_DisplayStringLine(Line4, (uint8_t*)lcd_HOR);
if(set_thros_flag==1)
{
set_thros_flag = 0;
iic_write(set_thros);
iic_read(iic_liq_thros);
}
}
else
{
if(lcd_clear_flag == 1)
{
LCD_Clear(Black);
lcd_clear_flag = 0;
}
LCD_DisplayStringLine(Line1, " Parameter Setup");
if(key_state.bits.B2 == 0){
LCD_SetTextColor(Green);
sprintf(lcd_thros, " Throsouth 1:%2dcm", set_thros[0]);
LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
LCD_SetTextColor(Black);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[1]);
LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[2]);
LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
if(b3_b4_flag != key_add_sub_flag){
set_thros_process(set_thros, 0);
}
}
else if(key_state.bits.B2 == 1){
sprintf(lcd_thros, " Throsouth 1:%2dcm", set_thros[0]);
LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
LCD_SetTextColor(Green);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[1]);
LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
LCD_SetTextColor(Black);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[2]);
LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
if(b3_b4_flag != key_add_sub_flag){
set_thros_process(set_thros, 1);
}
}
else if(key_state.bits.B2 == 2){
sprintf(lcd_thros, " Throsouth 1:%2dcm", set_thros[0]);
LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[1]);
LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
LCD_SetTextColor(Green);
sprintf(lcd_thros, " Throsouth 2:%2dcm", set_thros[2]);
LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
LCD_SetTextColor(Black);
if(b3_b4_flag != key_add_sub_flag){
set_thros_process(set_thros, 2);
}
}
}
}
/* 软甲模拟iic协议写入1byte */
void at24c02_write(uint8_t addr, uint8_t data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
/* 软件模拟iic协议读取1byte */
uint8_t at24c02_read(uint8_t addr)
{
uint8_t data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
data = I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return data;
}
/* 写入数据 */
void iic_write(uint8_t* data)
{
for(int i=0; i<3; i++)
{
at24c02_write(i, data[i]);
HAL_Delay(3);
}
}
/* 读取数据 */
void iic_read(uint8_t* data)
{
uint8_t temp = 0;
for(int i=0; i<3; i++)
{
temp = at24c02_read(i);
data[i] = temp;
HAL_Delay(3);
}
}
/* 验证读出数据是否正常 */
uint8_t cmp_thros(uint8_t *a)
{
for(int i=0; i<3; i++)
{
if(a[i] < 5 || a[i] > 95) return 1;
}
return 0;
}
/* 检测液深等级 */
uint32_t liq_level_process(uint8_t* liq_thros)
{
uint32_t temp = adc_smp_vtg.filter_val*100/4096;
if(temp <= liq_thros[0]) return 0;
else if(temp > liq_thros[0] && temp <= liq_thros[1]) return 1;
else if(temp > liq_thros[1] && temp <= liq_thros[2]) return 2;
else return 3;
}
/* 读取Bi按键状态 */
void key_process(key_state_t *keyS)
{
uint32_t tick = 0;
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
{
if(HAL_GetTick() - tick > KEY_REDUCTION){
tick = HAL_GetTick();
keyS->bits.B1 ^= 1;
// keyS->bits.B1++;
// if(keyS->bits.B1 == 2) keyS->bits.B1 = 0;
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) //B2
{
if(HAL_GetTick() - tick > KEY_REDUCTION){
tick = HAL_GetTick();
keyS->bits.B2++;
if(keyS->bits.B2 == 3) keyS->bits.B2 = 0;
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET) //B3
{
if(HAL_GetTick() - tick > KEY_REDUCTION){
tick = HAL_GetTick();
keyS->bits.B3 ^= 1;
// keyS->bits.B3++;
// if(keyS->bits.B3 == 2) keyS->bits.B3 = 0;
key_add_sub_flag++;
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
{
if(HAL_GetTick() - tick > KEY_REDUCTION){
tick = HAL_GetTick();
keyS->bits.B4 ^= 1;
// keyS->bits.B4++;
// if(keyS->bits.B4 == 2) keyS->bits.B4 = 0;
key_add_sub_flag--;
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
}
}
}
/* 设置阈值 */
void set_thros_process(uint8_t *des, uint8_t index)
{
if(key_add_sub_flag>b3_b4_flag && (des[index]>=5 && des[index]<=95))
{
des[index] += 5;
if(des[index] == 100) des[index] = 95;
}
else if(key_add_sub_flag<b3_b4_flag && (des[index]>=5 && des[index]<=95))
{
des[index] -= 5;
if(des[index] == 0) des[index] = 5;
}
set_thros_flag = 1;
b3_b4_flag = key_add_sub_flag;
}
/*
void led_process()
{
1:前面3if设置3种事件是否发生
2:3种事件相互组合形成8种混合事件
3:最后3if设置相关标志位
}
*/
void led_process()
{
uint8_t temp = 0;
uint8_t new_liq_level = liq_level_process(iic_liq_thros);
ld1_tim_flag++;
if(ld1_tim_flag == 5){
temp |= 1;
ld1_state_flag ^= 1;
}
if(old_liq_level != new_liq_level)
{
temp |= 2;
ld2_tim_flag++;
ld2_state_flag ^= 1;
if(ld2_tim_flag == 1) uart_inform_PC(new_liq_level);
}
if(uart_rec_flag == 1)
{
temp |= 4;
ld3_tim_flag++;
ld3_state_flag ^= 1;
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
if(temp == 0) GPIOC->ODR = 0xff00;
else if(temp == 1)
{
GPIOC->ODR = 0xfe00 ^ (ld1_state_flag << 8);
}
else if(temp == 2)
{
GPIOC->ODR = 0xfd00 ^ (ld2_state_flag << 9);
}
else if(temp == 3)
{
GPIOC->ODR = 0xfc00 ^ ((ld1_state_flag + (ld2_state_flag << 1)) << 8);
}
else if(temp == 4)
{
GPIOC->ODR = 0xfb00 ^ (ld3_state_flag << 10);
}
else if(temp == 5)
{
GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld3_state_flag << 2)) << 8);
}
else if(temp == 6)
{
GPIOC->ODR = 0xfa00 ^ (((ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
}
else if(temp == 7)
{
GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
if(ld1_tim_flag == 5){
ld1_tim_flag = 0;
}
if(ld2_tim_flag == 10)
{
old_liq_level = new_liq_level;
ld2_tim_flag = 0;
}
if(ld3_tim_flag == 10)
{
uart_rec_flag = 0;
ld3_tim_flag = 0;
}
}
/* 向pc端发送数据 */
void uart_inform_PC(uint8_t level)
{
if(old_liq_level<level)
{
sprintf(uart_resp, "A:H%2d+L%1d+U\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
HAL_UART_Transmit_IT(&huart1, (uint8_t*)uart_resp, 12);
}else if(old_liq_level>level)
{
sprintf(uart_resp, "A:H%2d+L%1d+D\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
HAL_UART_Transmit_IT(&huart1, (uint8_t*)uart_resp, 12);
}
}
/* 定时器时基中断回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint8_t test_val = 0;
if(htim == &htim2)
{
led_process();
}
else{
HAL_ADC_Start_IT(&hadc2);
HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
}
}
/* uart接收事件中断回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(uart_rec_char == 'C')
{
uart_rec_flag = 1;
sprintf(uart_resp, "C:H%2d+L%1d\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
HAL_UART_Transmit_IT(huart, (uint8_t*)uart_resp, 9);
}
else if(uart_rec_char == 'S')
{
uart_rec_flag = 1;
sprintf(uart_resp, "S:TL%2d+TM%2d+TH%2d\r\n", iic_liq_thros[0], iic_liq_thros[1], iic_liq_thros[2]);
HAL_UART_Transmit_IT(huart, (uint8_t*)uart_resp, 18);
}
}
/* adc规则组转换完成中断回调函数 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(adc_smp_flag < (FILTER_LEN+1))
{
adc_smp_flag++;
adc_smp_vtg.smp_val[adc_smp_flag] = HAL_ADC_GetValue(hadc);
if(adc_smp_flag == (FILTER_LEN+1))
{
adc_smp_flag =0;
filter_process(&adc_smp_vtg);
}
}
}
/* adc采集值进行滤波 */
void filter_process(adc_smp_t *adcSmp)
{
uint32_t temp = 0;
for(int i=0;i<FILTER_LEN;i++)
{
temp += adcSmp->smp_val[i];
}
adcSmp->filter_val = temp/10;
}
/* 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 */
__disable_irq();
while (1)
{
}
/* 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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
3.第七届题目