This commit is contained in:
2026-01-25 17:16:17 +08:00
commit 8d9bcd092b
171 changed files with 187944 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#include "correction.h"
//#include "fmac.h"
//#include "cordic.h"
// 外部的 FMAC 和 CORDIC 句柄
//extern FMAC_HandleTypeDef hfmac;
//extern CORDIC_HandleTypeDef hcordic;
/**
* @brief 初始化校正参数(示例)
* @param params: 参数结构体指针
* @retval None
*/
void Init_CorrectionParams(CorrectionParams_t *params)
{
// --- 请在这里填充你从校准中得到的实际参数 ---
// 偏移
params->offset_x = 0.0f;
params->offset_y = 0.0f;
params->offset_z = 0.0f;
// 灵敏度/非正交矩阵 (这里假设为单位矩阵)
params->scale_xx = 1.0f; params->scale_xy = 0.0f; params->scale_xz = 0.0f;
params->scale_yx = 0.0f; params->scale_yy = 1.0f; params->scale_yz = 0.0f;
params->scale_zx = 0.0f; params->scale_zy = 0.0f; params->scale_zz = 1.0f;
}
/**
* @brief 应用三分量校正
* @param raw_x, raw_y, raw_z: 原始 ADC 数据
* @param corrected_x, corrected_y, corrected_z: 校正后数据的指针
* @param params: 校正参数
* @retval None
*/
void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z,
float *corrected_x, float *corrected_y, float *corrected_z,
CorrectionParams_t *params)
{
// 1. 将原始数据转换为浮点数
float x_f = (float)raw_x;
float y_f = (float)raw_y;
float z_f = (float)raw_z;
float temp_x, temp_y, temp_z;
// 2. 灵敏度/非正交校正 (矩阵乘法)
// temp_X = Sxx*x_f + Sxy*y_f + Sxz*z_f
// temp_Y = Syx*x_f + Syy*y_f + Syz*z_f
// temp_Z = Szx*x_f + Szy*y_f + Szz*z_f
// 使用 FMAC 加速 (Q1.15 格式)
// FMAC 通常处理定点数,我们需要将 float 转为 Q1.15
// 或者,如果 FMAC 配置支持浮点,可以直接用浮点
// 这里先用纯 C 实现,并标记出 FMAC 可用的地方
temp_x = params->scale_xx * x_f + params->scale_xy * y_f + params->scale_xz * z_f;
temp_y = params->scale_yx * x_f + params->scale_yy * y_f + params->scale_yz * z_f;
temp_z = params->scale_zx * x_f + params->scale_zy * y_f + params->scale_zz * z_f;
// 3. 偏移校正
*corrected_x = temp_x - params->offset_x;
*corrected_y = temp_y - params->offset_y;
*corrected_z = temp_z - params->offset_z;
// --- 使用 FMAC 的示例 (需要配置 FMAC 和数据格式转换) ---
/*
// 假设输入 x_f, y_f, z_f 和系数 params->scale_** 已转换为 Q1.15
int16_t input_vector[3] = { (int16_t)(x_f * 32768.0f), (int16_t)(y_f * 32768.0f), (int16_t)(z_f * 32768.0f) };
int16_t coeffs_x[3] = { (int16_t)(params->scale_xx * 32768.0f), (int16_t)(params->scale_xy * 32768.0f), (int16_t)(params->scale_xz * 32768.0f) };
int16_t coeffs_y[3] = { (int16_t)(params->scale_yx * 32768.0f), (int16_t)(params->scale_yy * 32768.0f), (int16_t)(params->scale_yz * 32768.0f) };
int16_t coeffs_z[3] = { (int16_t)(params->scale_zx * 32768.0f), (int16_t)(params->scale_zy * 32768.0f), (int16_t)(params->scale_zz * 32768.0f) };
int16_t result_vector[3];
// 计算 X
FMAC_FilterConfig(&hfmac, coeffs_x, 3, input_vector, result_vector, ...); // 配置 FIR
HAL_FMAC_FilterStart(&hfmac, ...);
while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK);
temp_x = (float)result_vector[0] / 32768.0f; // 转换回 float (近似)
// 计算 Y
FMAC_FilterConfig(&hfmac, coeffs_y, 3, input_vector, result_vector, ...);
HAL_FMAC_FilterStart(&hfmac, ...);
while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK);
temp_y = (float)result_vector[0] / 32768.0f;
// 计算 Z
FMAC_FilterConfig(&hfmac, coeffs_z, 3, input_vector, result_vector, ...);
HAL_FMAC_FilterStart(&hfmac, ...);
while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK);
temp_z = (float)result_vector[0] / 32768.0f;
*corrected_x = temp_x - params->offset_x;
*corrected_y = temp_y - params->offset_y;
*corrected_z = temp_z - params->offset_z;
*/
// --- 使用 CORDIC 的示例 (例如,计算校正后向量的模和角度) ---
/*
// 伪代码
CORDIC_Config(&hcordic, ...); // 配置为计算模和相位
HAL_CORDIC_Calculate(&hcordic, input_coords, output_coords, ...);
// 等待 CORDIC 完成
*/
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef CORRECTION_H
#define CORRECTION_H
#include "main.h" // For CORDIC and FMAC handles
#include <stdint.h>
// 假设的校正参数结构体,你需要填充实际参数
typedef struct {
float offset_x, offset_y, offset_z;
float scale_xx, scale_xy, scale_xz;
float scale_yx, scale_yy, scale_yz;
float scale_zx, scale_zy, scale_zz;
} CorrectionParams_t;
void Init_CorrectionParams(CorrectionParams_t *params); // 初始化参数
void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z,
float *corrected_x, float *corrected_y, float *corrected_z,
CorrectionParams_t *params);
#endif // CORRECTION_H
+38
View File
@@ -0,0 +1,38 @@
#include "data_packet.h"
// CRC16-MODBUS
uint16_t Calculate_CRC16(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
return crc;
}
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3)
{
// packet->start_byte = PACKET_START_BYTE; // Incorrect assignment
uint32_t start = PACKET_START_BYTE;
packet->start_byte[0] = (start >> 24) & 0xFF; // A5
packet->start_byte[1] = (start >> 16) & 0xFF; // A5
packet->start_byte[2] = (start >> 8) & 0xFF; // 5A
packet->start_byte[3] = (start) & 0xFF; // 5A
// MCU 原生字节序 (小端)
packet->adc_data1 = adc1;
packet->adc_data2 = adc2;
packet->adc_data3 = adc3;
// 计算校验和 (只计算 ADC 数据部分)
// uint16_t checksum = Calculate_CRC16((uint8_t*)&packet->adc_data1, sizeof(uint32_t) * 3);
// packet->checksum = checksum; // 校验和也用小端
// packet->end_byte = PACKET_END_BYTE;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef DATA_PACKET_H
#define DATA_PACKET_H
#include <stdint.h>
#define PACKET_START_BYTE 0xFFFFFFFF
#define PACKET_END_BYTE 0x55
// 数据包结构
typedef struct __attribute__((packed)) {
uint8_t start_byte[4]; // 包头
int32_t adc_data1; // ADC1 数据 (高位在前)
int32_t adc_data2; // ADC2 数据 (高位在前)
int32_t adc_data3; // ADC3 数据 (高位在前)
// uint16_t checksum; // 校验和 (例如 CRC16, 高位在前)
// uint8_t end_byte; // 包尾
} DataPacket_t;
uint16_t Calculate_CRC16(uint8_t *data, uint16_t len);
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3);
#endif // DATA_PACKET_H
+107
View File
@@ -0,0 +1,107 @@
#include "ltc2508_driver.h"
#include <string.h> // For memset
// 全局变量定义
volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN] = {0};
volatile uint8_t g_adc_data_ready_flag = 0;
volatile uint8_t g_dma_complete_count = 0;
// SPI 句柄指针
static SPI_HandleTypeDef *g_hspi1 = NULL;
static SPI_HandleTypeDef *g_hspi2 = NULL;
static SPI_HandleTypeDef *g_hspi3 = NULL;
/**
* @brief 初始化 LTC2508 驱动
* @param hspi1: SPI1 句柄指针
* @param hspi2: SPI2 句柄指针
* @param hspi3: SPI3 句柄指针
* @retval None
*/
void LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3)
{
g_hspi1 = hspi1;
g_hspi2 = hspi2;
g_hspi3 = hspi3;
g_adc_data_ready_flag = 0;
g_dma_complete_count = 0;
memset((void*)g_adc_data, 0, sizeof(g_adc_data));
// 可以在这里添加对 LTC2508 的配置,如果需要通过 SPI 发送配置字
// 例如:HAL_SPI_Transmit(g_hspi1, &config_word, 1, 100);
}
/**
* @brief 触发三路 SPI 通过 DMA 读取数据
* @param None
* @retval None
*/
void LTC2508_TriggerDmaRead(void)
{
if (g_adc_data_ready_flag == 0 && g_dma_complete_count == 0) // 确保上次数据已处理且 DMA 未在进行
{
g_dma_complete_count = 0; // 重置计数
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
// SPI2 和 SPI3 作为从机只接收
if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], LTC2508_DATA_LEN) != HAL_OK)
{
Error_Handler();
}
if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)g_adc_data[2], LTC2508_DATA_LEN) != HAL_OK)
{
Error_Handler();
}
// SPI1 作为主机收发,先发一个 dummy 数据触发时钟
uint16_t dummy_tx[LTC2508_DATA_LEN] = {0}; // 可以是任意值
if (HAL_SPI_TransmitReceive_DMA(g_hspi1, (uint8_t*)dummy_tx, (uint8_t*)g_adc_data[0], LTC2508_DATA_LEN) != HAL_OK)
{
Error_Handler();
}
}
}
/**
* @brief SPI DMA 传输完成回调函数
* @param hspi: SPI 句柄指针
* @retval None
*/
void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi)
{
if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3)
{
g_dma_complete_count = NUM_LTC2508;
if (g_dma_complete_count == NUM_LTC2508)
{
g_adc_data_ready_flag = 1;
g_dma_complete_count = 0; // 为下一次读取做准备
}
}
}
// 需要在 stm32g4xx_it.c 中正确地调用 HAL_SPI_IRQHandler
// 并在 stm32g4xx_hal_spi.c 或 stm32g4xx_it.c 中添加以下回调函数的弱定义,
// 如果它们还没有被定义的话:
/*
__weak void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
LTC2508_DmaComplete_Callback(hspi);
}
__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
LTC2508_DmaComplete_Callback(hspi);
}
__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
// Handle error
Error_Handler();
}
*/
+22
View File
@@ -0,0 +1,22 @@
#ifndef LTC2508_DRIVER_H
#define LTC2508_DRIVER_H
#include "main.h" // 包含 main.h 以获取 SPI 和 GPIO 等的句柄
// 定义每个 ADC 采样的数据长度 (32-bit)
#define LTC2508_DATA_LEN 2 // 2个 16bit 数据
// 假设我们有3个 LTC2508
#define NUM_LTC2508 3
// 用于存储三路 ADC 数据的全局变量 (每个 ADC 2个 16-bit 数据)
extern volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN];
// ADC 数据准备就绪标志
extern volatile uint8_t g_adc_data_ready_flag;
// 函数原型
void LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3);
void LTC2508_TriggerDmaRead(void);
void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi);
#endif // LTC2508_DRIVER_H
+34
View File
@@ -0,0 +1,34 @@
#include "rs485_driver.h"
#include <string.h>
static UART_HandleTypeDef *g_huart_485 = NULL;
static GPIO_TypeDef* g_de_re_port = NULL;
static uint16_t g_de_re_pin = 0;
volatile uint8_t g_rs485_tx_busy = 0;
void RS485_Init(UART_HandleTypeDef *huart, GPIO_TypeDef* de_re_port, uint16_t de_re_pin)
{
g_huart_485 = huart;
g_de_re_port = de_re_port;
g_de_re_pin = de_re_pin;
g_rs485_tx_busy = 0;
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET); // 初始为接收模式
}
HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
{
HAL_StatusTypeDef ret;
if (g_rs485_tx_busy)
{
return HAL_BUSY;
}
g_rs485_tx_busy = 1;
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_SET); // 设置为发送模式
ret = HAL_UART_Transmit(g_huart_485, pData, Size, 0xffff);
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET); // 切换回接收模式
g_rs485_tx_busy = 0;
return ret;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef RS485_DRIVER_H
#define RS485_DRIVER_H
#include "main.h"
// 假设 DE/RE 控制引脚 - 请根据实际情况修改
#define RS485_DE_RE_PORT GPIOC
#define RS485_DE_RE_PIN GPIO_PIN_7
void RS485_Init(UART_HandleTypeDef *huart, GPIO_TypeDef* de_re_port, uint16_t de_re_pin);
HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size);
void RS485_TxCpltCallback(UART_HandleTypeDef *huart);
#endif // RS485_DRIVER_H