赞
踩
这届国赛是目前为止最难一届,我赛后完完整整又做了一遍,花了我两天大概12小时,这个难度完全可以当一个stm32的期末设计,下面将对本届的题结合对应代码做重点解析
对应试题在这里:
第十五届蓝桥杯物联网试题(国赛)
1、DMA串口配置:
2、TIM3配置:
3、TIM7定时器配置:
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 */ }
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(); }
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、PWM方波配置:
2、TIM7定时器配置:
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 */ }
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); }
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
下面将对比赛中的难点进行着重分析:
由题意可以看出来,设备采集器应是独立于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灯关掉 } } }
定时器一直保持着开启,通过接收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;
}
更新部分是在定时器里更新的,填充两个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 "); } }
显示部分由两个参数控制一个是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); }
设计算法找到让同步的结果和预期最接近的PSC和ARR
总结来说这次比赛难点在于功能复杂,导致难设计,以及代码量的增加
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。