From b8e49e29115076f107a3e650e536e11e2149c9c8 Mon Sep 17 00:00:00 2001 From: kkira Date: Thu, 18 Jun 2026 19:45:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=D0=B4=20?= =?UTF-8?q?=D0=BD=D0=B0=20C++,=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA,=20=D0=B4=D1=80=D0=B0=D0=B9=D0=B2=D0=B5=D1=80=20=D0=A1?= =?UTF-8?q?=D0=9E2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- STM32_CO2_NODE/.cproject | 2 + STM32_CO2_NODE/App/Tasks/sd_task.cpp | 39 ++-- STM32_CO2_NODE/App/Tasks/sd_task.hpp | 12 +- STM32_CO2_NODE/Core/Src/freertos.c | 18 +- STM32_CO2_NODE/Core/Src/freertos.cpp | 206 +++++------------- .../Drivers/CAN/co2_can_protocol.cpp | 0 .../Drivers/CAN/co2_can_protocol.hpp | 0 STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.cpp | 96 +++----- STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.hpp | 30 ++- 9 files changed, 137 insertions(+), 266 deletions(-) create mode 100644 STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp create mode 100644 STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp diff --git a/STM32_CO2_NODE/.cproject b/STM32_CO2_NODE/.cproject index ea94668..24c3b77 100644 --- a/STM32_CO2_NODE/.cproject +++ b/STM32_CO2_NODE/.cproject @@ -90,6 +90,7 @@ + @@ -211,4 +212,5 @@ + \ No newline at end of file diff --git a/STM32_CO2_NODE/App/Tasks/sd_task.cpp b/STM32_CO2_NODE/App/Tasks/sd_task.cpp index a2d2b9d..72cabee 100644 --- a/STM32_CO2_NODE/App/Tasks/sd_task.cpp +++ b/STM32_CO2_NODE/App/Tasks/sd_task.cpp @@ -1,27 +1,18 @@ -#include "sd_task.hpp" - -#include "queues.hpp" -#include "co2_data.hpp" #include "sdcard.hpp" +#include -static SDCard sd; - -void SDTask_Run() -{ - sd.Init(); - - CO2Data data; - - for (;;) - { - if (xQueueReceive( - g_sdQueue, - &data, - portMAX_DELAY)) - { - sd.AppendCO2( - data.timestamp, - data.ppm); - } - } +bool SDCardLogger::init() { + return (f_mount(&fs, "", 1) == FR_OK); +} + +bool SDCardLogger::write(const std::string &line) { + if (f_open(&file, "co2_log.txt", FA_OPEN_APPEND | FA_WRITE) != FR_OK) + return false; + + UINT bw; + f_write(&file, line.c_str(), line.size(), &bw); + f_write(&file, "\r\n", 2, &bw); + f_close(&file); + + return true; } diff --git a/STM32_CO2_NODE/App/Tasks/sd_task.hpp b/STM32_CO2_NODE/App/Tasks/sd_task.hpp index bba691c..5ee8e21 100644 --- a/STM32_CO2_NODE/App/Tasks/sd_task.hpp +++ b/STM32_CO2_NODE/App/Tasks/sd_task.hpp @@ -1,3 +1,13 @@ #pragma once +#include "fatfs.h" +#include -void SDTask_Run(); +class SDCardLogger { +public: + bool init(); + bool write(const std::string &line); + +private: + FIL file; + FATFS fs; +}; diff --git a/STM32_CO2_NODE/Core/Src/freertos.c b/STM32_CO2_NODE/Core/Src/freertos.c index 474823c..0ae8828 100644 --- a/STM32_CO2_NODE/Core/Src/freertos.c +++ b/STM32_CO2_NODE/Core/Src/freertos.c @@ -25,10 +25,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include "queues.hpp" -#include "co2_data.hpp" -#include "co2_task.hpp" -#include "sd_task.hpp" + /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -106,14 +103,6 @@ void MX_FREERTOS_Init(void) { /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ -g_sdQueue = xQueueCreate(10, sizeof(CO2Data)); -g_canQueue = xQueueCreate(10, sizeof(CO2Data)); - -if (g_sdQueue == NULL || g_canQueue == NULL) -{ - Error_Handler(); -} - /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ @@ -166,7 +155,10 @@ void StartSDTask(void *argument) { /* USER CODE BEGIN StartSDTask */ /* Infinite loop */ - SDTask_Run(); + for(;;) + { + osDelay(1); + } /* USER CODE END StartSDTask */ } diff --git a/STM32_CO2_NODE/Core/Src/freertos.cpp b/STM32_CO2_NODE/Core/Src/freertos.cpp index 474823c..9e7dc2b 100644 --- a/STM32_CO2_NODE/Core/Src/freertos.cpp +++ b/STM32_CO2_NODE/Core/Src/freertos.cpp @@ -1,195 +1,107 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * File Name : freertos.c - * Description : Code for freertos applications - ****************************************************************************** - * @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 "FreeRTOS.h" #include "task.h" -#include "main.h" #include "cmsis_os.h" +#include "main.h" + +#include "queue.h" -/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include "queues.hpp" #include "co2_data.hpp" +#include "queues.hpp" #include "co2_task.hpp" #include "sd_task.hpp" /* 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 Variables */ -/* USER CODE END Variables */ -/* Definitions for CO2Task */ +/* Queue handles */ +QueueHandle_t g_sdQueue = NULL; +QueueHandle_t g_canQueue = NULL; + +/* Task handles */ osThreadId_t CO2TaskHandle; -const osThreadAttr_t CO2Task_attributes = { - .name = "CO2Task", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityNormal, -}; -/* Definitions for SDTask */ osThreadId_t SDTaskHandle; -const osThreadAttr_t SDTask_attributes = { - .name = "SDTask", +osThreadId_t CANTaskHandle; + +/* Task attributes */ +const osThreadAttr_t CO2Task_attributes = +{ + .name = "CO2Task", .stack_size = 256 * 4, .priority = (osPriority_t) osPriorityNormal, }; -/* Definitions for CANTask */ -osThreadId_t CANTaskHandle; -const osThreadAttr_t CANTask_attributes = { - .name = "CANTask", - .stack_size = 128 * 4, + +const osThreadAttr_t SDTask_attributes = +{ + .name = "SDTask", + .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityNormal, }; -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN FunctionPrototypes */ - -/* USER CODE END FunctionPrototypes */ +const osThreadAttr_t CANTask_attributes = +{ + .name = "CANTask", + .stack_size = 256 * 4, + .priority = (osPriority_t) osPriorityNormal, +}; +/* Function prototypes */ void StartCO2Task(void *argument); void StartSDTask(void *argument); void StartCANTask(void *argument); -void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ - -/** - * @brief FreeRTOS initialization - * @param None - * @retval None - */ -void MX_FREERTOS_Init(void) { - /* USER CODE BEGIN Init */ - - /* USER CODE END Init */ - - /* USER CODE BEGIN RTOS_MUTEX */ - /* add mutexes, ... */ - /* USER CODE END RTOS_MUTEX */ - - /* USER CODE BEGIN RTOS_SEMAPHORES */ - /* add semaphores, ... */ - /* USER CODE END RTOS_SEMAPHORES */ - - /* USER CODE BEGIN RTOS_TIMERS */ - /* start timers, add new ones, ... */ - /* USER CODE END RTOS_TIMERS */ - - /* USER CODE BEGIN RTOS_QUEUES */ -g_sdQueue = xQueueCreate(10, sizeof(CO2Data)); -g_canQueue = xQueueCreate(10, sizeof(CO2Data)); - -if (g_sdQueue == NULL || g_canQueue == NULL) +/* FreeRTOS init ------------------------------------------------------------*/ +void MX_FREERTOS_Init(void) { - Error_Handler(); -} + /* Create queues */ + g_sdQueue = xQueueCreate(10, sizeof(CO2Data)); + g_canQueue = xQueueCreate(10, sizeof(CO2Data)); - /* add queues, ... */ - /* USER CODE END RTOS_QUEUES */ + if (g_sdQueue == NULL || g_canQueue == NULL) + { + Error_Handler(); + } - /* Create the thread(s) */ - /* creation of CO2Task */ + /* Create tasks */ CO2TaskHandle = osThreadNew(StartCO2Task, NULL, &CO2Task_attributes); - - /* creation of SDTask */ - SDTaskHandle = osThreadNew(StartSDTask, NULL, &SDTask_attributes); - - /* creation of CANTask */ + SDTaskHandle = osThreadNew(StartSDTask, NULL, &SDTask_attributes); CANTaskHandle = osThreadNew(StartCANTask, NULL, &CANTask_attributes); - - /* USER CODE BEGIN RTOS_THREADS */ - /* add threads, ... */ - /* USER CODE END RTOS_THREADS */ - - /* USER CODE BEGIN RTOS_EVENTS */ - /* add events, ... */ - /* USER CODE END RTOS_EVENTS */ - } -/* USER CODE BEGIN Header_StartCO2Task */ -/** - * @brief Function implementing the CO2Task thread. - * @param argument: Not used - * @retval None - */ -/* USER CODE END Header_StartCO2Task */ +/* ---------------- TASKS --------------------------------------------------*/ + void StartCO2Task(void *argument) { - /* USER CODE BEGIN StartCO2Task */ - /* Infinite loop */ - for(;;) + (void)argument; + + for (;;) { - osDelay(1); + CO2Task_RunOnce(); + osDelay(1000); } - /* USER CODE END StartCO2Task */ } -/* USER CODE BEGIN Header_StartSDTask */ -/** -* @brief Function implementing the SDTask thread. -* @param argument: Not used -* @retval None -*/ -/* USER CODE END Header_StartSDTask */ +/* SD Task */ void StartSDTask(void *argument) { - /* USER CODE BEGIN StartSDTask */ - /* Infinite loop */ - SDTask_Run(); - /* USER CODE END StartSDTask */ + (void)argument; + + for (;;) + { + SDTask_RunOnce(); + osDelay(10); + } } -/* USER CODE BEGIN Header_StartCANTask */ -/** -* @brief Function implementing the CANTask thread. -* @param argument: Not used -* @retval None -*/ -/* USER CODE END Header_StartCANTask */ +/* CAN Task */ void StartCANTask(void *argument) { - /* USER CODE BEGIN StartCANTask */ - /* Infinite loop */ - for(;;) + (void)argument; + + for (;;) { - osDelay(1); + /* example placeholder */ + osDelay(10); } - /* USER CODE END StartCANTask */ } - -/* Private application code --------------------------------------------------*/ -/* USER CODE BEGIN Application */ - -/* USER CODE END Application */ - diff --git a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp new file mode 100644 index 0000000..e69de29 diff --git a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp new file mode 100644 index 0000000..e69de29 diff --git a/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.cpp b/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.cpp index d5e913d..11e1de3 100644 --- a/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.cpp +++ b/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.cpp @@ -1,75 +1,43 @@ #include "mhz19c.hpp" -extern "C" -{ -#include "cmsis_os.h" -} - MHZ19C::MHZ19C(UART_HandleTypeDef* huart) - : uart_(huart) + : uart(huart) { + buildRequest(); } +void MHZ19C::buildRequest() { + txFrame[0] = 0xFF; + txFrame[1] = 0x01; + txFrame[2] = 0x86; + txFrame[3] = 0x00; + txFrame[4] = 0x00; + txFrame[5] = 0x00; + txFrame[6] = 0x00; + txFrame[7] = 0x00; + txFrame[8] = checksum(txFrame); +} -bool MHZ19C::ReadCO2(uint16_t& ppm) -{ - const uint8_t cmd[9] = - { - 0xFF, - 0x01, - 0x86, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x79 }; +uint8_t MHZ19C::checksum(uint8_t* data) { + uint8_t sum = 0; + for(int i=1;i<8;i++) sum += data[i]; + return 0xFF - sum + 1; +} - if (HAL_UART_Transmit( - uart_, - const_cast(cmd), - sizeof(cmd), - 100) != HAL_OK) - { - return false; } +void MHZ19C::requestCO2() { + HAL_UART_Transmit_DMA(uart, txFrame, 9); + HAL_UART_Receive_DMA(uart, rxFrame, 9); +} - if (HAL_UART_Receive_DMA( - uart_, - rxBuffer_, - 9) != HAL_OK) - { - return false; } +bool MHZ19C::readCO2(uint16_t &ppm) { + if(rxFrame[0] != 0xFF) return false; - osDelay(50); + ppm = (rxFrame[2] << 8) | rxFrame[3]; + return true; +} - if (rxBuffer_[0] != 0xFF || - rxBuffer_[1] != 0x86) - { - return false; } - - ppm = - (static_cast(rxBuffer_[2]) << 8) | - static_cast(rxBuffer_[3]); - - return true; } - - -bool MHZ19C::Calibrate() -{ - const uint8_t cmd[9] = - { - 0xFF, - 0x01, - 0x87, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x78 }; - - return HAL_UART_Transmit( - uart_, - (uint8_t*)cmd, - sizeof(cmd), - 100) == HAL_OK; } +void MHZ19C::calibrateZero() { + uint8_t cmd[9] = {0xFF,0x01,0x87,0,0,0,0,0,0}; + cmd[8] = checksum(cmd); + HAL_UART_Transmit(uart, cmd, 9, 100); +} diff --git a/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.hpp b/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.hpp index 6ef8347..f597b97 100644 --- a/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.hpp +++ b/STM32_CO2_NODE/Drivers/MHZ19C/mhz19c.hpp @@ -1,26 +1,22 @@ #pragma once - +#include "stm32f1xx_hal.h" #include -extern "C" -{ -#include "usart.h" -} - - -class MHZ19C -{ +class MHZ19C { public: + MHZ19C(UART_HandleTypeDef* huart); - explicit MHZ19C(UART_HandleTypeDef* huart); - - bool ReadCO2(uint16_t& ppm); - - bool Calibrate(); + void init(); + void calibrateZero(); + void requestCO2(); + bool readCO2(uint16_t &ppm); private: + UART_HandleTypeDef* uart; - UART_HandleTypeDef* uart_; + uint8_t txFrame[9]; + uint8_t rxFrame[9]; - uint8_t txBuffer_[9]; - uint8_t rxBuffer_[9]; }; + void buildRequest(); + uint8_t checksum(uint8_t* data); +};