工程结构
project/
├── Core/
│ ├── Inc/
│ │ ├── can_config.h
│ │ ├── network_config.h
│ │ ├── system_config.h
│ │ ├── can_bus.h
│ │ ├── w5500_net.h
│ │ ├── sd_storage.h
│ │ ├── data_processor.h
│ │ ├── watchdog.h
│ │ └── rtos_tasks.h
│ └── Src/
│ ├── main.c
│ ├── can_bus.c
│ ├── w5500_net.c
│ ├── sd_storage.c
│ ├── data_processor.c
│ ├── watchdog.c
│ └── rtos_tasks.c
├── Drivers/
│ └── STM32F4xx_HAL_Driver/
├── Middlewares/
│ ├── Third_Party/
│ │ └── FreeRTOS/
│ └── FATFS/
└── config/
└── FreeRTOSConfig.h
1.系统配置文件 system_config.h
#ifndef __SYSTEM_CONFIG_H
#define __SYSTEM_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32f4xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
#define FIRMWARE_VERSION "V1.0.0"
#define HARDWARE_VERSION "HW-001"
#define DEBUG_ENABLED 1
#define DEBUG_UART USART3
#define DEBUG_BAUDRATE 115200
#define SYSTEM_CLOCK_FREQ 168000000
#define HSE_VALUE 8000000
#define RTOS_TICK_RATE_HZ 1000
#define RTOS_HEAP_SIZE (30 * 1024)
#define TASK_PRIORITY_IDLE 0
#define TASK_PRIORITY_LOW 1
#define TASK_PRIORITY_BELOW_NORMAL 2
#define TASK_PRIORITY_NORMAL 3
#define TASK_PRIORITY_ABOVE_NORMAL 4
#define TASK_PRIORITY_HIGH 5
#define TASK_PRIORITY_REALTIME 6
#define TASK_STACK_SMALL 256
#define TASK_STACK_MEDIUM 512
#define TASK_STACK_LARGE 1024
#define TASK_STACK_XLARGE 2048
typedef enum {
SYS_STATE_INIT = 0,
SYS_STATE_IDLE,
SYS_STATE_NORMAL,
SYS_STATE_WARNING,
SYS_STATE_ERROR,
SYS_STATE_FATAL
} SystemState_t;
typedef enum {
ERROR_NONE = 0,
ERROR_CAN_INIT_FAILED,
ERROR_CAN_FILTER_FAILED,
ERROR_CAN_TX_FAILED,
ERROR_CAN_RX_FAILED,
ERROR_W5500_INIT_FAILED,
ERROR_W5500_CONFIG_FAILED,
ERROR_W5500_TCP_CONNECT_FAILED,
ERROR_W5500_TCP_SEND_FAILED,
ERROR_SD_INIT_FAILED,
ERROR_SD_MOUNT_FAILED,
ERROR_SD_FILE_OPEN_FAILED,
ERROR_SD_FILE_WRITE_FAILED,
ERROR_SD_FILE_READ_FAILED,
ERROR_SD_FULL,
ERROR_DATA_PROCESS_FAILED,
ERROR_WATCHDOG_TIMEOUT,
ERROR_RTOS_TASK_CREATE_FAILED,
ERROR_MEMORY_ALLOC_FAILED
} ErrorCode_t;
typedef struct {
uint32_t timestamp;
SystemState_t system_state;
ErrorCode_t last_error;
uint32_t can_rx_count;
uint32_t can_tx_count;
uint32_t network_tx_count;
uint32_t sd_write_count;
uint32_t error_count;
float cpu_usage;
} SystemStatus_t;
#if DEBUG_ENABLED
#define DEBUG_PRINT(fmt, ...) \
do { \
char debug_buf[256]; \
snprintf(debug_buf, sizeof(debug_buf), "[%lu] " fmt "\r\n", HAL_GetTick(), ##__VA_ARGS__); \
HAL_UART_Transmit(&DEBUG_UART, (uint8_t*)debug_buf, strlen(debug_buf), 100); \
} while(0)
#else
#define DEBUG_PRINT(fmt, ...)
#endif
#define SYSTEM_ASSERT(expr) \
do { \
if (!(expr)) { \
DEBUG_PRINT("Assert failed: %s, line %d", __FILE__, __LINE__); \
Error_Handler(); \
} \
} while(0)
#ifdef __cplusplus
}
#endif
#endif
2. CAN总线配置文件 can_config.h
#ifndef __CAN_CONFIG_H
#define __CAN_CONFIG_H
#include "system_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CAN_INTERFACE CAN1
#define CAN_BAUDRATE 500000
#define CAN_MODE CAN_MODE_NORMAL
#define CAN_FILTER_BANK_COUNT 14
#define CAN_FILTER_MODE CAN_FILTERMODE_IDMASK
#define CAN_FILTER_SCALE CAN_FILTERSCALE_32BIT
#define CAN_FILTER_FIFO CAN_FILTER_FIFO0
typedef enum {
CAN_ID_SENSOR_TEMP = 0x100,
CAN_ID_SENSOR_PRESSURE = 0x101,
CAN_ID_SENSOR_FLOW = 0x102,
CAN_ID_SENSOR_LEVEL = 0x103,
CAN_ID_SENSOR_VIBRATION = 0x104,
CAN_ID_CMD_START = 0x200,
CAN_ID_CMD_STOP = 0x201,
CAN_ID_CMD_RESET = 0x202,
CAN_ID_CMD_CONFIG = 0x203,
CAN_ID_SYS_STATUS = 0x300,
CAN_ID_SYS_ERROR = 0x301,
CAN_ID_SYS_HEARTBEAT = 0x302,
CAN_ID_EXT_LOG_DATA = 0x18000000,
CAN_ID_EXT_DEBUG = 0x18000001
} CanMessageId_t;
typedef struct {
uint32_t id;
uint8_t data[8];
uint8_t length;
uint8_t format;
uint8_t type;
uint32_t timestamp;
} CanMessage_t;
typedef struct {
float temperature;
float pressure;
float flow_rate;
float level;
float vibration;
uint32_t sensor_status;
uint32_t timestamp;
} SensorData_t;
typedef struct {
uint32_t filter_id_high;
uint32_t filter_id_low;
uint32_t filter_mask_id_high;
uint32_t filter_mask_id_low;
uint32_t filter_fifo;
uint32_t filter_bank;
uint32_t filter_mode;
uint32_t filter_scale;
uint32_t filter_activation;
} CanFilterConfig_t;
typedef struct {
uint32_t rx_total;
uint32_t tx_total;
uint32_t rx_error;
uint32_t tx_error;
uint32_t arbitration_lost;
uint32_t bus_error;
uint32_t overflow_error;
uint32_t last_error_code;
uint32_t last_error_timestamp;
} CanStatistics_t;
#define CAN_RX_QUEUE_SIZE 100
#define CAN_TX_QUEUE_SIZE 50
#define CAN_RX_TIMEOUT_MS 10
#define CAN_TX_TIMEOUT_MS 100
#define CAN_ERROR_THRESHOLD 10
#define CAN_HEARTBEAT_INTERVAL 1000
void CAN_Config_InitFilters(void);
void CAN_Config_SetStandardFilter(uint8_t filter_bank, uint16_t id, uint16_t mask);
void CAN_Config_SetExtendedFilter(uint8_t filter_bank, uint32_t id, uint32_t mask);
ErrorCode_t CAN_Config_Validate(void);
extern const CanFilterConfig_t g_default_filters[];
extern const uint8_t g_default_filter_count;
#ifdef __cplusplus
}
#endif
#endif
3. 网络配置文件 network_config.h
#ifndef __NETWORK_CONFIG_H
#define __NETWORK_CONFIG_H
#include "system_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define W5500_SPI SPI2
#define W5500_SPI_CS_PIN GPIO_PIN_12
#define W5500_SPI_CS_PORT GPIOB
#define W5500_SPI_TIMEOUT 1000
#define W5500_SPI_CLOCK_SPEED 18000000
#define W5500_MAC_ADDRESS {0x00, 0x08, 0xDC, 0x01, 0x02, 0x03}
#define W5500_IP_ADDRESS {192, 168, 1, 100}
#define W5500_SUBNET_MASK {255, 255, 255, 0}
#define W5500_GATEWAY {192, 168, 1, 1}
#define W5500_DNS_SERVER {8, 8, 8, 8}
#define TCP_SERVER_IP "192.168.1.50"
#define TCP_SERVER_PORT 5000
#define TCP_CLIENT_PORT 6000
#define TCP_KEEPALIVE_INTERVAL 30
#define TCP_RECONNECT_INTERVAL 5000
#define TCP_SEND_TIMEOUT 5000
#define TCP_RECV_BUFFER_SIZE 2048
#define PACKET_HEADER_SIZE 8
#define PACKET_MAX_SIZE 1024
#define PACKET_QUEUE_SIZE 50
typedef enum {
PROTOCOL_RAW = 0,
PROTOCOL_JSON,
PROTOCOL_MODBUS_TCP,
PROTOCOL_CUSTOM_BINARY
} ProtocolType_t;
typedef struct __attribute__((packed)) {
uint16_t magic;
uint16_t version;
uint16_t type;
uint16_t length;
uint32_t timestamp;
uint16_t checksum;
} PacketHeader_t;
typedef struct {
uint8_t mac[6];
uint8_t ip[4];
uint8_t subnet[4];
uint8_t gateway[4];
uint8_t dns[4];
bool dhcp_enabled;
bool link_status;
bool tcp_connected;
uint32_t tx_bytes;
uint32_t rx_bytes;
uint32_t tx_packets;
uint32_t rx_packets;
uint32_t connect_count;
uint32_t disconnect_count;
uint32_t last_connect_time;
uint32_t last_error_time;
} NetworkStatus_t;
typedef struct {
uint8_t mac[6];
uint8_t ip[4];
uint8_t subnet[4];
uint8_t gateway[4];
uint8_t dns[4];
char server_ip[16];
uint16_t server_port;
uint16_t client_port;
ProtocolType_t protocol;
uint16_t packet_size;
uint32_t send_interval;
bool auto_reconnect;
uint32_t reconnect_interval;
} NetworkConfig_t;
extern const NetworkConfig_t g_default_network_config;
ErrorCode_t Network_Config_Validate(void);
void Network_Config_LoadDefaults(void);
void Network_Config_SaveToFlash(void);
void Network_Config_LoadFromFlash(void);
#ifdef __cplusplus
}
#endif
#endif
4. CAN总线驱动文件 can_bus.h
#ifndef __CAN_BUS_H
#define __CAN_BUS_H
#include "can_config.h"
#include "system_config.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
extern CAN_HandleTypeDef hcan1;
extern osMessageQueueId_t can_rx_queue;
extern osMessageQueueId_t can_tx_queue;
ErrorCode_t CAN_Init(void);
ErrorCode_t CAN_Start(void);
ErrorCode_t CAN_Stop(void);
ErrorCode_t CAN_Reset(void);
ErrorCode_t CAN_SendMessage(CanMessage_t *msg);
ErrorCode_t CAN_ReceiveMessage(CanMessage_t *msg, uint32_t timeout);
ErrorCode_t CAN_ConfigureFilters(void);
void CAN_ProcessRxFifo(CAN_HandleTypeDef *hcan, uint32_t fifo);
void CAN_ErrorCallback(CAN_HandleTypeDef *hcan);
void CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
void CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan);
void CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan);
void CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan);
void CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan);
CanStatistics_t* CAN_GetStatistics(void);
void CAN_ClearStatistics(void);
bool CAN_IsBusOff(void);
ErrorCode_t CAN_RecoverFromBusOff(void);
void CAN_SendHeartbeat(void);
void CAN_SendSystemStatus(SystemStatus_t *status);
uint32_t CAN_CalculateBaudrate(uint32_t clock_freq, uint32_t baudrate);
uint16_t CAN_CalculateCRC16(uint8_t *data, uint8_t length);
bool CAN_ValidateMessage(CanMessage_t *msg);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan);
#ifdef __cplusplus
}
#endif
#endif
5. CAN总线驱动文件 can_bus.c
#include "can_bus.h"
#include <string.h>
CAN_HandleTypeDef hcan1;
osMessageQueueId_t can_rx_queue = NULL;
osMessageQueueId_t can_tx_queue = NULL;
static CanStatistics_t can_stats = {0};
static uint32_t last_heartbeat_time = 0;
const CanFilterConfig_t g_default_filters[] = {
{
.filter_id_high = 0x100 << 5,
.filter_id_low = 0,
.filter_mask_id_high = 0x10F << 5,
.filter_mask_id_low = 0,
.filter_fifo = CAN_FILTER_FIFO0,
.filter_bank = 0,
.filter_mode = CAN_FILTERMODE_IDMASK,
.filter_scale = CAN_FILTERSCALE_32BIT,
.filter_activation = ENABLE
},
{
.filter_id_high = 0x200 << 5,
.filter_id_low = 0,
.filter_mask_id_high = 0x20F << 5,
.filter_mask_id_low = 0,
.filter_fifo = CAN_FILTER_FIFO0,
.filter_bank = 1,
.filter_mode = CAN_FILTERMODE_IDMASK,
.filter_scale = CAN_FILTERSCALE_32BIT,
.filter_activation = ENABLE
},
{
.filter_id_high = (0x18000000 >> 13) & 0xFFFF,
.filter_id_low = ((0x18000000 << 3) & 0xFFF8) | 0x04,
.filter_mask_id_high = (0x1800FFFF >> 13) & 0xFFFF,
.filter_mask_id_low = ((0x1800FFFF << 3) & 0xFFF8) | 0x04,
.filter_fifo = CAN_FILTER_FIFO1,
.filter_bank = 2,
.filter_mode = CAN_FILTERMODE_IDMASK,
.filter_scale = CAN_FILTERSCALE_32BIT,
.filter_activation = ENABLE
}
};
const uint8_t g_default_filter_count = sizeof(g_default_filters) / sizeof(g_default_filters[0]);
ErrorCode_t CAN_Init(void)
{
DEBUG_PRINT("Initializing CAN bus...");
can_rx_queue = osMessageQueueNew(CAN_RX_QUEUE_SIZE, sizeof(CanMessage_t), NULL);
can_tx_queue = osMessageQueueNew(CAN_TX_QUEUE_SIZE, sizeof(CanMessage_t), NULL);
if (can_rx_queue == NULL || can_tx_queue == NULL) {
DEBUG_PRINT("Failed to create CAN queues");
return ERROR_RTOS_TASK_CREATE_FAILED;
}
hcan1.Instance = CAN_INTERFACE;
hcan1.Init.Prescaler = CAN_CalculateBaudrate(SYSTEM_CLOCK_FREQ, CAN_BAUDRATE);
hcan1.Init.Mode = CAN_MODE;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_13TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = ENABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
DEBUG_PRINT("CAN hardware initialization failed");
return ERROR_CAN_INIT_FAILED;
}
ErrorCode_t filter_error = CAN_ConfigureFilters();
if (filter_error != ERROR_NONE) {
DEBUG_PRINT("CAN filter configuration failed");
return filter_error;
}
CAN_ClearStatistics();
DEBUG_PRINT("CAN bus initialized successfully");
return ERROR_NONE;
}
ErrorCode_t CAN_Start(void)
{
DEBUG_PRINT("Starting CAN bus...");
if (HAL_CAN_Start(&hcan1) != HAL_OK) {
DEBUG_PRINT("Failed to start CAN bus");
return ERROR_CAN_INIT_FAILED;
}
if (HAL_CAN_ActivateNotification(&hcan1,
CAN_IT_RX_FIFO0_MSG_PENDING |
CAN_IT_RX_FIFO1_MSG_PENDING |
CAN_IT_TX_MAILBOX_EMPTY |
CAN_IT_ERROR) != HAL_OK) {
DEBUG_PRINT("Failed to activate CAN notifications");
return ERROR_CAN_INIT_FAILED;
}
DEBUG_PRINT("CAN bus started successfully");
return ERROR_NONE;
}
ErrorCode_t CAN_Stop(void)
{
DEBUG_PRINT("Stopping CAN bus...");
if (HAL_CAN_Stop(&hcan1) != HAL_OK) {
DEBUG_PRINT("Failed to stop CAN bus");
return ERROR_CAN_INIT_FAILED;
}
HAL_CAN_DeactivateNotification(&hcan1, CAN_IT_ALL);
DEBUG_PRINT("CAN bus stopped");
return ERROR_NONE;
}
ErrorCode_t CAN_Reset(void)
{
DEBUG_PRINT("Resetting CAN bus...");
CAN_Stop();
osDelay(10);
ErrorCode_t error = CAN_Init();
if (error != ERROR_NONE) {
return error;
}
error = CAN_Start();
if (error != ERROR_NONE) {
return error;
}
DEBUG_PRINT("CAN bus reset successfully");
return ERROR_NONE;
}
ErrorCode_t CAN_ConfigureFilters(void)
{
DEBUG_PRINT("Configuring CAN filters...");
CAN_FilterTypeDef filter_config;
for (uint8_t i = 0; i < g_default_filter_count; i++) {
const CanFilterConfig_t *filter = &g_default_filters[i];
filter_config.FilterBank = filter->filter_bank;
filter_config.FilterMode = filter->filter_mode;
filter_config.FilterScale = filter->filter_scale;
filter_config.FilterIdHigh = filter->filter_id_high;
filter_config.FilterIdLow = filter->filter_id_low;
filter_config.FilterMaskIdHigh = filter->filter_mask_id_high;
filter_config.FilterMaskIdLow = filter->filter_mask_id_low;
filter_config.FilterFIFOAssignment = filter->filter_fifo;
filter_config.FilterActivation = filter->filter_activation;
filter_config.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan1, &filter_config) != HAL_OK) {
DEBUG_PRINT("Failed to configure filter bank %d", i);
return ERROR_CAN_FILTER_FAILED;
}
}
DEBUG_PRINT("CAN filters configured successfully");
return ERROR_NONE;
}
ErrorCode_t CAN_SendMessage(CanMessage_t *msg)
{
if (msg == NULL || !CAN_ValidateMessage(msg)) {
DEBUG_PRINT("Invalid CAN message");
return ERROR_CAN_TX_FAILED;
}
if (CAN_IsBusOff()) {
DEBUG_PRINT("CAN bus is in bus-off state");
ErrorCode_t error = CAN_RecoverFromBusOff();
if (error != ERROR_NONE) {
return error;
}
}
CAN_TxHeaderTypeDef tx_header;
uint32_t tx_mailbox;
tx_header.StdId = (msg->format == 0) ? msg->id : 0;
tx_header.ExtId = (msg->format == 1) ? msg->id : 0;
tx_header.IDE = (msg->format == 0) ? CAN_ID_STD : CAN_ID_EXT;
tx_header.RTR = (msg->type == 0) ? CAN_RTR_DATA : CAN_RTR_REMOTE;
tx_header.DLC = msg->length;
tx_header.TransmitGlobalTime = DISABLE;
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(&hcan1, &tx_header, msg->data, &tx_mailbox);
if (status == HAL_OK) {
can_stats.tx_total++;
DEBUG_PRINT("CAN message sent: ID=0x%08X, Len=%d", msg->id, msg->length);
return ERROR_NONE;
} else {
can_stats.tx_error++;
DEBUG_PRINT("Failed to send CAN message: status=%d", status);
return ERROR_CAN_TX_FAILED;
}
}
ErrorCode_t CAN_ReceiveMessage(CanMessage_t *msg, uint32_t timeout)
{
if (msg == NULL) {
return ERROR_CAN_RX_FAILED;
}
if (osMessageQueueGet(can_rx_queue, msg, NULL, timeout) == osOK) {
can_stats.rx_total++;
return ERROR_NONE;
}
return ERROR_CAN_RX_FAILED;
}
void CAN_ProcessRxFifo(CAN_HandleTypeDef *hcan, uint32_t fifo)
{
CanMessage_t rx_msg;
CAN_RxHeaderTypeDef rx_header;
while (HAL_CAN_GetRxFifoFillLevel(hcan, fifo) > 0) {
if (HAL_CAN_GetRxMessage(hcan, fifo, &rx_header, rx_msg.data) == HAL_OK) {
rx_msg.id = (rx_header.IDE == CAN_ID_STD) ? rx_header.StdId : rx_header.ExtId;
rx_msg.length = rx_header.DLC;
rx_msg.format = (rx_header.IDE == CAN_ID_STD) ? 0 : 1;
rx_msg.type = (rx_header.RTR == CAN_RTR_DATA) ? 0 : 1;
rx_msg.timestamp = HAL_GetTick();
if (osMessageQueuePut(can_rx_queue, &rx_msg, 0, 0) != osOK) {
CanMessage_t dummy;
osMessageQueueGet(can_rx_queue, &dummy, NULL, 0);
osMessageQueuePut(can_rx_queue, &rx_msg, 0, 0);
DEBUG_PRINT("CAN RX queue overflow, message dropped");
}
}
}
}
void CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{
uint32_t error_code = HAL_CAN_GetError(hcan);
if (error_code & HAL_CAN_ERROR_EWG) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Error warning");
}
if (error_code & HAL_CAN_ERROR_EPV) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Error passive");
}
if (error_code & HAL_CAN_ERROR_BOF) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Bus-off");
}
if (error_code & HAL_CAN_ERROR_STF) {
can_stats.arbitration_lost++;
DEBUG_PRINT("CAN error: Stuff error");
}
if (error_code & HAL_CAN_ERROR_FOR) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Form error");
}
if (error_code & HAL_CAN_ERROR_ACK) {
can_stats.tx_error++;
DEBUG_PRINT("CAN error: Acknowledgment error");
}
if (error_code & HAL_CAN_ERROR_BR) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Bit recessive error");
}
if (error_code & HAL_CAN_ERROR_BD) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: Bit dominant error");
}
if (error_code & HAL_CAN_ERROR_CRC) {
can_stats.bus_error++;
DEBUG_PRINT("CAN error: CRC error");
}
can_stats.last_error_code = error_code;
can_stats.last_error_timestamp = HAL_GetTick();
}
CanStatistics_t* CAN_GetStatistics(void)
{
return &can_stats;
}
void CAN_ClearStatistics(void)
{
memset(&can_stats, 0, sizeof(CanStatistics_t));
}
bool CAN_IsBusOff(void)
{
return (HAL_CAN_GetError(&hcan1) & HAL_CAN_ERROR_BOF) != 0;
}
ErrorCode_t CAN_RecoverFromBusOff(void)
{
DEBUG_PRINT("Recovering from CAN bus-off state...");
HAL_CAN_Stop(&hcan1);
osDelay(100);
ErrorCode_t error = CAN_Init();
if (error != ERROR_NONE) {
return error;
}
error = CAN_Start();
if (error != ERROR_NONE) {
return error;
}
DEBUG_PRINT("CAN bus recovered from bus-off state");
return ERROR_NONE;
}
void CAN_SendHeartbeat(void)
{
uint32_t current_time = HAL_GetTick();
if (current_time - last_heartbeat_time >= CAN_HEARTBEAT_INTERVAL) {
CanMessage_t heartbeat_msg;
heartbeat_msg.id = CAN_ID_SYS_HEARTBEAT;
heartbeat_msg.length = 4;
heartbeat_msg.format = 0;
heartbeat_msg.type = 0;
heartbeat_msg.timestamp = current_time;
memcpy(heartbeat_msg.data, ¤t_time, 4);
CAN_SendMessage(&heartbeat_msg);
last_heartbeat_time = current_time;
}
}
uint32_t CAN_CalculateBaudrate(uint32_t clock_freq, uint32_t baudrate)
{
uint32_t time_quanta = 1 + 13 + 2;
uint32_t prescaler = clock_freq / (baudrate * time_quanta);
return prescaler;
}
uint16_t CAN_CalculateCRC16(uint8_t *data, uint8_t length)
{
uint16_t crc = 0xFFFF;
for (uint8_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
bool CAN_ValidateMessage(CanMessage_t *msg)
{
if (msg == NULL) {
return false;
}
if (msg->length > 8) {
return false;
}
if (msg->format == 0) {
if (msg->id > 0x7FF) {
return false;
}
} else {
if (msg->id > 0x1FFFFFFF) {
return false;
}
}
return true;
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_ProcessRxFifo(hcan, CAN_RX_FIFO0);
}
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_ProcessRxFifo(hcan, CAN_RX_FIFO1);
}
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
{
}
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
{
}
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
{
}
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{
CAN_ErrorCallback(hcan);
}
6. W5500网络驱动文件 w5500_net.h
#ifndef __W5500_NET_H
#define __W5500_NET_H
#include "network_config.h"
#include "system_config.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
extern SPI_HandleTypeDef hspi2;
extern osMessageQueueId_t net_tx_queue;
extern osMessageQueueId_t net_rx_queue;
#define W5500_MR 0x0000
#define W5500_GAR 0x0001
#define W5500_SUBR 0x0005
#define W5500_SHAR 0x0009
#define W5500_SIPR 0x000F
#define W5500_RTR 0x0017
#define W5500_RCR 0x0019
#define SOCKET_BASE 0x0400
#define SOCKET_REG_SIZE 0x0100
#define SOCKET_MR 0x0000
#define SOCKET_CR 0x0001
#define SOCKET_IR 0x0002
#define SOCKET_SR 0x0003
#define SOCKET_PORT 0x0004
#define SOCKET_DHAR 0x0006
#define SOCKET_DIPR 0x000C
#define SOCKET_DPORT 0x0010
#define SOCKET_TX_FSR 0x0020
#define SOCKET_TX_RD 0x0022
#define SOCKET_TX_WR 0x0024
#define SOCKET_RX_RSR 0x0026
#define SOCKET_RX_RD 0x0028
#define SOCKET_RX_WR 0x002A
#define SOCKET_CMD_OPEN 0x01
#define SOCKET_CMD_LISTEN 0x02
#define SOCKET_CMD_CONNECT 0x04
#define SOCKET_CMD_DISCON 0x08
#define SOCKET_CMD_CLOSE 0x10
#define SOCKET_CMD_SEND 0x20
#define SOCKET_CMD_SEND_MAC 0x21
#define SOCKET_CMD_SEND_KEEP 0x22
#define SOCKET_CMD_RECV 0x40
#define SOCKET_CLOSED 0x00
#define SOCKET_INIT 0x13
#define SOCKET_LISTEN 0x14
#define SOCKET_ESTABLISHED 0x17
#define SOCKET_CLOSE_WAIT 0x1C
#define SOCKET_UDP 0x22
#define SOCKET_MACRAW 0x42
ErrorCode_t W5500_Init(void);
ErrorCode_t W5500_ConfigureNetwork(void);
ErrorCode_t W5500_TCPConnect(void);
ErrorCode_t W5500_TCPDisconnect(void);
ErrorCode_t W5500_TCPSend(uint8_t *data, uint16_t length);
ErrorCode_t W5500_TCPReceive(uint8_t *buffer, uint16_t *length);
bool W5500_IsConnected(void);
NetworkStatus_t* W5500_GetStatus(void);
void W5500_UpdateStatus(void);
ErrorCode_t W5500_SendPacket(PacketHeader_t *header, uint8_t *data);
ErrorCode_t W5500_ProcessTxQueue(void);
ErrorCode_t W5500_ProcessRxQueue(void);
void W5500_HandleConnection(void);
void W5500_Reset(void);
uint8_t W5500_ReadByte(uint16_t address);
void W5500_WriteByte(uint16_t address, uint8_t data);
uint16_t W5500_ReadWord(uint16_t address);
void W5500_WriteWord(uint16_t address, uint16_t data);
void W5500_ReadBuffer(uint16_t address, uint8_t *buffer, uint16_t length);
void W5500_WriteBuffer(uint16_t address, uint8_t *buffer, uint16_t length);
uint8_t W5500_GetSocketStatus(uint8_t socket);
ErrorCode_t W5500_SocketOpen(uint8_t socket, uint8_t protocol);
ErrorCode_t W5500_SocketClose(uint8_t socket);
ErrorCode_t W5500_SocketConnect(uint8_t socket, uint8_t *ip, uint16_t port);
ErrorCode_t W5500_SocketSend(uint8_t socket, uint8_t *data, uint16_t length);
ErrorCode_t W5500_SocketReceive(uint8_t socket, uint8_t *buffer, uint16_t *length);
#ifdef __cplusplus
}
#endif
#endif
7. W5500网络驱动文件 w5500_net.c
#include "w5500_net.h"
#include <string.h>
SPI_HandleTypeDef hspi2;
osMessageQueueId_t net_tx_queue = NULL;
osMessageQueueId_t net_rx_queue = NULL;
static NetworkStatus_t net_status = {0};
static NetworkConfig_t net_config;
static uint8_t socket = 0;
const NetworkConfig_t g_default_network_config = {
.mac = {0x00, 0x08, 0xDC, 0x01, 0x02, 0x03},
.ip = {192, 168, 1, 100},
.subnet = {255, 255, 255, 0},
.gateway = {192, 168, 1, 1},
.dns = {8, 8, 8, 8},
.server_ip = "192.168.1.50",
.server_port = 5000,
.client_port = 6000,
.protocol = PROTOCOL_CUSTOM_BINARY,
.packet_size = 256,
.send_interval = 100,
.auto_reconnect = true,
.reconnect_interval = 5000
};
ErrorCode_t W5500_Init(void)
{
DEBUG_PRINT("Initializing W5500...");
net_tx_queue = osMessageQueueNew(PACKET_QUEUE_SIZE, sizeof(PacketHeader_t) + PACKET_MAX_SIZE, NULL);
net_rx_queue = osMessageQueueNew(PACKET_QUEUE_SIZE, sizeof(PacketHeader_t) + PACKET_MAX_SIZE, NULL);
if (net_tx_queue == NULL || net_rx_queue == NULL) {
DEBUG_PRINT("Failed to create network queues");
return ERROR_RTOS_TASK_CREATE_FAILED;
}
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK) {
DEBUG_PRINT("SPI initialization failed");
return ERROR_W5500_INIT_FAILED;
}
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = W5500_SPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(W5500_SPI_CS_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_SET);
osDelay(100);
W5500_WriteByte(W5500_MR, 0x80);
osDelay(10);
W5500_WriteByte(W5500_MR, 0x00);
uint8_t version = W5500_ReadByte(0x0039);
if (version != 0x04) {
DEBUG_PRINT("W5500 version mismatch: 0x%02X", version);
return ERROR_W5500_INIT_FAILED;
}
memcpy(&net_config, &g_default_network_config, sizeof(NetworkConfig_t));
ErrorCode_t error = W5500_ConfigureNetwork();
if (error != ERROR_NONE) {
return error;
}
memcpy(net_status.mac, net_config.mac, 6);
memcpy(net_status.ip, net_config.ip, 4);
memcpy(net_status.subnet, net_config.subnet, 4);
memcpy(net_status.gateway, net_config.gateway, 4);
memcpy(net_status.dns, net_config.dns, 4);
net_status.dhcp_enabled = false;
net_status.link_status = true;
net_status.tcp_connected = false;
DEBUG_PRINT("W5500 initialized successfully");
DEBUG_PRINT("MAC: %02X:%02X:%02X:%02X:%02X:%02X",
net_config.mac[0], net_config.mac[1], net_config.mac[2],
net_config.mac[3], net_config.mac[4], net_config.mac[5]);
DEBUG_PRINT("IP: %d.%d.%d.%d",
net_config.ip[0], net_config.ip[1], net_config.ip[2], net_config.ip[3]);
return ERROR_NONE;
}
ErrorCode_t W5500_ConfigureNetwork(void)
{
DEBUG_PRINT("Configuring W5500 network...");
W5500_WriteBuffer(W5500_SHAR, net_config.mac, 6);
W5500_WriteBuffer(W5500_SIPR, net_config.ip, 4);
W5500_WriteBuffer(W5500_SUBR, net_config.subnet, 4);
W5500_WriteBuffer(W5500_GAR, net_config.gateway, 4);
W5500_WriteWord(W5500_RTR, 2000);
W5500_WriteByte(W5500_RCR, 8);
DEBUG_PRINT("W5500 network configured");
return ERROR_NONE;
}
ErrorCode_t W5500_TCPConnect(void)
{
DEBUG_PRINT("Establishing TCP connection...");
ErrorCode_t error = W5500_SocketOpen(socket, 0x01);
if (error != ERROR_NONE) {
return error;
}
W5500_WriteWord(SOCKET_BASE + socket * SOCKET_REG_SIZE + SOCKET_PORT, net_config.client_port);
uint8_t server_ip[4];
if (sscanf(net_config.server_ip, "%hhu.%hhu.%hhu.%hhu",
&server_ip[0], &server_ip[1], &server_ip[2], &server_ip[3]) != 4) {
DEBUG_PRINT("Invalid server IP address: %s", net_config.server_ip);
return ERROR_W5500_TCP_CONNECT_FAILED;
}
error = W5500_SocketConnect(socket, server_ip, net_config.server_port);
if (error != ERROR_NONE) {
return error;
}
uint32_t timeout = HAL_GetTick();
while (W5500_GetSocketStatus(socket) != SOCKET_ESTABLISHED) {
if (HAL_GetTick() - timeout > 5000) {
DEBUG_PRINT("TCP connection timeout");
W5500_SocketClose(socket);
return ERROR_W5500_TCP_CONNECT_FAILED;
}
osDelay(10);
}
net_status.tcp_connected = true;
net_status.connect_count++;
net_status.last_connect_time = HAL_GetTick();
DEBUG_PRINT("TCP connection established");
return ERROR_NONE;
}
ErrorCode_t W5500_TCPDisconnect(void)
{
DEBUG_PRINT("Closing TCP connection...");
ErrorCode_t error = W5500_SocketClose(socket);
if (error != ERROR_NONE) {
return error;
}
net_status.tcp_connected = false;
net_status.disconnect_count++;
DEBUG_PRINT("TCP connection closed");
return ERROR_NONE;
}
ErrorCode_t W5500_TCPSend(uint8_t *data, uint16_t length)
{
if (data == NULL || length == 0) {
return ERROR_W5500_TCP_SEND_FAILED;
}
if (!W5500_IsConnected()) {
DEBUG_PRINT("TCP not connected, cannot send data");
return ERROR_W5500_TCP_SEND_FAILED;
}
ErrorCode_t error = W5500_SocketSend(socket, data, length);
if (error == ERROR_NONE) {
net_status.tx_bytes += length;
net_status.tx_packets++;
} else {
net_status.last_error_time = HAL_GetTick();
}
return error;
}
ErrorCode_t W5500_TCPReceive(uint8_t *buffer, uint16_t *length)
{
if (buffer == NULL || length == NULL) {
return ERROR_W5500_TCP_SEND_FAILED;
}
if (!W5500_IsConnected()) {
*length = 0;
return ERROR_W5500_TCP_SEND_FAILED;
}
ErrorCode_t error = W5500_SocketReceive(socket, buffer, length);
if (error == ERROR_NONE && *length > 0) {
net_status.rx_bytes += *length;
net_status.rx_packets++;
}
return error;
}
bool W5500_IsConnected(void)
{
return net_status.tcp_connected &&
(W5500_GetSocketStatus(socket) == SOCKET_ESTABLISHED);
}
NetworkStatus_t* W5500_GetStatus(void)
{
return &net_status;
}
void W5500_UpdateStatus(void)
{
net_status.link_status = true;
if (net_status.tcp_connected) {
uint8_t status = W5500_GetSocketStatus(socket);
if (status != SOCKET_ESTABLISHED && status != SOCKET_CLOSE_WAIT) {
net_status.tcp_connected = false;
DEBUG_PRINT("TCP connection lost, status=0x%02X", status);
}
}
}
ErrorCode_t W5500_SendPacket(PacketHeader_t *header, uint8_t *data)
{
if (header == NULL) {
return ERROR_W5500_TCP_SEND_FAILED;
}
uint8_t packet[PACKET_MAX_SIZE];
uint16_t packet_size = PACKET_HEADER_SIZE + header->length;
if (packet_size > PACKET_MAX_SIZE) {
DEBUG_PRINT("Packet too large: %d > %d", packet_size, PACKET_MAX_SIZE);
return ERROR_W5500_TCP_SEND_FAILED;
}
memcpy(packet, header, PACKET_HEADER_SIZE);
if (data != NULL && header->length > 0) {
memcpy(packet + PACKET_HEADER_SIZE, data, header->length);
}
header->checksum = 0;
for (uint16_t i = 0; i < packet_size; i++) {
header->checksum += packet[i];
}
memcpy(packet, header, PACKET_HEADER_SIZE);
return W5500_TCPSend(packet, packet_size);
}
ErrorCode_t W5500_ProcessTxQueue(void)
{
uint8_t packet[PACKET_MAX_SIZE];
if (osMessageQueueGet(net_tx_queue, packet, NULL, 0) == osOK) {
PacketHeader_t *header = (PacketHeader_t *)packet;
ErrorCode_t error = W5500_SendPacket(header, packet + PACKET_HEADER_SIZE);
if (error != ERROR_NONE) {
DEBUG_PRINT("Failed to send packet from queue");
return error;
}
}
return ERROR_NONE;
}
ErrorCode_t W5500_ProcessRxQueue(void)
{
uint8_t buffer[TCP_RECV_BUFFER_SIZE];
uint16_t length = 0;
ErrorCode_t error = W5500_TCPReceive(buffer, &length);
if (error == ERROR_NONE && length > 0) {
DEBUG_PRINT("Received %d bytes from TCP", length);
if (osMessageQueuePut(net_rx_queue, buffer, 0, 0) != osOK) {
DEBUG_PRINT("Net RX queue full, data dropped");
}
}
return error;
}
void W5500_HandleConnection(void)
{
static uint32_t last_reconnect_time = 0;
uint32_t current_time = HAL_GetTick();
W5500_UpdateStatus();
if (!W5500_IsConnected()) {
if (net_config.auto_reconnect &&
(current_time - last_reconnect_time >= net_config.reconnect_interval)) {
DEBUG_PRINT("Attempting to reconnect...");
ErrorCode_t error = W5500_TCPConnect();
if (error == ERROR_NONE) {
DEBUG_PRINT("Reconnected successfully");
} else {
DEBUG_PRINT("Reconnect failed: %d", error);
last_reconnect_time = current_time;
}
}
} else {
static uint32_t last_keepalive_time = 0;
if (current_time - last_keepalive_time >= TCP_KEEPALIVE_INTERVAL * 1000) {
last_keepalive_time = current_time;
}
}
}
void W5500_Reset(void)
{
DEBUG_PRINT("Resetting W5500...");
W5500_WriteByte(W5500_MR, 0x80);
osDelay(100);
W5500_WriteByte(W5500_MR, 0x00);
osDelay(100);
W5500_ConfigureNetwork();
net_status.tcp_connected = false;
DEBUG_PRINT("W5500 reset complete");
}
uint8_t W5500_ReadByte(uint16_t address)
{
uint8_t control_byte = (address >> 8) & 0xF8;
uint8_t addr_low = address & 0xFF;
uint8_t tx_data[4] = {control_byte, addr_low, 0x00, 0x00};
uint8_t rx_data[4];
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi2, tx_data, rx_data, 4, W5500_SPI_TIMEOUT);
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_SET);
return rx_data[3];
}
void W5500_WriteByte(uint16_t address, uint8_t data)
{
uint8_t control_byte = ((address >> 8) & 0xF8) | 0x04;
uint8_t addr_low = address & 0xFF;
uint8_t tx_data[4] = {control_byte, addr_low, 0x00, data};
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, tx_data, 4, W5500_SPI_TIMEOUT);
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_SET);
}
uint16_t W5500_ReadWord(uint16_t address)
{
uint16_t value = 0;
value = W5500_ReadByte(address) << 8;
value |= W5500_ReadByte(address + 1);
return value;
}
void W5500_WriteWord(uint16_t address, uint16_t data)
{
W5500_WriteByte(address, (data >> 8) & 0xFF);
W5500_WriteByte(address + 1, data & 0xFF);
}
void W5500_ReadBuffer(uint16_t address, uint8_t *buffer, uint16_t length)
{
uint8_t control_byte = (address >> 8) & 0xF8;
uint8_t addr_low = address & 0xFF;
uint8_t tx_cmd[3] = {control_byte, addr_low, 0x00};
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, tx_cmd, 3, W5500_SPI_TIMEOUT);
HAL_SPI_Receive(&hspi2, buffer, length, W5500_SPI_TIMEOUT);
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_SET);
}
void W5500_WriteBuffer(uint16_t address, uint8_t *buffer, uint16_t length)
{
uint8_t control_byte = ((address >> 8) & 0xF8) | 0x04;
uint8_t addr_low = address & 0xFF;
uint8_t tx_cmd[3] = {control_byte, addr_low, 0x00};
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, tx_cmd, 3, W5500_SPI_TIMEOUT);
HAL_SPI_Transmit(&hspi2, buffer, length, W5500_SPI_TIMEOUT);
HAL_GPIO_WritePin(W5500_SPI_CS_PORT, W5500_SPI_CS_PIN, GPIO_PIN_SET);
}
uint8_t W5500_GetSocketStatus(uint8_t socket)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE + SOCKET_SR;
return W5500_ReadByte(reg_addr);
}
ErrorCode_t W5500_SocketOpen(uint8_t socket, uint8_t protocol)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE;
W5500_WriteByte(reg_addr + SOCKET_MR, protocol);
W5500_WriteByte(reg_addr + SOCKET_CR, SOCKET_CMD_OPEN);
osDelay(1);
while (W5500_ReadByte(reg_addr + SOCKET_CR) != 0) {
osDelay(1);
}
uint8_t status = W5500_GetSocketStatus(socket);
if (status == SOCKET_CLOSED) {
DEBUG_PRINT("Failed to open socket %d", socket);
return ERROR_W5500_CONFIG_FAILED;
}
return ERROR_NONE;
}
ErrorCode_t W5500_SocketClose(uint8_t socket)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE;
W5500_WriteByte(reg_addr + SOCKET_CR, SOCKET_CMD_CLOSE);
osDelay(1);
while (W5500_ReadByte(reg_addr + SOCKET_CR) != 0) {
osDelay(1);
}
uint32_t timeout = HAL_GetTick();
while (W5500_GetSocketStatus(socket) != SOCKET_CLOSED) {
if (HAL_GetTick() - timeout > 1000) {
DEBUG_PRINT("Socket close timeout");
return ERROR_W5500_CONFIG_FAILED;
}
osDelay(10);
}
return ERROR_NONE;
}
ErrorCode_t W5500_SocketConnect(uint8_t socket, uint8_t *ip, uint16_t port)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE;
W5500_WriteBuffer(reg_addr + SOCKET_DIPR, ip, 4);
W5500_WriteWord(reg_addr + SOCKET_DPORT, port);
W5500_WriteByte(reg_addr + SOCKET_CR, SOCKET_CMD_CONNECT);
osDelay(1);
while (W5500_ReadByte(reg_addr + SOCKET_CR) != 0) {
osDelay(1);
}
return ERROR_NONE;
}
ErrorCode_t W5500_SocketSend(uint8_t socket, uint8_t *data, uint16_t length)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE;
uint16_t free_size = W5500_ReadWord(reg_addr + SOCKET_TX_FSR);
if (free_size < length) {
DEBUG_PRINT("TX buffer full: %d < %d", free_size, length);
return ERROR_W5500_TCP_SEND_FAILED;
}
uint16_t write_ptr = W5500_ReadWord(reg_addr + SOCKET_TX_WR);
uint16_t tx_buffer_addr = 0x8000 + socket * 0x0800;
uint16_t tx_offset = write_ptr + tx_buffer_addr;
W5500_WriteBuffer(tx_offset, data, length);
write_ptr += length;
W5500_WriteWord(reg_addr + SOCKET_TX_WR, write_ptr);
W5500_WriteByte(reg_addr + SOCKET_CR, SOCKET_CMD_SEND);
osDelay(1);
while (W5500_ReadByte(reg_addr + SOCKET_CR) != 0) {
osDelay(1);
}
return ERROR_NONE;
}
ErrorCode_t W5500_SocketReceive(uint8_t socket, uint8_t *buffer, uint16_t *length)
{
uint16_t reg_addr = SOCKET_BASE + socket * SOCKET_REG_SIZE;
uint16_t data_size = W5500_ReadWord(reg_addr + SOCKET_RX_RSR);
if (data_size == 0) {
*length = 0;
return ERROR_NONE;
}
if (data_size > *length) {
data_size = *length;
}
uint16_t read_ptr = W5500_ReadWord(reg_addr + SOCKET_RX_RD);
uint16_t rx_buffer_addr = 0xC000 + socket * 0x0800;
uint16_t rx_offset = read_ptr + rx_buffer_addr;
W5500_ReadBuffer(rx_offset, buffer, data_size);
read_ptr += data_size;
W5500_WriteWord(reg_addr + SOCKET_RX_RD, read_ptr);
W5500_WriteByte(reg_addr + SOCKET_CR, SOCKET_CMD_RECV);
osDelay(1);
while (W5500_ReadByte(reg_addr + SOCKET_CR) != 0) {
osDelay(1);
}
*length = data_size;
return ERROR_NONE;
}
8. SD卡存储驱动文件 sd_storage.h
#ifndef __SD_STORAGE_H
#define __SD_STORAGE_H
#include "system_config.h"
#include "ff.h"
#include "diskio.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SD_SPI SPI1
#define SD_SPI_CS_PIN GPIO_PIN_2
#define SD_SPI_CS_PORT GPIOC
#define SD_SPI_TIMEOUT 1000
#define SD_CARD_DETECT_PIN GPIO_PIN_3
#define SD_CARD_DETECT_PORT GPIOC
#define MAX_FILES 10
#define MAX_FILENAME_LENGTH 32
#define MAX_PATH_LENGTH 128
#define FILE_BUFFER_SIZE 512
#define LOG_FILE_SIZE_LIMIT (10 * 1024 * 1024)
#define BACKUP_FILE_COUNT 5
typedef enum {
FILE_TYPE_DATA = 0,
FILE_TYPE_LOG,
FILE_TYPE_CONFIG,
FILE_TYPE_TEMP
} FileType_t;
typedef struct {
char filename[MAX_FILENAME_LENGTH];
FileType_t type;
uint32_t size;
uint32_t timestamp;
bool is_open;
FIL file_handle;
} FileInfo_t;
typedef struct {
uint32_t total_space;
uint32_t free_space;
uint32_t files_written;
uint32_t bytes_written;
uint32_t write_errors;
uint32_t last_error;
bool is_mounted;
bool card_present;
} StorageStatus_t;
typedef struct {
uint32_t timestamp;
uint16_t data_type;
uint16_t data_length;
uint8_t data[256];
} DataRecord_t;
ErrorCode_t SD_Storage_Init(void);
ErrorCode_t SD_Storage_Mount(void);
ErrorCode_t SD_Storage_Unmount(void);
bool SD_Storage_IsCardPresent(void);
bool SD_Storage_IsMounted(void);
StorageStatus_t* SD_Storage_GetStatus(void);
void SD_Storage_UpdateStatus(void);
ErrorCode_t SD_Storage_OpenFile(const char *filename, FileType_t type, FileInfo_t *file_info);
ErrorCode_t SD_Storage_CloseFile(FileInfo_t *file_info);
ErrorCode_t SD_Storage_WriteData(FileInfo_t *file_info, uint8_t *data, uint32_t size);
ErrorCode_t SD_Storage_ReadData(FileInfo_t *file_info, uint8_t *buffer, uint32_t size, uint32_t *bytes_read);
ErrorCode_t SD_Storage_Seek(FileInfo_t *file_info, uint32_t offset);
ErrorCode_t SD_Storage_Truncate(FileInfo_t *file_info);
ErrorCode_t SD_Storage_WriteLog(const char *message);
ErrorCode_t SD_Storage_WriteDataRecord(DataRecord_t *record);
ErrorCode_t SD_Storage_RotateLogs(void);
ErrorCode_t SD_Storage_CreateDirectory(const char *path);
ErrorCode_t SD_Storage_ListFiles(const char *path, char **file_list, uint32_t *count);
ErrorCode_t SD_Storage_DeleteFile(const char *filename);
ErrorCode_t SD_Storage_Format(void);
uint32_t SD_Storage_GetFreeSpace(void);
uint32_t SD_Storage_GetTotalSpace(void);
ErrorCode_t SD_Storage_CheckIntegrity(void);
void SD_Storage_CleanupOldFiles(void);
DSTATUS disk_initialize(BYTE pdrv);
DSTATUS disk_status(BYTE pdrv);
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count);
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count);
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);
#ifdef __cplusplus
}
#endif
#endif
9. SD卡存储驱动文件 sd_storage.c
#include "sd_storage.h"
#include <string.h>
#include <stdio.h>
static FATFS fatfs;
static StorageStatus_t storage_status = {0};
static char current_log_file[MAX_PATH_LENGTH] = "";
ErrorCode_t SD_Storage_Init(void)
{
DEBUG_PRINT("Initializing SD card storage...");
SPI_HandleTypeDef hspi1;
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
DEBUG_PRINT("SD SPI initialization failed");
return ERROR_SD_INIT_FAILED;
}
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = SD_SPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SD_SPI_CS_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(SD_SPI_CS_PORT, SD_SPI_CS_PIN, GPIO_PIN_SET);
GPIO_InitStruct.Pin = SD_CARD_DETECT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SD_CARD_DETECT_PORT, &GPIO_InitStruct);
memset(&storage_status, 0, sizeof(StorageStatus_t));
storage_status.card_present = SD_Storage_IsCardPresent();
if (storage_status.card_present) {
ErrorCode_t mount_error = SD_Storage_Mount();
if (mount_error != ERROR_NONE) {
DEBUG_PRINT("SD card mount failed: %d", mount_error);
return mount_error;
}
} else {
DEBUG_PRINT("SD card not present");
return ERROR_SD_INIT_FAILED;
}
SD_Storage_CreateDirectory("/data");
SD_Storage_CreateDirectory("/logs");
SD_Storage_CreateDirectory("/config");
time_t rawtime;
struct tm *timeinfo;
char timestamp[20];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", timeinfo);
snprintf(current_log_file, sizeof(current_log_file), "/logs/data_%s.csv", timestamp);
DEBUG_PRINT("SD card storage initialized successfully");
DEBUG_PRINT("Log file: %s", current_log_file);
return ERROR_NONE;
}
ErrorCode_t SD_Storage_Mount(void)
{
FRESULT fr;
fr = f_mount(&fatfs, "", 1);
if (fr != FR_OK) {
DEBUG_PRINT("Failed to mount filesystem: %d", fr);
storage_status.is_mounted = false;
return ERROR_SD_MOUNT_FAILED;
}
storage_status.is_mounted = true;
DWORD free_clusters, total_clusters;
FATFS *fs;
fr = f_getfree("", &free_clusters, &fs);
if (fr == FR_OK) {
storage_status.total_space = (fs->csize * total_clusters) / 2;
storage_status.free_space = (fs->csize * free_clusters) / 2;
}
DEBUG_PRINT("Filesystem mounted, free space: %lu KB", storage_status.free_space);
return ERROR_NONE;
}
ErrorCode_t SD_Storage_Unmount(void)
{
FRESULT fr = f_mount(NULL, "", 0);
if (fr != FR_OK) {
DEBUG_PRINT("Failed to unmount filesystem: %d", fr);
return ERROR_SD_MOUNT_FAILED;
}
storage_status.is_mounted = false;
DEBUG_PRINT("Filesystem unmounted");
return ERROR_NONE;
}
bool SD_Storage_IsCardPresent(void)
{
return (HAL_GPIO_ReadPin(SD_CARD_DETECT_PORT, SD_CARD_DETECT_PIN) == GPIO_PIN_RESET);
}
bool SD_Storage_IsMounted(void)
{
return storage_status.is_mounted;
}
StorageStatus_t* SD_Storage_GetStatus(void)
{
return &storage_status;
}
void SD_Storage_UpdateStatus(void)
{
bool card_present = SD_Storage_IsCardPresent();
if (card_present != storage_status.card_present) {
storage_status.card_present = card_present;
if (card_present) {
DEBUG_PRINT("SD card inserted");
SD_Storage_Mount();
} else {
DEBUG_PRINT("SD card removed");
SD_Storage_Unmount();
}
}
if (storage_status.is_mounted) {
DWORD free_clusters, total_clusters;
FATFS *fs;
FRESULT fr = f_getfree("", &free_clusters, &fs);
if (fr == FR_OK) {
storage_status.total_space = (fs->csize * total_clusters) / 2;
storage_status.free_space = (fs->csize * free_clusters) / 2;
}
}
}
ErrorCode_t SD_Storage_OpenFile(const char *filename, FileType_t type, FileInfo_t *file_info)
{
if (filename == NULL || file_info == NULL) {
return ERROR_SD_FILE_OPEN_FAILED;
}
if (!storage_status.is_mounted) {
DEBUG_PRINT("Filesystem not mounted");
return ERROR_SD_MOUNT_FAILED;
}
BYTE mode = FA_WRITE | FA_READ | FA_OPEN_ALWAYS;
if (type == FILE_TYPE_LOG || type == FILE_TYPE_DATA) {
mode = FA_WRITE | FA_READ | FA_OPEN_APPEND;
}
FRESULT fr = f_open(&file_info->file_handle, filename, mode);
if (fr != FR_OK) {
DEBUG_PRINT("Failed to open file %s: %d", filename, fr);
storage_status.last_error = fr;
storage_status.write_errors++;
return ERROR_SD_FILE_OPEN_FAILED;
}
strncpy(file_info->filename, filename, MAX_FILENAME_LENGTH - 1);
file_info->type = type;
file_info->is_open = true;
file_info->size = f_size(&file_info->file_handle);
file_info->timestamp = HAL_GetTick();
DEBUG_PRINT("File opened: %s, size: %lu", filename, file_info->size);
return ERROR_NONE;
}
ErrorCode_t SD_Storage_CloseFile(FileInfo_t *file_info)
{
if (file_info == NULL || !file_info->is_open) {
return ERROR_NONE;
}
FRESULT fr = f_close(&file_info->file_handle);
if (fr != FR_OK) {
DEBUG_PRINT("Failed to close file %s: %d", file_info->filename, fr);
storage_status.last_error = fr;
return ERROR_SD_FILE_WRITE_FAILED;
}
file_info->is_open = false;
DEBUG_PRINT("File closed: %s", file_info->filename);
return ERROR_NONE;
}
ErrorCode_t SD_Storage_WriteData(FileInfo_t *file_info, uint8_t *data, uint32_t size)
{
if (file_info == NULL || data == NULL || size == 0) {
return ERROR_SD_FILE_WRITE_FAILED;
}
if (!file_info->is_open) {
DEBUG_PRINT("File not open: %s", file_info->filename);
return ERROR_SD_FILE_WRITE_FAILED;
}
if (storage_status.free_space * 1024 < size) {
DEBUG_PRINT("Insufficient disk space: %lu < %lu",
storage_status.free_space * 1024, size);
return ERROR_SD_FULL;
}
UINT bytes_written;
FRESULT fr = f_write(&file_info->file_handle, data, size, &bytes_written);
if (fr != FR_OK || bytes_written != size) {
DEBUG_PRINT("Failed to write to file %s: %d, written: %u",
file_info->filename, fr, bytes_written);
storage_status.last_error = fr;
storage_status.write_errors++;
return ERROR_SD_FILE_WRITE_FAILED;
}
file_info->size += bytes_written;
storage_status.bytes_written += bytes_written;
storage_status.files_written++;
fr = f_sync(&file_info->file_handle);
if (fr != FR_OK) {
DEBUG_PRINT("Failed to sync file %s: %d", file_info->filename, fr);
}
return ERROR_NONE;
}
ErrorCode_t SD_Storage_WriteLog(const char *message)
{
if (message == NULL) {
return ERROR_SD_FILE_WRITE_FAILED;
}
if (strlen(current_log_file) > 0) {
FILINFO fno;
FRESULT fr = f_stat(current_log_file, &fno);
if (fr == FR_OK && fno.fsize > LOG_FILE_SIZE_LIMIT) {
SD_Storage_RotateLogs();
}
}
FileInfo_t log_file;
ErrorCode_t error = SD_Storage_OpenFile(current_log_file, FILE_TYPE_LOG, &log_file);
if (error != ERROR_NONE) {
return error;
}
char log_entry[256];
uint32_t timestamp = HAL_GetTick();
snprintf(log_entry, sizeof(log_entry), "[%lu] %s\r\n", timestamp, message);
error = SD_Storage_WriteData(&log_file, (uint8_t *)log_entry, strlen(log_entry));
SD_Storage_CloseFile(&log_file);
return error;
}
ErrorCode_t SD_Storage_WriteDataRecord(DataRecord_t *record)
{
if (record == NULL || record->data_length == 0) {
return ERROR_SD_FILE_WRITE_FAILED;
}
char csv_line[512];
int pos = 0;
pos += snprintf(csv_line + pos, sizeof(csv_line) - pos, "%lu,", record->timestamp);
pos += snprintf(csv_line + pos, sizeof(csv_line) - pos, "%u,", record->data_type);
for (uint16_t i = 0; i < record->data_length; i++) {
pos += snprintf(csv_line + pos, sizeof(csv_line) - pos, "%02X", record->data[i]);
}
pos += snprintf(csv_line + pos, sizeof(csv_line) - pos, "\r\n");
return SD_Storage_WriteLog(csv_line);
}
ErrorCode_t SD_Storage_RotateLogs(void)
{
DEBUG_PRINT("Rotating log files...");
if (strlen(current_log_file) > 0) {
}
time_t rawtime;
struct tm *timeinfo;
char timestamp[20];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", timeinfo);
snprintf(current_log_file, sizeof(current_log_file), "/logs/data_%s.csv", timestamp);
SD_Storage_CleanupOldFiles();
DEBUG_PRINT("New log file: %s", current_log_file);
return ERROR_NONE;
}
ErrorCode_t SD_Storage_CreateDirectory(const char *path)
{
if (path == NULL) {
return ERROR_SD_FILE_OPEN_FAILED;
}
if (!storage_status.is_mounted) {
return ERROR_SD_MOUNT_FAILED;
}
FRESULT fr = f_mkdir(path);
if (fr != FR_OK && fr != FR_EXIST) {
DEBUG_PRINT("Failed to create directory %s: %d", path, fr);
return ERROR_SD_FILE_OPEN_FAILED;
}
return ERROR_NONE;
}
uint32_t SD_Storage_GetFreeSpace(void)
{
return storage_status.free_space;
}
void SD_Storage_CleanupOldFiles(void)
{
DIR dir;
FILINFO fno;
FRESULT fr;
fr = f_opendir(&dir, "/logs");
if (fr != FR_OK) {
return;
}
uint32_t file_count = 0;
char *files[100];
while (f_readdir(&dir, &fno) == FR_OK && fno.fname[0] != 0) {
if (!(fno.fattrib & AM_DIR)) {
file_count++;
}
}
f_closedir(&dir);
if (file_count > BACKUP_FILE_COUNT) {
}
}
10. 数据处理文件 data_processor.h
#ifndef __DATA_PROCESSOR_H
#define __DATA_PROCESSOR_H
#include "can_config.h"
#include "network_config.h"
#include "sd_storage.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
#define DATA_QUEUE_SIZE 100
#define MAX_PROCESSING_TIME_MS 10
#define DATA_COMPRESSION_RATIO 0.5f
#define MAX_CACHE_SIZE (10 * 1024)
typedef enum {
DATA_TYPE_RAW_CAN = 0,
DATA_TYPE_SENSOR,
DATA_TYPE_SYSTEM_STATUS,
DATA_TYPE_EVENT_LOG,
DATA_TYPE_CONFIG,
DATA_TYPE_DIAGNOSTIC
} DataType_t;
typedef enum {
PROCESS_STATE_IDLE = 0,
PROCESS_STATE_READY,
PROCESS_STATE_PROCESSING,
PROCESS_STATE_COMPRESSING,
PROCESS_STATE_SENDING,
PROCESS_STATE_ERROR
} ProcessState_t;
typedef struct {
uint8_t *buffer;
uint32_t size;
uint32_t capacity;
uint32_t write_index;
uint32_t read_index;
osMutexId_t mutex;
} DataBuffer_t;
typedef struct {
uint32_t total_packets;
uint32_t processed_packets;
uint32_t sent_packets;
uint32_t stored_packets;
uint32_t dropped_packets;
uint32_t compression_saved;
uint32_t processing_time_max;
uint32_t processing_time_avg;
uint32_t last_error;
} ProcessorStats_t;
ErrorCode_t DataProcessor_Init(void);
ErrorCode_t DataProcessor_Start(void);
ErrorCode_t DataProcessor_Stop(void);
ErrorCode_t DataProcessor_ProcessCanMessage(CanMessage_t *msg);
ErrorCode_t DataProcessor_ProcessSensorData(SensorData_t *sensor_data);
ErrorCode_t DataProcessor_BatchProcess(void);
ErrorCode_t DataProcessor_SendToNetwork(DataBuffer_t *buffer);
ErrorCode_t DataProcessor_StoreToSD(DataBuffer_t *buffer);
ProcessorStats_t* DataProcessor_GetStats(void);
void DataProcessor_ClearStats(void);
ProcessState_t DataProcessor_GetState(void);
uint32_t DataProcessor_GetQueueSize(void);
ErrorCode_t DataBuffer_Init(DataBuffer_t *buffer, uint32_t capacity);
ErrorCode_t DataBuffer_Write(DataBuffer_t *buffer, uint8_t *data, uint32_t size);
ErrorCode_t DataBuffer_Read(DataBuffer_t *buffer, uint8_t *data, uint32_t *size);
ErrorCode_t DataBuffer_Clear(DataBuffer_t *buffer);
uint32_t DataBuffer_GetFreeSpace(DataBuffer_t *buffer);
uint32_t DataBuffer_GetUsedSpace(DataBuffer_t *buffer);
void DataBuffer_Destroy(DataBuffer_t *buffer);
ErrorCode_t DataProcessor_CompressData(uint8_t *input, uint32_t input_size,
uint8_t *output, uint32_t *output_size);
ErrorCode_t DataProcessor_FormatToJSON(uint8_t *buffer, uint32_t *size, DataType_t type);
ErrorCode_t DataProcessor_FormatToBinary(uint8_t *buffer, uint32_t *size, DataType_t type);
ErrorCode_t DataProcessor_AddTimestamp(uint8_t *buffer, uint32_t *size);
ErrorCode_t DataProcessor_CalculateChecksum(uint8_t *data, uint32_t size, uint16_t *checksum);
#ifdef __cplusplus
}
#endif
#endif
11. 看门狗驱动文件 watchdog.h
#ifndef __WATCHDOG_H
#define __WATCHDOG_H
#include "system_config.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
#define WATCHDOG_TIMEOUT_MS 10000
#define WATCHDOG_REFRESH_INTERVAL 1000
#define WATCHDOG_TASK_COUNT 5
typedef struct {
char task_name[16];
osThreadId_t task_id;
uint32_t last_alive_time;
uint32_t check_interval;
uint32_t max_miss_count;
uint32_t miss_count;
bool is_enabled;
} TaskMonitor_t;
typedef enum {
WATCHDOG_DISABLED = 0,
WATCHDOG_ENABLED,
WATCHDOG_TRIGGERED,
WATCHDOG_RECOVERING
} WatchdogState_t;
typedef struct {
WatchdogState_t state;
uint32_t reset_count;
uint32_t last_reset_time;
uint32_t last_refresh_time;
uint32_t task_timeout_count;
uint32_t recovery_count;
uint32_t max_recovery_time;
} WatchdogStats_t;
ErrorCode_t Watchdog_Init(void);
ErrorCode_t Watchdog_Start(void);
ErrorCode_t Watchdog_Stop(void);
ErrorCode_t Watchdog_Refresh(void);
WatchdogState_t Watchdog_GetState(void);
WatchdogStats_t* Watchdog_GetStats(void);
ErrorCode_t Watchdog_RegisterTask(const char *task_name, osThreadId_t task_id,
uint32_t check_interval, uint32_t max_miss_count);
ErrorCode_t Watchdog_UnregisterTask(const char *task_name);
ErrorCode_t Watchdog_TaskAlive(const char *task_name);
void Watchdog_CheckTasks(void);
void Watchdog_MonitorSystemResources(void);
bool Watchdog_CheckSystemHealth(void);
ErrorCode_t Watchdog_RecoverSystem(void);
void Watchdog_SystemReset(void);
ErrorCode_t IWDG_Init(uint32_t timeout_ms);
ErrorCode_t IWDG_Refresh(void);
ErrorCode_t IWDG_Start(void);
ErrorCode_t IWDG_Stop(void);
ErrorCode_t WWDG_Init(uint32_t timeout_ms);
ErrorCode_t WWDG_Refresh(void);
#ifdef __cplusplus
}
#endif
#endif
12. FreeRTOS任务管理文件 rtos_tasks.h
#ifndef __RTOS_TASKS_H
#define __RTOS_TASKS_H
#include "system_config.h"
#include "cmsis_os.h"
#ifdef __cplusplus
extern "C" {
#endif
extern osThreadId_t canRxTaskHandle;
extern osThreadId_t canTxTaskHandle;
extern osThreadId_t dataProcessTaskHandle;
extern osThreadId_t networkTaskHandle;
extern osThreadId_t storageTaskHandle;
extern osThreadId_t watchdogTaskHandle;
extern osThreadId_t systemMonitorTaskHandle;
extern osMessageQueueId_t canDataQueue;
extern osMessageQueueId_t processedDataQueue;
extern osMessageQueueId_t networkDataQueue;
extern osMessageQueueId_t storageDataQueue;
extern osSemaphoreId_t canSemaphore;
extern osSemaphoreId_t networkSemaphore;
extern osSemaphoreId_t storageSemaphore;
extern osSemaphoreId_t systemSemaphore;
extern osMutexId_t canMutex;
extern osMutexId_t networkMutex;
extern osMutexId_t storageMutex;
extern osEventFlagsId_t systemEvents;
#define EVENT_CAN_DATA_READY (1UL << 0)
#define EVENT_NETWORK_CONNECTED (1UL << 1)
#define EVENT_STORAGE_READY (1UL << 2)
#define EVENT_SYSTEM_ERROR (1UL << 3)
#define EVENT_SYSTEM_RECOVERY (1UL << 4)
#define EVENT_CONFIG_CHANGED (1UL << 5)
void CAN_Rx_Task(void *argument);
void CAN_Tx_Task(void *argument);
void Data_Process_Task(void *argument);
void Network_Task(void *argument);
void Storage_Task(void *argument);
void Watchdog_Task(void *argument);
void System_Monitor_Task(void *argument);
ErrorCode_t RTOS_Tasks_Init(void);
ErrorCode_t RTOS_Tasks_Start(void);
ErrorCode_t RTOS_Tasks_Stop(void);
ErrorCode_t RTOS_Tasks_Suspend(void);
ErrorCode_t RTOS_Tasks_Resume(void);
void RTOS_Tasks_PrintStatus(void);
uint32_t RTOS_Tasks_GetCpuUsage(void);
uint32_t RTOS_Tasks_GetStackUsage(osThreadId_t task_handle);
ErrorCode_t RTOS_CreateQueues(void);
ErrorCode_t RTOS_CreateSemaphores(void);
ErrorCode_t RTOS_CreateMutexes(void);
ErrorCode_t RTOS_CreateEvents(void);
void RTOS_CleanupResources(void);
void RTOS_EnableTrace(void);
void RTOS_PrintTaskInfo(void);
void RTOS_PrintQueueInfo(void);
void RTOS_PrintHeapInfo(void);
#ifdef __cplusplus
}
#endif
#endif
13. FreeRTOS任务管理文件 rtos_tasks.c
#include "rtos_tasks.h"
#include "can_bus.h"
#include "w5500_net.h"
#include "sd_storage.h"
#include "data_processor.h"
#include "watchdog.h"
osThreadId_t canRxTaskHandle;
osThreadId_t canTxTaskHandle;
osThreadId_t dataProcessTaskHandle;
osThreadId_t networkTaskHandle;
osThreadId_t storageTaskHandle;
osThreadId_t watchdogTaskHandle;
osThreadId_t systemMonitorTaskHandle;
osMessageQueueId_t canDataQueue;
osMessageQueueId_t processedDataQueue;
osMessageQueueId_t networkDataQueue;
osMessageQueueId_t storageDataQueue;
osSemaphoreId_t canSemaphore;
osSemaphoreId_t networkSemaphore;
osSemaphoreId_t storageSemaphore;
osSemaphoreId_t systemSemaphore;
osMutexId_t canMutex;
osMutexId_t networkMutex;
osMutexId_t storageMutex;
osEventFlagsId_t systemEvents;
static const osThreadAttr_t canRxTask_attributes = {
.name = "CAN_Rx_Task",
.stack_size = TASK_STACK_MEDIUM,
.priority = TASK_PRIORITY_HIGH,
};
static const osThreadAttr_t canTxTask_attributes = {
.name = "CAN_Tx_Task",
.stack_size = TASK_STACK_MEDIUM,
.priority = TASK_PRIORITY_NORMAL,
};
static const osThreadAttr_t dataProcessTask_attributes = {
.name = "Data_Process_Task",
.stack_size = TASK_STACK_LARGE,
.priority = TASK_PRIORITY_ABOVE_NORMAL,
};
static const osThreadAttr_t networkTask_attributes = {
.name = "Network_Task",
.stack_size = TASK_STACK_LARGE,
.priority = TASK_PRIORITY_NORMAL,
};
static const osThreadAttr_t storageTask_attributes = {
.name = "Storage_Task",
.stack_size = TASK_STACK_LARGE,
.priority = TASK_PRIORITY_NORMAL,
};
static const osThreadAttr_t watchdogTask_attributes = {
.name = "Watchdog_Task",
.stack_size = TASK_STACK_SMALL,
.priority = TASK_PRIORITY_REALTIME,
};
static const osThreadAttr_t systemMonitorTask_attributes = {
.name = "System_Monitor_Task",
.stack_size = TASK_STACK_MEDIUM,
.priority = TASK_PRIORITY_LOW,
};
void CAN_Rx_Task(void *argument)
{
DEBUG_PRINT("CAN Rx Task started");
CanMessage_t rx_msg;
uint32_t last_process_time = 0;
Watchdog_RegisterTask("CAN_Rx", osThreadGetId(), 1000, 3);
while (1) {
Watchdog_TaskAlive("CAN_Rx");
ErrorCode_t error = CAN_ReceiveMessage(&rx_msg, 100);
if (error == ERROR_NONE) {
if (osMessageQueuePut(canDataQueue, &rx_msg, 0, 0) != osOK) {
DEBUG_PRINT("CAN data queue full, message dropped");
}
osEventFlagsSet(systemEvents, EVENT_CAN_DATA_READY);
}
osDelay(1);
}
}
void CAN_Tx_Task(void *argument)
{
DEBUG_PRINT("CAN Tx Task started");
Watchdog_RegisterTask("CAN_Tx", osThreadGetId(), 2000, 3);
while (1) {
Watchdog_TaskAlive("CAN_Tx");
CAN_SendHeartbeat();
osDelay(500);
}
}
void Data_Process_Task(void *argument)
{
DEBUG_PRINT("Data Process Task started");
CanMessage_t rx_msg;
DataRecord_t data_record;
uint32_t process_count = 0;
Watchdog_RegisterTask("Data_Process", osThreadGetId(), 1000, 3);
while (1) {
Watchdog_TaskAlive("Data_Process");
if (osMessageQueueGet(canDataQueue, &rx_msg, NULL, 0) == osOK) {
DataProcessor_ProcessCanMessage(&rx_msg);
process_count++;
if (process_count % 10 == 0) {
DEBUG_PRINT("Processed %lu CAN messages", process_count);
}
}
DataProcessor_BatchProcess();
osDelay(5);
}
}
void Network_Task(void *argument)
{
DEBUG_PRINT("Network Task started");
uint32_t last_connect_time = 0;
bool network_initialized = false;
Watchdog_RegisterTask("Network", osThreadGetId(), 1000, 3);
ErrorCode_t error = W5500_Init();
if (error != ERROR_NONE) {
DEBUG_PRINT("Network initialization failed: %d", error);
osEventFlagsSet(systemEvents, EVENT_SYSTEM_ERROR);
} else {
network_initialized = true;
}
while (1) {
Watchdog_TaskAlive("Network");
if (network_initialized) {
W5500_HandleConnection();
W5500_ProcessTxQueue();
W5500_ProcessRxQueue();
W5500_UpdateStatus();
}
osDelay(100);
}
}
void Storage_Task(void *argument)
{
DEBUG_PRINT("Storage Task started");
DataRecord_t data_record;
uint32_t last_cleanup_time = 0;
Watchdog_RegisterTask("Storage", osThreadGetId(), 2000, 3);
ErrorCode_t error = SD_Storage_Init();
if (error != ERROR_NONE) {
DEBUG_PRINT("Storage initialization failed: %d", error);
osEventFlagsSet(systemEvents, EVENT_SYSTEM_ERROR);
} else {
osEventFlagsSet(systemEvents, EVENT_STORAGE_READY);
}
while (1) {
Watchdog_TaskAlive("Storage");
SD_Storage_UpdateStatus();
uint32_t current_time = HAL_GetTick();
if (current_time - last_cleanup_time > 10 * 60 * 1000) {
SD_Storage_CleanupOldFiles();
last_cleanup_time = current_time;
}
if (SD_Storage_GetFreeSpace() < 1024) {
DEBUG_PRINT("Low disk space: %lu KB", SD_Storage_GetFreeSpace());
osEventFlagsSet(systemEvents, EVENT_SYSTEM_ERROR);
}
osDelay(1000);
}
}
void Watchdog_Task(void *argument)
{
DEBUG_PRINT("Watchdog Task started");
ErrorCode_t error = Watchdog_Init();
if (error != ERROR_NONE) {
DEBUG_PRINT("Watchdog initialization failed: %d", error);
}
error = Watchdog_Start();
if (error != ERROR_NONE) {
DEBUG_PRINT("Failed to start watchdog: %d", error);
}
while (1) {
Watchdog_CheckTasks();
Watchdog_MonitorSystemResources();
if (!Watchdog_CheckSystemHealth()) {
DEBUG_PRINT("System health check failed");
osEventFlagsSet(systemEvents, EVENT_SYSTEM_ERROR);
error = Watchdog_RecoverSystem();
if (error != ERROR_NONE) {
DEBUG_PRINT("System recovery failed, resetting...");
Watchdog_SystemReset();
}
}
Watchdog_Refresh();
osDelay(1000);
}
}
void System_Monitor_Task(void *argument)
{
DEBUG_PRINT("System Monitor Task started");
uint32_t last_status_time = 0;
SystemStatus_t system_status;
Watchdog_RegisterTask("SysMonitor", osThreadGetId(), 5000, 3);
while (1) {
Watchdog_TaskAlive("SysMonitor");
uint32_t events = osEventFlagsWait(systemEvents,
EVENT_SYSTEM_ERROR | EVENT_SYSTEM_RECOVERY,
osFlagsWaitAny, 0);
if (events & EVENT_SYSTEM_ERROR) {
DEBUG_PRINT("System error event detected");
osEventFlagsClear(systemEvents, EVENT_SYSTEM_ERROR);
}
if (events & EVENT_SYSTEM_RECOVERY) {
DEBUG_PRINT("System recovery event detected");
osEventFlagsClear(systemEvents, EVENT_SYSTEM_RECOVERY);
}
uint32_t current_time = HAL_GetTick();
if (current_time - last_status_time > 30000) {
RTOS_Tasks_PrintStatus();
CanStatistics_t *can_stats = CAN_GetStatistics();
DEBUG_PRINT("CAN Stats: RX=%lu, TX=%lu, Errors=%lu",
can_stats->rx_total, can_stats->tx_total, can_stats->bus_error);
NetworkStatus_t *net_status = W5500_GetStatus();
DEBUG_PRINT("Network: %s, TX=%lu, RX=%lu",
net_status->tcp_connected ? "Connected" : "Disconnected",
net_status->tx_bytes, net_status->rx_bytes);
StorageStatus_t *storage_status = SD_Storage_GetStatus();
DEBUG_PRINT("Storage: %s, Free=%lu KB",
storage_status->is_mounted ? "Mounted" : "Unmounted",
storage_status->free_space);
last_status_time = current_time;
}
osDelay(1000);
}
}
ErrorCode_t RTOS_Tasks_Init(void)
{
DEBUG_PRINT("Initializing RTOS tasks...");
if (RTOS_CreateQueues() != ERROR_NONE ||
RTOS_CreateSemaphores() != ERROR_NONE ||
RTOS_CreateMutexes() != ERROR_NONE ||
RTOS_CreateEvents() != ERROR_NONE) {
return ERROR_RTOS_TASK_CREATE_FAILED;
}
canRxTaskHandle = osThreadNew(CAN_Rx_Task, NULL, &canRxTask_attributes);
canTxTaskHandle = osThreadNew(CAN_Tx_Task, NULL, &canTxTask_attributes);
dataProcessTaskHandle = osThreadNew(Data_Process_Task, NULL, &dataProcessTask_attributes);
networkTaskHandle = osThreadNew(Network_Task, NULL, &networkTask_attributes);
storageTaskHandle = osThreadNew(Storage_Task, NULL, &storageTask_attributes);
watchdogTaskHandle = osThreadNew(Watchdog_Task, NULL, &watchdogTask_attributes);
systemMonitorTaskHandle = osThreadNew(System_Monitor_Task, NULL, &systemMonitorTask_attributes);
if (canRxTaskHandle == NULL || canTxTaskHandle == NULL ||
dataProcessTaskHandle == NULL || networkTaskHandle == NULL ||
storageTaskHandle == NULL || watchdogTaskHandle == NULL ||
systemMonitorTaskHandle == NULL) {
DEBUG_PRINT("Failed to create one or more RTOS tasks");
return ERROR_RTOS_TASK_CREATE_FAILED;
}
DEBUG_PRINT("RTOS tasks initialized successfully");
return ERROR_NONE;
}
ErrorCode_t RTOS_CreateQueues(void)
{
canDataQueue = osMessageQueueNew(DATA_QUEUE_SIZE, sizeof(CanMessage_t), NULL);
processedDataQueue = osMessageQueueNew(DATA_QUEUE_SIZE, sizeof(DataRecord_t), NULL);
networkDataQueue = osMessageQueueNew(PACKET_QUEUE_SIZE, sizeof(PacketHeader_t) + PACKET_MAX_SIZE, NULL);
storageDataQueue = osMessageQueueNew(DATA_QUEUE_SIZE, sizeof(DataRecord_t), NULL);
if (canDataQueue == NULL || processedDataQueue == NULL ||
networkDataQueue == NULL || storageDataQueue == NULL) {
return ERROR_RTOS_TASK_CREATE_FAILED;
}
return ERROR_NONE;
}
void RTOS_Tasks_PrintStatus(void)
{
DEBUG_PRINT("=== System Status ===");
DEBUG_PRINT("Uptime: %lu ms", HAL_GetTick());
DEBUG_PRINT("CPU Usage: %lu%%", RTOS_Tasks_GetCpuUsage());
}
14. 主函数文件 main.c
#include "main.h"
#include "rtos_tasks.h"
#include "system_config.h"
#include <stdio.h>
RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart3;
static SystemStatus_t system_status;
void Error_Handler(void)
{
DEBUG_PRINT("!!! FATAL ERROR !!!");
CAN_Stop();
W5500_TCPDisconnect();
SD_Storage_Unmount();
system_status.last_error = ERROR_WATCHDOG_TIMEOUT;
system_status.system_state = SYS_STATE_FATAL;
while (1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(100);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
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 = HSE_VALUE / 1000000;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
Error_Handler();
}
}
static void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK) {
Error_Handler();
}
sTime.Hours = 0;
sTime.Minutes = 0;
sTime.Seconds = 0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) {
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 1;
sDate.Year = 0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) {
Error_Handler();
}
}
static void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = DEBUG_BAUDRATE;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK) {
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void System_Init(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
MX_USART3_UART_Init();
memset(&system_status, 0, sizeof(SystemStatus_t));
system_status.system_state = SYS_STATE_INIT;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
DEBUG_PRINT("\r\n========================================");
DEBUG_PRINT("CAN Bus Data Acquisition System");
DEBUG_PRINT("Version: %s", FIRMWARE_VERSION);
DEBUG_PRINT("Hardware: %s", HARDWARE_VERSION);
DEBUG_PRINT("Build: %s %s", __DATE__, __TIME__);
DEBUG_PRINT("System Clock: %lu MHz", SYSTEM_CLOCK_FREQ / 1000000);
DEBUG_PRINT("========================================\r\n");
}
void Hardware_Init(void)
{
DEBUG_PRINT("Initializing hardware...");
ErrorCode_t error = CAN_Init();
if (error != ERROR_NONE) {
DEBUG_PRINT("CAN initialization failed: %d", error);
system_status.last_error = error;
} else {
error = CAN_Start();
if (error != ERROR_NONE) {
DEBUG_PRINT("CAN start failed: %d", error);
}
}
DEBUG_PRINT("Hardware initialization complete");
}
void System_Main_Loop(void)
{
uint32_t last_status_time = 0;
DEBUG_PRINT("Starting system main loop...");
ErrorCode_t error = RTOS_Tasks_Init();
if (error != ERROR_NONE) {
DEBUG_PRINT("RTOS tasks initialization failed: %d", error);
Error_Handler();
}
DEBUG_PRINT("Starting FreeRTOS scheduler...");
osKernelStart();
while (1) {
Error_Handler();
}
}
int main(void)
{
System_Init();
Hardware_Init();
System_Main_Loop();
return 0;
}
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
15. 使用说明
硬件连接
STM32F407引脚分配:
- PD0, PD1 -> CAN1 (CAN_H, CAN_L)
- PA5, PA6, PA7 -> SPI1 (SD卡: SCK, MISO, MOSI)
- PB13, PB14, PB15 -> SPI2 (W5500: SCK, MISO, MOSI)
- PC2 -> SD卡 CS
- PB12 -> W5500 CS
- PC3 -> SD卡检测
- PC13 -> 用户LED
- PA2, PA3 -> USART2 (调试串口)
- VBAT -> 3V电池(用于RTC)
编译和配置
- 使用STM32CubeMX生成基础工程
- 添加FreeRTOS和FATFS中间件
- 配置正确的时钟和引脚
- 将上述文件添加到工程中
- 配置FreeRTOS堆大小(至少30KB)
系统启动流程
- 系统初始化(时钟、GPIO、外设)
- 硬件初始化(CAN、网络、存储)
- 创建RTOS任务和资源
- 启动FreeRTOS调度器
- 各任务开始并行运行
任务功能说明
- CAN_Rx_Task:接收CAN总线数据,放入处理队列
- CAN_Tx_Task:发送CAN消息(心跳、命令等)
- Data_Process_Task:处理CAN数据,格式化打包
- Network_Task:管理网络连接,发送接收数据
- Storage_Task:管理SD卡存储,数据记录
- Watchdog_Task:监控系统健康,处理异常
- System_Monitor_Task:系统状态监控和日志
数据流
CAN总线 → CAN接收任务 → 数据处理队列 → 数据处理任务
↓
网络发送队列 → 网络任务 → TCP服务器
↓
存储队列 → 存储任务 → SD卡文件系统
扩展功能建议
- 添加Modbus TCP支持:在W5500驱动中添加Modbus协议栈
- 实现数据加密:在数据处理中添加AES加密
- 添加Web配置界面:通过W5500实现HTTP服务器
- 实现OTA升级:通过网络进行固件更新
- 添加GPS模块:记录地理位置信息
- 实现数据压缩:在存储前压缩数据以节省空间