蓝桥杯嵌入式——第十二届蓝桥杯嵌入式第一场省赛
一、赛题分析
这是刚刚过去的第十二届第一场嵌入式的省赛,也是我刚刚参加的。由于我用的是旧版,我们那个考场只测试了新版的环境,而旧版的软件环境有问题,和新版的存在冲突,耽搁了很久的时间,有点搞人心态。但是最终还是基本上把赛题的功能全部实现完了的,仅仅串口有一个小bug,就是第8辆车进去过后不能出来,其他的都没有什么问题,比赛的时候时间也做的比较久了,实在是不想再调试了,这个bug就没有管了,最后还有点担心进不了国赛,但是成绩下来那一刻,进国赛了,更加没想到还是全省前三,还是不错了。
比赛的时候,拿到赛题,就发现串口部分不是那么简单。所以,就先一步一步的把其他的模块先实现了,除了串口,其他的模块都很简单,非常中规中矩。接下来就搞串口部分,串口其实说难也不是很难,主要是比较麻烦。
我觉得在我们拿到赛题的时候,应该分模块来实现,首先看看用到了哪些模块, 再去看每一个模块,赛题的要求是什么。比如说输出PWM, 题目要求就是PA7输出2kHz,占空比20%,,只用到了一个通道,并且占空比和频率是固定的,所以直接就想到用定时器的PWM模式就行了,就不需要再去用什么OCTOGGLE模式浪费时间了。
我个人觉得,进国赛是比较简单的,只要选择题不要错的太多,就拿这一届来说,串口部分比较难,所以其他部分必须全部实现了,串口实现一部分,不要有太大的逻辑错误, 影响系统运行,应该进国赛都稳了吧。
二、问题总结
其他的模块应该都不会遇到什么大的问题,主要就是串口。我串口使用的是IDLE+RXNE来实现串口的不定长数据的接收的。
在实现串口的部分,首先要实现能够正确识别的进入以及出去,然后再注意一些细节的逻辑错误;
- 接收到正确信息的长度为22个字符,冒号的位置等等。
- 车型只有CNBR和VNBR两种
- 时间格式必须正确,并且不能出现时间的逻辑错误,如年份大于99,小时大于23等。
- 进入车辆信息和出去车辆信息要匹配,如进入和出去的车辆的ID相同,但是他们的车型不同是不应该的,因为对于同一个车的ID,它的信息一定全都是相同的。
- 出去的时间一定要晚于进入的时间。
- 整数,单位为小时, 不足 1 小时,按 1 小时统计。
下面附上串口部分的关键代码:
void substr(uint8_t* d_str,uint8_t* s_str,uint8_t locate,uint8_t length)
{
uint8_t i = 0;
for(i = 0; i < length; i++)
{
d_str[i] = s_str[locate + i];
}
d_str[length] = '\0';
}
uint8_t findLocate(void) // 找一个空闲的位置
{
uint8_t i = 0;
for(i = 0; i < 8; i++)
{
if(!car[i].notEmpty) // 如果是空闲
return i;
}
return 0xFF;
}
uint8_t isExist(uint8_t* str) // 判断车辆是否存在
{
uint8_t i = 0;
for(i = 0; i < 8; i++)
{
if(strcmp((const char*)str,(const char*)car[i].id) == 0)
{
return i; // 如果这辆车存在,则返回这辆车所在的车位i
}
}
return 0xFF; // 返回0xFF表示这辆车不存在
}
_Bool checkCmd(uint8_t* str)
{
// VNBR:D583:200202120000
// 0123456789012345678901
if(RxCounter != 22)
return 0;
if((str[0] == 'C' || str[0] == 'V') && str[1] == 'N' && str[2] == 'B' && str[3] == 'R' && str[4] == ':' && str[9] == ':')
{
uint8_t i;
for(i = 10; i < 22; i++)
{
if(str[i] > '9' || str[i] < '0')
return 0;
}
}
return 1;
}
void usart_proc(void)
{
if(RxFlag)
{
RxFlag = 0;
// 将接收到的字符串显示到LCD上面
// memset(lcd_str,0,sizeof(lcd_str));
// sprintf((char*)lcd_str,"%-20.20s",RxBuffer);
// LCD_DisplayStringLine(Line9,lcd_str);
// VNBR:D583:200202120000
// 0123456789012345678901
if(checkCmd(RxBuffer)) // 接收到的标准信息应该是22个字符,并且只有在有空闲车位的时候有效
{
uint8_t car_id[5];
uint8_t car_type[5];
uint8_t locate = 0xFF;
uint8_t year_temp,month_temp,day_temp,hour_temp,min_temp,sec_temp;
// 将字符串中时间的信息提取出来
year_temp = (RxBuffer[10] - '0') * 10 + (RxBuffer[11] - '0');
month_temp = (RxBuffer[12] - '0') * 10 + (RxBuffer[13] - '0');
day_temp = (RxBuffer[14] - '0') * 10 + (RxBuffer[15] - '0');
hour_temp = (RxBuffer[16] - '0') * 10 + (RxBuffer[17] - '0');
min_temp = (RxBuffer[18] - '0') * 10 + (RxBuffer[19] - '0');
sec_temp = (RxBuffer[20] - '0') * 10 + (RxBuffer[21] - '0');
if(year_temp > 99 || month_temp > 12 || day_temp > 31 || hour_temp > 23 || min_temp > 59 || sec_temp > 59)
{
// printf("shi jian ge shi error!\r\n");
goto SEND_ERROR;
}
substr(car_id,RxBuffer,5,4); // 将车辆的编号信息提取到car_id
substr(car_type,RxBuffer,0,4); // 将车辆的类型信息提取到car_type
locate = isExist(car_id); // 查询这辆车是否在车库从存在
if(locate != 0xFF) // 这辆车在车库中存在
{
int time_val;
printf("locate:%d,type:%s,id:%s\r\n",locate,car[locate].type,car[locate].id);
if(strcmp((const char *)car_type,(const char *)car[locate].type)) // 如果车辆的id和车辆的类型不同,则表示信息错误
{
// printf("id and type pi pei error!\r\n");
goto SEND_ERROR;
}
// 假设一年365天,一个月30天,秒为单位
time_val = (year_temp - car[locate].year_in) * 365 * 24 * 3600 + (month_temp - car[locate].month_in) * 30 * 24 * 3600 + (day_temp - car[locate].day_in) * 24 * 3600 + \
(hour_temp - car[locate].hour_in) * 3600 + (min_temp - car[locate].min_in) * 60 + (sec_temp - car[locate].sec_in);
if(time_val < 0)
{
// printf("time_val error!\r\n");
goto SEND_ERROR;
}
time_val = (time_val + 3599) / 3600; // 换算成小时,并且不足一个小时按一个小时算
// 输出计费信息
printf("%s:%s:%d:%.2f\r\n",car[locate].type,car[locate].id,time_val,time_val / 10.0 * (RxBuffer[0] == 'C'?CNBR_fee:VNBR_fee));
if(RxBuffer[0] == 'C')
CNBR_cnt--;
else if(RxBuffer[0] == 'V')
VNBR_cnt--;
memset(&car[locate],0,sizeof(car[locate])); // 将当前结构体清空
}
else // 这辆车在车库中不存在
{
uint8_t locate = findLocate(); // 找一个空闲的车位
if(locate == 0xFF) // 没有找到空闲车位
{
goto SEND_ERROR;
}
// printf("locate:%d,type:%s\r\n",locate,car[locate].type);
// 保存车辆信息
substr(car[locate].type,RxBuffer,0,4);
substr(car[locate].id,RxBuffer,5,4);
car[locate].year_in = year_temp;
car[locate].month_in = month_temp;
car[locate].day_in = day_temp;
car[locate].hour_in = hour_temp;
car[locate].min_in = min_temp;
car[locate].sec_in = sec_temp;
car[locate].notEmpty = 1; // 标记为非空闲
if(RxBuffer[0] == 'C')
CNBR_cnt++;
else if(RxBuffer[0] == 'V')
VNBR_cnt++;
}
goto CMD_YES;
}
SEND_ERROR:printf("ERROR\r\n");
CMD_YES: memset(RxBuffer,0,sizeof(RxBuffer));
RxCounter = 0;
}
}
/* 测试数据,用来测试逻辑是否有错误
1. *
VNBR:D583:200202120000
VNBR:D583:200202213205
2. *
CNBR:D593:200202120000
CNBR:D593:200203213205
3. *
VNBR:D883:200202120000
VNBR:D883:200202223205
4. *
CNBR:D588:200202120000
CNBR:D588:200202313205 会提示时间设置错误
CNBR:D588:200202223205 时间设置正确
5. *
CNBR:D580:200202120000
CNBR:D580:200202215205
6. *
VNBR:D58S:200202120000
VNBR:D58S:200203213205
7. *
CNBR:D58E:200202120000
CNBR:D58E:200204213205
8. *
CNBR:D58B:200202120000
CNBR:D58B:200205213205
9.
CNBR:D555:200202120000
CNBR:D555:200205213205
*/
三、代码(完整代码,功能全部实现,附有注释)
版权声明:本文为CSDN博主「FILWY_M」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43715171/article/details/116451070
蓝桥杯嵌入式——第十二届蓝桥杯嵌入式国赛
之前准备省赛的时候用的是旧版的STM32F103,从准备国赛开始就用新版STM32G431平台了,主要是想经过新版的准备学习一下HAL库以及CubeMX的使用。用了几天的新版,感觉新版的还是比较香,单纯从配置各个模块来说,比旧版的省太多时间了,而且速度也比较块,单纯从比赛来说,还是推荐新版,因为配置方便,调试器兼容KEIL5,KEI5比KEIL4好用太多了,也有自动补全,在写代码的时候速度也会比较快一些。不过旧版的资料确实比较多,选择也看大家。所以之后的国赛赛题都是用的新版,当前除了模块的配置外,其他的代码其实都是一样的,没多大区别,所以旧版也是可以参考我的代码。
一、赛题分析
刚刚比赛完,前两天刚出成绩。感觉这一届的难度还是挺大的,比前面的几届都要难一些。赛题更加着重逻辑考察,也考察了字符串的处理和一些小的算法。
- 在逻辑方面体现在有一些参数并不是直接告诉的,而是需要我们进行一些简单的推导,如本届的吊绳和吊臂之间的角度,这里很多人看似简单,实际还要分情况进行讨论的,再比如说角度占空比的换算,赛题是给了一个角度和占空比关系的折线图,具体换算关系则需要我们自己进行推导。
- 字符串的处理在这一次并没有多大的难度,使用strcmp即可,但是在省赛的时候,字符串的解析还是比较难的,相信有很多的人都是被搞自闭了的。
- 小的算法在这一次的赛题体现在串口方面,要求我们按照采集时间先后顺序排列输出,相当于队列的先进先出。还有就是要求我们能够实现按照从小到大的顺序排列输出。这里就涉及到排序的知识了,数据量不大,使用冒泡排序或者选择排序都是可以的。
要说赛题的难度有多大,其实也没有多大,发现都是一些基础的知识,比如说排序,这个在我们大一的C语言肯定是学过的吧。其他的比如说推导一些换算的关系,这个就是麻烦了一点,都是很简单的推导。 这些都是一些基础的知识,但是难的就是把这些知识全部集中到赛题上面,很容易出现错误,就要求我们要细致细致再细致,也有一些人,说自己功能全部都实现完了,但是最后的结果不令人满意,很大可能就是出现在细节的错误上面, 存在很多的BUG导致的。
在硬件的模块部分考察了LCD、LED、串口的不定长数据接收和发送,按键,定时器对方波频率的捕获,定时器捕获双通道的PWM的占空比,ADC等,其实老老实实准备了省赛,这些配置都是没有什么问题的。
二、CubeMX模块配置
-
LED和按键的GPIO配置
由于直接使用的考场提供的实例程序,里面的LCD以及LED的GPIO都是配置好了的,我们只需要额外再配置一下LED的使能端口,也就是PD2。与开发板按键相对应的是PB0,PB1,PB2,PA0等。
-
时钟配置
这里我使用的外部晶振,将系统时钟配置成170MHz,也可以使用HSI,其他频率也是可以的。
-
定时器TIM4配置
定时器在这里的作用就是产生1ms的中断,用于定时,用来扫描按键进行消抖,以及其他需要用到定时的模块。
还要记得打开定时器的中断, -
定时器TIM2,TIM3捕获的配置
通过PA1捕获扩展板上的方波PULS1,对应的是TIM2的CH2,通过PA6和PA7来捕获扩展板上的PWM波,对应的是TIM3的CH1和CH2。
最后不要完了打开定时器的全局中断
-
ADC的配置
通过ADC来获取光敏电阻的值的大小,使用到的是PA4,对应ADC2_IN17。
-
串口的配置
基本设置,注意波特率为9600,这是试题指定的波特率。
我使用的是串口的IDLE+DMA来接收不定长数据,这样比较方便,当然也可以有其他的方法,可以看我之前写的博客,所以这里还需要开启一个DMA用于串口的接收。
然后还要记得要打开串口的总中断,由于我们在这里用不到DMA的中断,所以直接关闭DM的中断即可。
三、部分程序分析
- 角度与占空比转换计算
使用PWM1和PWM2模拟旋转角度传感器输出信号,输出信号占空比值与角度关系如下图所示:
根据关系图可以解得:
angle_a = TIM3_IC1_Duty * 100.0 * 2.25 - 22.5;
angle_b = TIM3_IC2_Duty * 100.0 * 1.125 - 11.5;
- 模式B,通过光敏电阻来触发角度数据更新
经过的的测试如果手没有遮挡,大概读到的ADC的值为2000,如果手挡住光敏电阻大概读到的值是3000,所以这里可以取一个中间的值,当ADC的值大于2500表示有东西遮挡传感器。这个值会收到环境的影响,根据自己的测试修改即可。
还需要注意的是,不要一直让ADC进行刷新,我推荐500ms刷新一次,其实就相当于按键消抖。 - 吊绳与吊臂之间的夹角
这里其实应该分两种情况进行讨论,因为角度a的范围是0~180,所以要以吊臂的竖直为边界进行讨论。具体分析请看下图:
所以根据上面的推导,有以下的代码:
#define LED5_STATE (angle_a < 90 + angle_b) && 90 - angle_a + angle_b < 10 || (angle_a > 90 + angle_b) && angle_a - 90 - angle_b < 10
led_ctrl(LD5,LED5_STATE);
- 串口部分
void sendAngleOderByTime(float* sendBuffer)
{
uint8_t index = 0,i,upper_limit = angle_cnt;
if(angle_cnt_overflow)
{
index = angle_cnt;
upper_limit = 5;
}
for(i = 0; i < upper_limit; i++)
{
if(i != upper_limit - 1)
printf("%.1f-",sendBuffer[index]);
else
printf("%.1f",sendBuffer[index]);
index = (index + 1) % 5;
}
printf("\r\n");
}
void sendAngleBySort(float *array1)
{
float sendBuffer[20];
uint8_t i = 0,j,upper_limit;
for(i = 0; i < 5; i++)
sendBuffer[i] = array1[i];
if(angle_cnt_overflow)
upper_limit = 5;
else
upper_limit = angle_cnt;
for(i = upper_limit - 1; i > 0 && upper_limit; i--)
{
for(j = 0; j < i; j++)
{
if(sendBuffer[j] > sendBuffer[j + 1])
{
float temp;
temp = sendBuffer[j];
sendBuffer[j] = sendBuffer[j + 1];
sendBuffer[j + 1] = temp;
}
}
}
for(i = 0; i < upper_limit; i++)
{
if(i != upper_limit - 1)
printf("%.1f-",sendBuffer[i]);
else
printf("%.1f",sendBuffer[i]);
}
printf("\r\n");
}
void uart_proc(void)
{
static _Bool firstRx = 1;
if(RxFlag && firstRx)
{
firstRx = 0;
RxFlag = 0;
memset(RxBuffer,0, sizeof(RxBuffer));
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,RxBuffer,100);
return;
}
if(RxFlag)
{
RxFlag = 0;
if(strcmp((const char *)RxBuffer,"a?") == 0)
{
printf("a:%.1f\r\n",angle_a);
}
else if(strcmp((const char *)RxBuffer,"b?") == 0)
{
printf("b:%.1f\r\n",angle_b);
}
else if(strcmp((const char *)RxBuffer,"aa?") == 0)
{
printf("aa:");
sendAngleOderByTime(angle_a_buffer);
}
else if(strcmp((const char *)RxBuffer,"bb?") == 0)
{
printf("bb:");
sendAngleOderByTime(angle_b_buffer);
}
else if(strcmp((const char *)RxBuffer,"qa?") == 0)
{
printf("qa:");
sendAngleBySort(angle_a_buffer);
}
else if(strcmp((const char *)RxBuffer,"qb?") == 0)
{
printf("qb:");
sendAngleBySort(angle_b_buffer);
}
else
{
printf("error\r\n");
}
memset(RxBuffer,0, sizeof(RxBuffer));
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,RxBuffer,100);
}
}
五、main.c程序
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 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 "dma.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 */
#define DATA 0
#define PARA 1
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
__IO _Bool TRUE = 1;
uint32_t TIM2_IC2_Value1,TIM2_IC2_Value2;
uint32_t TIM2_IC2_Fre;
uint8_t TIM2_IC2_Number;
uint16_t TIM3_IC1_Value1,TIM3_IC1_Value2;
uint16_t TIM3_IC1_High,TIM3_IC1_Low;
float TIM3_IC1_Duty;
uint8_t TIM3_IC1_Number;
uint16_t TIM3_IC2_Value1,TIM3_IC2_Value2;
uint16_t TIM3_IC2_High,TIM3_IC2_Low;
float TIM3_IC2_Duty;
uint8_t TIM3_IC2_Number;
uint16_t adc_value = 0;
uint16_t adc_tick = 0;
_Bool adc_flag = 0;
uint8_t RxBuffer[100];
_Bool RxFlag = 0;
_Bool interface = DATA;
float angle_a = 0.0;
float angle_b = 0.0;
uint8_t ax = 0;
uint8_t bx = 0;
uint8_t mode = 'A';
uint16_t Pf = 1000;
uint8_t Pax = 20;
uint8_t Pbx = 20;
uint16_t Pf_temp = 1000;
uint8_t Pax_temp = 20;
uint8_t Pbx_temp = 20;
_Bool angle_flag = 0;
float angle_a_buffer[5];
float angle_b_buffer[5];
uint8_t angle_cnt = 0;
_Bool angle_cnt_overflow = 0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void key_proc(void);
void led_proc(void);
void adc_proc(void);
void lcd_proc(void);
void uart_proc(void);
void angle_proc(void);
void sendAngleBySort(float *array1);
void USER_UART_IdleCallback(UART_HandleTypeDef *huart);
void sendAngleOderByTime(float* sendBuffer);
/* 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_DMA_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
MX_ADC2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
led_init();
HAL_TIM_Base_Start_IT(&htim4);
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
HAL_ADC_Start(&hadc2);
HAL_UART_Receive_DMA(&huart1,RxBuffer,100);
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
printf("error\r\n");
printf("error\r\n");
printf("error\r\n");
while (TRUE)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
adc_proc();
led_proc();
lcd_proc();
uart_proc();
angle_proc();
}
/* 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_BOOST);
/** 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_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 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_8) != 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 */
void angle_proc(void)
{
static float angle_a_pre = 0.0;
static float angle_b_pre = 0.0;
if(angle_flag)
{
angle_flag = 0;
if(TIM3_IC1_Duty < 0.1)
angle_a = 0.0;
else if(TIM3_IC1_Duty > 0.9)
angle_a = 180.0;
else
angle_a = TIM3_IC1_Duty * 100.0 * 2.25 - 22.5;
if(TIM3_IC2_Duty < 0.1)
angle_b = 0.0;
else if(TIM3_IC2_Duty > 0.9)
angle_b = 90.0;
else
angle_b = TIM3_IC2_Duty * 100.0 * 1.125 - 11.5;
angle_a_buffer[angle_cnt] = angle_a;
angle_b_buffer[angle_cnt] = angle_b;
if(angle_cnt_overflow == 0 && angle_cnt == 4)
{
angle_cnt_overflow = 1;
}
angle_cnt = (angle_cnt + 1) % 5;
if(angle_a_pre > angle_a)
ax = angle_a_pre - angle_a;
else
ax = angle_a - angle_a_pre;
if(angle_b_pre > angle_b)
bx = angle_b_pre - angle_b;
else
bx = angle_b - angle_b_pre;
angle_a_pre = angle_a;
angle_b_pre = angle_b;
}
}
void sendAngleOderByTime(float* sendBuffer)
{
uint8_t index = 0,i,upper_limit = angle_cnt;
if(angle_cnt_overflow)
{
index = angle_cnt;
upper_limit = 5;
}
for(i = 0; i < upper_limit; i++)
{
if(i != upper_limit - 1)
printf("%.1f-",sendBuffer[index]);
else
printf("%.1f",sendBuffer[index]);
index = (index + 1) % 5;
}
printf("\r\n");
}
void sendAngleBySort(float *array1)
{
float sendBuffer[20];
uint8_t i = 0,j,upper_limit;
for(i = 0; i < 5; i++)
sendBuffer[i] = array1[i];
if(angle_cnt_overflow)
upper_limit = 5;
else
upper_limit = angle_cnt;
for(i = upper_limit - 1; i > 0 && upper_limit; i--)
{
for(j = 0; j < i; j++)
{
if(sendBuffer[j] > sendBuffer[j + 1])
{
float temp;
temp = sendBuffer[j];
sendBuffer[j] = sendBuffer[j + 1];
sendBuffer[j + 1] = temp;
}
}
}
for(i = 0; i < upper_limit; i++)
{
if(i != upper_limit - 1)
printf("%.1f-",sendBuffer[i]);
else
printf("%.1f",sendBuffer[i]);
}
printf("\r\n");
}
void uart_proc(void)
{
static _Bool firstRx = 1;
if(RxFlag && firstRx)
{
firstRx = 0;
RxFlag = 0;
memset(RxBuffer,0, sizeof(RxBuffer));
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,RxBuffer,100);
return;
}
if(RxFlag)
{
RxFlag = 0;
if(strcmp((const char *)RxBuffer,"a?") == 0)
{
printf("a:%.1f\r\n",angle_a);
}
else if(strcmp((const char *)RxBuffer,"b?") == 0)
{
printf("b:%.1f\r\n",angle_b);
}
else if(strcmp((const char *)RxBuffer,"aa?") == 0)
{
printf("aa:");
sendAngleOderByTime(angle_a_buffer);
}
else if(strcmp((const char *)RxBuffer,"bb?") == 0)
{
printf("bb:");
sendAngleOderByTime(angle_b_buffer);
}
else if(strcmp((const char *)RxBuffer,"qa?") == 0)
{
printf("qa:");
sendAngleBySort(angle_a_buffer);
}
else if(strcmp((const char *)RxBuffer,"qb?") == 0)
{
printf("qb:");
sendAngleBySort(angle_b_buffer);
}
else
{
printf("error\r\n");
}
memset(RxBuffer,0, sizeof(RxBuffer));
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,RxBuffer,100);
}
}
#define LED5_STATE (angle_a < 90 + angle_b) && 90 - angle_a + angle_b < 10 || (angle_a > 90 + angle_b) && angle_a - 90 - angle_b < 10
void led_proc(void)
{
led_ctrl(LD1,(ax > Pax));
led_ctrl(LD2,(bx > Pbx));
led_ctrl(LD3,(TIM2_IC2_Fre > Pf));
led_ctrl(LD4,(mode == 'A'));
led_ctrl(LD5,LED5_STATE);
}
void adc_proc(void)
{
if(adc_flag && mode == 'B' && interface == DATA)
{
adc_flag = 0;
HAL_ADC_Start(&hadc2);
while(HAL_ADC_PollForConversion(&hadc2,0xFF) != HAL_OK);
adc_value = HAL_ADC_GetValue(&hadc2);
HAL_ADC_Stop(&hadc2);
HAL_ADC_Start(&hadc2);
HAL_ADC_PollForConversion(&hadc2,0xFF);
if(adc_value > 2500)
angle_flag = 1;
}
}
void lcd_proc(void)
{
uint8_t lcd_str[20];
if(interface == DATA)
{
snprintf((char*)lcd_str,20," DATA ");
LCD_DisplayStringLine(Line1, lcd_str);
snprintf((char*)lcd_str,20," a:%.1f ",angle_a);
LCD_DisplayStringLine(Line2, lcd_str);
snprintf((char*)lcd_str,20," b:%.1f ",angle_b);
LCD_DisplayStringLine(Line3, lcd_str);
snprintf((char*)lcd_str,20," f:%dHz ",TIM2_IC2_Fre);
LCD_DisplayStringLine(Line4, lcd_str);
snprintf((char*)lcd_str,20," ax:%d ",ax);
LCD_DisplayStringLine(Line6, lcd_str);
snprintf((char*)lcd_str,20," bx:%d ",bx);
LCD_DisplayStringLine(Line7, lcd_str);
snprintf((char*)lcd_str,20," mode:%c ",mode);
LCD_DisplayStringLine(Line8, lcd_str);
}
else
{
snprintf((char*)lcd_str,20," PARA ");
LCD_DisplayStringLine(Line1, lcd_str);
snprintf((char*)lcd_str,20," Pax:%d ",Pax_temp);
LCD_DisplayStringLine(Line2, lcd_str);
snprintf((char*)lcd_str,20," Pbx:%d ",Pbx_temp);
LCD_DisplayStringLine(Line3, lcd_str);
snprintf((char*)lcd_str,20," f:%d ", Pf_temp );
LCD_DisplayStringLine(Line4, lcd_str);
snprintf((char*)lcd_str,20," ");
LCD_DisplayStringLine(Line6, lcd_str);
snprintf((char*)lcd_str,20," ");
LCD_DisplayStringLine(Line7, lcd_str);
snprintf((char*)lcd_str,20," ");
LCD_DisplayStringLine(Line8, lcd_str);
}
}
void key_proc(void)
{
key_refresh();
if(key_falling == B1)
{
if(interface == DATA)
{
interface = PARA;
} else
{
Pax = Pax_temp;
Pbx = Pbx_temp;
Pf = Pf_temp;
interface = DATA;
}
}
else if (key_falling == B2 && interface == PARA)
{
Pax_temp = Pax_temp % 60 + 10;
Pbx_temp = Pbx_temp % 60 + 10;
}
else if (key_falling == B3)
{
if(interface == PARA)
Pf_temp = Pf_temp % 10000 + 1000;
else
{
if(mode == 'A')
mode = 'B';
else
mode = 'A';
}
}
else if (key_falling == B4 && interface == DATA && mode == 'A')
{
angle_flag = 1;
}
}
void USER_UART_IdleCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE))
{
RxFlag = 1;
__HAL_UART_CLEAR_IDLEFLAG(huart);
}
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(TIM2_IC2_Number == 0)
{
TIM2_IC2_Value1 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_2);
TIM2_IC2_Number = 1;
}
else if(TIM2_IC2_Number == 1)
{
TIM2_IC2_Value2 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_2);
if(TIM2_IC2_Value1 > TIM2_IC2_Value2)
TIM2_IC2_Fre = 1000000 / ((0xFFFFFFFF - TIM2_IC2_Value1) + TIM2_IC2_Value2);
else
TIM2_IC2_Fre = 1000000 / (TIM2_IC2_Value2 - TIM2_IC2_Value1);
TIM2_IC2_Number = 0;
}
}
}
if(htim->Instance == TIM3)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(TIM3_IC1_Number == 0)
{
TIM3_IC1_Value1 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
TIM3_IC1_Number = 1;
}
else if(TIM3_IC1_Number == 1)
{
TIM3_IC1_Value2 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
if(TIM3_IC1_Value1 > TIM3_IC1_Value2)
TIM3_IC1_High = (0xFFFF - TIM3_IC1_Value1) + TIM3_IC1_Value2;
else
TIM3_IC1_High = TIM3_IC1_Value2 - TIM3_IC1_Value1;
TIM3_IC1_Value1 = TIM3_IC1_Value2;
TIM3_IC1_Number = 2;
}
else if(TIM3_IC1_Number == 2)
{
TIM3_IC1_Value2 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_1);
if(TIM3_IC1_Value1 > TIM3_IC1_Value2)
TIM3_IC1_Low = (0xFFFF - TIM3_IC1_Value1) + TIM3_IC1_Value2;
else
TIM3_IC1_Low = TIM3_IC1_Value2 - TIM3_IC1_Value1;
TIM3_IC1_Duty = TIM3_IC1_High * 1.0 / (TIM3_IC1_High + TIM3_IC1_Low);
TIM3_IC1_Number = 0;
}
}
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(TIM3_IC2_Number == 0)
{
TIM3_IC2_Value1 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
TIM3_IC2_Number = 1;
}
else if(TIM3_IC2_Number == 1)
{
TIM3_IC2_Value2 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
if(TIM3_IC2_Value1 > TIM3_IC2_Value2)
TIM3_IC2_High = (0xFFFF - TIM3_IC2_Value1) + TIM3_IC2_Value2;
else
TIM3_IC2_High = TIM3_IC2_Value2 - TIM3_IC2_Value1;
TIM3_IC2_Value1 = TIM3_IC2_Value2;
TIM3_IC2_Number = 2;
}
else if(TIM3_IC2_Number == 2)
{
TIM3_IC2_Value2 = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_2);
if(TIM3_IC2_Value1 > TIM3_IC2_Value2)
TIM3_IC2_Low = (0xFFFF - TIM3_IC2_Value1) + TIM3_IC2_Value2;
else
TIM3_IC2_Low = TIM3_IC2_Value2 - TIM3_IC2_Value1;
TIM3_IC2_Duty = TIM3_IC2_High * 1.0 / (TIM3_IC2_High + TIM3_IC2_Low);
TIM3_IC2_Number = 0;
}
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint16_t key_tick = 0;
if(htim->Instance == TIM4)
{
if(++key_tick == 10)
{
key_tick = 0;
key_proc();
}
if(++adc_tick == 500)
{
adc_tick = 0;
adc_flag = 1;
}
}
}
int fputc(int ch,FILE* f)
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,0xFF);
return ch;
}
/* 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****/
六、完整代码下载
版权声明:本文为CSDN博主「FILWY_M」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43715171/article/details/117767150
暂无评论