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);
+};