当前位置:   article > 正文

蓝桥杯物联网竞赛_STM32L071KBU6_第十五届蓝桥杯物联网竞赛国赛代码解析

蓝桥杯物联网竞赛_STM32L071KBU6_第十五届蓝桥杯物联网竞赛国赛代码解析

前言:

这届国赛是目前为止最难一届,我赛后完完整整又做了一遍,花了我两天大概12小时,这个难度完全可以当一个stm32的期末设计,下面将对本届的题结合对应代码做重点解析

对应试题在这里: 第十五届蓝桥杯物联网试题(国赛)

1、配置及代码:

(1) A板:

[1] CUBMX配置:

1、DMA串口配置:
在这里插入图片描述
在这里插入图片描述
2、TIM3配置:
在这里插入图片描述
3、TIM7定时器配置:
在这里插入图片描述
在这里插入图片描述


[2] keil5代码:

main.c

#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* 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 */
#include "Function.h"
#include "oled.h"
#include "lora.h"
/* 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_DMA_Init();
  MX_I2C3_Init();
  MX_TIM3_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  MX_TIM7_Init();
  /* USER CODE BEGIN 2 */
  Function_OledInit(50);
	LORA_Init();
	HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_3);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		Function_MyMain();
  }
  /* USER CODE END 3 */
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

Function.c

#include "Function.h"
#include "main.h"
#include "oled.h"
#include "i2c.h"
#include "spi.h"
#include "lora.h"
#include <stdarg.h>
#include <stdio.h>
#include "usart.h"
#include "tim.h"
#include <string.h>

unsigned char URXMSG[20];
unsigned char UTXMSG[20];
unsigned char LTXMSG[20];
unsigned char LRXMSG[20];
int BEIGNNUMBER = 0;
int ENDNUMBER = 0;
unsigned char STATETIM = 0;
unsigned char ARRAY1[20];
int PLUSEVALUE = 0;
uint16_t COUNTNUMBER = 0;
unsigned char MEMORDER[20] = {'N', 'F', ' '};


void OLED_Write(unsigned char type, unsigned char data){
	unsigned char WriteData[2];
	WriteData[0] = type;
	WriteData[1] = data;
	HAL_I2C_Master_Transmit(&hi2c3, 0x78, WriteData, 2, 0xff);
}

void Function_OledInit(unsigned char ms){
	HAL_GPIO_WritePin(OLED_Power_GPIO_Port, OLED_Power_Pin, GPIO_PIN_RESET);
  HAL_Delay(ms);
	OLED_Init();
}


unsigned char SPI_WriteRead(unsigned char address, unsigned char data){
	unsigned char TxData[2], RxData[2];
	TxData[0] = address;
	TxData[1] = data;
	HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
	HAL_SPI_TransmitReceive(&hspi1, TxData, RxData, sizeof(TxData), 0xff);
	HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);
	return RxData[1];
}

void Function_ArrayClean(unsigned char* array, uint16_t len){
  for(unsigned char i = 0; i < len; i ++) array[i] = '\0';
}


void myprintf(unsigned char address, const char* format, ...) {
    char ARRAY[40];
	
	  // 使用va_list和va_start来处理可变参数
    va_list args;
    va_start(args, format);

    // 使用vsprintf将可变参数列表格式化的字符串存储到ARRAY中
    vsprintf(ARRAY, format, args);
    
    // 清理可变参数列表
    va_end(args);

    // 假设OLED_ShowString函数可以在OLED屏幕上显示字符串
    OLED_ShowString(address, (unsigned char*)ARRAY);
}

void Function_UartTxOk(){
  HAL_UART_Transmit(&huart2, (unsigned char* )"OK ", 5, 0xff);
}

void Function_UartTxError(){
  HAL_UART_Transmit(&huart2, (unsigned char* )"ERROR ", 8, 0xff);
}

void Function_HandleURxMsg(){
  if(URXMSG[0] == '$' && URXMSG[1] == '\0'){
	  LORA_Tx((unsigned char* )"$", 1);
	}
	
	if(URXMSG[0] == '?' && URXMSG[1] == '\0'){
	  LORA_Tx((unsigned char* )"?", 1);
	}
	
	if(URXMSG[0] == '@' && URXMSG[1] == '\0'){
		
		sprintf((char* )LTXMSG, "%d", PLUSEVALUE);
    LORA_Tx(LTXMSG, 10);	
    Function_ArrayClean(LTXMSG, sizeof(LTXMSG));	
		
	}
	
	if(URXMSG[0] == 'F'){
	 
	 if(strncmp((char* )URXMSG, "FS1:", 4) == 0 || strncmp((char* )URXMSG, "FS2:", 4) == 0)	LORA_Tx(URXMSG, 20);  // 判断是不是正确的
	 else Function_UartTxError(); 
	}
	
	unsigned char temp = URXMSG[0];
	if(temp == '$' && URXMSG[1] == '\0'){  // 切换和同步命令需要返还OK
	  Function_UartTxOk();  // 返还OK
		Function_ArrayClean(URXMSG, sizeof(URXMSG));  // 清理
	}		
 	
	if(((temp == '?' || temp == '@') && URXMSG[1] == '\0') || temp == 'F'){  // 参数和查询指令交给B端处理后统一返还
	  Function_ArrayClean(URXMSG, sizeof(URXMSG));
	}		 
 
	if(URXMSG[0] != '\0') {  // 接收了其他垃圾消息
		Function_ArrayClean(URXMSG, sizeof(URXMSG));
		Function_UartTxError();  // 返还错误
	}
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  // 10ms
  	if(COUNTNUMBER < 300) COUNTNUMBER ++;
	  else{
		  COUNTNUMBER = 0;
			HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);  // 随手关灯
		}
}

void Function_LoRxMsg(){  // B端处理后的结果
  LORA_Rx(LRXMSG);
	if(LRXMSG[0] != '\0'){

	  if(LRXMSG[0] == '0') Function_UartTxError();  // A端接收的数据不正确
		else if(LRXMSG[0] == 'R' || LRXMSG[0] == 'N'){  // 接收到LORB传递的数据
			HAL_UART_Transmit(&huart2, LRXMSG, strlen((char* )LRXMSG), 0xff);
			HAL_TIM_Base_Start_IT(&htim7);  // 开启定时器
			HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);  // 开灯
		}
		else if(LRXMSG[0] == '1') Function_UartTxOk();  // A端接收的数据正确
		Function_ArrayClean(LRXMSG, sizeof(LRXMSG));  // 清除接收的数据
	}
	
}
 

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
	//OLED_ShowString(0, "ok");
	if(STATETIM == 0){
		STATETIM ++;
		BEIGNNUMBER = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);
		__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3, TIM_ICPOLARITY_FALLING);
	}else if(STATETIM == 1){
		STATETIM ++;
		__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3, TIM_ICPOLARITY_RISING);
	}else if(STATETIM == 2){
		STATETIM ++;
		ENDNUMBER = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);
	}
}

void Function_UartRxMsg(){
  HAL_UARTEx_ReceiveToIdle_IT(&huart2, URXMSG, 50);
	if(URXMSG[0] != '\0'){
	  HAL_Delay(10);  // 让cpu等待DMA把数据接收完
		memcpy(MEMORDER, URXMSG, 20);
		 
		Function_HandleURxMsg();
	}
}

void Function_PluseShow(){
  if(STATETIM == 3){
		PLUSEVALUE = (int)(1000000 * 1.0 / (ENDNUMBER - BEIGNNUMBER));
		myprintf(2, "     %dHZ      ",  PLUSEVALUE);
		//myprintf(0, "   %d  ", ENDNUMBER - BEIGNNUMBER); 
		//myprintf(2, "   %.1f   ", (ENDNUMBER - BEIGNNUMBER) / 10.0);
		STATETIM = 0;
	  HAL_Delay(200);
	}
}

void Function_MyMain(){
  Function_UartRxMsg();
  //myprintf(0, URXMSG);
  myprintf(0, "     %s       ", MEMORDER);  // 显示最近一次接收到的数据
  Function_LoRxMsg();
  Function_PluseShow();
	//Function_HandleURxMsg();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188

Function.h

#ifndef __FUNCTION_H__
#define __FUNCTION_H__
#include "main.h"

void OLED_Write(unsigned char type, unsigned char data);

void Function_OledInit(unsigned char ms);

void Function_MyMain();

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

(2) B板:

[1] CUBMX配置:

1、PWM方波配置:
在这里插入图片描述
在这里插入图片描述
2、TIM7定时器配置:
在这里插入图片描述
在这里插入图片描述


[2] keil5代码:

main.c

#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* 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 */
#include "Function.h"
#include "oled.h"
#include "lora.h"
/* 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_I2C3_Init();
  MX_SPI1_Init();
  MX_TIM2_Init();
  MX_TIM7_Init();
  MX_ADC_Init();
  /* USER CODE BEGIN 2 */
  Function_OledInit(50);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);  // 开启方波 1kHZ
	HAL_TIM_Base_Start_IT(&htim7);
	LORA_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		Function_MyMain();
  }
  /* USER CODE END 3 */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

Function.c

#include "Function.h"
#include "main.h"
#include "i2c.h"
#include "oled.h"
#include <stdio.h>
#include "tim.h"
#include "adc.h"
#include <stdarg.h>
#include "spi.h"
#include "lora.h"
#include <string.h>
#include <stdlib.h>

float FS1 = 6.0;
float FS2 = 6.0;
float F1VL = 0;
float F2VL = 0;
unsigned char STATEADC = 0;  // ADC状态
unsigned char OLEDSHOW = 0;  // OLED显示
uint16_t COUNTNUM = 0;
unsigned char LEDSTATE = 0;
float DERTF1F2 = 0;  // 获取FS1与FS2差值 / 0.2
unsigned char INDEX = 7;  // 算一下AA中第一个A的具体位置
unsigned char MEMWINNER[20] = {'N', 'F', ' '};
uint16_t ADCRUNNUM = 0;
unsigned char RUNSHOWARR[20];
unsigned char LORXMSG[20];
int NEWPWM = 0;
int CLK = 32000000;
int MAINDRT = 32000000;
int INDEXX = 0;
int INDEXY = 0;  // 获取要调的参数


void OLED_Write(unsigned char type, unsigned char data){
	unsigned char WriteData[2];
	WriteData[0] = type;
	WriteData[1] = data;
	HAL_I2C_Master_Transmit(&hi2c3, 0x78, WriteData, 2, 0xff);
}

void Function_OledInit(unsigned char ms){
	HAL_GPIO_WritePin(OLED_Power_GPIO_Port, OLED_Power_Pin, GPIO_PIN_RESET);
  HAL_Delay(ms);
	OLED_Init();
}

unsigned char SPI_WriteRead(unsigned char address, unsigned char data){
	unsigned char TxData[2], RxData[2];
	TxData[0] = address;
	TxData[1] = data;
	HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
	HAL_SPI_TransmitReceive(&hspi1, TxData, RxData, sizeof(TxData), 0xff);
	HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);
	return RxData[1];
}


void myprintf(unsigned char address, const char* format, ...) {
    char ARRAY[40];
	
	  // 使用va_list和va_start来处理可变参数
    va_list args;
    va_start(args, format);

    // 使用vsprintf将可变参数列表格式化的字符串存储到ARRAY中
    vsprintf(ARRAY, format, args);
    
    // 清理可变参数列表
    va_end(args);

    // 假设OLED_ShowString函数可以在OLED屏幕上显示字符串
    OLED_ShowString(address, (unsigned char*)ARRAY);
}

void Function_ArrayClean(unsigned char* array, uint16_t len){
  for(unsigned char i = 0; i < len; i ++) array[i] = '\0';
}

void Function_GetAdc(){
  uint16_t AdcData[2];
	float AdcValue[2];
	for(unsigned char i = 0; i < 2; i ++){
	  HAL_ADC_Start(&hadc);
		HAL_ADC_PollForConversion(&hadc, 0xff);
		AdcData[i] = HAL_ADC_GetValue(&hadc);
		AdcValue[i] = AdcData[i] * 3.30f / 4095;
	}
	HAL_ADC_Stop(&hadc);
	F1VL = FS1 / 3.0 * AdcValue[1] - 0.1 * FS1;
	F2VL = FS2 / 3.0 * AdcValue[0] - 0.1 * FS1;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){  // 按键
  //OLED_ShowString(0, "we");
	OLEDSHOW = (OLEDSHOW + 1) % 3;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  // 10ms中断一次
	
	/* 为run状态服务 */
	if(STATEADC == 2){   
		
		
		if(ADCRUNNUM % 20 == 0) Function_GetAdc();  // 按题意理解采集器在run状态才会采集且采集间隔为0.2s
    ADCRUNNUM ++;
		
		
		// 更新A的坐标
	  if(F1VL >= F2VL){
			
			DERTF1F2 = (int)((F1VL - F2VL) / 0.2);  // 记得要强转int一下,注意(int)的优先级
			if(DERTF1F2 >= 7) INDEX = 0;  // 更新A的坐标
			else INDEX = 7 - DERTF1F2;
			
		}else{
			
		  DERTF1F2 = (int)((F2VL - F1VL) / 0.2);
			if(DERTF1F2 + 7 >= 14) INDEX = 14;
			else INDEX = 7 + DERTF1F2;
			
		}
		
		if(INDEX == 0 || INDEX == 14){  // 判断AA是否在左右两边
			
			if(COUNTNUM < 500) COUNTNUM ++;
			else{  // 坚持5s,记录获胜者
				
				COUNTNUM = 0;
				ADCRUNNUM = 0;
				STATEADC = 0;
				
				if(INDEX == 0) sprintf((char* )MEMWINNER, "RP1:%.1f    ", F1VL); 
				else sprintf((char* )MEMWINNER, "RP2:%.1f ", F2VL);
				
				LEDSTATE = 1;  // 有人获胜开启LD5
				
			}
			
		}else COUNTNUM = 0;  // AA没在边缘不记时
	
	}
	
	
	
	/* 为LED闪烁服务 */
	if(LEDSTATE == 1){    
	  
		if(COUNTNUM < 500){
			if(COUNTNUM % 10 == 0) HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);  // 0.1s也就是100ms,整10倍数闪烁一次即可
			COUNTNUM ++;
		}else{
			
			COUNTNUM = 0;
			LEDSTATE = 0;
			
			HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);  // 将LD5灯关掉
			
		}
		
	}
	
}

void Function_RunStateShow(){
  for(unsigned char i = 0; i < 16; i ++) RUNSHOWARR[i] = '#';   
	RUNSHOWARR[INDEX] = 'A';
	RUNSHOWARR[INDEX + 1] = 'A';  // 填充 
	myprintf(0, "      RUN       ");
	myprintf(2, (char* )RUNSHOWARR);
}

void Function_OledShow(){
  if(OLEDSHOW == 0){
		if(STATEADC == 0){
			myprintf(0, "      Idle      ");
			myprintf(2, "#######AA#######");
		}else if(STATEADC == 1){
			myprintf(0, "      Ready     ");
			myprintf(2, "#######AA#######");
		}else if(STATEADC == 2){
			Function_RunStateShow();
		}
	}else if(OLEDSHOW == 1){
		myprintf(0, "    F1:%.1fKN    ", F1VL);
    myprintf(2, "    F2:%.1fKN    ", F2VL);		
	}else if(OLEDSHOW == 2){
		myprintf(0, "    FS1:%.1fKN   ", FS1);
		myprintf(2, "    FS2:%.1fKN   ", FS2);
		//myprintf(2, "      kkkk      ");
	}
}

void Function_PwmChange(){  // 传过来的PWM不一定能整除,选择最接近的PWM
	NEWPWM = (int)strtof((char* )LORXMSG, NULL);  // 获取要配置的新的PWM
	MAINDRT = CLK;
	for(int i = 1; i <= 65535; i ++){
	  for(int j = 1; j <= 65535; j ++){
		  
			if(i * j * NEWPWM - CLK > MAINDRT) break;  // 差值太大说明j太大
			int temp = abs(i * j * NEWPWM - CLK); 
			
			if(temp <= MAINDRT){  // 如果差值很小
				MAINDRT = temp;
				INDEXX = i;
				INDEXY = j;
			}

		}
		if(MAINDRT == 0) break;  // 能整除就没必要继续了
  }
	__HAL_TIM_SET_PRESCALER(&htim2, INDEXX - 1);
	__HAL_TIM_SET_AUTORELOAD(&htim2, INDEXY - 1);  // 修改预分频与自动重装载
	
	//myprintf(0, "MIN: %d    ", MAINDRT); 
	//myprintf(2, "NPM: %d    ",CLK / INDEXX / INDEXY);
	//myprintf(2, "%d %d", INDEXX, INDEXY);
}

void Function_LoRxMsg(){
  LORA_Rx(LORXMSG);
	//myprintf(0, LORXMSG);
	if(LORXMSG[0] == '$'){  // 切换模式
		STATEADC = (STATEADC + 1) % 3;
		//myprintf(0, "%d", STATEADC);
	}
	
	if(LORXMSG[0] == '?'){  // 发送上一次的胜利者
	  LORA_Tx(MEMWINNER, sizeof(MEMWINNER));
	}
	
	if(LORXMSG[0] >= '0' && LORXMSG[0] <= '9'){  // 传回了脉冲信号
		//myprintf(2, "%d", STATEADC);
		if(STATEADC == 0){
			Function_PwmChange();
			LORA_Tx((unsigned char* )"1", 1);
		}
		else LORA_Tx((unsigned char* )"0", 1);  // 传回报错信息 
	}
	
	if(LORXMSG[0] == 'F'){  // 修改命令
	  
		unsigned char memfs[20];
		memcpy(memfs, LORXMSG + 4, 10);
		char* q = NULL;
		float temp = strtof((char* )memfs, &q);
		if(*q != '\0') LORA_Tx((unsigned char* )"0", 1);  // 错误数据
		else if(LORXMSG[2] == '1'){
			FS1 = temp;
			LORA_Tx((unsigned char* )"1", 1);
		}else if(LORXMSG[2] == '2'){
		  FS2 = temp;
			LORA_Tx((unsigned char* )"1", 1);  // 返回成功信息
		}
		//myprintf(0, "temp: %.1f", temp);
		//myprintf(2, "F1: %.1f F2: %.1f", FS1, FS2);
	}
	
	
	
	if(LORXMSG[0] != '\0') Function_ArrayClean(LORXMSG, sizeof(LORXMSG));
}

void Function_K1K2Ctrl(){
  if(STATEADC == 0){  // 空闲
		HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
	}else if(STATEADC == 1){
		HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
		HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
	}else if(STATEADC == 2){
		HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
		HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_SET);
	}
}	

void Function_MyMain(){
	Function_LoRxMsg();
	Function_K1K2Ctrl();
	Function_OledShow();
	//myprintf(0, "%d,%c,%s,%.1fH", 20, 'a', "hello", 11.1);
	 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283

Function.h

#ifndef __FUNCTION_H__
#define __FUNCTION_H__
#include "main.h"

void OLED_Write(unsigned char type, unsigned char data);

void Function_OledInit(unsigned char ms);

void Function_MyMain();

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

void myprintf(unsigned char address, const char* format, ...);

unsigned char SPI_WriteRead(unsigned char address, unsigned char data);

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2、代码解析:

下面将对比赛中的难点进行着重分析:

在这里插入图片描述
由题意可以看出来,设备采集器应是独立于OLED显示的,也就是说OLED显示的界面不影响设备采集器的状态,同样设备采集器只会在OLED出现对应显示的时候才会对其做特定影响

怎样分开两者呢?

这里可以将设备采集器放在定时器里,而oled显示放在主函数里,首先题意明确了设备采集器的采集间隔为0.2s,获胜条件为AA在左右两端保持5s,有获胜者还要LD5闪烁5s,所以说毫无疑问可以将这些过程全部放在定时器做处理,刚好定时器是中断处理,与主函数分开

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  // 10ms中断一次
	
	/* 为run状态服务 */
	if(STATEADC == 2){   
		
		
		if(ADCRUNNUM % 20 == 0) Function_GetAdc();  // 按题意理解采集器在run状态才会采集且采集间隔为0.2s
    ADCRUNNUM ++;
		
		
		// 更新A的坐标
	  if(F1VL >= F2VL){
			
			DERTF1F2 = (int)((F1VL - F2VL) / 0.2);  // 记得要强转int一下,注意(int)的优先级
			if(DERTF1F2 >= 7) INDEX = 0;  // 更新A的坐标
			else INDEX = 7 - DERTF1F2;
			
		}else{
			
		  DERTF1F2 = (int)((F2VL - F1VL) / 0.2);
			if(DERTF1F2 + 7 >= 14) INDEX = 14;
			else INDEX = 7 + DERTF1F2;
			
		}
		
		if(INDEX == 0 || INDEX == 14){  // 判断AA是否在左右两边
			
			if(COUNTNUM < 500) COUNTNUM ++;
			else{  // 坚持5s,记录获胜者
				
				COUNTNUM = 0;
				ADCRUNNUM = 0;
				STATEADC = 0;
				
				if(INDEX == 0) sprintf((char* )MEMWINNER, "RP1:%.1f    ", F1VL); 
				else sprintf((char* )MEMWINNER, "RP2:%.1f ", F2VL);
				
				LEDSTATE = 1;  // 有人获胜开启LD5
				
			}
			
		}else COUNTNUM = 0;  // AA没在边缘不记时
	
	}
	
	
	
	/* 为LED闪烁服务 */
	if(LEDSTATE == 1){    
	  
		if(COUNTNUM < 500){
			if(COUNTNUM % 10 == 0) HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);  // 0.1s也就是100ms,整10倍数闪烁一次即可
			COUNTNUM ++;
		}else{
			
			COUNTNUM = 0;
			LEDSTATE = 0;
			
			HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);  // 将LD5灯关掉
			
		}
		
	}
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

定时器一直保持着开启,通过接收A板的信息来改变STATEADC的值,进入定时器后就能做相应操作

在这里插入图片描述
动态页面的实现逻辑其实就是填充往########填充AA,所以只需记录A的下标即可,显示的时候直接根据下标填充显示

// 更新A的坐标
	  if(F1VL >= F2VL){
			
			DERTF1F2 = (int)((F1VL - F2VL) / 0.2);  // 记得要强转int一下,注意(int)的优先级
			if(DERTF1F2 >= 7) INDEX = 0;  // 更新A的坐标
			else INDEX = 7 - DERTF1F2;
			
		}else{
			
		  DERTF1F2 = (int)((F2VL - F1VL) / 0.2);
			if(DERTF1F2 + 7 >= 14) INDEX = 14;
			else INDEX = 7 + DERTF1F2;
			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

更新部分是在定时器里更新的,填充两个A只需要记录左边一个A的下标即可右边一个A的下标就是index + 1

在这里插入图片描述

void Function_RunStateShow(){
  for(unsigned char i = 0; i < 16; i ++) RUNSHOWARR[i] = '#';   
	RUNSHOWARR[INDEX] = 'A';
	RUNSHOWARR[INDEX + 1] = 'A';  // 填充 
	myprintf(0, "      RUN       ");
	myprintf(2, (char* )RUNSHOWARR);
}

void Function_OledShow(){
  if(OLEDSHOW == 0){
		if(STATEADC == 0){
			myprintf(0, "      Idle      ");
			myprintf(2, "#######AA#######");
		}else if(STATEADC == 1){
			myprintf(0, "      Ready     ");
			myprintf(2, "#######AA#######");
		}else if(STATEADC == 2){
			Function_RunStateShow();
		}
	}else if(OLEDSHOW == 1){
		myprintf(0, "    F1:%.1fKN    ", F1VL);
    myprintf(2, "    F2:%.1fKN    ", F2VL);		
	}else if(OLEDSHOW == 2){
		myprintf(0, "    FS1:%.1fKN   ", FS1);
		myprintf(2, "    FS2:%.1fKN   ", FS2);
		//myprintf(2, "      kkkk      ");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

显示部分由两个参数控制一个是OLEDSHOW这个参数是由按键控制其值,STATADC由B端发送的数据控制

在这里插入图片描述
串口发送的数据给A板,让A板对数据做检验或初步检验,减轻B板数据处理的负担,A板检验后的数据B板能直接用数据,B板处理后又能回复给A板

在这里插入图片描述
脉冲同步,比较麻烦因为B端要同步A端脉冲不一定能完美的同步因为32M / PSC / ARR不一定等于PWM

那就只能设计一个算法让他近似等于了

void Function_PwmChange(){  // 传过来的PWM不一定能整除,选择最接近的PWM
	NEWPWM = (int)strtof((char* )LORXMSG, NULL);  // 获取要配置的新的PWM
	MAINDRT = CLK;
	for(int i = 1; i <= 65535; i ++){
	  for(int j = 1; j <= 65535; j ++){
		  
			if(i * j * NEWPWM - CLK > MAINDRT) break;  // 差值太大说明j太大
			int temp = abs(i * j * NEWPWM - CLK); 
			
			if(temp <= MAINDRT){  // 如果差值很小
				MAINDRT = temp;
				INDEXX = i;
				INDEXY = j;
			}

		}
		if(MAINDRT == 0) break;  // 能整除就没必要继续了
  }
	__HAL_TIM_SET_PRESCALER(&htim2, INDEXX - 1);
	__HAL_TIM_SET_AUTORELOAD(&htim2, INDEXY - 1);  // 修改预分频与自动重装载
	
	//myprintf(0, "MIN: %d    ", MAINDRT); 
	//myprintf(2, "NPM: %d    ",CLK / INDEXX / INDEXY);
	//myprintf(2, "%d %d", INDEXX, INDEXY);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

设计算法找到让同步的结果和预期最接近的PSC和ARR

3、总结:

总结来说这次比赛难点在于功能复杂,导致难设计,以及代码量的增加

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/689073
推荐阅读
相关标签
  

闽ICP备14008679号