init
This commit is contained in:
@@ -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 完成
|
||||
*/
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user