嵌入式开发之 SPI 通信的高级封装库实现

这里简单贴出来之前的部分嵌入式系统 SPI 通信的高级封装库实现,这个库提供了清晰的 API 接口、设备管理、错误处理和中断支持等特性,适用于大多数 ARM Cortex-M 系列微控制器。

/**
 * @file spi_master.h
 * @brief 嵌入式SPI总线高级封装库
 * @author start_up_go
 * @date 2025-06-29
 */

#ifndef SPI_MASTER_H
#define SPI_MASTER_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/** SPI总线设备句柄类型 */
typedef struct SpiDevice* SpiHandle;

/** SPI通信模式 */
typedef enum {
    SPI_MODE0 = 0,  // CPOL=0, CPHA=0
    SPI_MODE1,      // CPOL=0, CPHA=1
    SPI_MODE2,      // CPOL=1, CPHA=0
    SPI_MODE3       // CPOL=1, CPHA=1
} SpiMode;

/** SPI数据位宽 */
typedef enum {
    SPI_BITS_8 = 8,
    SPI_BITS_16 = 16,
    SPI_BITS_32 = 32
} SpiBits;

/** SPI传输速率 */
typedef enum {
    SPI_SPEED_1MHz = 1000000,
    SPI_SPEED_2MHz = 2000000,
    SPI_SPEED_4MHz = 4000000,
    SPI_SPEED_8MHz = 8000000,
    SPI_SPEED_16MHz = 16000000
} SpiSpeed;

/** SPI传输方向 */
typedef enum {
    SPI_DIR_BOTH = 0,     // 全双工
    SPI_DIR_TX_ONLY = 1,  // 只发送
    SPI_DIR_RX_ONLY = 2   // 只接收
} SpiDirection;

/** SPI错误码 */
typedef enum {
    SPI_SUCCESS = 0,          // 操作成功
    SPI_ERROR_INIT = -1,      // 初始化失败
    SPI_ERROR_PARAM = -2,     // 参数错误
    SPI_ERROR_BUSY = -3,      // 总线忙
    SPI_ERROR_TRANSFER = -4,  // 传输错误
    SPI_ERROR_TIMEOUT = -5,   // 超时错误
    SPI_ERROR_NOMEM = -6      // 内存不足
} SpiError;

/** SPI传输完成回调函数类型 */
typedef void (*SpiCallback)(SpiHandle handle, int error, void* user_data);

/** SPI设备配置结构体 */
typedef struct {
    uint8_t bus_id;           // SPI总线ID
    uint8_t cs_pin;           // 片选引脚
    bool cs_active_low;       // 片选低电平有效
    SpiMode mode;             // SPI模式
    SpiBits bits;             // 数据位宽
    SpiSpeed speed;           // 传输速率
    uint32_t timeout_ms;      // 超时时间(毫秒)
    SpiDirection direction;   // 传输方向
    SpiCallback callback;     // 传输完成回调函数
    void* user_data;          // 用户数据
} SpiConfig;

/**
 * @brief 初始化SPI总线驱动
 * @param bus_id SPI总线ID
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_master_init(uint8_t bus_id);

/**
 * @brief 反初始化SPI总线驱动
 * @param bus_id SPI总线ID
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_master_deinit(uint8_t bus_id);

/**
 * @brief 创建SPI设备实例
 * @param config SPI设备配置
 * @param[out] handle 输出的SPI设备句柄
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_device_create(const SpiConfig* config, SpiHandle* handle);

/**
 * @brief 销毁SPI设备实例
 * @param handle SPI设备句柄
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_device_destroy(SpiHandle handle);

/**
 * @brief 同步SPI传输(阻塞模式)
 * @param handle SPI设备句柄
 * @param tx_data 发送数据缓冲区
 * @param rx_data 接收数据缓冲区
 * @param length 数据长度(字节)
 * @return 成功返回实际传输的字节数,失败返回错误码
 */
int spi_device_transfer(SpiHandle handle, const void* tx_data, void* rx_data, size_t length);

/**
 * @brief 异步SPI传输(非阻塞模式)
 * @param handle SPI设备句柄
 * @param tx_data 发送数据缓冲区
 * @param rx_data 接收数据缓冲区
 * @param length 数据长度(字节)
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_device_transfer_async(SpiHandle handle, const void* tx_data, void* rx_data, size_t length);

/**
 * @brief 设置SPI设备参数
 * @param handle SPI设备句柄
 * @param config 新的SPI设备配置
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_device_configure(SpiHandle handle, const SpiConfig* config);

/**
 * @brief 获取SPI设备状态
 * @param handle SPI设备句柄
 * @param[out] is_busy 输出设备是否繁忙
 * @return 成功返回SPI_SUCCESS,失败返回错误码
 */
int spi_device_get_status(SpiHandle handle, bool* is_busy);

/**
 * @brief 获取SPI错误信息
 * @param error 错误码
 * @return 错误信息字符串
 */
const char* spi_get_error_string(int error);

#ifdef __cplusplus
}
#endif

#endif // SPI_MASTER_H

 

/**
 * @file spi_master.c
 * @brief 嵌入式SPI总线高级封装库实现
 * @author start_up_go
 * @date 2025-06-29
 */

#include "spi_master.h"
#include <stdlib.h>
#include <string.h>
#include "driver/spi.h"  // 假设这是底层SPI驱动

/** SPI设备结构体 */
struct SpiDevice {
    uint8_t bus_id;           // SPI总线ID
    uint8_t cs_pin;           // 片选引脚
    bool cs_active_low;       // 片选低电平有效
    SpiMode mode;             // SPI模式
    SpiBits bits;             // 数据位宽
    SpiSpeed speed;           // 传输速率
    uint32_t timeout_ms;      // 超时时间(毫秒)
    SpiDirection direction;   // 传输方向
    SpiCallback callback;     // 传输完成回调函数
    void* user_data;          // 用户数据
    bool is_busy;             // 设备忙标志
};

/** 错误信息表 */
static const char* error_strings[] = {
    "Success",
    "Initialization error",
    "Parameter error",
    "Busy",
    "Transfer error",
    "Timeout error",
    "Memory allocation failed"
};

/**
 * @brief SPI传输完成回调函数(底层驱动调用)
 * @param bus_id SPI总线ID
 * @param error 错误码
 * @param user_data 用户数据
 */
static void spi_transfer_complete_callback(uint8_t bus_id, int error, void* user_data) {
    SpiHandle handle = (SpiHandle)user_data;
    if (handle) {
        handle->is_busy = false;
        if (handle->callback) {
            handle->callback(handle, error, handle->user_data);
        }
    }
}

int spi_master_init(uint8_t bus_id) {
    // 初始化底层SPI驱动
    return spi_driver_init(bus_id);
}

int spi_master_deinit(uint8_t bus_id) {
    // 反初始化底层SPI驱动
    return spi_driver_deinit(bus_id);
}

int spi_device_create(const SpiConfig* config, SpiHandle* handle) {
    if (!config || !handle) {
        return SPI_ERROR_PARAM;
    }
    
    // 分配设备结构体内存
    SpiHandle dev = (SpiHandle)malloc(sizeof(struct SpiDevice));
    if (!dev) {
        return SPI_ERROR_NOMEM;
    }
    
    // 复制配置参数
    memcpy(dev, config, sizeof(struct SpiDevice));
    dev->is_busy = false;
    
    // 配置底层SPI驱动
    int ret = spi_driver_configure(
        dev->bus_id, 
        dev->mode, 
        dev->bits, 
        dev->speed, 
        dev->direction
    );
    
    if (ret != 0) {
        free(dev);
        return SPI_ERROR_INIT;
    }
    
    *handle = dev;
    return SPI_SUCCESS;
}

int spi_device_destroy(SpiHandle handle) {
    if (!handle) {
        return SPI_ERROR_PARAM;
    }
    
    // 释放设备结构体内存
    free(handle);
    return SPI_SUCCESS;
}

int spi_device_transfer(SpiHandle handle, const void* tx_data, void* rx_data, size_t length) {
    if (!handle || (!tx_data && !rx_data) || length == 0) {
        return SPI_ERROR_PARAM;
    }
    
    if (handle->is_busy) {
        return SPI_ERROR_BUSY;
    }
    
    handle->is_busy = true;
    
    // 使能片选
    gpio_set_level(handle->cs_pin, handle->cs_active_low ? 0 : 1);
    
    // 执行SPI传输
    int ret = spi_driver_transfer(
        handle->bus_id, 
        tx_data, 
        rx_data, 
        length, 
        handle->timeout_ms
    );
    
    // 禁用片选
    gpio_set_level(handle->cs_pin, handle->cs_active_low ? 1 : 0);
    
    handle->is_busy = false;
    return ret >= 0 ? ret : SPI_ERROR_TRANSFER;
}

int spi_device_transfer_async(SpiHandle handle, const void* tx_data, void* rx_data, size_t length) {
    if (!handle || (!tx_data && !rx_data) || length == 0) {
        return SPI_ERROR_PARAM;
    }
    
    if (handle->is_busy) {
        return SPI_ERROR_BUSY;
    }
    
    handle->is_busy = true;
    
    // 使能片选
    gpio_set_level(handle->cs_pin, handle->cs_active_low ? 0 : 1);
    
    // 执行异步SPI传输
    int ret = spi_driver_transfer_async(
        handle->bus_id, 
        tx_data, 
        rx_data, 
        length, 
        handle->timeout_ms,
        spi_transfer_complete_callback,
        handle
    );
    
    if (ret != 0) {
        // 传输启动失败,禁用片选
        gpio_set_level(handle->cs_pin, handle->cs_active_low ? 1 : 0);
        handle->is_busy = false;
        return SPI_ERROR_TRANSFER;
    }
    
    return SPI_SUCCESS;
}

int spi_device_configure(SpiHandle handle, const SpiConfig* config) {
    if (!handle || !config) {
        return SPI_ERROR_PARAM;
    }
    
    // 复制配置参数
    memcpy(handle, config, sizeof(struct SpiDevice));
    
    // 配置底层SPI驱动
    return spi_driver_configure(
        handle->bus_id, 
        handle->mode, 
        handle->bits, 
        handle->speed, 
        handle->direction
    );
}

int spi_device_get_status(SpiHandle handle, bool* is_busy) {
    if (!handle || !is_busy) {
        return SPI_ERROR_PARAM;
    }
    
    *is_busy = handle->is_busy;
    return SPI_SUCCESS;
}

const char* spi_get_error_string(int error) {
    if (error >= SPI_SUCCESS && error <= SPI_ERROR_NOMEM) {
        return error_strings[error * -1];
    }
    return "Unknown error";
}

这个 SPI 库提供了以下特性:

  1. 面向对象的 API 设计,使用句柄管理多个 SPI 设备
  2. 支持同步和异步两种传输模式
  3. 完整的错误处理和错误码系统
  4. 可配置的 SPI 参数,包括模式、位宽、速率等
  5. 支持多设备管理,可同时操作多个 SPI 从设备
  6. 清晰的设备状态管理
  7. 片选信号自动控制

使用时,你需要根据具体的硬件平台实现底层驱动接口 (spi_driver_*)。这个库设计为可移植的,适用于 STM32、ESP32 等多种嵌入式平台。

 

内容概要:本文介绍了基于贝叶斯优化的CNN-LSTM混合神经网络在时间序列预测中的应用,并提供了完整的Matlab代码实现。该模型结合了卷积神经网络(CNN)在特征提取方面的优势与长短期记忆网络(LSTM)在处理时序依赖问题上的强大能力,形成一种高效的混合预测架构。通过贝叶斯优化算法自动调参,提升了模型的预测精度与泛化能力,适用于风电、光伏、负荷、交通流等多种复杂非线性系统的预测任务。文中还展示了模型训练流程、参数优化机制及实际预测效果分析,突出其在科研与工程应用中的实用性。; 适合人群:具备一定机器学习基基于贝叶斯优化CNN-LSTM混合神经网络预测(Matlab代码实现)础和Matlab编程经验的高校研究生、科研人员及从事预测建模的工程技术人员,尤其适合关注深度学习与智能优化算法结合应用的研究者。; 使用场景及目标:①解决各类时间序列预测问题,如能源出力预测、电力负荷预测、环境数据预测等;②学习如何将CNN-LSTM模型与贝叶斯优化相结合,提升模型性能;③掌握Matlab环境下深度学习模型搭建与超参数自动优化的技术路线。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注贝叶斯优化模块与混合神经网络结构的设计逻辑,通过调整数据集和参数加深对模型工作机制的理解,同时可将其框架迁移至其他预测场景中验证效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

start_up_go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值