922 lines
26 KiB
C
922 lines
26 KiB
C
/* USER CODE BEGIN Header */
|
||
/**
|
||
******************************************************************************
|
||
* @file : main.c
|
||
* @brief : Main program body
|
||
******************************************************************************
|
||
* @attention
|
||
*
|
||
* Copyright (c) 2026 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 "cmsis_os.h"
|
||
|
||
/* Private includes ----------------------------------------------------------*/
|
||
/* USER CODE BEGIN Includes */
|
||
#include "hw_can.h"
|
||
#include "app_uds.h"
|
||
#include "app_iap.h"
|
||
#include "app_flash.h"
|
||
|
||
#include "stdio.h"
|
||
#include "string.h"
|
||
#if 1
|
||
#pragma import(__use_no_semihosting)
|
||
struct __FILE
|
||
{
|
||
int handle;
|
||
};
|
||
|
||
FILE __stdout;
|
||
void _sys_exit(int x)
|
||
{
|
||
x = x;
|
||
}
|
||
int fputc(int ch, FILE *f)
|
||
{
|
||
while((USART2->SR&0X40)==0);
|
||
USART2->DR = (unsigned char) ch;
|
||
return ch;
|
||
}
|
||
#endif
|
||
/* 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 ---------------------------------------------------------*/
|
||
CAN_HandleTypeDef hcan;
|
||
|
||
UART_HandleTypeDef huart2;
|
||
|
||
/* Definitions for defaultTask */
|
||
osThreadId_t defaultTaskHandle;
|
||
const osThreadAttr_t defaultTask_attributes = {
|
||
.name = "defaultTask",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityNormal,
|
||
};
|
||
/* Definitions for myTask02 */
|
||
osThreadId_t myTask02Handle;
|
||
const osThreadAttr_t myTask02_attributes = {
|
||
.name = "myTask02",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityLow,
|
||
};
|
||
/* Definitions for myTask03 */
|
||
osThreadId_t myTask03Handle;
|
||
const osThreadAttr_t myTask03_attributes = {
|
||
.name = "myTask03",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityLow,
|
||
};
|
||
/* Definitions for myTask04 */
|
||
osThreadId_t myTask04Handle;
|
||
const osThreadAttr_t myTask04_attributes = {
|
||
.name = "myTask04",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityLow,
|
||
};
|
||
/* Definitions for myTask05 */
|
||
osThreadId_t myTask05Handle;
|
||
const osThreadAttr_t myTask05_attributes = {
|
||
.name = "myTask05",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityLow,
|
||
};
|
||
/* Definitions for myTask06 */
|
||
osThreadId_t myTask06Handle;
|
||
const osThreadAttr_t myTask06_attributes = {
|
||
.name = "myTask06",
|
||
.stack_size = 128 * 4,
|
||
.priority = (osPriority_t) osPriorityLow,
|
||
};
|
||
/* Definitions for myTimer01 */
|
||
osTimerId_t myTimer01Handle;
|
||
const osTimerAttr_t myTimer01_attributes = {
|
||
.name = "myTimer01"
|
||
};
|
||
/* Definitions for myTimer02 */
|
||
osTimerId_t myTimer02Handle;
|
||
const osTimerAttr_t myTimer02_attributes = {
|
||
.name = "myTimer02"
|
||
};
|
||
/* Definitions for myMutex01 */
|
||
osMutexId_t myMutex01Handle;
|
||
const osMutexAttr_t myMutex01_attributes = {
|
||
.name = "myMutex01"
|
||
};
|
||
/* Definitions for myRecursiveMutex01 */
|
||
osMutexId_t myRecursiveMutex01Handle;
|
||
const osMutexAttr_t myRecursiveMutex01_attributes = {
|
||
.name = "myRecursiveMutex01",
|
||
.attr_bits = osMutexRecursive,
|
||
};
|
||
/* Definitions for myBinarySem01 */
|
||
osSemaphoreId_t myBinarySem01Handle;
|
||
const osSemaphoreAttr_t myBinarySem01_attributes = {
|
||
.name = "myBinarySem01"
|
||
};
|
||
/* Definitions for myBinarySem02 */
|
||
osSemaphoreId_t myBinarySem02Handle;
|
||
const osSemaphoreAttr_t myBinarySem02_attributes = {
|
||
.name = "myBinarySem02"
|
||
};
|
||
/* Definitions for myCountingSem01 */
|
||
osSemaphoreId_t myCountingSem01Handle;
|
||
const osSemaphoreAttr_t myCountingSem01_attributes = {
|
||
.name = "myCountingSem01"
|
||
};
|
||
/* Definitions for myCountingSem02 */
|
||
osSemaphoreId_t myCountingSem02Handle;
|
||
const osSemaphoreAttr_t myCountingSem02_attributes = {
|
||
.name = "myCountingSem02"
|
||
};
|
||
/* Definitions for myEvent01 */
|
||
osEventFlagsId_t myEvent01Handle;
|
||
const osEventFlagsAttr_t myEvent01_attributes = {
|
||
.name = "myEvent01"
|
||
};
|
||
/* Definitions for myEvent02 */
|
||
osEventFlagsId_t myEvent02Handle;
|
||
const osEventFlagsAttr_t myEvent02_attributes = {
|
||
.name = "myEvent02"
|
||
};
|
||
/* USER CODE BEGIN PV */
|
||
|
||
/* USER CODE END PV */
|
||
|
||
/* Private function prototypes -----------------------------------------------*/
|
||
void SystemClock_Config(void);
|
||
static void MX_GPIO_Init(void);
|
||
static void MX_USART2_UART_Init(void);
|
||
static void MX_CAN_Init(void);
|
||
void StartDefaultTask(void *argument);
|
||
void SampleTask(void *argument);
|
||
void Commtask(void *argument);
|
||
void CalcTask(void *argument);
|
||
void ProtectTask(void *argument);
|
||
void Can_Task(void *argument);
|
||
void Callback01(void *argument);
|
||
void Callback02(void *argument);
|
||
|
||
/* USER CODE BEGIN PFP */
|
||
|
||
/* USER CODE END PFP */
|
||
|
||
/* Private user code ---------------------------------------------------------*/
|
||
/* USER CODE BEGIN 0 */
|
||
/* 简化的 CAN 帧结构 */
|
||
//typedef struct {
|
||
// uint32_t id;
|
||
// uint32_t seq;
|
||
// uint8_t data[8];
|
||
// uint8_t dlc;
|
||
// uint32_t tick;
|
||
//} CanFrame_t;
|
||
|
||
/* 帧缓冲:环形缓冲区,模拟收到的帧 */
|
||
#define FRAME_BUF_SIZE 200
|
||
static CanFrame_t frame_buf[FRAME_BUF_SIZE];
|
||
static volatile uint8_t frame_write_idx = 0;
|
||
static uint8_t frame_read_idx = 0;
|
||
static volatile uint32_t frame_seq = 0; /* 帧序号,方便观察丢没丢 */
|
||
|
||
/* 模拟处理一帧 CAN 数据(耗时约 50ms) */
|
||
void parse_can_frame(CanFrame_t *frame)
|
||
{
|
||
// printf("[处理] seq=%lu id=0x%lX tick=%lu ...处理中\r\n",
|
||
// frame->seq, frame->id, frame->tick);
|
||
|
||
// printf("[完成] seq=%lu 处理完毕\r\n", frame->seq);
|
||
// osDelay(5);
|
||
}
|
||
|
||
typedef struct{
|
||
uint16_t cell_voltage;
|
||
uint16_t cell_temp;
|
||
}Cell_Data;
|
||
Cell_Data cell_data;
|
||
|
||
|
||
|
||
/* USER CODE END 0 */
|
||
|
||
/**
|
||
* @brief The application entry point.
|
||
* @retval int
|
||
*/
|
||
int main(void)
|
||
{
|
||
|
||
/* USER CODE BEGIN 1 */
|
||
/* Bootloader 启动检查: 在 HAL_Init 之前调用, 此时环境最干净
|
||
* flag=UPGRADING → 停留 Bootloader 处理 IAP
|
||
* flag=COMPLETE/NONE → 跳转 App */
|
||
uds_bootloader_check();
|
||
/* USER CODE END 1 */
|
||
|
||
/* MCU Configuration--------------------------------------------------------*/
|
||
|
||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||
HAL_Init();
|
||
|
||
/* USER CODE BEGIN Init */
|
||
/* 如果是APP编程请求进入的Bootloader, 清除编程请求标志
|
||
* (擦除参数页, Flash只能1→0无法直接写0xFFFFFFFF) */
|
||
// if (iap_check_prog_request())
|
||
// iap_clear_prog_request();
|
||
/* 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_USART2_UART_Init();
|
||
MX_CAN_Init();
|
||
|
||
__disable_irq(); // 关中断
|
||
// iap_clear_prog_request();
|
||
uint8_t ret = flash_erase_page(IAP_PARAM_ADDR); // 擦除(~30ms)
|
||
__enable_irq();
|
||
/* USER CODE BEGIN 2 */
|
||
#if 0
|
||
__HAL_RCC_GPIOB_CLK_DISABLE(); // PB3 SWO 调试用,量产关闭
|
||
|
||
/* 2. 关闭未用 GPIO 的漏电流 */
|
||
/* STM32F103 未用引脚默认浮空输入,会漏电 */
|
||
/* 设为模拟输入可消除漏电流 */
|
||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
||
/* GPIOB 所有引脚(已关时钟,但先配置再关更安全) */
|
||
GPIO_InitStruct.Pin = GPIO_PIN_All;
|
||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||
|
||
/* GPIOC 整个端口没用到,关时钟 + 模拟输入 */
|
||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||
GPIO_InitStruct.Pin = GPIO_PIN_All;
|
||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||
__HAL_RCC_GPIOC_CLK_DISABLE();
|
||
#endif
|
||
/* USER CODE END 2 */
|
||
|
||
/* Init scheduler */
|
||
osKernelInitialize();
|
||
/* Create the mutex(es) */
|
||
/* creation of myMutex01 */
|
||
myMutex01Handle = osMutexNew(&myMutex01_attributes);
|
||
|
||
/* Create the recursive mutex(es) */
|
||
/* creation of myRecursiveMutex01 */
|
||
myRecursiveMutex01Handle = osMutexNew(&myRecursiveMutex01_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_MUTEX */
|
||
/* add mutexes, ... */
|
||
/* USER CODE END RTOS_MUTEX */
|
||
|
||
/* Create the semaphores(s) */
|
||
/* creation of myBinarySem01 */
|
||
myBinarySem01Handle = osSemaphoreNew(1, 1, &myBinarySem01_attributes);
|
||
|
||
/* creation of myBinarySem02 */
|
||
myBinarySem02Handle = osSemaphoreNew(1, 1, &myBinarySem02_attributes);
|
||
|
||
/* creation of myCountingSem01 */
|
||
myCountingSem01Handle = osSemaphoreNew(200, 0, &myCountingSem01_attributes);
|
||
|
||
/* creation of myCountingSem02 */
|
||
myCountingSem02Handle = osSemaphoreNew(2, 0, &myCountingSem02_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||
/* add semaphores, ... */
|
||
/* USER CODE END RTOS_SEMAPHORES */
|
||
|
||
/* Create the timer(s) */
|
||
/* creation of myTimer01 */
|
||
myTimer01Handle = osTimerNew(Callback01, osTimerPeriodic, NULL, &myTimer01_attributes);
|
||
|
||
/* creation of myTimer02 */
|
||
myTimer02Handle = osTimerNew(Callback02, osTimerPeriodic, NULL, &myTimer02_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_TIMERS */
|
||
/* start timers, add new ones, ... */
|
||
// osTimerStart(myTimer01Handle, 10); // 50ms 一帧,和生产匹配
|
||
osTimerStart(myTimer02Handle, 500); // 50ms 一帧,和生产匹配
|
||
/* USER CODE END RTOS_TIMERS */
|
||
|
||
/* USER CODE BEGIN RTOS_QUEUES */
|
||
/* add queues, ... */
|
||
/* USER CODE END RTOS_QUEUES */
|
||
|
||
/* Create the thread(s) */
|
||
/* creation of defaultTask */
|
||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||
|
||
/* creation of myTask02 */
|
||
myTask02Handle = osThreadNew(SampleTask, NULL, &myTask02_attributes);
|
||
|
||
/* creation of myTask03 */
|
||
myTask03Handle = osThreadNew(Commtask, NULL, &myTask03_attributes);
|
||
|
||
/* creation of myTask04 */
|
||
myTask04Handle = osThreadNew(CalcTask, NULL, &myTask04_attributes);
|
||
|
||
/* creation of myTask05 */
|
||
myTask05Handle = osThreadNew(ProtectTask, NULL, &myTask05_attributes);
|
||
|
||
/* creation of myTask06 */
|
||
myTask06Handle = osThreadNew(Can_Task, NULL, &myTask06_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_THREADS */
|
||
/* add threads, ... */
|
||
/* USER CODE END RTOS_THREADS */
|
||
|
||
/* creation of myEvent01 */
|
||
myEvent01Handle = osEventFlagsNew(&myEvent01_attributes);
|
||
|
||
/* creation of myEvent02 */
|
||
myEvent02Handle = osEventFlagsNew(&myEvent02_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_EVENTS */
|
||
/* add events, ... */
|
||
/* USER CODE END RTOS_EVENTS */
|
||
|
||
/* Start scheduler */
|
||
osKernelStart();
|
||
|
||
/* We should never get here as control is now taken by the scheduler */
|
||
|
||
/* Infinite loop */
|
||
/* USER CODE BEGIN WHILE */
|
||
while (1)
|
||
{
|
||
/* USER CODE END WHILE */
|
||
|
||
/* USER CODE BEGIN 3 */
|
||
}
|
||
/* USER CODE END 3 */
|
||
}
|
||
|
||
/**
|
||
* @brief System Clock Configuration
|
||
* @retval None
|
||
*/
|
||
void SystemClock_Config(void)
|
||
{
|
||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||
|
||
/** 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.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
|
||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
|
||
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_DIV2;
|
||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||
|
||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
|
||
{
|
||
Error_Handler();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief CAN Initialization Function
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
static void MX_CAN_Init(void)
|
||
{
|
||
|
||
/* USER CODE BEGIN CAN_Init 0 */
|
||
|
||
/* USER CODE END CAN_Init 0 */
|
||
|
||
/* USER CODE BEGIN CAN_Init 1 */
|
||
|
||
/* USER CODE END CAN_Init 1 */
|
||
hcan.Instance = CAN1;
|
||
hcan.Init.Prescaler = 9;
|
||
hcan.Init.Mode = CAN_MODE_NORMAL;
|
||
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
|
||
hcan.Init.TimeSeg1 = CAN_BS1_6TQ;
|
||
hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
|
||
hcan.Init.TimeTriggeredMode = DISABLE;
|
||
hcan.Init.AutoBusOff = ENABLE;
|
||
hcan.Init.AutoWakeUp = ENABLE;
|
||
hcan.Init.AutoRetransmission = DISABLE;
|
||
hcan.Init.ReceiveFifoLocked = DISABLE;
|
||
hcan.Init.TransmitFifoPriority = DISABLE;
|
||
if (HAL_CAN_Init(&hcan) != HAL_OK)
|
||
{
|
||
Error_Handler();
|
||
}
|
||
/* USER CODE BEGIN CAN_Init 2 */
|
||
hwCanInit();
|
||
/* USER CODE END CAN_Init 2 */
|
||
|
||
}
|
||
|
||
/**
|
||
* @brief USART2 Initialization Function
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
static void MX_USART2_UART_Init(void)
|
||
{
|
||
|
||
/* USER CODE BEGIN USART2_Init 0 */
|
||
|
||
/* USER CODE END USART2_Init 0 */
|
||
|
||
/* USER CODE BEGIN USART2_Init 1 */
|
||
|
||
/* USER CODE END USART2_Init 1 */
|
||
huart2.Instance = USART2;
|
||
huart2.Init.BaudRate = 115200;
|
||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||
huart2.Init.Parity = UART_PARITY_NONE;
|
||
huart2.Init.Mode = UART_MODE_TX_RX;
|
||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart2) != HAL_OK)
|
||
{
|
||
Error_Handler();
|
||
}
|
||
/* USER CODE BEGIN USART2_Init 2 */
|
||
|
||
/* USER CODE END USART2_Init 2 */
|
||
|
||
}
|
||
|
||
/**
|
||
* @brief GPIO Initialization Function
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
static void MX_GPIO_Init(void)
|
||
{
|
||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||
/* USER CODE BEGIN MX_GPIO_Init_1 */
|
||
|
||
/* USER CODE END MX_GPIO_Init_1 */
|
||
|
||
/* GPIO Ports Clock Enable */
|
||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||
|
||
/*Configure GPIO pin Output Level */
|
||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
|
||
|
||
/*Configure GPIO pin : PA15 */
|
||
GPIO_InitStruct.Pin = GPIO_PIN_15;
|
||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||
|
||
/* USER CODE BEGIN MX_GPIO_Init_2 */
|
||
|
||
/* USER CODE END MX_GPIO_Init_2 */
|
||
}
|
||
volatile uint32_t rx_total_cnt = 0; /* 接收成功计数 */
|
||
volatile uint32_t rx_fail_cnt = 0; /* 接收失败计数(HAL_LOCK冲突) */
|
||
volatile uint32_t tx_fail_cnt = 0; /* 发送失败计数 */
|
||
/* USER CODE BEGIN 4 */
|
||
/* CAN 接收中断回调:把收到的帧存入环形缓冲并通知处理任务 */
|
||
static void can_rx_store(uint8_t fifo)
|
||
{
|
||
#if 1
|
||
CAN_RxHeaderTypeDef rx_hdr;
|
||
CanFrame_t *f = &frame_buf[frame_write_idx % FRAME_BUF_SIZE];
|
||
|
||
/* 从 FIFO 取出一帧(中断里必须立即取走,否则会溢出) */
|
||
if (HAL_CAN_GetRxMessage(&hcan, fifo, &rx_hdr, f->data) != HAL_OK){
|
||
rx_fail_cnt++;
|
||
return;
|
||
}
|
||
else {
|
||
rx_total_cnt++;
|
||
}
|
||
|
||
|
||
f->id = rx_hdr.StdId;
|
||
f->dlc = rx_hdr.DLC;
|
||
f->seq = frame_seq++;
|
||
f->tick = HAL_GetTick();
|
||
frame_write_idx++;
|
||
|
||
/* 通知处理任务(CMSIS-RTOS2 自动识别中断上下文,内部走 FromISR) */
|
||
/* 判空防抖:信号量可能尚未创建(启动瞬间) */
|
||
if (myCountingSem01Handle != NULL)
|
||
osSemaphoreRelease(myCountingSem01Handle);
|
||
#else
|
||
CAN_RxHeaderTypeDef rx_hdr;
|
||
CanFrame_t *f = &frame_buf[frame_write_idx % FRAME_BUF_SIZE];
|
||
|
||
/* 直接读FIFO寄存器,绕过HAL_LOCK */
|
||
uint8_t fifo_offset = (fifo == CAN_RX_FIFO0) ? 0 : 3;
|
||
|
||
/* 检查FIFO非空 */
|
||
if ((hcan.Instance->RF0R & CAN_RF0R_FMP0) == 0 && fifo == CAN_RX_FIFO0)
|
||
{
|
||
rx_fail_cnt++;
|
||
return;
|
||
}
|
||
if ((hcan.Instance->RF1R & CAN_RF1R_FMP1) == 0 && fifo == CAN_RX_FIFO1)
|
||
{
|
||
rx_fail_cnt++;
|
||
return;
|
||
}
|
||
|
||
/* 读标准帧ID */
|
||
if (fifo == CAN_RX_FIFO0)
|
||
{
|
||
rx_hdr.StdId = (hcan.Instance->sFIFOMailBox[0].RIR >> 21) & 0x7FF;
|
||
rx_hdr.DLC = hcan.Instance->sFIFOMailBox[0].RDTR & 0x0F;
|
||
((uint32_t*)f->data)[0] = hcan.Instance->sFIFOMailBox[0].RDLR;
|
||
((uint32_t*)f->data)[1] = hcan.Instance->sFIFOMailBox[0].RDHR;
|
||
/* 释放FIFO0 */
|
||
hcan.Instance->RF0R |= CAN_RF0R_RFOM0;
|
||
}
|
||
else
|
||
{
|
||
rx_hdr.StdId = (hcan.Instance->sFIFOMailBox[1].RIR >> 21) & 0x7FF;
|
||
rx_hdr.DLC = hcan.Instance->sFIFOMailBox[1].RDTR & 0x0F;
|
||
((uint32_t*)f->data)[0] = hcan.Instance->sFIFOMailBox[1].RDLR;
|
||
((uint32_t*)f->data)[1] = hcan.Instance->sFIFOMailBox[1].RDHR;
|
||
/* 释放FIFO1 */
|
||
hcan.Instance->RF1R |= CAN_RF1R_RFOM1;
|
||
}
|
||
rx_total_cnt++;
|
||
|
||
f->id = rx_hdr.StdId;
|
||
f->dlc = rx_hdr.DLC;
|
||
f->seq = frame_seq++;
|
||
f->tick = HAL_GetTick();
|
||
frame_write_idx++;
|
||
|
||
if (myCountingSem01Handle != NULL)
|
||
osSemaphoreRelease(myCountingSem01Handle);
|
||
#endif
|
||
}
|
||
|
||
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_def)
|
||
{
|
||
(void)hcan_def;
|
||
if(hcan_def == &hcan){
|
||
can_rx_store(CAN_RX_FIFO0);
|
||
}
|
||
}
|
||
|
||
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan_def)
|
||
{
|
||
(void)hcan_def;
|
||
if(hcan_def == &hcan){
|
||
can_rx_store(CAN_RX_FIFO1);
|
||
}
|
||
}
|
||
|
||
volatile uint32_t tx_complete_cnt_mail00 = 0;
|
||
volatile uint32_t tx_complete_cnt_mail01 = 0;
|
||
volatile uint32_t tx_complete_cnt_mail02 = 0;
|
||
|
||
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
tx_complete_cnt_mail00++;
|
||
}
|
||
|
||
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
tx_complete_cnt_mail01++;
|
||
}
|
||
|
||
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
tx_complete_cnt_mail02++;
|
||
}
|
||
void test_uds(void)
|
||
{
|
||
}
|
||
/* USER CODE END 4 */
|
||
uint32_t frame_seq_task = 0;
|
||
|
||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||
/**
|
||
* @brief Function implementing the defaultTask thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_StartDefaultTask */
|
||
void StartDefaultTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN 5 */
|
||
uint32_t can_test_id = 0x0000;
|
||
/* Infinite loop */
|
||
for(;;)
|
||
{
|
||
// ① Binary Sem:等 Timer release 后通过
|
||
// if (osSemaphoreAcquire(myBinarySem01Handle, osWaitForever) == osOK)
|
||
// {
|
||
// printf("Binary Sem acquired, tick=%lu\r\n", HAL_GetTick());
|
||
// }
|
||
|
||
// ② Counting Sem:等 Timer release 后通过
|
||
// if (osSemaphoreAcquire(myCountingSem01Handle, osWaitForever) == osOK)
|
||
// {
|
||
// printf("Counting Sem acquired, tick=%lu\r\n", HAL_GetTick());
|
||
// }
|
||
/* 阻塞等待 Counting Sem,有帧可处理才往下走 */
|
||
if (osSemaphoreAcquire(myCountingSem01Handle, osWaitForever) == osOK)
|
||
{
|
||
CanFrame_t *f = &frame_buf[frame_read_idx % FRAME_BUF_SIZE];
|
||
frame_read_idx++;
|
||
|
||
/* 打印当前积压数(max=2,超过2的会被丢弃) */
|
||
// printf(">>> 取出 seq=%lu, 当前积压=%d\r\n",
|
||
// f->seq, osSemaphoreGetCount(myCountingSem01Handle));
|
||
// can_test_id = frame_read_idx;
|
||
// uds_frame_handle(f);
|
||
// parse_can_frame(f);
|
||
// test_uds();
|
||
// if (hwCanSend(can_test_id, f->data, f->dlc))
|
||
// {
|
||
// // printf("[发送] ID=0x180 成功\r\n");
|
||
// frame_seq_task++;
|
||
// }
|
||
// else{
|
||
// printf("[发送] ID=0x181 失败\r\n");
|
||
// }
|
||
iap_process_frame(f->id,f->data,f->dlc);
|
||
|
||
}
|
||
|
||
// if(osSemaphoreAcquire(myBinarySem02Handle,osWaitForever) == osOK){
|
||
// // printf("this is BinarySem02\r\n");
|
||
// HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_15);
|
||
// }
|
||
}
|
||
/* USER CODE END 5 */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_SampleTask */
|
||
/**
|
||
* @brief Function implementing the myTask02 thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_SampleTask */
|
||
void SampleTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN SampleTask */
|
||
/* Infinite loop */
|
||
for(;;)
|
||
{
|
||
// iap_clear_prog_request();
|
||
osDelay(500);
|
||
}
|
||
/* USER CODE END SampleTask */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_Commtask */
|
||
/**
|
||
* @brief Function implementing the myTask03 thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_Commtask */
|
||
void Commtask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN Commtask */
|
||
/* Infinite loop */
|
||
for(;;)
|
||
{
|
||
// osMutexAcquire(myMutex01Handle, osWaitForever);
|
||
// // printf("cell_data.cellvoltage:%d ",cell_data.cell_voltage);
|
||
// // printf("cell_data.cell_temp:%d \r\n",cell_data.cell_temp);
|
||
// osMutexRelease(myMutex01Handle);
|
||
// osDelay(100);
|
||
}
|
||
/* USER CODE END Commtask */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_CalcTask */
|
||
/**
|
||
* @brief Function implementing the myTask04 thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_CalcTask */
|
||
void CalcTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN CalcTask */
|
||
/* Infinite loop */
|
||
for(;;)
|
||
{
|
||
// /* 等 bit0 和 bit1 都置位才唤醒 */
|
||
// osEventFlagsWait(myEvent01Handle,
|
||
// EVT_VOLTAGE_READY | EVT_TEMP_READY,
|
||
// osFlagsWaitAll, /* AND 逻辑 */
|
||
// osWaitForever);
|
||
// osMutexAcquire(myMutex01Handle, osWaitForever);
|
||
// uint16_t v = cell_data.cell_voltage;
|
||
// uint16_t t = cell_data.cell_temp;
|
||
// osMutexRelease(myMutex01Handle);
|
||
// printf("[计算] V=%d T=%d\r\n", v, t);
|
||
}
|
||
/* USER CODE END CalcTask */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_ProtectTask */
|
||
/**
|
||
* @brief Function implementing the myTask05 thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_ProtectTask */
|
||
void ProtectTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN ProtectTask */
|
||
/* Infinite loop */
|
||
for(;;)
|
||
{
|
||
/* 等 bit2/bit3/bit4 任一个置位就唤醒 */
|
||
// uint32_t flags = osEventFlagsWait(myEvent01Handle,
|
||
// EVT_OVER_VOLTAGE | EVT_OVER_TEMP | EVT_COMM_TIMEOUT,
|
||
// osFlagsWaitAny, /* OR 逻辑 */
|
||
// osWaitForever);
|
||
|
||
// if (flags & EVT_OVER_VOLTAGE)
|
||
// printf("[报警] 过压! V=%d\r\n", cell_data.cell_voltage);
|
||
// if (flags & EVT_OVER_TEMP)
|
||
// printf("[报警] 过温! T=%d\r\n", cell_data.cell_temp);
|
||
// if (flags & EVT_COMM_TIMEOUT)
|
||
// printf("[报警] 通信超时!\r\n");
|
||
}
|
||
/* USER CODE END ProtectTask */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_Can_Task */
|
||
/**
|
||
* @brief Function implementing the myTask06 thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_Can_Task */
|
||
void Can_Task(void *argument)
|
||
{
|
||
/* USER CODE BEGIN Can_Task */
|
||
uint8_t tx_data[8] = {0};
|
||
uint32_t counter = 0;
|
||
|
||
for(;;)
|
||
{
|
||
/* 周期发送 BMS 电压/温度上报帧 0x180 */
|
||
// tx_data[0] = counter++;
|
||
// tx_data[1] = cell_data.cell_voltage >> 8; /* 电压高字节 */
|
||
// tx_data[2] = cell_data.cell_voltage & 0xFF; /* 电压低字节 */
|
||
// tx_data[3] = cell_data.cell_temp >> 8; /* 温度高字节 */
|
||
// tx_data[4] = cell_data.cell_temp & 0xFF; /* 温度低字节 */
|
||
|
||
// if (hwCanSend(0x180, tx_data, 8))
|
||
// {
|
||
// // printf("[发送] ID=0x180 成功\r\n");
|
||
// }
|
||
// else
|
||
// {
|
||
// printf("[发送] ID=0x180 失败(邮箱忙)\r\n");
|
||
// }
|
||
osDelay(100); /* 100ms 发送一帧 */
|
||
}
|
||
/* USER CODE END Can_Task */
|
||
}
|
||
|
||
/* Callback01 function */
|
||
void Callback01(void *argument)
|
||
{
|
||
/* USER CODE BEGIN Callback01 */
|
||
/* 模拟收到一帧 CAN 数据 */
|
||
// CanFrame_t *f = &frame_buf[frame_write_idx % FRAME_BUF_SIZE];
|
||
// f->id = 0x180 + (frame_seq % 8); /* 模拟不同 ID */
|
||
// f->dlc = 8;
|
||
// f->seq = frame_seq;
|
||
// f->tick = HAL_GetTick();
|
||
// memset(f->data, frame_seq, 8);
|
||
// frame_write_idx++;
|
||
// frame_seq++;
|
||
// // 周期触发,给 Counting Sem 释放一次(计数 +1)
|
||
// osSemaphoreRelease(myCountingSem01Handle); // 给 Counting Sem
|
||
// osSemaphoreRelease(myBinarySem01Handle); // 给 Binary Sem
|
||
|
||
/* USER CODE END Callback01 */
|
||
}
|
||
|
||
/* Callback02 function */
|
||
void Callback02(void *argument)
|
||
{
|
||
/* USER CODE BEGIN Callback02 */
|
||
osSemaphoreRelease(myBinarySem02Handle); // 给 Counting Sem
|
||
osEventFlagsSet(myEvent01Handle, EVT_COMM_TIMEOUT);
|
||
/* USER CODE END Callback02 */
|
||
}
|
||
|
||
/**
|
||
* @brief Period elapsed callback in non blocking mode
|
||
* @note This function is called when TIM1 interrupt took place, inside
|
||
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
||
* a global variable "uwTick" used as application time base.
|
||
* @param htim : TIM handle
|
||
* @retval None
|
||
*/
|
||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||
{
|
||
/* USER CODE BEGIN Callback 0 */
|
||
|
||
/* USER CODE END Callback 0 */
|
||
if (htim->Instance == TIM1)
|
||
{
|
||
HAL_IncTick();
|
||
}
|
||
/* USER CODE BEGIN Callback 1 */
|
||
|
||
/* USER CODE END Callback 1 */
|
||
}
|
||
|
||
/**
|
||
* @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 */
|