硬件协同设计 C/C++ 实例
1. 嵌入式系统设计与驱动开发
1.1 GPIO 控制实例
以下是一个针对通用微控制器的 GPIO 控制库,展示了软件如何直接操作硬件寄存器:
c
/**
* gpio.h - 通用 GPIO 控制接口
*
* 硬件协同设计的典型示例:直接操作硬件寄存器的同时
* 提供抽象接口方便软件层使用
*/
#ifndef GPIO_H
#define GPIO_H
#include <stdint.h>
// GPIO 方向设置
typedef enum {
GPIO_DIR_INPUT = 0,
GPIO_DIR_OUTPUT = 1
} GpioDirection;
// GPIO 输出电平
typedef enum {
GPIO_LEVEL_LOW = 0,
GPIO_LEVEL_HIGH = 1
} GpioLevel;
// GPIO 模式配置
typedef enum {
GPIO_MODE_PUSHPULL = 0, // 推挽输出
GPIO_MODE_OPENDRAIN = 1, // 开漏输出
GPIO_MODE_PULLUP = 2, // 上拉输入
GPIO_MODE_PULLDOWN = 3, // 下拉输入
GPIO_MODE_FLOAT = 4 // 浮空输入
} GpioMode;
// GPIO 端口定义
typedef enum {
GPIO_PORT_A = 0,
GPIO_PORT_B = 1,
GPIO_PORT_C = 2,
GPIO_PORT_D = 3,
GPIO_PORT_E = 4
} GpioPort;
/**
* 初始化 GPIO 端口
*
* @param port GPIO 端口号
* @param pin 引脚编号 (0-15)
* @param direction 输入/输出方向
* @param mode GPIO 模式
* @return 0 表示成功,非零表示失败
*/
int gpio_init(GpioPort port, uint8_t pin, GpioDirection direction, GpioMode mode);
/**
* 设置 GPIO 引脚电平
*
* @param port GPIO 端口号
* @param pin 引脚编号 (0-15)
* @param level 输出电平
* @return 0 表示成功,非零表示失败
*/
int gpio_write(GpioPort port, uint8_t pin, GpioLevel level);
/**
* 读取 GPIO 引脚电平
*
* @param port GPIO 端口号
* @param pin 引脚编号 (0-15)
* @return 引脚电平
*/
GpioLevel gpio_read(GpioPort port, uint8_t pin);
/**
* 切换 GPIO 引脚电平
*
* @param port GPIO 端口号
* @param pin 引脚编号 (0-15)
* @return 0 表示成功,非零表示失败
*/
int gpio_toggle(GpioPort port, uint8_t pin);
#endif /* GPIO_H */
c
/**
* gpio.c - GPIO 控制接口实现 (基于 STM32F4xx)
*
* 硬件协同设计示例:根据特定微控制器寄存器布局实现抽象接口
* 这使得软件可以适应不同的硬件平台,同时保持相同的 API
*/
#include "gpio.h"
// STM32F4xx 的 GPIO 寄存器定义
#define GPIO_BASE_ADDRESS 0x40020000
#define GPIOA_BASE_OFFSET 0x0000
#define GPIOB_BASE_OFFSET 0x0400
#define GPIOC_BASE_OFFSET 0x0800
#define GPIOD_BASE_OFFSET 0x0C00
#define GPIOE_BASE_OFFSET 0x1000
// GPIO 寄存器偏移
#define GPIO_MODER_OFFSET 0x00 // 模式寄存器
#define GPIO_OTYPER_OFFSET 0x04 // 输出类型寄存器
#define GPIO_OSPEEDR_OFFSET 0x08 // 输出速度寄存器
#define GPIO_PUPDR_OFFSET 0x0C // 上拉/下拉寄存器
#define GPIO_IDR_OFFSET 0x10 // 输入数据寄存器
#define GPIO_ODR_OFFSET 0x14 // 输出数据寄存器
#define GPIO_BSRR_OFFSET 0x18 // 位设置/复位寄存器
// 启用 GPIO 时钟的 RCC 寄存器
#define RCC_BASE_ADDRESS 0x40023800
#define RCC_AHB1ENR_OFFSET 0x30
#define RCC_AHB1ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_AHB1ENR_OFFSET))
// 获取 GPIO 寄存器地址
static volatile uint32_t* gpio_get_register(GpioPort port, uint32_t offset) {
uint32_t base_addr = GPIO_BASE_ADDRESS;
switch (port) {
case GPIO_PORT_A: base_addr += GPIOA_BASE_OFFSET; break;
case GPIO_PORT_B: base_addr += GPIOB_BASE_OFFSET; break;
case GPIO_PORT_C: base_addr += GPIOC_BASE_OFFSET; break;
case GPIO_PORT_D: base_addr += GPIOD_BASE_OFFSET; break;
case GPIO_PORT_E: base_addr += GPIOE_BASE_OFFSET; break;
default: return NULL;
}
return (volatile uint32_t*)(base_addr + offset);
}
int gpio_init(GpioPort port, uint8_t pin, GpioDirection direction, GpioMode mode) {
// 检查参数有效性
if (pin > 15 || port > GPIO_PORT_E) {
return -1;
}
// 启用对应 GPIO 端口的时钟
RCC_AHB1ENR |= (1 << port);
// 获取寄存器地址
volatile uint32_t* moder = gpio_get_register(port, GPIO_MODER_OFFSET);
volatile uint32_t* otyper = gpio_get_register(port, GPIO_OTYPER_OFFSET);
volatile uint32_t* pupdr = gpio_get_register(port, GPIO_PUPDR_OFFSET);
if (!moder || !otyper || !pupdr) {
return -1;
}
// 设置 GPIO 方向 (输入/输出模式)
// 每个引脚用 2 位表示模式
*moder &= ~(3UL << (pin * 2)); // 清除原来的设置
*moder |= ((uint32_t)direction << (pin * 2));
// 设置输出类型 (推挽/开漏)
if (mode == GPIO_MODE_OPENDRAIN) {
*otyper |= (1UL << pin); // 开漏输出
} else {
*otyper &= ~(1UL << pin); // 推挽输出
}
// 设置上拉/下拉电阻
*pupdr &= ~(3UL << (pin * 2)); // 清除原来的设置
if (mode == GPIO_MODE_PULLUP) {
*pupdr |= (1UL << (pin * 2)); // 上拉电阻
} else if (mode == GPIO_MODE_PULLDOWN) {
*pupdr |= (2UL << (pin * 2)); // 下拉电阻
}
// 其它模式保持浮空
return 0;
}
int gpio_write(GpioPort port, uint8_t pin, GpioLevel level) {
// 检查参数有效性
if (pin > 15 || port > GPIO_PORT_E) {
return -1;
}
// 使用 BSRR (位设置/复位寄存器) 进行原子写操作
volatile uint32_t* bsrr = gpio_get_register(port, GPIO_BSRR_OFFSET);
if (!bsrr) {
return -1;
}
if (level == GPIO_LEVEL_HIGH) {
*bsrr = (1UL << pin); // 设置位
} else {
*bsrr = (1UL << (pin + 16)); // 复位位 (高 16 位用于复位)
}
return 0;
}
GpioLevel gpio_read(GpioPort port, uint8_t pin) {
// 检查参数有效性
if (pin > 15 || port > GPIO_PORT_E) {
return GPIO_LEVEL_LOW; // 出错时默认返回低电平
}
// 读取输入数据寄存器
volatile uint32_t* idr = gpio_get_register(port, GPIO_IDR_OFFSET);
if (!idr) {
return GPIO_LEVEL_LOW;
}
// 检查对应位是否为高电平
return (*idr & (1UL << pin)) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW;
}
int gpio_toggle(GpioPort port, uint8_t pin) {
// 检查参数有效性
if (pin > 15 || port > GPIO_PORT_E) {
return -1;
}
// 读取当前输出数据寄存器
volatile uint32_t* odr = gpio_get_register(port, GPIO_ODR_OFFSET);
if (!odr) {
return -1;
}
// 切换对应位
*odr ^= (1UL << pin);
return 0;
}
1.2 SPI 通信驱动实例
下面是一个 SPI 通信驱动,展示了如何通过软件控制 SPI 硬件模块:
c
/**
* spi.h - SPI 控制接口
*
* 提供软件接口以控制硬件 SPI 模块
*/
#ifndef SPI_H
#define SPI_H
#include <stdint.h>
// SPI 模块选择
typedef enum {
SPI_MODULE_1 = 0,
SPI_MODULE_2 = 1,
SPI_MODULE_3 = 2
} SpiModule;
// SPI 模式
typedef enum {
SPI_MODE_0 = 0, // CPOL=0, CPHA=0
SPI_MODE_1 = 1, // CPOL=0, CPHA=1
SPI_MODE_2 = 2, // CPOL=1, CPHA=0
SPI_MODE_3 = 3 // CPOL=1, CPHA=1
} SpiMode;
// SPI 波特率预分频系数
typedef enum {
SPI_BAUDRATE_DIV2 = 0,
SPI_BAUDRATE_DIV4 = 1,
SPI_BAUDRATE_DIV8 = 2,
SPI_BAUDRATE_DIV16 = 3,
SPI_BAUDRATE_DIV32 = 4,
SPI_BAUDRATE_DIV64 = 5,
SPI_BAUDRATE_DIV128 = 6,
SPI_BAUDRATE_DIV256 = 7
} SpiBaudRatePrescaler;
// SPI 数据大小
typedef enum {
SPI_DATASIZE_8BIT = 0,
SPI_DATASIZE_16BIT = 1
} SpiDataSize;
// SPI 配置结构体
typedef struct {
SpiMode mode; // SPI 模式
SpiBaudRatePrescaler baud; // 波特率预分频
SpiDataSize dataSize; // 数据大小
uint8_t lsbFirst; // 1 = LSB 优先,0 = MSB 优先
} SpiConfig;
/**
* 初始化 SPI 模块
*
* @param module SPI 模块编号
* @param config SPI 配置参数
* @return 0 表示成功,非零表示失败
*/
int spi_init(SpiModule module, const SpiConfig* config);
/**
* 发送并接收一个字节/字的数据 (全双工)
*
* @param module SPI 模块编号
* @param data 要发送的数据
* @return 接收到的数据
*/
uint16_t spi_transfer(SpiModule module, uint16_t data);
/**
* 发送多个字节的数据
*
* @param module SPI 模块编号
* @param txData 要发送的数据缓冲区
* @param rxData 接收数据的缓冲区 (可以为 NULL)
* @param length 数据长度
* @return 0 表示成功,非零表示失败
*/
int spi_transfer_buffer(SpiModule module, const uint8_t* txData, uint8_t* rxData, uint16_t length);
/**
* 选择 SPI 片选信号
*
* @param port 片选信号所在的 GPIO 端口
* @param pin 片选信号的引脚编号
* @param select 1 表示选中,0 表示取消选中
* @return 0 表示成功,非零表示失败
*/
int spi_chip_select(uint8_t port, uint8_t pin, uint8_t select);
#endif /* SPI_H */
c
/**
* spi.c - SPI 控制接口实现 (基于 STM32F4xx)
*
* 硬件协同设计示例:软件根据硬件寄存器映射实现通信接口
*/
#include "spi.h"
#include "gpio.h" // 使用前文定义的 GPIO 函数
// STM32F4xx 的 SPI 寄存器定义
#define SPI1_BASE_ADDRESS 0x40013000
#define SPI2_BASE_ADDRESS 0x40003800
#define SPI3_BASE_ADDRESS 0x40003C00
// SPI 寄存器偏移量
#define SPI_CR1_OFFSET 0x00 // 控制寄存器 1
#define SPI_CR2_OFFSET 0x04 // 控制寄存器 2
#define SPI_SR_OFFSET 0x08 // 状态寄存器
#define SPI_DR_OFFSET 0x0C // 数据寄存器
// SPI 控制寄存器 1 (CR1) 位定义
#define SPI_CR1_CPHA 0x01 // 时钟相位
#define SPI_CR1_CPOL 0x02 // 时钟极性
#define SPI_CR1_MSTR 0x04 // 主模式
#define SPI_CR1_BR_SHIFT 3 // 波特率控制位偏移
#define SPI_CR1_SPE 0x40 // SPI 使能
#define SPI_CR1_LSBFIRST 0x80 // 帧格式 (LSB/MSB)
#define SPI_CR1_SSI 0x100 // 内部从设备选择
#define SPI_CR1_SSM 0x200 // 软件从设备管理
#define SPI_CR1_DFF 0x800 // 数据帧格式 (8/16 位)
// SPI 状态寄存器 (SR) 位定义
#define SPI_SR_RXNE 0x01 // 接收缓冲区非空
#define SPI_SR_TXE 0x02 // 发送缓冲区空
#define SPI_SR_BSY 0x80 // 忙标志
// 启用时钟的 RCC 寄存器
#define RCC_BASE_ADDRESS 0x40023800
#define RCC_APB2ENR_OFFSET 0x44 // APB2 外设时钟使能寄存器
#define RCC_APB1ENR_OFFSET 0x40 // APB1 外设时钟使能寄存器
#define RCC_APB2ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_APB2ENR_OFFSET))
#define RCC_APB1ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_APB1ENR_OFFSET))
// SPI1 在 APB2 上,SPI2/3 在 APB1 上
#define RCC_APB2ENR_SPI1EN 0x1000 // SPI1 时钟使能位
#define RCC_APB1ENR_SPI2EN 0x4000 // SPI2 时钟使能位
#define RCC_APB1ENR_SPI3EN 0x8000 // SPI3 时钟使能位
// 获取 SPI 寄存器地址
static volatile uint32_t* spi_get_register(SpiModule module, uint32_t offset) {
uint32_t base_addr;
switch (module) {
case SPI_MODULE_1: base_addr = SPI1_BASE_ADDRESS; break;
case SPI_MODULE_2: base_addr = SPI2_BASE_ADDRESS; break;
case SPI_MODULE_3: base_addr = SPI3_BASE_ADDRESS; break;
default: return NULL;
}
return (volatile uint32_t*)(base_addr + offset);
}
int spi_init(SpiModule module, const SpiConfig* config) {
// 检查参数有效性
if (module > SPI_MODULE_3 || !config) {
return -1;
}
// 启用 SPI 时钟
switch (module) {
case SPI_MODULE_1:
RCC_APB2ENR |= RCC_APB2ENR_SPI1EN;
break;
case SPI_MODULE_2:
RCC_APB1ENR |= RCC_APB1ENR_SPI2EN;
break;
case SPI_MODULE_3:
RCC_APB1ENR |= RCC_APB1ENR_SPI3EN;
break;
}
// 获取控制寄存器
volatile uint32_t* cr1 = spi_get_register(module, SPI_CR1_OFFSET);
volatile uint32_t* cr2 = spi_get_register(module, SPI_CR2_OFFSET);
if (!cr1 || !cr2) {
return -1;
}
// 禁用 SPI 以进行配置
*cr1 &= ~SPI_CR1_SPE;
// 配置 SPI 模式 (CPOL, CPHA)
uint32_t temp = *cr1;
temp &= ~(SPI_CR1_CPHA | SPI_CR1_CPOL); // 清除模式位
temp |= config->mode; // 设置模式
// 配置为主模式
temp |= SPI_CR1_MSTR;
// 配置波特率
temp &= ~(0x7 << SPI_CR1_BR_SHIFT); // 清除波特率位
temp |= (config->baud << SPI_CR1_BR_SHIFT);
// 配置数据大小 (8/16 位)
if (config->dataSize == SPI_DATASIZE_16BIT) {
temp |= SPI_CR1_DFF;
} else {
temp &= ~SPI_CR1_DFF;
}
// 配置位顺序 (MSB/LSB 优先)
if (config->lsbFirst) {
temp |= SPI_CR1_LSBFIRST;
} else {
temp &= ~SPI_CR1_LSBFIRST;
}
// 启用软件 NSS 管理并将 NSS 内部拉高 (避免进入从模式)
temp |= (SPI_CR1_SSM | SPI_CR1_SSI);
// 写回 CR1 寄存器
*cr1 = temp;
// 配置 CR2 寄存器,开启 RXNE 中断
*cr2 = 0x00; // 默认不启用中断
// 启用 SPI
*cr1 |= SPI_CR1_SPE;
return 0;
}
uint16_t spi_transfer(SpiModule module, uint16_t data) {
// 获取 SPI 寄存器
volatile uint32_t* sr = spi_get_register(module, SPI_SR_OFFSET);
volatile uint32_t* dr = spi_get_register(module, SPI_DR_OFFSET);
if (!sr || !dr) {
return 0;
}
// 等待发送缓冲区为空
while (!(*sr & SPI_SR_TXE));
// 发送数据
*dr = data;
// 等待接收数据完成
while (!(*sr & SPI_SR_RXNE));
// 读取接收到的数据
return *dr;
}
int spi_transfer_buffer(SpiModule module, const uint8_t* txData, uint8_t* rxData, uint16_t length) {
// 获取 SPI 寄存器
volatile uint32_t* sr = spi_get_register(module, SPI_SR_OFFSET);
volatile uint32_t* dr = spi_get_register(module, SPI_DR_OFFSET);
volatile uint32_t* cr1 = spi_get_register(module, SPI_CR1_OFFSET);
if (!sr || !dr || !cr1) {
return -1;
}
// 检查数据帧格式,确定是 8 位还是 16 位模式
uint8_t is16bit = (*cr1 & SPI_CR1_DFF) ? 1 : 0;
// 对于每个字节/字进行传输
for (uint16_t i = 0; i < length; i++) {
uint16_t out_data, in_data;
// 准备发送数据
if (is16bit) {
if (txData) {
out_data = (txData[i*2] << 8) | txData[i*2 + 1];
} else {
out_data = 0xFFFF; // 发送哑数据以接收有效数据
}
} else {
if (txData) {
out_data = txData[i];
} else {
out_data = 0xFF; // 发送哑数据以接收有效数据
}
}
// 等待发送缓冲区为空
while (!(*sr & SPI_SR_TXE));
// 发送数据
*dr = out_data;
// 等待接收数据完成
while (!(*sr & SPI_SR_RXNE));
// 读取接收到的数据
in_data = *dr;
// 保存接收到的数据
if (rxData) {
if (is16bit) {
rxData[i*2] = (in_data >> 8) & 0xFF;
rxData[i*2 + 1] = in_data & 0xFF;
} else {
rxData[i] = in_data & 0xFF;
}
}
}
// 等待 SPI 不忙
while (*sr & SPI_SR_BSY);
return 0;
}
int spi_chip_select(uint8_t port, uint8_t pin, uint8_t select) {
// 使用 GPIO 函数管理片选信号
return gpio_write((GpioPort)port, pin, select ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH);
}
1.3 定时器PWM控制实例
以下是一个生成PWM信号的示例,展示了如何使用定时器硬件单元:
c
/**
* pwm.h - PWM 控制接口
*
* 提供软件接口以控制定时器生成 PWM 信号
*/
#ifndef PWM_H
#define PWM_H
#include <stdint.h>
// 定时器选择
typedef enum {
TIMER_1 = 0,
TIMER_2 = 1,
TIMER_3 = 2,
TIMER_4 = 3,
TIMER_5 = 4
} TimerNumber;
// 定时器通道
typedef enum {
TIMER_CHANNEL_1 = 0,
TIMER_CHANNEL_2 = 1,
TIMER_CHANNEL_3 = 2,
TIMER_CHANNEL_4 = 3
} TimerChannel;
// PWM 配置结构体
typedef struct {
uint32_t frequency; // PWM 频率 (Hz)
uint8_t dutyCycle; // 占空比 (0-100%)
uint8_t polarity; // 0 = 正向极性,1 = 反向极性
} PwmConfig;
/**
* 初始化 PWM 通道
*
* @param timer 定时器编号
* @param channel 通道编号
* @param config PWM 配置参数
* @return 0 表示成功,非零表示失败
*/
int pwm_init(TimerNumber timer, TimerChannel channel, const PwmConfig* config);
/**
* 启动 PWM 输出
*
* @param timer 定时器编号
* @param channel 通道编号
* @return 0 表示成功,非零表示失败
*/
int pwm_start(TimerNumber timer, TimerChannel channel);
/**
* 停止 PWM 输出
*
* @param timer 定时器编号
* @param channel 通道编号
* @return 0 表示成功,非零表示失败
*/
int pwm_stop(TimerNumber timer, TimerChannel channel);
/**
* 更新 PWM 占空比
*
* @param timer 定时器编号
* @param channel 通道编号
* @param dutyCycle 占空比 (0-100%)
* @return 0 表示成功,非零表示失败
*/
int pwm_set_duty_cycle(TimerNumber timer, TimerChannel channel, uint8_t dutyCycle);
/**
* 更新 PWM 频率
*
* @param timer 定时器编号
* @param frequency 频率 (Hz)
* @return 0 表示成功,非零表示失败
*/
int pwm_set_frequency(TimerNumber timer, uint32_t frequency);
#endif /* PWM_H */
c
/**
* pwm.c - PWM 控制接口实现 (基于 STM32F4xx)
*
* 硬件协同设计示例:通过软件控制定时器硬件单元产生精确的 PWM 信号
*/
#include "pwm.h"
// STM32F4xx 的定时器寄存器定义
#define TIM1_BASE_ADDRESS 0x40010000
#define TIM2_BASE_ADDRESS 0x40000000
#define TIM3_BASE_ADDRESS 0x40000400
#define TIM4_BASE_ADDRESS 0x40000800
#define TIM5_BASE_ADDRESS 0x40000C00
// 定时器寄存器偏移量
#define TIM_CR1_OFFSET 0x00 // 控制寄存器 1
#define TIM_CR2_OFFSET 0x04 // 控制寄存器 2
#define TIM_SMCR_OFFSET 0x08 // 从模式控制寄存器
#define TIM_DIER_OFFSET 0x0C // DMA/中断使能寄存器
#define TIM_SR_OFFSET 0x10 // 状态寄存器
#define TIM_EGR_OFFSET 0x14 // 事件生成寄存器
#define TIM_CCMR1_OFFSET 0x18 // 捕获/比较模式寄存器 1
#define TIM_CCMR2_OFFSET 0x1C // 捕获/比较模式寄存器 2
#define TIM_CCER_OFFSET 0x20 // 捕获/比较使能寄存器
#define TIM_CNT_OFFSET 0x24 // 计数器
#define TIM_PSC_OFFSET 0x28 // 预分频器
#define TIM_ARR_OFFSET 0x2C // 自动重装载寄存器
#define TIM_CCR1_OFFSET 0x34 // 捕获/比较寄存器 1
#define TIM_CCR2_OFFSET 0x38 // 捕获/比较寄存器 2
#define TIM_CCR3_OFFSET 0x3C // 捕获/比较寄存器 3
#define TIM_CCR4_OFFSET 0x40 // 捕获/比较寄存器 4
#define TIM_BDTR_OFFSET 0x44 // 刹车和死区寄存器 (仅高级定时器)
// 定义控制位
#define TIM_CR1_CEN 0x0001 // 计数器使能
#define TIM_CR1_ARPE 0x0080 // 自动重装载使能
#define TIM_CCMR1_OC1M 0x0070 // 输出比较 1 模式掩码
#define TIM_CCMR1_OC2M 0x7000 // 输出比较 2 模式掩码
#define TIM_CCMR2_OC3M 0x0070 // 输出比较 3 模式掩码
#define TIM_CCMR2_OC4M 0x7000 // 输出比较 4 模式掩码
#define TIM_CCMR1_OC1PE 0x0008 // 输出比较 1 预装载使能
#define TIM_CCMR1_OC2PE 0x0800 // 输出比较 2 预装载使能
#define TIM_CCMR2_OC3PE 0x0008 // 输出比较 3 预装载使能
#define TIM_CCMR2_OC4PE 0x0800 // 输出比较 4 预装载使能
#define TIM_CCER_CC1E 0x0001 // 捕获/比较 1 输出使能
#define TIM_CCER_CC2E 0x0010 // 捕获/比较 2 输出使能
#define TIM_CCER_CC3E 0x0100 // 捕获/比较 3 输出使能
#define TIM_CCER_CC4E 0x1000 // 捕获/比较 4 输出使能
#define TIM_CCER_CC1P 0x0002 // 捕获/比较 1 输出极性
#define TIM_CCER_CC2P 0x0020 // 捕获/比较 2 输出极性
#define TIM_CCER_CC3P 0x0200 // 捕获/比较 3 输出极性
#define TIM_CCER_CC4P 0x2000 // 捕获/比较 4 输出极性
#define TIM_BDTR_MOE 0x8000 // 主输出使能 (仅高级定时器)
// PWM 模式 1 的模式值 (当计数值<比较值时通道为有效电平)
#define TIM_OCMODE_PWM1 0x0060
// 启用时钟的 RCC 寄存器
#define RCC_BASE_ADDRESS 0x40023800
#define RCC_APB2ENR_OFFSET 0x44 // APB2 外设时钟使能寄存器
#define RCC_APB1ENR_OFFSET 0x40 // APB1 外设时钟使能寄存器
#define RCC_APB2ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_APB2ENR_OFFSET))
#define RCC_APB1ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_APB1ENR_OFFSET))
// TIM1 在 APB2 上,TIM2-5 在 APB1 上
#define RCC_APB2ENR_TIM1EN 0x0001 // TIM1 时钟使能位
#define RCC_APB1ENR_TIM2EN 0x0001 // TIM2 时钟使能位
#define RCC_APB1ENR_TIM3EN 0x0002 // TIM3 时钟使能位
#define RCC_APB1ENR_TIM4EN 0x0004 // TIM4 时钟使能位
#define RCC_APB1ENR_TIM5EN 0x0008 // TIM5 时钟使能位
// 系统时钟 (假设为 84MHz)
#define SYSTEM_CLOCK 84000000UL
// 获取定时器寄存器地址
static volatile uint32_t* timer_get_register(TimerNumber timer, uint32_t offset) {
uint32_t base_addr;
switch (timer) {
case TIMER_1: base_addr = TIM1_BASE_ADDRESS; break;
case TIMER_2: base_addr = TIM2_BASE_ADDRESS; break;
case TIMER_3: base_addr = TIM3_BASE_ADDRESS; break;
case TIMER_4: base_addr = TIM4_BASE_ADDRESS; break;
case TIMER_5: base_addr = TIM5_BASE_ADDRESS; break;
default: return NULL;
}
return (volatile uint32_t*)(base_addr + offset);
}
// 获取捕获比较寄存器地址
static volatile uint32_t* timer_get_ccr_register(TimerNumber timer, TimerChannel channel) {
uint32_t offset;
switch (channel) {
case TIMER_CHANNEL_1: offset = TIM_CCR1_OFFSET; break;
case TIMER_CHANNEL_2: offset = TIM_CCR2_OFFSET; break;
case TIMER_CHANNEL_3: offset = TIM_CCR3_OFFSET; break;
case TIMER_CHANNEL_4: offset = TIM_CCR4_OFFSET; break;
default: return NULL;
}
return timer_get_register(timer, offset);
}
int pwm_init(TimerNumber timer, TimerChannel channel, const PwmConfig* config) {
// 检查参数有效性
if (timer > TIMER_5 || channel > TIMER_CHANNEL_4 || !config ||
config->dutyCycle > 100) {
return -1;
}
// 启用定时器时钟
switch (timer) {
case TIMER_1:
RCC_APB2ENR |= RCC_APB2ENR_TIM1EN;
break;
case TIMER_2:
RCC_APB1ENR |= RCC_APB1ENR_TIM2EN;
break;
case TIMER_3:
RCC_APB1ENR |= RCC_APB1ENR_TIM3EN;
break;
case TIMER_4:
RCC_APB1ENR |= RCC_APB1ENR_TIM4EN;
break;
case TIMER_5:
RCC_APB1ENR |= RCC_APB1ENR_TIM5EN;
break;
}
// 获取关键寄存器
volatile uint32_t* cr1 = timer_get_register(timer, TIM_CR1_OFFSET);
volatile uint32_t* psc = timer_get_register(timer, TIM_PSC_OFFSET);
volatile uint32_t* arr = timer_get_register(timer, TIM_ARR_OFFSET);
volatile uint32_t* ccmr1 = timer_get_register(timer, TIM_CCMR1_OFFSET);
volatile uint32_t* ccmr2 = timer_get_register(timer, TIM_CCMR2_OFFSET);
volatile uint32_t* ccer = timer_get_register(timer, TIM_CCER_OFFSET);
volatile uint32_t* ccr = timer_get_ccr_register(timer, channel);
volatile uint32_t* bdtr = NULL;
if (timer == TIMER_1) {
bdtr = timer_get_register(timer, TIM_BDTR_OFFSET);
}
if (!cr1 || !psc || !arr || !ccmr1 || !ccmr2 || !ccer || !ccr) {
return -1;
}
// 禁用定时器便于设置
*cr1 &= ~TIM_CR1_CEN;
// 计算 PSC 和 ARR 值以获得所需频率
// 假设定时器时钟为 84MHz
uint32_t timerClock = SYSTEM_CLOCK;
if (timer != TIMER_1) {
timerClock /= 2; // APB1 定时器时钟为系统时钟的一半
}
// 需要确定最佳的 PSC 值,使 ARR 在合适的范围内 (16-bit 或 32-bit)
uint32_t prescaler = 0;
uint32_t period = 0;
uint32_t maxARR = (timer == TIMER_2 || timer == TIMER_5) ? 0xFFFFFFFF : 0xFFFF;
// 尝试找到最佳预分频值
for (prescaler = 0; prescaler <= 0xFFFF; prescaler++) {
period = timerClock / ((prescaler + 1) * config->frequency);
if (period <= maxARR) {
break;
}
}
if (prescaler > 0xFFFF || period < 2) {
// 无法达到请求的频率
return -1;
}
// 设置预分频和自动重装载值
*psc = prescaler;
*arr = period;
// 计算占空比对应的比较值
uint32_t compareValue = (period * config->dutyCycle) / 100;
// 防止占空比 100% 时比较值等于 ARR+1
if (compareValue >= period) {
compareValue = period - 1;
}
// 根据通道配置输出比较模式为 PWM 模式 1
switch (channel) {
case TIMER_CHANNEL_1:
*ccmr1 &= ~TIM_CCMR1_OC1M; // 清除当前模式
*ccmr1 |= TIM_OCMODE_PWM1; // 设置为 PWM 模式 1
*ccmr1 |= TIM_CCMR1_OC1PE; // 启用预装载
break;
case TIMER_CHANNEL_2:
*ccmr1 &= ~TIM_CCMR1_OC2M; // 清除当前模式
*ccmr1 |= (TIM_OCMODE_PWM1 << 8); // 设置为 PWM 模式 1
*ccmr1 |= TIM_CCMR1_OC2PE; // 启用预装载
break;
case TIMER_CHANNEL_3:
*ccmr2 &= ~TIM_CCMR2_OC3M; // 清除当前模式
*ccmr2 |= TIM_OCMODE_PWM1; // 设置为 PWM 模式 1
*ccmr2 |= TIM_CCMR2_OC3PE; // 启用预装载
break;
case TIMER_CHANNEL_4:
*ccmr2 &= ~TIM_CCMR2_OC4M; // 清除当前模式
*ccmr2 |= (TIM_OCMODE_PWM1 << 8); // 设置为 PWM 模式 1
*ccmr2 |= TIM_CCMR2_OC4PE; // 启用预装载
break;
}
// 设置通道极性
switch (channel) {
case TIMER_CHANNEL_1:
if (config->polarity) {
*ccer |= TIM_CCER_CC1P; // 反向极性
} else {
*ccer &= ~TIM_CCER_CC1P; // 正向极性
}
break;
case TIMER_CHANNEL_2:
if (config->polarity) {
*ccer |= TIM_CCER_CC2P; // 反向极性
} else {
*ccer &= ~TIM_CCER_CC2P; // 正向极性
}
break;
case TIMER_CHANNEL_3:
if (config->polarity) {
*ccer |= TIM_CCER_CC3P; // 反向极性
} else {
*ccer &= ~TIM_CCER_CC3P; // 正向极性
}
break;
case TIMER_CHANNEL_4:
if (config->polarity) {
*ccer |= TIM_CCER_CC4P; // 反向极性
} else {
*ccer &= ~TIM_CCER_CC4P; // 正向极性
}
break;
}
// 设置比较值
*ccr = compareValue;
// 配置 CR1 寄存器
*cr1 |= TIM_CR1_ARPE; // 使能自动重装载预装寄存器
// 如果是高级定时器,需要设置 BDTR 寄存器
if (timer == TIMER_1 && bdtr) {
*bdtr |= TIM_BDTR_MOE; // 主输出使能
}
return 0;
}
int pwm_start(TimerNumber timer, TimerChannel channel) {
// 检查参数有效性
if (timer > TIMER_5 || channel > TIMER_CHANNEL_4) {
return -1;
}
// 获取关键寄存器
volatile uint32_t* cr1 = timer_get_register(timer, TIM_CR1_OFFSET);
volatile uint32_t* ccer = timer_get_register(timer, TIM_CCER_OFFSET);
if (!cr1 || !ccer) {
return -1;
}
// 启用对应通道的输出
switch (channel) {
case TIMER_CHANNEL_1:
*ccer |= TIM_CCER_CC1E;
break;
case TIMER_CHANNEL_2:
*ccer |= TIM_CCER_CC2E;
break;
case TIMER_CHANNEL_3:
*ccer |= TIM_CCER_CC3E;
break;
case TIMER_CHANNEL_4:
*ccer |= TIM_CCER_CC4E;
break;
}
// 启用定时器
*cr1 |= TIM_CR1_CEN;
return 0;
}
int pwm_stop(TimerNumber timer, TimerChannel channel) {
// 检查参数有效性
if (timer > TIMER_5 || channel > TIMER_CHANNEL_4) {
return -1;
}
// 获取关键寄存器
volatile uint32_t* ccer = timer_get_register(timer, TIM_CCER_OFFSET);
if (!ccer) {
return -1;
}
// 禁用对应通道的输出
switch (channel) {
case TIMER_CHANNEL_1:
*ccer &= ~TIM_CCER_CC1E;
break;
case TIMER_CHANNEL_2:
*ccer &= ~TIM_CCER_CC2E;
break;
case TIMER_CHANNEL_3:
*ccer &= ~TIM_CCER_CC3E;
break;
case TIMER_CHANNEL_4:
*ccer &= ~TIM_CCER_CC4E;
break;
}
return 0;
}
int pwm_set_duty_cycle(TimerNumber timer, TimerChannel channel, uint8_t dutyCycle) {
// 检查参数有效性
if (timer > TIMER_5 || channel > TIMER_CHANNEL_4 || dutyCycle > 100) {
return -1;
}
// 获取关键寄存器
volatile uint32_t* arr = timer_get_register(timer, TIM_ARR_OFFSET);
volatile uint32_t* ccr = timer_get_ccr_register(timer, channel);
if (!arr || !ccr) {
return -1;
}
// 获取当前周期值
uint32_t period = *arr;
// 计算新的比较值
uint32_t compareValue = (period * dutyCycle) / 100;
// 防止占空比 100% 时比较值等于 ARR+1
if (compareValue >= period) {
compareValue = period - 1;
}
// 设置新的比较值
*ccr = compareValue;
return 0;
}
int pwm_set_frequency(TimerNumber timer, uint32_t frequency) {
// 检查参数有效性
if (timer > TIMER_5 || frequency == 0) {
return -1;
}
// 获取关键寄存器
volatile uint32_t* cr1 = timer_get_register(timer, TIM_CR1_OFFSET);
volatile uint32_t* psc = timer_get_register(timer, TIM_PSC_OFFSET);
volatile uint32_t* arr = timer_get_register(timer, TIM_ARR_OFFSET);
if (!cr1 || !psc || !arr) {
return -1;
}
// 临时停止定时器
uint32_t cr1_val = *cr1;
*cr1 &= ~TIM_CR1_CEN;
// 计算新的 PSC 和 ARR 值以获得所需频率
uint32_t timerClock = SYSTEM_CLOCK;
if (timer != TIMER_1) {
timerClock /= 2; // APB1 定时器时钟为系统时钟的一半
}
// 尝试找到最佳预分频值
uint32_t prescaler = 0;
uint32_t period = 0;
uint32_t maxARR = (timer == TIMER_2 || timer == TIMER_5) ? 0xFFFFFFFF : 0xFFFF;
for (prescaler = 0; prescaler <= 0xFFFF; prescaler++) {
period = timerClock / ((prescaler + 1) * frequency);
if (period <= maxARR) {
break;
}
}
if (prescaler > 0xFFFF || period < 2) {
// 无法达到请求的频率
// 恢复定时器运行状态
*cr1 = cr1_val;
return -1;
}
// 设置新的预分频和自动重装载值
*psc = prescaler;
*arr = period;
// 恢复定时器运行状态
*cr1 = cr1_val;
return 0;
}
1.4 ADC转换实例
以下示例展示了一个 ADC 驱动的实现:
c
/**
* adc.h - ADC 控制接口
*
* 提供软件接口以控制 ADC 模块进行模拟量采集
*/
#ifndef ADC_H
#define ADC_H
#include <stdint.h>
// ADC 模块编号
typedef enum {
ADC_MODULE_1 = 0,
ADC_MODULE_2 = 1,
ADC_MODULE_3 = 2
} AdcModule;
// ADC 通道
typedef enum {
ADC_CHANNEL_0 = 0,
ADC_CHANNEL_1 = 1,
ADC_CHANNEL_2 = 2,
ADC_CHANNEL_3 = 3,
ADC_CHANNEL_4 = 4,
ADC_CHANNEL_5 = 5,
ADC_CHANNEL_6 = 6,
ADC_CHANNEL_7 = 7,
ADC_CHANNEL_8 = 8,
ADC_CHANNEL_9 = 9,
ADC_CHANNEL_10 = 10,
ADC_CHANNEL_11 = 11,
ADC_CHANNEL_12 = 12,
ADC_CHANNEL_13 = 13,
ADC_CHANNEL_14 = 14,
ADC_CHANNEL_15 = 15,
ADC_CHANNEL_TEMP = 16, // 内部温度传感器
ADC_CHANNEL_VREF = 17 // 内部参考电压
} AdcChannel;
// ADC 采样周期
typedef enum {
ADC_SAMPLETIME_3CYCLES = 0,
ADC_SAMPLETIME_15CYCLES = 1,
ADC_SAMPLETIME_28CYCLES = 2,
ADC_SAMPLETIME_56CYCLES = 3,
ADC_SAMPLETIME_84CYCLES = 4,
ADC_SAMPLETIME_112CYCLES = 5,
ADC_SAMPLETIME_144CYCLES = 6,
ADC_SAMPLETIME_480CYCLES = 7
} AdcSampleTime;
// ADC 分辨率
typedef enum {
ADC_RESOLUTION_12BIT = 0,
ADC_RESOLUTION_10BIT = 1,
ADC_RESOLUTION_8BIT = 2,
ADC_RESOLUTION_6BIT = 3
} AdcResolution;
// ADC 触发源(用于外部触发)
typedef enum {
ADC_TRIGGER_NONE = 0,
ADC_TRIGGER_TIMER1_CC1 = 1,
ADC_TRIGGER_TIMER1_CC2 = 2,
ADC_TRIGGER_TIMER1_CC3 = 3,
ADC_TRIGGER_TIMER2_CC2 = 4,
ADC_TRIGGER_TIMER3_TRGO = 6,
ADC_TRIGGER_EXTI11 = 15
} AdcTrigger;
// ADC 配置结构体
typedef struct {
AdcResolution resolution; // ADC 分辨率
uint8_t continuousMode; // 1 = 连续转换模式,0 = 单次转换模式
AdcTrigger externalTrigger; // 外部触发源,ADC_TRIGGER_NONE 表示软件触发
uint8_t dataAlign; // 1 = 左对齐,0 = 右对齐
} AdcConfig;
// ADC 通道配置结构体
typedef struct {
AdcChannel channel; // ADC 通道
AdcSampleTime sampleTime; // 采样时间
uint8_t rank; // 转换序列中的顺序 (1-16)
} AdcChannelConfig;
/**
* 初始化 ADC 模块
*
* @param module ADC 模块编号
* @param config ADC 配置参数
* @return 0 表示成功,非零表示失败
*/
int adc_init(AdcModule module, const AdcConfig* config);
/**
* 配置 ADC 通道
*
* @param module ADC 模块编号
* @param channelConfig 通道配置参数
* @return 0 表示成功,非零表示失败
*/
int adc_config_channel(AdcModule module, const AdcChannelConfig* channelConfig);
/**
* 启动 ADC 转换
*
* @param module ADC 模块编号
* @return 0 表示成功,非零表示失败
*/
int adc_start_conversion(AdcModule module);
/**
* 等待 ADC 转换完成
*
* @param module ADC 模块编号
* @param timeout 超时时间 (毫秒),0 表示无限等待
* @return 0 表示成功,非零表示失败或超时
*/
int adc_wait_for_conversion(AdcModule module, uint32_t timeout);
/**
* 读取 ADC 转换结果
*
* @param module ADC 模块编号
* @return ADC 转换结果
*/
uint16_t adc_read_value(AdcModule module);
/**
* 进行单通道 ADC 采样(阻塞方式)
*
* @param module ADC 模块编号
* @param channel ADC 通道
* @param sampleTime 采样时间
* @return ADC 转换结果,失败时返回 0xFFFF
*/
uint16_t adc_sample_channel(AdcModule module, AdcChannel channel, AdcSampleTime sampleTime);
#endif /* ADC_H */
c
/**
* adc.c - ADC 控制接口实现 (基于 STM32F4xx)
*
* 硬件协同设计示例:通过软件控制 ADC 硬件单元进行模拟量采集
*/
#include "adc.h"
// STM32F4xx 的 ADC 寄存器定义
#define ADC1_BASE_ADDRESS 0x40012000
#define ADC2_BASE_ADDRESS 0x40012100
#define ADC3_BASE_ADDRESS 0x40012200
#define ADC_COMMON_BASE 0x40012300
// ADC 寄存器偏移量
#define ADC_SR_OFFSET 0x00 // 状态寄存器
#define ADC_CR1_OFFSET 0x04 // 控制寄存器 1
#define ADC_CR2_OFFSET 0x08 // 控制寄存器 2
#define ADC_SMPR1_OFFSET 0x0C // 采样时间寄存器 1
#define ADC_SMPR2_OFFSET 0x10 // 采样时间寄存器 2
#define ADC_JOFR1_OFFSET 0x14 // 注入通道数据偏移寄存器 1
#define ADC_JOFR2_OFFSET 0x18 // 注入通道数据偏移寄存器 2
#define ADC_JOFR3_OFFSET 0x1C // 注入通道数据偏移寄存器 3
#define ADC_JOFR4_OFFSET 0x20 // 注入通道数据偏移寄存器 4
#define ADC_HTR_OFFSET 0x24 // 看门狗高阈值寄存器
#define ADC_LTR_OFFSET 0x28 // 看门狗低阈值寄存器
#define ADC_SQR1_OFFSET 0x2C // 规则序列寄存器 1
#define ADC_SQR2_OFFSET 0x30 // 规则序列寄存器 2
#define ADC_SQR3_OFFSET 0x34 // 规则序列寄存器 3
#define ADC_JSQR_OFFSET 0x38 // 注入序列寄存器
#define ADC_JDR1_OFFSET 0x3C // 注入数据寄存器 1
#define ADC_JDR2_OFFSET 0x40 // 注入数据寄存器 2
#define ADC_JDR3_OFFSET 0x44 // 注入数据寄存器 3
#define ADC_JDR4_OFFSET 0x48 // 注入数据寄存器 4
#define ADC_DR_OFFSET 0x4C // 规则数据寄存器
// ADC 通用寄存器偏移量
#define ADC_CSR_OFFSET 0x00 // 通用状态寄存器
#define ADC_CCR_OFFSET 0x04 // 通用控制寄存器
#define ADC_CDR_OFFSET 0x08 // 通用规则数据寄存器
// ADC 控制位定义
#define ADC_SR_EOC 0x00000002 // 转换结束标志
#define ADC_SR_STRT 0x00000010 // 规则转换开始标志
#define ADC_CR1_SCAN 0x00000100 // 扫描模式
#define ADC_CR1_EOCIE 0x00000020 // 转换结束中断使能
#define ADC_CR1_RES_MASK 0x00000030 // 分辨率掩码
#define ADC_CR1_RES_12BIT 0x00000000 // 12 位分辨率
#define ADC_CR1_RES_10BIT 0x00000010 // 10 位分辨率
#define ADC_CR1_RES_8BIT 0x00000020 // 8 位分辨率
#define ADC_CR1_RES_6BIT 0x00000030 // 6 位分辨率
#define ADC_CR2_ADON 0x00000001 // ADC 开启
#define ADC_CR2_CONT 0x00000002 // 连续转换模式
#define ADC_CR2_ALIGN 0x00000800 // 数据对齐 (0=右对齐,1=左对齐)
#define ADC_CR2_EXTEN_MASK 0x0000C000 // 外部触发使能掩码
#define ADC_CR2_EXTEN_NONE 0x00000000 // 禁用外部触发
#define ADC_CR2_EXTEN_RISING 0x00004000 // 上升沿触发
#define ADC_CR2_EXTSEL_MASK 0x00000F00 // 外部触发选择掩码
#define ADC_CR2_SWSTART 0x40000000 // 启动规则转换
// RCC 寄存器定义
#define RCC_BASE_ADDRESS 0x40023800
#define RCC_APB2ENR_OFFSET 0x44 // APB2 外设时钟使能寄存器
#define RCC_APB2ENR (*(volatile uint32_t*)(RCC_BASE_ADDRESS + RCC_APB2ENR_OFFSET))
#define RCC_APB2ENR_ADC1EN 0x00000100 // ADC1 时钟使能位
#define RCC_APB2ENR_ADC2EN 0x00000200 // ADC2 时钟使能位
#define RCC_APB2ENR_ADC3EN 0x00000400 // ADC3 时钟使能位
// 系统滴答定时器,用于延时
#define SYSTICK_BASE 0xE000E010
#define SYSTICK_CTRL (*(volatile uint32_t*)(SYSTICK_BASE))
#define SYSTICK_LOAD (*(volatile uint32_t*)(SYSTICK_BASE + 0x04))
#define SYSTICK_VAL (*(volatile uint32_t*)(SYSTICK_BASE + 0x08))
// 系统时钟 (假设为 84MHz)
#define SYSTEM_CLOCK 84000000UL
// 毫秒延时函数
static void delay_ms(uint32_t ms) {
// 设置滴答定时器
SYSTICK_LOAD = SYSTEM_CLOCK / 8000; // 1 ms
SYSTICK_VAL = 0;
SYSTICK_CTRL = 0x01; // 启用定时器
for (uint32_t i = 0; i < ms; i++) {
// 等待计数到 0 (位 16 会被置 1)
while (!(SYSTICK_CTRL & 0x10000));
}
// 禁用定时器
SYSTICK_CTRL = 0;
}
// 获取 ADC 寄存器地址
static volatile uint32_t* adc_get_register(AdcModule module, uint32_t offset) {
uint32_t base_addr;
switch (module) {
case ADC_MODULE_1: base_addr = ADC1_BASE_ADDRESS; break;
case ADC_MODULE_2: base_addr = ADC2_BASE_ADDRESS; break;
case ADC_MODULE_3: base_addr = ADC3_BASE_ADDRESS; break;
default: return NULL;
}
return (volatile uint32_t*)(base_addr + offset);
}
// 获取 ADC 通用寄存器地址
static volatile uint32_t* adc_get_common_register(uint32_t offset) {
return (volatile uint32_t*)(ADC_COMMON_BASE + offset);
}
int adc_init(AdcModule module, const AdcConfig* config) {
// 检查参数有效性
if (module > ADC_MODULE_3 || !config) {
return -1;
}
// 启用 ADC 时钟
switch (module) {
case ADC_MODULE_1:
RCC_APB2ENR |= RCC_APB2ENR_ADC1EN;
break;
case ADC_MODULE_2:
RCC_APB2ENR |= RCC_APB2ENR_ADC2EN;
break;
case ADC_MODULE_3:
RCC_APB2ENR |= RCC_APB2ENR_ADC3EN;
break;
}
// 获取关键寄存器
volatile uint32_t* cr1 = adc_get_register(module, ADC_CR1_OFFSET);
volatile uint32_t* cr2 = adc_get_register(module, ADC_CR2_OFFSET);
if (!cr1 || !cr2) {
return -1;
}
// 复位 ADC 配置
*cr1 = 0;
*cr2 = 0;
// 设置 ADC 分辨率
switch (config->resolution) {
case ADC_RESOLUTION_12BIT:
*cr1 |= ADC_CR1_RES_12BIT;
break;
case ADC_RESOLUTION_10BIT:
*cr1 |= ADC_CR1_RES_10BIT;
break;
case ADC_RESOLUTION_8BIT:
*cr1 |= ADC_CR1_RES_8BIT;
break;
case ADC_RESOLUTION_6BIT:
*cr1 |= ADC_CR1_RES_6BIT;
break;
}
// 设置扫描模式
*cr1 |= ADC_CR1_SCAN;
// 设置连续转换模式
if (config->continuousMode) {
*cr2 |= ADC_CR2_CONT;
}
// 设置数据对齐
if (config->dataAlign) {
*cr2 |= ADC_CR2_ALIGN;
}
// 设置外部触发源
if (config->externalTrigger != ADC_TRIGGER_NONE) {
*cr2 &= ~ADC_CR2_EXTSEL_MASK;
*cr2 |= ((config->externalTrigger & 0x0F) << 24);
*cr2 |= ADC_CR2_EXTEN_RISING;
}
// 使能 ADC
*cr2 |= ADC_CR2_ADON;
// 延时稳定
delay_ms(1);
return 0;
}
int adc_config_channel(AdcModule module, const AdcChannelConfig* channelConfig) {
// 检查参数有效性
if (module > ADC_MODULE_3 || !channelConfig ||
channelConfig->channel > ADC_CHANNEL_VREF ||
channelConfig->rank < 1 || channelConfig->rank > 16) {
return -1;
}
// 获取采样时间寄存器
volatile uint32_t* smpr1 = adc_get_register(module, ADC_SMPR1_OFFSET);
volatile uint32_t* smpr2 = adc_get_register(module, ADC_SMPR2_OFFSET);
// 获取序列寄存器
volatile uint32_t* sqr1 = adc_get_register(module, ADC_SQR1_OFFSET);
volatile uint32_t* sqr2 = adc_get_register(module, ADC_SQR2_OFFSET);
volatile uint32_t* sqr3 = adc_get_register(module, ADC_SQR3_OFFSET);
if (!smpr1 || !smpr2 || !sqr1 || !sqr2 || !sqr3) {
return -1;
}
// 设置通道采样时间
if (channelConfig->channel < 10) {
// 通道0-9在SMPR2中
uint32_t shift = channelConfig->channel * 3;
*smpr2 &= ~(0x7UL << shift);
*smpr2 |= (channelConfig->sampleTime & 0x7) << shift;
} else if (channelConfig->channel < 18) {
// 通道10-17在SMPR1中
uint32_t shift = (channelConfig->channel - 10) * 3;
*smpr1 &= ~(0x7UL << shift);
*smpr1 |= (channelConfig->sampleTime & 0x7) << shift;
}
// 设置转换序列
uint8_t rank = channelConfig->rank;
if (rank <= 6) {
// 排序1-6在SQR3中
uint32_t shift = (rank - 1) * 5;
*sqr3 &= ~(0x1FUL << shift);
*sqr3 |= (channelConfig->channel & 0x1F) << shift;
} else if (rank <= 12) {
// 排序7-12在SQR2中
uint32_t shift = (rank - 7) * 5;
*sqr2 &= ~(0x1FUL << shift);
*sqr2 |= (channelConfig->channel & 0x1F) << shift;
} else {
// 排序13-16在SQR1中
uint32_t shift = (rank - 13) * 5;
*sqr1 &= ~(0x1FUL << shift);
*sqr1 |= (channelConfig->channel & 0x1F) << shift;
}
// 设置序列长度
*sqr1 &= ~(0xFUL << 20);
if (rank > (*sqr1 >> 20) & 0xF) {
*sqr1 |= ((rank & 0xF) << 20);
}
// 如果是温度传感器或内部参考电压通道,需要额外配置
if (channelConfig->channel == ADC_CHANNEL_TEMP ||
channelConfig->channel == ADC_CHANNEL_VREF) {
volatile uint32_t* ccr = adc_get_common_register(ADC_CCR_OFFSET);
if (ccr) {
*ccr |= 0x00800000; // 启用温度传感器和内部参考电压
}
}
return 0;
}
int adc_start_conversion(AdcModule module) {
// 检查参数有效性
if (module > ADC_MODULE_3) {
return -1;
}
// 获取状态和控制寄存器
volatile uint32_t* sr = adc_get_register(module, ADC_SR_OFFSET);
volatile uint32_t* cr2 = adc_get_register(module, ADC_CR2_OFFSET);
if (!sr || !cr2) {
return -1;
}
// 清除转换结束标志
*sr &= ~ADC_SR_EOC;
// 启动转换
*cr2 |= ADC_CR2_SWSTART;
return 0;
}
int adc_wait_for_conversion(AdcModule module, uint32_t timeout) {
// 检查参数有效性
if (module > ADC_MODULE_3) {
return -1;
}
// 获取状态寄存器
volatile uint32_t* sr = adc_get_register(module, ADC_SR_OFFSET);
if (!sr) {
return -1;
}
// 等待转换完成或超时
uint32_t elapsed = 0;
while (!(*sr & ADC_SR_EOC)) {
if (timeout && elapsed >= timeout) {
return -1; // 超时
}
delay_ms(1);
elapsed++;
}
return 0;
}
uint16_t adc_read_value(AdcModule module) {
// 检查参数有效性
if (module > ADC_MODULE_3) {
return 0xFFFF; // 返回最大值表示错误
}
// 获取数据寄存器
volatile uint32_t* dr = adc_get_register(module, ADC_DR_OFFSET);
if (!dr) {
return 0xFFFF;
}
// 读取并返回转换结果
return (*dr & 0xFFFF);
}
uint16_t adc_sample_channel(AdcModule module, AdcChannel channel, AdcSampleTime sampleTime) {
// 设置 ADC 配置
AdcConfig config = {
.resolution = ADC_RESOLUTION_12BIT,
.continuousMode = 0, // 单次转换模式
.externalTrigger = ADC_TRIGGER_NONE, // 软件触发
.dataAlign = 0 // 右对齐
};
// 初始化 ADC
if (adc_init(module, &config) != 0) {
return 0xFFFF;
}
// 设置通道配置
AdcChannelConfig channelConfig = {
.channel = channel,
.sampleTime = sampleTime,
.rank = 1 // 只有一个通道时,排序为1
};
if (adc_config_channel(module, &channelConfig) != 0) {
return 0xFFFF;
}
// 启动转换
if (adc_start_conversion(module) != 0) {
return 0xFFFF;
}
// 等待转换完成
if (adc_wait_for_conversion(module, 100) != 0) { // 设置超时为100ms
return 0xFFFF;
}
// 读取并返回转换结果
return adc_read_value(module);
}
2. FPGA 与软件协同设计
2.1 基于 AXI 总线的软件/硬件接口
c
/**
* axi_hw_acc.h - AXI 总线硬件加速器接口
*
* 用于在 SoC 上控制 FPGA 内实现的硬件加速器
*/
#ifndef AXI_HW_ACC_H
#define AXI_HW_ACC_H
#include <stdint.h>
// 硬件加速器命令类型
typedef enum {
AXI_CMD_START = 0x01, // 启动加速器
AXI_CMD_STOP = 0x02, // 停止加速器
AXI_CMD_RESET = 0x03, // 重置加速器
AXI_CMD_CONFIG = 0x04, // 配置加速器
AXI_CMD_GET_STATUS = 0x05 // 获取加速器状态
} AxiCommand;
// 硬件加速器状态标志
typedef enum {
AXI_STATUS_IDLE = 0x00, // 空闲状态
AXI_STATUS_BUSY = 0x01, // 忙状态
AXI_STATUS_DONE = 0x02, // 完成状态
AXI_STATUS_ERROR = 0x03 // 错误状态
} AxiStatus;
// 硬件加速器配置结构体 (根据具体加速器可以修改)
typedef struct {
uint32_t inputAddress; // 输入数据地址
uint32_t outputAddress; // 输出数据地址
uint32_t dataLength; // 数据长度
uint32_t operation; // 操作类型
uint32_t flags; // 其他配置标志
} AxiAccConfig;
/**
* 打开 AXI 硬件加速器设备
*
* @param baseAddress 加速器基地址
* @return 0 表示成功,非零表示失败
*/
int axi_acc_open(uint32_t baseAddress);
/**
* 关闭 AXI 硬件加速器设备
*
* @return 0 表示成功,非零表示失败
*/
int axi_acc_close(void);
/**
* 发送命令到硬件加速器
*
* @param cmd 命令类型
* @param arg 命令参数 (根据命令类型而定)
* @return 0 表示成功,非零表示失败
*/
int axi_acc_send_command(AxiCommand cmd, uint32_t arg);
/**
* 配置硬件加速器
*
* @param config 配置参数
* @return 0 表示成功,非零表示失败
*/
int axi_acc_configure(const AxiAccConfig* config);
/**
* 获取硬件加速器状态
*
* @return 加速器状态
*/
AxiStatus axi_acc_get_status(void);
/**
* 等待硬件加速器完成操作
*
* @param timeout_ms 超时时间 (毫秒),0 表示无限等待
* @return 0 表示成功,非零表示超时或失败
*/
int axi_acc_wait_completion(uint32_t timeout_ms);
/**
* 读取硬件加速器寄存器
*
* @param regOffset 寄存器偏移地址
* @return 寄存器值
*/
uint32_t axi_acc_read_register(uint32_t regOffset);
/**
* 写入硬件加速器寄存器
*
* @param regOffset 寄存器偏移地址
* @param value 要写入的值
* @return 0 表示成功,非零表示失败
*/
int axi_acc_write_register(uint32_t regOffset, uint32_t value);
#endif /* AXI_HW_ACC_H */
c
/**
* axi_hw_acc.c - AXI 总线硬件加速器接口实现
*
* 基于内存映射 I/O 实现与 FPGA 加速器的通信
*/
#include "axi_hw_acc.h"
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
// 硬件加速器寄存器偏移定义
#define AXI_REG_CONTROL 0x00 // 控制寄存器
#define AXI_REG_STATUS 0x04 // 状态寄存器
#define AXI_REG_INPUT_ADDR 0x08 // 输入数据地址寄存器
#define AXI_REG_OUTPUT_ADDR 0x0C // 输出数据地址寄存器
#define AXI_REG_DATA_LENGTH 0x10 // 数据长度寄存器
#define AXI_REG_OPERATION 0x14 // 操作类型寄存器
#define AXI_REG_FLAGS 0x18 // 标志寄存器
#define AXI_REG_INTERRUPT 0x1C // 中断状态/清除寄存器
// 控制寄存器位定义
#define AXI_CTRL_START 0x00000001 // 启动位
#define AXI_CTRL_STOP 0x00000002 // 停止位
#define AXI_CTRL_RESET 0x00000004 // 复位位
#define AXI_CTRL_IRQ_ENABLE 0x00000008 // 中断使能位
// 状态寄存器位定义
#define AXI_STATUS_MASK 0x00000003 // 状态掩码
#define AXI_STATUS_IRQ_FLAG 0x00000010 // 中断标志
// 文件描述符和内存映射指针
static int mem_fd = -1;
static volatile uint32_t* axi_base_ptr = NULL;
static uint32_t axi_base_addr = 0;
// 毫秒级延时函数
static void delay_ms(uint32_t ms) {
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, NULL);
}
int axi_acc_open(uint32_t baseAddress) {
// 保存基址以便后续使用
axi_base_addr = baseAddress;
// 打开 /dev/mem 设备以进行内存映射访问
mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (mem_fd < 0) {
perror("打开 /dev/mem 失败");
return -1;
}
// 映射硬件加速器寄存器空间到进程地址空间
// 假设加速器有 4KB (0x1000) 的寄存器空间
axi_base_ptr = (volatile uint32_t*)mmap(NULL, 0x1000,
PROT_READ | PROT_WRITE,
MAP_SHARED,
mem_fd,
baseAddress);
if (axi_base_ptr == MAP_FAILED) {
perror("内存映射失败");
close(mem_fd);
mem_fd = -1;
return -1;
}
// 发送复位命令确保加速器处于已知状态
return axi_acc_send_command(AXI_CMD_RESET, 0);
}
int axi_acc_close(void) {
int ret = 0;
// 关闭前确保加速器不在运行
axi_acc_send_command(AXI_CMD_STOP, 0);
// 取消内存映射
if (axi_base_ptr != NULL && axi_base_ptr != MAP_FAILED) {
if (munmap((void*)axi_base_ptr, 0x1000) != 0) {
perror("取消内存映射失败");
ret = -1;
}
axi_base_ptr = NULL;
}
// 关闭文件描述符
if (mem_fd >= 0) {
if (close(mem_fd) != 0) {
perror("关闭文件描述符失败");
ret = -1;
}
mem_fd = -1;
}
return ret;
}
int axi_acc_send_command(AxiCommand cmd, uint32_t arg) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return -1;
}
// 根据命令类型设置相应的控制寄存器位
uint32_t ctrl_value = 0;
switch (cmd) {
case AXI_CMD_START:
ctrl_value = AXI_CTRL_START;
if (arg & 0x1) {
ctrl_value |= AXI_CTRL_IRQ_ENABLE; // 启用中断
}
break;
case AXI_CMD_STOP:
ctrl_value = AXI_CTRL_STOP;
break;
case AXI_CMD_RESET:
ctrl_value = AXI_CTRL_RESET;
break;
case AXI_CMD_CONFIG:
// 配置命令由 axi_acc_configure 函数处理
return -1;
case AXI_CMD_GET_STATUS:
// 获取状态命令由 axi_acc_get_status 函数处理
return -1;
default:
fprintf(stderr, "未知命令\n");
return -1;
}
// 写入控制寄存器
axi_base_ptr[AXI_REG_CONTROL / 4] = ctrl_value;
// 如果是复位命令,需要等待一段时间后再清除复位状态
if (cmd == AXI_CMD_RESET) {
delay_ms(10); // 等待10毫秒
axi_base_ptr[AXI_REG_CONTROL / 4] = 0; // 清除复位状态
}
return 0;
}
int axi_acc_configure(const AxiAccConfig* config) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return -1;
}
// 确保加速器处于空闲状态
AxiStatus status = axi_acc_get_status();
if (status != AXI_STATUS_IDLE && status != AXI_STATUS_DONE) {
fprintf(stderr, "加速器非空闲状态, 当前状态: %d\n", status);
return -1;
}
// 写入配置参数到相应寄存器
axi_base_ptr[AXI_REG_INPUT_ADDR / 4] = config->inputAddress;
axi_base_ptr[AXI_REG_OUTPUT_ADDR / 4] = config->outputAddress;
axi_base_ptr[AXI_REG_DATA_LENGTH / 4] = config->dataLength;
axi_base_ptr[AXI_REG_OPERATION / 4] = config->operation;
axi_base_ptr[AXI_REG_FLAGS / 4] = config->flags;
return 0;
}
AxiStatus axi_acc_get_status(void) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return AXI_STATUS_ERROR;
}
// 读取状态寄存器并提取状态位
uint32_t status_reg = axi_base_ptr[AXI_REG_STATUS / 4];
return (AxiStatus)(status_reg & AXI_STATUS_MASK);
}
int axi_acc_wait_completion(uint32_t timeout_ms) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return -1;
}
// 记录开始时间
uint32_t start_time = (uint32_t)time(NULL) * 1000;
uint32_t current_time;
AxiStatus status;
// 轮询加速器状态直到完成、出错或超时
do {
status = axi_acc_get_status();
if (status == AXI_STATUS_DONE || status == AXI_STATUS_ERROR) {
// 如果有中断标志,清除它
if (axi_base_ptr[AXI_REG_STATUS / 4] & AXI_STATUS_IRQ_FLAG) {
axi_base_ptr[AXI_REG_INTERRUPT / 4] = AXI_STATUS_IRQ_FLAG;
}
// 如果操作完成并且没有错误,返回成功
return (status == AXI_STATUS_DONE) ? 0 : -1;
}
// 检查是否超时
if (timeout_ms > 0) {
current_time = (uint32_t)time(NULL) * 1000;
if (current_time - start_time >= timeout_ms) {
fprintf(stderr, "等待加速器完成操作超时\n");
return -1;
}
}
// 短暂休眠以避免忙等待占用过多 CPU
delay_ms(1);
} while (1);
// 不应该到达这里
return -1;
}
uint32_t axi_acc_read_register(uint32_t regOffset) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return 0xFFFFFFFF; // 返回全1表示错误
}
// 确保偏移地址有效 (假设寄存器空间为4KB)
if (regOffset >= 0x1000 || (regOffset & 0x3) != 0) {
fprintf(stderr, "无效的寄存器偏移: 0x%08X\n", regOffset);
return 0xFFFFFFFF;
}
// 读取并返回寄存器值
return axi_base_ptr[regOffset / 4];
}
int axi_acc_write_register(uint32_t regOffset, uint32_t value) {
// 确保设备已打开
if (axi_base_ptr == NULL || axi_base_ptr == MAP_FAILED) {
fprintf(stderr, "设备未打开\n");
return -1;
}
// 确保偏移地址有效 (假设寄存器空间为4KB)
if (regOffset >= 0x1000 || (regOffset & 0x3) != 0) {
fprintf(stderr, "无效的寄存器偏移: 0x%08X\n", regOffset);
return -1;
}
// 写入寄存器
axi_base_ptr[regOffset / 4] = value;
return 0;
}
2.2 硬件加速器应用示例 - 矩阵乘法
c
/**
* matrix_multiply.h - 矩阵乘法硬件加速器接口
*
* 提供利用FPGA矩阵乘法加速器的软件API
*/
#ifndef MATRIX_MULTIPLY_H
#define MATRIX_MULTIPLY_H
#include <stdint.h>
#include "axi_hw_acc.h"
// 矩阵乘法操作类型
typedef enum {
MATRIX_OP_NORMAL = 0, // 普通矩阵乘法 C = A * B
MATRIX_OP_TRANSPOSE_A = 1, // A转置乘法 C = A^T * B
MATRIX_OP_TRANSPOSE_B = 2, // B转置乘法 C = A * B^T
MATRIX_OP_TRANSPOSE_AB = 3 // 双转置乘法 C = A^T * B^T
} MatrixOperation;
// 矩阵乘法描述符
typedef struct {
float* matrixA; // 矩阵A数据指针
float* matrixB; // 矩阵B数据指针
float* matrixC; // 结果矩阵C数据指针
uint32_t rowsA; // 矩阵A的行数
uint32_t colsA; // 矩阵A的列数
uint32_t colsB; // 矩阵B的列数
MatrixOperation op; // 操作类型
} MatrixMultiplyDesc;
/**
* 初始化矩阵乘法加速器
*
* @param baseAddress 加速器基地址
* @return 0 表示成功,非零表示失败
*/
int matrix_multiply_init(uint32_t baseAddress);
/**
* 关闭矩阵乘法加速器
*
* @return 0 表示成功,非零表示失败
*/
int matrix_multiply_close(void);
/**
* 执行矩阵乘法运算
*
* @param desc 矩阵乘法描述符
* @param useHardware 是否使用硬件加速 (1=使用,0=软件实现)
* @return 0 表示成功,非零表示失败
*/
int matrix_multiply_execute(MatrixMultiplyDesc* desc, int useHardware);
/**
* 进行矩阵乘法性能测试
*
* @param size 方阵大小
* @param iterations 迭代次数
* @return 0 表示成功,非零表示失败
*/
int matrix_multiply_benchmark(uint32_t size, uint32_t iterations);
#endif /* MATRIX_MULTIPLY_H */
c
/**
* matrix_multiply.c - 矩阵乘法硬件加速器实现
*
* 硬件协同设计的典型应用:同时提供硬件加速和软件实现
*/
#include "matrix_multiply.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
// DMA缓冲区分配和内存管理函数
static void* alloc_dma_buffer(size_t size);
static void free_dma_buffer(void* buffer);
static uint64_t get_physical_address(void* virtual_address);
// 软件矩阵乘法实现
static int matrix_multiply_software(MatrixMultiplyDesc* desc);
// 获取当前时间(毫秒)
static uint64_t get_time_ms(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
int matrix_multiply_init(uint32_t baseAddress) {
// 打开并初始化AXI硬件加速器
return axi_acc_open(baseAddress);
}
int matrix_multiply_close(void) {
// 关闭AXI硬件加速器
return axi_acc_close();
}
int matrix_multiply_execute(MatrixMultiplyDesc* desc, int useHardware) {
// 参数验证
if (!desc || !desc->matrixA || !desc->matrixB || !desc->matrixC) {
fprintf(stderr, "矩阵描述符或矩阵数据为空\n");
return -1;
}
if (desc->rowsA == 0 || desc->colsA == 0 || desc->colsB == 0) {
fprintf(stderr, "矩阵维度无效\n");
return -1;
}
// 根据需要选择硬件或软件实现
if (useHardware) {
// 使用硬件加速器实现
// 分配DMA缓冲区用于传输数据
size_t sizeA = desc->rowsA * desc->colsA * sizeof(float);
size_t sizeB = desc->colsA * desc->colsB * sizeof(float);
size_t sizeC = desc->rowsA * desc->colsB * sizeof(float);
float* dmaA = (float*)alloc_dma_buffer(sizeA);
float* dmaB = (float*)alloc_dma_buffer(sizeB);
float* dmaC = (float*)alloc_dma_buffer(sizeC);
if (!dmaA || !dmaB || !dmaC) {
fprintf(stderr, "分配DMA缓冲区失败\n");
if (dmaA) free_dma_buffer(dmaA);
if (dmaB) free_dma_buffer(dmaB);
if (dmaC) free_dma_buffer(dmaC);
return -1;
}
// 复制输入数据到DMA缓冲区
memcpy(dmaA, desc->matrixA, sizeA);
memcpy(dmaB, desc->matrixB, sizeB);
// 获取物理地址用于配置硬件加速器
uint64_t phyAddrA = get_physical_address(dmaA);
uint64_t phyAddrB = get_physical_address(dmaB);
uint64_t phyAddrC = get_physical_address(dmaC);
if (phyAddrA == 0 || phyAddrB == 0 || phyAddrC == 0) {
fprintf(stderr, "获取物理地址失败\n");
free_dma_buffer(dmaA);
free_dma_buffer(dmaB);
free_dma_buffer(dmaC);
return -1;
}
// 配置硬件加速器
AxiAccConfig hwConfig;
hwConfig.inputAddress = (uint32_t)phyAddrA; // 矩阵A物理地址
hwConfig.outputAddress = (uint32_t)phyAddrC; // 结果矩阵C物理地址
hwConfig.dataLength = desc->rowsA; // 行数
hwConfig.operation = desc->op; // 操作类型
// 额外配置信息(使用flags字段)
hwConfig.flags = ((uint32_t)phyAddrB & 0xFFFFFFFF) // 矩阵B物理地址低32位
| ((uint32_t)desc->colsA << 16) // A列数(高16位)
| ((uint32_t)desc->colsB); // B列数(低16位)
// 发送配置到硬件
if (axi_acc_configure(&hwConfig) != 0) {
fprintf(stderr, "配置硬件加速器失败\n");
free_dma_buffer(dmaA);
free_dma_buffer(dmaB);
free_dma_buffer(dmaC);
return -1;
}
// 启动硬件加速器
if (axi_acc_send_command(AXI_CMD_START, 1) != 0) {
fprintf(stderr, "启动硬件加速器失败\n");
free_dma_buffer(dmaA);
free_dma_buffer(dmaB);
free_dma_buffer(dmaC);
return -1;
}
// 等待计算完成
if (axi_acc_wait_completion(5000) != 0) { // 5秒超时
fprintf(stderr, "硬件加速器执行超时或出错\n");
free_dma_buffer(dmaA);
free_dma_buffer(dmaB);
free_dma_buffer(dmaC);
return -1;
}
// 从DMA缓冲区复制结果到目标矩阵
memcpy(desc->matrixC, dmaC, sizeC);
// 释放DMA缓冲区
free_dma_buffer(dmaA);
free_dma_buffer(dmaB);
free_dma_buffer(dmaC);
} else {
// 使用软件实现
return matrix_multiply_software(desc);
}
return 0;
}
int matrix_multiply_benchmark(uint32_t size, uint32_t iterations) {
int ret = 0;
uint64_t sw_time_total = 0, hw_time_total = 0;
uint64_t start_time, end_time;
// 分配矩阵内存
float* matrixA = (float*)malloc(size * size * sizeof(float));
float* matrixB = (float*)malloc(size * size * sizeof(float));
float* matrixC_sw = (float*)malloc(size * size * sizeof(float));
float* matrixC_hw = (float*)malloc(size * size * sizeof(float));
if (!matrixA || !matrixB || !matrixC_sw || !matrixC_hw) {
fprintf(stderr, "内存分配失败\n");
if (matrixA) free(matrixA);
if (matrixB) free(matrixB);
if (matrixC_sw) free(matrixC_sw);
if (matrixC_hw) free(matrixC_hw);
return -1;
}
// 随机生成测试数据
srand(time(NULL));
for (uint32_t i = 0; i < size * size; i++) {
matrixA[i] = (float)rand() / RAND_MAX;
matrixB[i] = (float)rand() / RAND_MAX;
}
// 准备矩阵乘法描述符
MatrixMultiplyDesc desc;
desc.matrixA = matrixA;
desc.matrixB = matrixB;
desc.rowsA = size;
desc.colsA = size;
desc.colsB = size;
desc.op = MATRIX_OP_NORMAL;
// 执行软件矩阵乘法基准测试
for (uint32_t i = 0; i < iterations; i++) {
desc.matrixC = matrixC_sw;
start_time = get_time_ms();
ret = matrix_multiply_execute(&desc, 0); // 使用软件实现
end_time = get_time_ms();
if (ret != 0) {
fprintf(stderr, "软件矩阵乘法执行失败\n");
break;
}
sw_time_total += (end_time - start_time);
}
// 执行硬件矩阵乘法基准测试
for (uint32_t i = 0; i < iterations; i++) {
desc.matrixC = matrixC_hw;
start_time = get_time_ms();
ret = matrix_multiply_execute(&desc, 1); // 使用硬件加速
end_time = get_time_ms();
if (ret != 0) {
fprintf(stderr, "硬件矩阵乘法执行失败\n");
break;
}
hw_time_total += (end_time - start_time);
}
// 验证结果一致性
if (ret == 0) {
int mismatch = 0;
for (uint32_t i = 0; i < size * size; i++) {
if (fabsf(matrixC_sw[i] - matrixC_hw[i]) > 1e-4) {
mismatch++;
}
}
if (mismatch > 0) {
fprintf(stderr, "结果不匹配: %d 个元素(共 %u 个)\n", mismatch, size * size);
ret = -1;
}
}
// 打印性能数据
if (ret == 0) {
float sw_avg_time = (float)sw_time_total / iterations;
float hw_avg_time = (float)hw_time_total / iterations;
float speedup = sw_avg_time / hw_avg_time;
printf("矩阵乘法基准测试 (尺寸: %u x %u, 迭代: %u)\n", size, size, iterations);
printf("软件实现平均时间: %.2f ms\n", sw_avg_time);
printf("硬件加速平均时间: %.2f ms\n", hw_avg_time);
printf("加速比: %.2f x\n", speedup);
}
// 释放内存
free(matrixA);
free(matrixB);
free(matrixC_sw);
free(matrixC_hw);
return ret;
}
// 软件矩阵乘法实现
static int matrix_multiply_software(MatrixMultiplyDesc* desc) {
uint32_t i, j, k;
uint32_t rowsA = desc->rowsA;
uint32_t colsA = desc->colsA;
uint32_t colsB = desc->colsB;
// 初始化结果矩阵
memset(desc->matrixC, 0, rowsA * colsB * sizeof(float));
// 根据操作类型执行不同的矩阵乘法
switch (desc->op) {
case MATRIX_OP_NORMAL:
// C = A * B
for (i = 0; i < rowsA; i++) {
for (j = 0; j < colsB; j++) {
for (k = 0; k < colsA; k++) {
desc->matrixC[i * colsB + j] +=
desc->matrixA[i * colsA + k] * desc->matrixB[k * colsB + j];
}
}
}
break;
case MATRIX_OP_TRANSPOSE_A:
// C = A^T * B
for (i = 0; i < colsA; i++) {
for (j = 0; j < colsB; j++) {
for (k = 0; k < rowsA; k++) {
desc->matrixC[i * colsB + j] +=
desc->matrixA[k * colsA + i] * desc->matrixB[k * colsB + j];
}
}
}
break;
case MATRIX_OP_TRANSPOSE_B:
// C = A * B^T
for (i = 0; i < rowsA; i++) {
for (j = 0; j < colsA; j++) {
for (k = 0; k < colsB; k++) {
desc->matrixC[i * colsA + j] +=
desc->matrixA[i * colsA + k] * desc->matrixB[j * colsB + k];
}
}
}
break;
case MATRIX_OP_TRANSPOSE_AB:
// C = A^T * B^T
for (i = 0; i < colsA; i++) {
for (j = 0; j < colsA; j++) {
for (k = 0; k < rowsA; k++) {
desc->matrixC[i * colsA + j] +=
desc->matrixA[k * colsA + i] * desc->matrixB[j * colsB + k];
}
}
}
break;
default:
fprintf(stderr, "未知的矩阵操作类型: %d\n", desc->op);
return -1;
}
return 0;
}
// DMA缓冲区分配 (简化实现,实际代码需根据目标平台调整)
static void* alloc_dma_buffer(size_t size) {
// 在实际系统中,这里通常使用特殊的API来分配物理连续内存
// 例如在Linux中可能使用DMA缓冲区API或contiguous memory allocator
// 这里仅作为示例,使用常规内存分配
return malloc(size);
}
static void free_dma_buffer(void* buffer) {
free(buffer);
}
static uint64_t get_physical_address(void* virtual_address) {
// 在实际系统中,这里需要使用特定平台的方法获取物理地址
// 例如在Linux中可能使用/proc/self/pagemap或特定驱动API
// 这里仅作为示例,直接返回虚拟地址的值(不正确,但作为示例)
return (uint64_t)virtual_address;
}
2.3 自定义硬件IP核的接口实现
cpp
/**
* custom_ip.h - 自定义硬件IP核的C++接口
*
* 提供面向对象的封装,用于访问FPGA中的自定义IP核
*/
#ifndef CUSTOM_IP_H
#define CUSTOM_IP_H
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
namespace hw_accel {
// 前向声明
class CustomIPImpl;
/**
* 自定义硬件IP核的C++接口类
*/
class CustomIP {
public:
/**
* 构造函数
*
* @param device_name 设备名称
* @param base_address 基地址
*/
CustomIP(const std::string& device_name, uint64_t base_address);
/**
* 析构函数
*/
~CustomIP();
/**
* 打开设备
*
* @return 成功返回true,失败返回false
*/
bool open();
/**
* 关闭设备
*/
void close();
/**
* 检查设备是否已打开
*
* @return 已打开返回true,否则返回false
*/
bool is_open() const;
/**
* 获取设备名称
*
* @return 设备名称
*/
std::string get_device_name() const;
/**
* 获取设备基地址
*
* @return 基地址
*/
uint64_t get_base_address() const;
/**
* 从指定偏移读取32位数据
*
* @param offset 寄存器偏移
* @return 32位寄存器值
*/
uint32_t read_register(uint32_t offset) const;
/**
* 向指定偏移写入32位数据
*
* @param offset 寄存器偏移
* @param value 要写入的值
*/
void write_register(uint32_t offset, uint32_t value);
/**
* 读取一块连续的32位数据
*
* @param offset 起始偏移
* @param length 数据长度(32位字数)
* @return 32位数据向量
*/
std::vector<uint32_t> read_block(uint32_t offset, size_t length) const;
/**
* 写入一块连续的32位数据
*
* @param offset 起始偏移
* @param data 要写入的数据向量
*/
void write_block(uint32_t offset, const std::vector<uint32_t>& data);
/**
* 等待指定位置位
*
* @param offset 寄存器偏移
* @param mask 位掩码
* @param timeout_ms 超时时间(毫秒)
* @return 成功返回true,超时返回false
*/
bool wait_for_bit_set(uint32_t offset, uint32_t mask, uint32_t timeout_ms = 1000) const;
/**
* 等待指定位清零
*
* @param offset 寄存器偏移
* @param mask 位掩码
* @param timeout_ms 超时时间(毫秒)
* @return 成功返回true,超时返回false
*/
bool wait_for_bit_clear(uint32_t offset, uint32_t mask, uint32_t timeout_ms = 1000) const;
/**
* 获取最后一个错误消息
*
* @return 错误消息
*/
std::string get_last_error() const;
private:
// 私有实现 (PIMPL模式)
std::unique_ptr<CustomIPImpl> impl_;
// 禁止拷贝和赋值
CustomIP(const CustomIP&) = delete;
CustomIP& operator=(const CustomIP&) = delete;
};
} // namespace hw_accel
#endif /* CUSTOM_IP_H */
cpp
/**
* custom_ip.cpp - 自定义硬件IP核的C++接口实现
*
* 使用PIMPL设计模式隐藏实现细节
*/
#include "custom_ip.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <chrono>
#include <thread>
#include <system_error>
#include <cerrno>
#include <cstring>
namespace hw_accel {
// 私有实现类
class CustomIPImpl {
public:
CustomIPImpl(const std::string& device_name, uint64_t base_address)
: device_name_(device_name),
base_address_(base_address),
fd_(-1),
mapped_addr_(nullptr),
mapped_size_(0),
last_error_() {}
~CustomIPImpl() {
close();
}
bool open() {
// 如果已经打开,先关闭
if (fd_ >= 0) {
close();
}
// 清除上一次错误
last_error_.clear();
// 打开/dev/mem设备文件
fd_ = ::open("/dev/mem", O_RDWR | O_SYNC);
if (fd_ < 0) {
last_error_ = "打开/dev/mem失败: " + std::string(strerror(errno));
return false;
}
// 设置映射大小 (假设为4KB)
mapped_size_ = 4096;
// 使用mmap映射硬件地址空间
mapped_addr_ = mmap(nullptr, mapped_size_, PROT_READ | PROT_WRITE,
MAP_SHARED, fd_, base_address_);
if (mapped_addr_ == MAP_FAILED) {
last_error_ = "内存映射失败: " + std::string(strerror(errno));
::close(fd_);
fd_ = -1;
mapped_addr_ = nullptr;
return false;
}
return true;
}
void close() {
if (mapped_addr_ != nullptr && mapped_addr_ != MAP_FAILED) {
munmap(mapped_addr_, mapped_size_);
mapped_addr_ = nullptr;
}
if (fd_ >= 0) {
::close(fd_);
fd_ = -1;
}
}
bool is_open() const {
return (fd_ >= 0 && mapped_addr_ != nullptr && mapped_addr_ != MAP_FAILED);
}
std::string get_device_name() const {
return device_name_;
}
uint64_t get_base_address() const {
return base_address_;
}
uint32_t read_register(uint32_t offset) const {
if (!is_open()) {
const_cast<CustomIPImpl*>(this)->last_error_ = "设备未打开";
return 0xFFFFFFFF;
}
if (offset >= mapped_size_) {
const_cast<CustomIPImpl*>(this)->last_error_ = "访问超出映射范围";
return 0xFFFFFFFF;
}
// 读取寄存器值
volatile uint32_t* reg_ptr = static_cast<volatile uint32_t*>(mapped_addr_) + (offset / 4);
return *reg_ptr;
}
void write_register(uint32_t offset, uint32_t value) {
if (!is_open()) {
last_error_ = "设备未打开";
return;
}
if (offset >= mapped_size_) {
last_error_ = "访问超出映射范围";
return;
}
// 写入寄存器值
volatile uint32_t* reg_ptr = static_cast<volatile uint32_t*>(mapped_addr_) + (offset / 4);
*reg_ptr = value;
}
std::vector<uint32_t> read_block(uint32_t offset, size_t length) const {
std::vector<uint32_t> result;
if (!is_open()) {
const_cast<CustomIPImpl*>(this)->last_error_ = "设备未打开";
return result;
}
if (offset + length * 4 > mapped_size_) {
const_cast<CustomIPImpl*>(this)->last_error_ = "访问超出映射范围";
return result;
}
// 预先分配空间
result.reserve(length);
// 读取连续的寄存器块
volatile uint32_t* reg_ptr = static_cast<volatile uint32_t*>(mapped_addr_) + (offset / 4);
for (size_t i = 0; i < length; ++i) {
result.push_back(reg_ptr[i]);
}
return result;
}
void write_block(uint32_t offset, const std::vector<uint32_t>& data) {
if (!is_open()) {
last_error_ = "设备未打开";
return;
}
if (offset + data.size() * 4 > mapped_size_) {
last_error_ = "访问超出映射范围";
return;
}
// 写入连续的寄存器块
volatile uint32_t* reg_ptr = static_cast<volatile uint32_t*>(mapped_addr_) + (offset / 4);
for (size_t i = 0; i < data.size(); ++i) {
reg_ptr[i] = data[i];
}
}
bool wait_for_bit_set(uint32_t offset, uint32_t mask, uint32_t timeout_ms) const {
if (!is_open()) {
const_cast<CustomIPImpl*>(this)->last_error_ = "设备未打开";
return false;
}
// 获取当前时间
auto start_time = std::chrono::steady_clock::now();
// 轮询等待指定位置位
while (true) {
uint32_t value = read_register(offset);
// 检查指定位是否已置位
if ((value & mask) == mask) {
return true;
}
// 检查是否超时
auto current_time = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
current_time - start_time).count();
if (elapsed >= timeout_ms) {
const_cast<CustomIPImpl*>(this)->last_error_ = "等待位置位超时";
return false;
}
// 短暂休眠以避免过度占用CPU
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
bool wait_for_bit_clear(uint32_t offset, uint32_t mask, uint32_t timeout_ms) const {
if (!is_open()) {
const_cast<CustomIPImpl*>(this)->last_error_ = "设备未打开";
return false;
}
// 获取当前时间
auto start_time = std::chrono::steady_clock::now();
// 轮询等待指定位
cpp
// 轮询等待指定位清零
while (true) {
uint32_t value = read_register(offset);
// 检查指定位是否已清零
if ((value & mask) == 0) {
return true;
}
// 检查是否超时
auto current_time = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
current_time - start_time).count();
if (elapsed >= timeout_ms) {
const_cast<CustomIPImpl*>(this)->last_error_ = "等待位清零超时";
return false;
}
// 短暂休眠以避免过度占用CPU
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
std::string get_last_error() const {
return last_error_;
}
private:
std::string device_name_; // 设备名称
uint64_t base_address_; // 基地址
int fd_; // 文件描述符
void* mapped_addr_; // 内存映射地址
size_t mapped_size_; // 映射大小
std::string last_error_; // 最后一个错误消息
};
// CustomIP的外部实现,委托给CustomIPImpl
CustomIP::CustomIP(const std::string& device_name, uint64_t base_address)
: impl_(new CustomIPImpl(device_name, base_address)) {
}
CustomIP::~CustomIP() = default;
bool CustomIP::open() {
return impl_->open();
}
void CustomIP::close() {
impl_->close();
}
bool CustomIP::is_open() const {
return impl_->is_open();
}
std::string CustomIP::get_device_name() const {
return impl_->get_device_name();
}
uint64_t CustomIP::get_base_address() const {
return impl_->get_base_address();
}
uint32_t CustomIP::read_register(uint32_t offset) const {
return impl_->read_register(offset);
}
void CustomIP::write_register(uint32_t offset, uint32_t value) {
impl_->write_register(offset, value);
}
std::vector<uint32_t> CustomIP::read_block(uint32_t offset, size_t length) const {
return impl_->read_block(offset, length);
}
void CustomIP::write_block(uint32_t offset, const std::vector<uint32_t>& data) {
impl_->write_block(offset, data);
}
bool CustomIP::wait_for_bit_set(uint32_t offset, uint32_t mask, uint32_t timeout_ms) const {
return impl_->wait_for_bit_set(offset, mask, timeout_ms);
}
bool CustomIP::wait_for_bit_clear(uint32_t offset, uint32_t mask, uint32_t timeout_ms) const {
return impl_->wait_for_bit_clear(offset, mask, timeout_ms);
}
std::string CustomIP::get_last_error() const {
return impl_->get_last_error();
}
} // namespace hw_accel
2.4 FFT 硬件加速器实例
cpp
/**
* fft_accelerator.h - FFT 硬件加速器接口
*
* 使用自定义IP核实现FFT运算的硬件加速
*/
#ifndef FFT_ACCELERATOR_H
#define FFT_ACCELERATOR_H
#include <cstdint>
#include <vector>
#include <complex>
#include <memory>
#include "custom_ip.h"
namespace hw_accel {
// 前向声明
class FFTAcceleratorImpl;
/**
* FFT 硬件加速器类
*/
class FFTAccelerator {
public:
/**
* 构造函数
*
* @param ip_core 自定义IP核对象
*/
explicit FFTAccelerator(std::shared_ptr<CustomIP> ip_core);
/**
* 析构函数
*/
~FFTAccelerator();
/**
* 初始化加速器
*
* @return 成功返回true,失败返回false
*/
bool initialize();
/**
* 执行FFT运算
*
* @param input 输入数据 (复数向量)
* @param inverse 是否执行IFFT (true = IFFT, false = FFT)
* @param useHardware 是否使用硬件加速 (true = 硬件, false = 软件)
* @return 结果数据 (复数向量)
*/
std::vector<std::complex<float>> execute(
const std::vector<std::complex<float>>& input,
bool inverse = false,
bool useHardware = true);
/**
* 获取最后一个错误消息
*
* @return 错误消息
*/
std::string get_last_error() const;
/**
* 执行性能基准测试
*
* @param fft_size FFT尺寸 (2的幂次方)
* @param iterations 迭代次数
* @return 成功返回true,失败返回false
*/
bool benchmark(uint32_t fft_size, uint32_t iterations);
private:
// 私有实现 (PIMPL模式)
std::unique_ptr<FFTAcceleratorImpl> impl_;
// 禁止拷贝和赋值
FFTAccelerator(const FFTAccelerator&) = delete;
FFTAccelerator& operator=(const FFTAccelerator&) = delete;
};
} // namespace hw_accel
#endif /* FFT_ACCELERATOR_H */
cpp
/**
* fft_accelerator.cpp - FFT 硬件加速器实现
*
* 实现软硬件协同的FFT运算,支持在硬件加速不可用时回退到软件实现
*/
#include "fft_accelerator.h"
#include <cmath>
#include <algorithm>
#include <iostream>
#include <chrono>
#include <cstring>
#include <numeric>
namespace hw_accel {
// FFT加速器寄存器偏移
#define FFT_REG_CONTROL 0x00 // 控制寄存器
#define FFT_REG_STATUS 0x04 // 状态寄存器
#define FFT_REG_SIZE 0x08 // FFT大小寄存器
#define FFT_REG_DATA_ADDR 0x0C // 数据地址寄存器
#define FFT_REG_CONFIG 0x10 // 配置寄存器
#define FFT_REG_SCALE 0x14 // 缩放因子寄存器
#define FFT_REG_VERSION 0x18 // 版本信息寄存器
// 控制寄存器位
#define FFT_CTRL_START 0x01 // 启动计算
#define FFT_CTRL_RESET 0x02 // 复位核心
#define FFT_CTRL_INVERSE 0x04 // IFFT模式
#define FFT_CTRL_IRQ_ENABLE 0x08 // 中断使能
// 状态寄存器位
#define FFT_STATUS_DONE 0x01 // 操作完成
#define FFT_STATUS_BUSY 0x02 // 正在计算
#define FFT_STATUS_ERROR 0x04 // 错误标志
#define FFT_STATUS_IRQ 0x08 // 中断标志
// 配置寄存器位
#define FFT_CONFIG_SCALING 0x01 // 启用自动缩放
#define FFT_CONFIG_ZEROFILL 0x02 // 启用零填充
// 私有实现类
class FFTAcceleratorImpl {
public:
FFTAcceleratorImpl(std::shared_ptr<CustomIP> ip_core)
: ip_core_(ip_core),
initialized_(false),
last_error_() {}
bool initialize() {
// 检查IP核是否已打开
if (!ip_core_ || !ip_core_->is_open()) {
last_error_ = "IP核未打开";
return false;
}
// 读取版本信息
uint32_t version = ip_core_->read_register(FFT_REG_VERSION);
// 检查版本兼容性 (假设版本号必须大于等于0x01000000)
if (version < 0x01000000) {
char version_str[16];
snprintf(version_str, sizeof(version_str), "0x%08X", version);
last_error_ = "不支持的FFT加速器版本: " + std::string(version_str);
return false;
}
// 复位FFT核心
ip_core_->write_register(FFT_REG_CONTROL, FFT_CTRL_RESET);
// 等待复位完成
if (!ip_core_->wait_for_bit_clear(FFT_REG_CONTROL, FFT_CTRL_RESET, 1000)) {
last_error_ = "FFT核心复位超时";
return false;
}
// 设置标准配置
ip_core_->write_register(FFT_REG_CONFIG, FFT_CONFIG_SCALING);
initialized_ = true;
return true;
}
std::vector<std::complex<float>> execute(
const std::vector<std::complex<float>>& input,
bool inverse,
bool useHardware) {
// 检查输入大小是否为2的幂次方
size_t size = input.size();
if (size == 0 || (size & (size - 1)) != 0) {
last_error_ = "输入大小必须为2的幂次方";
return std::vector<std::complex<float>>();
}
// 根据需要选择硬件或软件实现
if (useHardware && initialized_) {
return execute_hardware(input, inverse);
} else {
return execute_software(input, inverse);
}
}
std::string get_last_error() const {
if (!last_error_.empty()) {
return last_error_;
}
if (ip_core_) {
return ip_core_->get_last_error();
}
return "未知错误";
}
bool benchmark(uint32_t fft_size, uint32_t iterations) {
if (fft_size == 0 || (fft_size & (fft_size - 1)) != 0) {
last_error_ = "FFT大小必须为2的幂次方";
return false;
}
std::cout << "FFT基准测试 (尺寸: " << fft_size << ", 迭代: " << iterations << ")" << std::endl;
// 生成随机测试数据
std::vector<std::complex<float>> test_data;
test_data.reserve(fft_size);
for (uint32_t i = 0; i < fft_size; i++) {
float real = static_cast<float>(rand()) / RAND_MAX * 2.0f - 1.0f;
float imag = static_cast<float>(rand()) / RAND_MAX * 2.0f - 1.0f;
test_data.push_back(std::complex<float>(real, imag));
}
// 软件FFT基准测试
auto sw_start = std::chrono::high_resolution_clock::now();
for (uint32_t i = 0; i < iterations; i++) {
auto sw_result = execute_software(test_data, false);
// 防止编译器优化掉结果
if (sw_result.size() == 0) {
std::cout << "软件FFT失败" << std::endl;
return false;
}
}
auto sw_end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> sw_time = sw_end - sw_start;
// 硬件FFT基准测试
auto hw_start = std::chrono::high_resolution_clock::now();
for (uint32_t i = 0; i < iterations; i++) {
auto hw_result = execute_hardware(test_data, false);
// 防止编译器优化掉结果
if (hw_result.size() == 0) {
std::cout << "硬件FFT失败: " << get_last_error() << std::endl;
return false;
}
}
auto hw_end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> hw_time = hw_end - hw_start;
// 计算加速比
double speedup = sw_time.count() / hw_time.count();
// 打印性能结果
std::cout << "软件FFT时间: " << sw_time.count() / iterations << " ms/op" << std::endl;
std::cout << "硬件FFT时间: " << hw_time.count() / iterations << " ms/op" << std::endl;
std::cout << "加速比: " << speedup << " x" << std::endl;
return true;
}
private:
// 硬件FFT实现
std::vector<std::complex<float>> execute_hardware(
const std::vector<std::complex<float>>& input,
bool inverse) {
size_t size = input.size();
// 检查输入大小是否为2的幂次方
if (size == 0 || (size & (size - 1)) != 0) {
last_error_ = "输入大小必须为2的幂次方";
return std::vector<std::complex<float>>();
}
// 配置FFT大小
ip_core_->write_register(FFT_REG_SIZE, static_cast<uint32_t>(size));
// 准备输入/输出缓冲区
std::vector<uint32_t> data_buffer;
data_buffer.reserve(size * 2); // 每个复数需要两个32位值
// 将输入数据转换为硬件格式 (交替的实部/虚部)
for (const auto& complex_val : input) {
// 使用IEEE-754单精度浮点表示
uint32_t real_bits, imag_bits;
memcpy(&real_bits, &complex_val.real(), sizeof(real_bits));
memcpy(&imag_bits, &complex_val.imag(), sizeof(imag_bits));
data_buffer.push_back(real_bits);
data_buffer.push_back(imag_bits);
}
// 分配DMA内存并复制数据 (简化实现)
// 在实际系统中,这里应该使用正确的DMA API
void* dma_buffer = allocate_dma_buffer(data_buffer.size() * sizeof(uint32_t));
if (!dma_buffer) {
last_error_ = "分配DMA缓冲区失败";
return std::vector<std::complex<float>>();
}
// 复制数据到DMA缓冲区
memcpy(dma_buffer, data_buffer.data(), data_buffer.size() * sizeof(uint32_t));
// 获取DMA缓冲区物理地址
uint64_t dma_phys_addr = get_physical_address(dma_buffer);
// 配置数据地址
ip_core_->write_register(FFT_REG_DATA_ADDR, static_cast<uint32_t>(dma_phys_addr));
// 设置FFT模式 (正向或逆向)
uint32_t control = FFT_CTRL_START;
if (inverse) {
control |= FFT_CTRL_INVERSE;
}
// 启动FFT计算
ip_core_->write_register(FFT_REG_CONTROL, control);
// 等待计算完成
if (!ip_core_->wait_for_bit_set(FFT_REG_STATUS, FFT_STATUS_DONE, 5000)) {
last_error_ = "FFT计算超时";
free_dma_buffer(dma_buffer);
return std::vector<std::complex<float>>();
}
// 检查是否有错误
uint32_t status = ip_core_->read_register(FFT_REG_STATUS);
if (status & FFT_STATUS_ERROR) {
last_error_ = "FFT计算出错";
free_dma_buffer(dma_buffer);
return std::vector<std::complex<float>>();
}
// 清除状态标志
ip_core_->write_register(FFT_REG_STATUS, 0);
// 从DMA缓冲区读取结果
memcpy(data_buffer.data(), dma_buffer, data_buffer.size() * sizeof(uint32_t));
// 释放DMA缓冲区
free_dma_buffer(dma_buffer);
// 将硬件格式转换回复数向量
std::vector<std::complex<float>> result;
result.reserve(size);
for (size_t i = 0; i < data_buffer.size(); i += 2) {
float real, imag;
uint32_t real_bits = data_buffer[i];
uint32_t imag_bits = data_buffer[i + 1];
memcpy(&real, &real_bits, sizeof(real));
memcpy(&imag, &imag_bits, sizeof(imag));
result.push_back(std::complex<float>(real, imag));
}
return result;
}
// 软件FFT实现 (Cooley-Tukey算法)
std::vector<std::complex<float>> execute_software(
const std::vector<std::complex<float>>& input,
bool inverse) {
size_t n = input.size();
// 如果只有一个元素,直接返回
if (n <= 1) {
return input;
}
// 创建结果向量
std::vector<std::complex<float>> result = input;
// 位反转排序
size_t j = 0;
for (size_t i = 0; i < n - 1; i++) {
if (i < j) {
std::swap(result[i], result[j]);
}
size_t k = n / 2;
while (k <= j) {
j -= k;
k /= 2;
}
j += k;
}
// 蝶形计算
for (size_t len = 2; len <= n; len *= 2) {
float angle = (inverse ? 2.0f : -2.0f) * M_PI / len;
std::complex<float> wm(cos(angle), sin(angle));
for (size_t i = 0; i < n; i += len) {
std::complex<float> w(1.0f, 0.0f);
for (size_t j = 0; j < len / 2; j++) {
std::complex<float> u = result[i + j];
std::complex<float> t = w * result[i + j + len / 2];
result[i + j] = u + t;
result[i + j + len / 2] = u - t;
w *= wm;
}
}
}
// 如果是IFFT,需要除以n
if (inverse) {
for (auto& val : result) {
val /= static_cast<float>(n);
}
}
return result;
}
// DMA缓冲区分配 (简化实现)
void* allocate_dma_buffer(size_t size) {
// 在实际系统中,这里应该使用正确的DMA缓冲区分配API
return malloc(size);
}
void free_dma_buffer(void* buffer) {
free(buffer);
}
uint64_t get_physical_address(void* virtual_address) {
// 在实际系统中,这里需要使用平台特定方法获取物理地址
// 这里仅作为示例,直接返回虚拟地址值
return reinterpret_cast<uint64_t>(virtual_address);
}
private:
std::shared_ptr<CustomIP> ip_core_; // IP核对象
bool initialized_; // 初始化标志
std::string last_error_; // 最后一个错误消息
};
// FFTAccelerator的外部实现,委托给FFTAcceleratorImpl
FFTAccelerator::FFTAccelerator(std::shared_ptr<CustomIP> ip_core)
: impl_(new FFTAcceleratorImpl(ip_core)) {
}
FFTAccelerator::~FFTAccelerator() = default;
bool FFTAccelerator::initialize() {
return impl_->initialize();
}
std::vector<std::complex<float>> FFTAccelerator::execute(
const std::vector<std::complex<float>>& input,
bool inverse,
bool useHardware) {
return impl_->execute(input, inverse, useHardware);
}
std::string FFTAccelerator::get_last_error() const {
return impl_->get_last_error();
}
bool FFTAccelerator::benchmark(uint32_t fft_size, uint32_t iterations) {
return impl_->benchmark(fft_size, iterations);
}
} // namespace hw_accel
3. 嵌入式系统与外设通信
3.1 UART/RS-232 通信实现
c
/**
* uart.h - UART/RS232 通信接口
*
* 提供基本的串口通信功能
*/
#ifndef UART_H
#define UART_H
#include <stdint.h>
// 波特率定义
typedef enum {
UART_BAUD_9600 = 9600,
UART_BAUD_19200 = 19200,
UART_BAUD_38400 = 38400,
UART_BAUD_57600 = 57600,
UART_BAUD_115200 = 115200,
UART_BAUD_230400 = 230400,
UART_BAUD_460800 = 460800,
UART_BAUD_921600 = 921600
} UartBaudRate;
// 数据位定义
typedef enum {
UART_DATA_BITS_7 = 7,
UART_DATA_BITS_8 = 8,
UART_DATA_BITS_9 = 9
} UartDataBits;
// 停止位定义
typedef enum {
UART_STOP_BITS_1 = 0,
UART_STOP_BITS_2 = 1
} UartStopBits;
// 校验位定义
typedef enum {
UART_PARITY_NONE = 0,
UART_PARITY_ODD = 1,
UART_PARITY_EVEN = 2
} UartParity;
// 流控制定义
typedef enum {
UART_FLOW_CONTROL_NONE = 0,
UART_FLOW_CONTROL_RTS_CTS = 1,
UART_FLOW_CONTROL_XON_XOFF = 2
} UartFlowControl;
// UART配置结构体
typedef struct {
UartBaudRate baudRate;
UartDataBits dataBits;
UartStopBits stopBits;
UartParity parity;
UartFlowControl flowControl;
} UartConfig;
// UART句柄
typedef struct UartHandle* UartHandle_t;
/**
* 打开UART设备
*
* @param deviceName 设备名称 (如"/dev/ttyS0"或"COM1")
* @param config UART配置参数
* @return UART句柄,失败返回NULL
*/
UartHandle_t uart_open(const char* deviceName, const UartConfig* config);
/**
* 关闭UART设备
*
* @param handle UART句柄
* @return 0表示成功,非0表示失败
*/
int uart_close(UartHandle_t handle);
/**
* 发送数据
*
* @param handle UART句柄
* @param data 数据缓冲区
* @param size 数据大小
* @return 实际发送的字节数,小于0表示错误
*/
int uart_send(UartHandle_t handle, const uint8_t* data, int size);
/**
* 接收数据
*
* @param handle UART句柄
* @param data 数据缓冲区
* @param size 最大接收数据大小
* @param timeout_ms 超时时间(毫秒),0表示非阻塞,负数表示一直等待
* @return 实际接收的字节数,小于0表示错误
*/
int uart_receive(UartHandle_t handle, uint8_t* data, int size, int timeout_ms);
/**
* 清空接收缓冲区
*
* @param handle UART句柄
* @return 0表示成功,非0表示失败
*/
int uart_flush_rx(UartHandle_t handle);
/**
* 清空发送缓冲区
*
* @param handle UART句柄
* @return 0表示成功,非0表示失败
*/
int uart_flush_tx(UartHandle_t handle);
/**
* 获取最后一个错误消息
*
* @return 错误消息字符串
*/
const char* uart_get_last_error(void);
/**
* 设置接收超时
*
* @param handle UART句柄
* @param timeout_ms 读取超时(毫秒)
* @return 0表示成功,非0表示失败
*/
int uart_set_timeout(UartHandle_t handle, int timeout_ms);
/**
* 获取接收缓冲区中可用数据量
*
* @param handle UART句柄
* @return 可用数据量,小于0表示错误
*/
int uart_bytes_available(UartHandle_t handle);
#endif /* UART_H */
c
/**
* uart.c - UART/RS232 通信接口实现 (基于POSIX)
*
* 提供跨平台的串口通信实现
*/
#include "uart.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
// Windows平台
#include <windows.h>
#define SERIALCOM_HANDLE HANDLE
#else
// POSIX平台 (Linux, macOS, etc.)
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#define SERIALCOM_HANDLE int
#endif
// 定义UART句柄结构体
struct UartHandle {
SERIALCOM_HANDLE fd; // 文件描述符/句柄
char deviceName[64]; // 设备名称
UartConfig config; // UART配置
int timeout_ms; // 读取超时(毫秒)
};
// 最后一个错误消息
static char lastErrorMessage[256] = {0};
// 设置最后一个错误消息
static void set_last_error(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(lastErrorMessage, sizeof(lastErrorMessage), format, args);
va_end(args);
}
#ifdef _WIN32
// Windows平台特定的UART配置函数
static int configure_uart_win32(UartHandle_t handle) {
DCB dcb = {0};
COMMTIMEOUTS timeouts = {0};
dcb.DCBlength = sizeof(DCB);
// 获取当前配置
if (!GetCommState(handle->fd, &dcb)) {
set_last_error("GetCommState失败: %d", GetLastError());
return -1;
}
// 设置波特率
dcb.BaudRate = handle->config.baudRate;
// 设置数据位
dcb.ByteSize = handle->config.dataBits;
// 设置停止位
if (handle->config.stopBits == UART_STOP_BITS_1) {
dcb.StopBits = ONESTOPBIT;
} else {
dcb.StopBits = TWOSTOPBITS;
}
// 设置校验位
switch (handle->config.parity) {
case UART_PARITY_NONE:
dcb.Parity = NOPARITY;
break;
case UART_PARITY_ODD:
dcb.Parity = ODDPARITY;
break;
case UART_PARITY_EVEN:
dcb.Parity = EVENPARITY;
break;
default:
dcb.Parity = NOPARITY;
break;
}
// 设置流控制
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
if (handle->config.flowControl == UART_FLOW_CONTROL_RTS_CTS) {
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutxCtsFlow = TRUE;
} else if (handle->config.flowControl == UART_FLOW_CONTROL_XON_XOFF) {
dcb.fOutX = TRUE;
dcb.fInX = TRUE;
}
// 更新配置
if (!SetCommState(handle->fd, &dcb)) {
set_last_error("SetCommState失败: %d", GetLastError());
return -1;
}
// 设置超时
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(handle->fd, &timeouts)) {
set_last_error("SetCommTimeouts失败: %d", GetLastError());
return -1;
}
return 0;
}
#else
// POSIX平台特定的UART配置函数
static int configure_uart_posix(UartHandle_t handle) {
struct termios tty;
memset(&tty, 0, sizeof(tty));
// 获取当前配置
if (tcgetattr(handle->fd, &tty) != 0) {
set_last_error("tcgetattr失败: %s", strerror(errno));
return -1;
}
// 设置基本配置
tty.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器状态,启用接收
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 禁用规范模式,禁用回显,禁用信号
tty.c_oflag &= ~OPOST; // 禁用输出处理
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制
// 设置波特率
speed_t baudRate;
switch (handle->config.baudRate) {
case UART_BAUD_9600: baudRate = B9600; break;
case UART_BAUD_19200: baudRate = B19200; break;
case UART_BAUD_38400: baudRate = B38400; break;
case UART_BAUD_57600: baudRate = B57600; break;
case UART_BAUD_115200: baudRate = B115200; break;
case UART_BAUD_230400: baudRate = B230400; break;
#ifdef B460800
case UART_BAUD_460800: baudRate = B460800; break;
#endif
#ifdef B921600
case UART_BAUD_921600: baudRate = B921600; break;
#endif
default:
set_last_error("不支持的波特率: %d", handle->config.baudRate);
return -1;
}
cfsetospeed(&tty, baudRate);
cfsetispeed(&tty, baudRate);
// 设置数据位
tty.c_cflag &= ~CSIZE;
switch (handle->config.dataBits) {
case UART_DATA_BITS_7:
tty.c_cflag |= CS7;
break;
case UART_DATA_BITS_8:
tty.c_cflag |= CS8;
break;
default:
set_last_error("不支持的数据位: %d", handle->config.dataBits);
return -1;
}
// 设置停止位
if (handle->config.stopBits == UART_STOP_BITS_2) {
tty.c_cflag |= CSTOPB;
} else {
tty.c_cflag &= ~CSTOPB;
}
// 设置校验位
switch (handle->config.parity) {
case UART_PARITY_NONE:
tty.c_cflag &= ~PARENB;
break;
case UART_PARITY_ODD:
tty.c_cflag |= PARENB;
tty.c_cflag |= PARODD;
break;
case UART_PARITY_EVEN:
tty.c_cflag |= PARENB;
tty.c_cflag &= ~PARODD;
break;
default:
tty.c_cflag &= ~PARENB;
break;
}
// 设置流控制
if (handle->config.flowControl == UART_FLOW_CONTROL_RTS_CTS) {
#ifdef CRTSCTS
tty.c_cflag |= CRTSCTS;
#else
set_last_error("平台不支持硬件流控制");
return -1;
#endif
} else if (handle->config.flowControl == UART_FLOW_CONTROL_XON_XOFF) {
tty.c_iflag |= (IXON | IXOFF);
}
// 设置超时和最小读取字符数
tty.c_cc[VMIN] = 0; // 最小字符数
tty.c_cc[VTIME] = 0; // 超时 (0表示非阻塞)
// 清空缓冲区并应用新配置
tcflush(handle->fd, TCIOFLUSH);
if (tcsetattr(handle->fd, TCSANOW, &tty) != 0) {
set_last_error("tcsetattr失败: %s", strerror(errno));
return -1;
}
return 0;
}
#endif
// 打开UART设备
UartHandle_t uart_open(const char* deviceName, const UartConfig* config) {
if (!deviceName || !config) {
set_last_error("无效的参数");
return NULL;
}
// 分配句柄
UartHandle_t handle = (UartHandle_t)malloc(sizeof(struct UartHandle));
if (!handle) {
set_last_error("内存分配失败");
return NULL;
}
// 初始化句柄
memset(handle, 0, sizeof(struct UartHandle));
strncpy(handle->deviceName, deviceName, sizeof(handle->deviceName) - 1);
memcpy(&handle->config, config, sizeof(UartConfig));
handle->timeout_ms = -1; // 默认无限等待
#ifdef _WIN32
// Windows平台打开串口
char fullPath[80];
snprintf(fullPath, sizeof(fullPath), "\\\\.\\%s", deviceName);
handle->fd = CreateFileA(
fullPath,
GENERIC_READ | GENERIC_WRITE,
0, // 不共享
NULL, // 默认安全属性
OPEN_EXISTING, // 打开现有设备
0, // 非重叠I/O
NULL // 模板文件
);
if (handle->fd == INVALID_HANDLE_VALUE) {
set_last_error("无法打开串口设备 %s: 错误码 %d", deviceName, GetLastError());
free(handle);
return NULL;
}
// 配置UART
if (configure_uart_win32(handle) != 0) {
CloseHandle(handle->fd);
free(handle);
return NULL;
}
#else
// POSIX平台打开串口
handle->fd = open(deviceName, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (handle->fd < 0) {
set_last_error("无法打开串口设备 %s: %s", deviceName, strerror(errno));
free(handle);
return NULL;
}
// 配置UART
if (configure_uart_posix(handle) != 0) {
close(handle->fd);
free(handle);
return NULL;
}
#endif
return handle;
}
// 关闭UART设备
int uart_close(UartHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
#ifdef _WIN32
CloseHandle(handle->fd);
#else
close(handle->fd);
#endif
free(handle);
return 0;
}
// 发送数据
int uart_send(UartHandle_t handle, const uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
#ifdef _WIN32
DWORD bytesWritten = 0;
if (!WriteFile(handle->fd, data, size, &bytesWritten, NULL)) {
set_last_error("写入失败: %d", GetLastError());
return -1;
}
return bytesWritten;
#else
ssize_t bytesWritten = write(handle->fd, data, size);
if (bytesWritten < 0) {
set_last_error("写入失败: %s", strerror(errno));
return -1;
}
return bytesWritten;
#endif
}
// 接收数据
int uart_receive(UartHandle_t handle, uint8_t* data, int size, int timeout_ms) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
#ifdef _WIN32
DWORD bytesRead = 0;
COMMTIMEOUTS timeouts = {0};
// 设置超时
if (timeout_ms >= 0) {
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = timeout_ms;
} else {
// 无限等待
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
}
if (!SetCommTimeouts(handle->fd, &timeouts)) {
set_last_error("设置超时失败: %d", GetLastError());
return -1;
}
if (!ReadFile(handle->fd, data, size, &bytesRead, NULL)) {
DWORD error = GetLastError();
if (error != ERROR_TIMEOUT) {
set_last_error("读取失败: %d", error);
return -1;
}
return 0; // 超时
}
return bytesRead;
#else
fd_set readfds;
struct timeval tv;
FD_ZERO(&readfds);
FD_SET(handle->fd, &readfds);
if (timeout_ms >= 0) {
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
}
// 等待数据可读或超时
int ret = select(handle->fd + 1, &readfds, NULL, NULL,
(timeout_ms >= 0) ? &tv : NULL);
if (ret < 0) {
set_last_error("select失败: %s", strerror(errno));
return -1;
} else if (ret == 0) {
// 超时
return 0;
}
// 读取数据
ssize_t bytesRead = read(handle->fd, data, size);
if (bytesRead < 0) {
set_last_error("读取失败: %s", strerror(errno));
return -1;
}
return bytesRead;
#endif
}
// 清空接收缓冲区
int uart_flush_rx(UartHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
#ifdef _WIN32
if (!PurgeComm(handle->fd, PURGE_RXCLEAR)) {
set_last_error("清空接收缓冲区失败: %d", GetLastError());
return -1;
}
#else
if (tcflush(handle->fd, TCIFLUSH) != 0) {
set_last_error("清空接收缓冲区失败: %s", strerror(errno));
return -1;
}
#endif
return 0;
}
// 清空发送缓冲区
int uart_flush_tx(UartHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
#ifdef _WIN32
if (!PurgeComm(handle->fd, PURGE_TXCLEAR)) {
set_last_error("清空发送缓冲区失败: %d", GetLastError());
return -1;
}
#else
if (tcflush(handle->fd, TCOFLUSH) != 0) {
set_last_error("清空发送缓冲区失败: %s", strerror(errno));
return -1;
}
#endif
return 0;
}
// 获取最后一个错误消息
const char* uart_get_last_error(void) {
return lastErrorMessage;
}
// 设置接收超时
int uart_set_timeout(UartHandle_t handle, int timeout_ms) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
handle->timeout_ms = timeout_ms;
#ifdef _WIN32
COMMTIMEOUTS timeouts = {0};
// 设置超时
if (timeout_ms >= 0) {
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = timeout_ms;
} else {
// 无限等待
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
}
if (!SetCommTimeouts(handle->fd, &timeouts)) {
set_last_error("设置超时失败: %d", GetLastError());
return -1;
}
#else
struct termios tty;
if (tcgetattr(handle->fd, &tty) != 0) {
set_last_error("tcgetattr失败: %s", strerror(errno));
return -1;
}
if (timeout_ms >= 0) {
// 设置字符超时 (VTIME以1/10秒为单位)
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = (timeout_ms / 100) & 0xFF;
} else {
// 无限等待
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
}
if (tcsetattr(handle->fd, TCSANOW, &tty) != 0) {
set_last_error("tcsetattr失败: %s", strerror(errno));
return -1;
}
#endif
return 0;
}
// 获取接收缓冲区中可用数据量
int uart_bytes_available(UartHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
#ifdef _WIN32
COMSTAT status;
DWORD errors;
if (!ClearCommError(handle->fd, &errors, &status)) {
set_last_error("ClearCommError失败: %d", GetLastError());
return -1;
}
return status.cbInQue;
#else
int bytes_available = 0;
if (ioctl(handle->fd, FIONREAD, &bytes_available) < 0) {
set_last_error("ioctl失败: %s", strerror(errno));
return -1;
}
return bytes_available;
#endif
}
3.2 I2C设备通信实现
c
/**
* i2c.h - I2C通信接口
*
* 提供与I2C设备通信的功能
*/
#ifndef I2C_H
#define I2C_H
#include <stdint.h>
// I2C句柄
typedef struct I2cHandle* I2cHandle_t;
/**
* 打开I2C设备
*
* @param deviceName 设备名称 (如"/dev/i2c-1")
* @return I2C句柄,失败返回NULL
*/
I2cHandle_t i2c_open(const char* deviceName);
/**
* 关闭I2C设备
*
* @param handle I2C句柄
* @return 0表示成功,非0表示失败
*/
int i2c_close(I2cHandle_t handle);
/**
* 设置I2C从设备地址
*
* @param handle I2C句柄
* @param address 7位或10位设备地址
* @param is10bit 是否为10位地址 (0=7位地址,1=10位地址)
* @return 0表示成功,非0表示失败
*/
int i2c_set_slave_address(I2cHandle_t handle, uint16_t address, int is10bit);
/**
* 写入数据到I2C设备
*
* @param handle I2C句柄
* @param data 数据缓冲区
* @param size 数据大小
* @return 实际写入的字节数,小于0表示错误
*/
int i2c_write(I2cHandle_t handle, const uint8_t* data, int size);
/**
* 从I2C设备读取数据
*
* @param handle I2C句柄
* @param data 数据缓冲区
* @param size 最大读取数据大小
* @return 实际读取的字节数,小于0表示错误
*/
int i2c_read(I2cHandle_t handle, uint8_t* data, int size);
/**
* 写入寄存器(8位寄存器地址)
*
* @param handle I2C句柄
* @param reg_addr 寄存器地址
* @param data 数据缓冲区
* @param size 数据大小
* @return 实际写入的字节数(不包括寄存器地址),小于0表示错误
*/
int i2c_write_reg8(I2cHandle_t handle, uint8_t reg_addr, const uint8_t* data, int size);
/**
* 读取寄存器(8位寄存器地址)
*
* @param handle I2C句柄
* @param reg_addr 寄存器地址
* @param data 数据缓冲区
* @param size 最大读取数据大小
* @return 实际读取的字节数,小于0表示错误
*/
int i2c_read_reg8(I2cHandle_t handle, uint8_t reg_addr, uint8_t* data, int size);
/**
* 写入寄存器(16位寄存器地址)
*
* @param handle I2C句柄
* @param reg_addr 寄存器地址
* @param data 数据缓冲区
* @param size 数据大小
* @return 实际写入的字节数(不包括寄存器地址),小于0表示错误
*/
int i2c_write_reg16(I2cHandle_t handle, uint16_t reg_addr, const uint8_t* data, int size);
/**
* 读取寄存器(16位寄存器地址)
*
* @param handle I2C句柄
* @param reg_addr 寄存器地址
* @param data 数据缓冲区
* @param size 最大读取数据大小
* @return 实际读取的字节数,小于0表示错误
*/
int i2c_read_reg16(I2cHandle_t handle, uint16_t reg_addr, uint8_t* data, int size);
/**
* 设置I2C传输超时
*
* @param handle I2C句柄
* @param timeout_ms 超时时间(毫秒)
* @return 0表示成功,非0表示失败
*/
int i2c_set_timeout(I2cHandle_t handle, int timeout_ms);
/**
* 获取最后一个错误消息
*
* @return 错误消息字符串
*/
const char* i2c_get_last_error(void);
#endif /* I2C_H */
c
/**
* i2c.c - I2C通信接口实现 (基于Linux I2C驱动)
*
* 提供与I2C设备通信的功能
*/
#include "i2c.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
// 定义I2C句柄结构体
struct I2cHandle {
int fd; // 文件描述符
char deviceName[64]; // 设备名称
uint16_t slaveAddress; // 从设备地址
int is10bit; // 是否为10位地址
int timeout_ms; // 超时时间(毫秒)
};
// 最后一个错误消息
static char lastErrorMessage[256] = {0};
// 设置最后一个错误消息
static void set_last_error(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(lastErrorMessage, sizeof(lastErrorMessage), format, args);
va_end(args);
}
// 执行I2C传输
static int i2c_transfer(I2cHandle_t handle, struct i2c_msg* msgs, int num_msgs) {
struct i2c_rdwr_ioctl_data msgset;
if (!handle || !msgs || num_msgs <= 0) {
set_last_error("无效的参数");
return -1;
}
msgset.msgs = msgs;
msgset.nmsgs = num_msgs;
if (ioctl(handle->fd, I2C_RDWR, &msgset) < 0) {
set_last_error("I2C传输失败: %s", strerror(errno));
return -1;
}
return 0;
}
// 打开I2C设备
I2cHandle_t i2c_open(const char* deviceName) {
if (!deviceName) {
set_last_error("设备名称为空");
return NULL;
}
// 分配句柄
I2cHandle_t handle = (I2cHandle_t)malloc(sizeof(struct I2cHandle));
if (!handle) {
set_last_error("内存分配失败");
return NULL;
}
// 初始化句柄
memset(handle, 0, sizeof(struct I2cHandle));
strncpy(handle->deviceName, deviceName, sizeof(handle->deviceName) - 1);
handle->timeout_ms = 1000; // 默认超时1秒
// 打开I2C设备
handle->fd = open(deviceName, O_RDWR);
if (handle->fd < 0) {
set_last_error("无法打开I2C设备 %s: %s", deviceName, strerror(errno));
free(handle);
return NULL;
}
return handle;
}
// 关闭I2C设备
int i2c_close(I2cHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
if (handle->fd >= 0) {
close(handle->fd);
}
free(handle);
return 0;
}
// 设置I2C从设备地址
int i2c_set_slave_address(I2cHandle_t handle, uint16_t address, int is10bit) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
handle->slaveAddress = address;
handle->is10bit = is10bit;
unsigned long flag = is10bit ? I2C_M_TEN : 0;
// 尝试使用旧的IOCTL设置从设备地址
if (ioctl(handle->fd, I2C_SLAVE, address) < 0 &&
ioctl(handle->fd, I2C_SLAVE_FORCE, address) < 0) {
// 如果失败,可能不支持常规的方式,或者地址冲突
// 这没有问题,因为我们将使用I2C_RDWR来指定目标地址
}
return 0;
}
// 写入数据到I2C设备
int i2c_write(I2cHandle_t handle, const uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
struct i2c_msg msgs[1];
// 设置写消息
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = handle->is10bit ? I2C_M_TEN : 0;
msgs[0].len = size;
msgs[0].buf = (uint8_t*)data;
if (i2c_transfer(handle, msgs, 1) < 0) {
return -1;
}
return size;
}
// 从I2C设备读取数据
int i2c_read(I2cHandle_t handle, uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
struct i2c_msg msgs[1];
// 设置读消息
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = I2C_M_RD | (handle->is10bit ? I2C_M_TEN : 0);
msgs[0].len = size;
msgs[0].buf = data;
if (i2c_transfer(handle, msgs, 1) < 0) {
return -1;
}
return size;
}
// 写入寄存器(8位寄存器地址)
int i2c_write_reg8(I2cHandle_t handle, uint8_t reg_addr, const uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
// 分配缓冲区包含寄存器地址和数据
uint8_t* buffer = (uint8_t*)malloc(size + 1);
if (!buffer) {
set_last_error("内存分配失败");
return -1;
}
// 填充缓冲区
buffer[0] = reg_addr;
memcpy(buffer + 1, data, size);
struct i2c_msg msgs[1];
// 设置写消息
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = handle->is10bit ? I2C_M_TEN : 0;
msgs[0].len = size + 1;
msgs[0].buf = buffer;
int result = i2c_transfer(handle, msgs, 1);
free(buffer);
if (result < 0) {
return -1;
}
return size;
}
// 读取寄存器(8位寄存器地址)
int i2c_read_reg8(I2cHandle_t handle, uint8_t reg_addr, uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
struct i2c_msg msgs[2];
// 设置写消息(寄存器地址)
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = handle->is10bit ? I2C_M_TEN : 0;
msgs[0].len = 1;
msgs[0].buf = ®_addr;
// 设置读消息(数据)
msgs[1].addr = handle->slaveAddress;
msgs[1].flags = I2C_M_RD | (handle->is10bit ? I2C_M_TEN : 0);
msgs[1].len = size;
msgs[1].buf = data;
if (i2c_transfer(handle, msgs, 2) < 0) {
return -1;
}
return size;
}
// 写入寄存器(16位寄存器地址)
int i2c_write_reg16(I2cHandle_t handle, uint16_t reg_addr, const uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
// 分配缓冲区包含寄存器地址和数据
uint8_t* buffer = (uint8_t*)malloc(size + 2);
if (!buffer) {
set_last_error("内存分配失败");
return -1;
}
// 填充缓冲区 (寄存器地址高字节在前)
buffer[0] = (reg_addr >> 8) & 0xFF;
buffer[1] = reg_addr & 0xFF;
memcpy(buffer + 2, data, size);
struct i2c_msg msgs[1];
// 设置写消息
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = handle->is10bit ? I2C_M_TEN : 0;
msgs[0].len = size + 2;
msgs[0].buf = buffer;
int result = i2c_transfer(handle, msgs, 1);
free(buffer);
if (result < 0) {
return -1;
}
return size;
}
// 读取寄存器(16位寄存器地址)
int i2c_read_reg16(I2cHandle_t handle, uint16_t reg_addr, uint8_t* data, int size) {
if (!handle || !data || size <= 0) {
set_last_error("无效的参数");
return -1;
}
uint8_t reg_addr_buf[2];
reg_addr_buf[0] = (reg_addr >> 8) & 0xFF;
reg_addr_buf[1] = reg_addr & 0xFF;
struct i2c_msg msgs[2];
// 设置写消息(寄存器地址)
msgs[0].addr = handle->slaveAddress;
msgs[0].flags = handle->is10bit ? I2C_M_TEN : 0;
msgs[0].len = 2;
msgs[0].buf = reg_addr_buf;
// 设置读消息(数据)
msgs[1].addr = handle->slaveAddress;
msgs[1].flags = I2C_M_RD | (handle->is10bit ? I2C_M_TEN : 0);
msgs[1].len = size;
msgs[1].buf = data;
if (i2c_transfer(handle, msgs, 2) < 0) {
return -1;
}
return size;
}
// 设置I2C传输超时
int i2c_set_timeout(I2cHandle_t handle, int timeout_ms) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
handle->timeout_ms = timeout_ms;
// Linux I2C-dev驱动不直接支持超时设置
// 我们可以使用非阻塞模式和select超时,但这需要扩展更多代码
// 在这里,我们只是保存超时值以供将来可能的实现使用
return 0;
}
// 获取最后一个错误消息
const char* i2c_get_last_error(void) {
return lastErrorMessage;
}
3.3 CAN总线通信
c
/**
* can.h - CAN总线通信接口
*
* 提供与CAN总线设备通信的基本功能
*/
#ifndef CAN_H
#define CAN_H
#include <stdint.h>
// CAN帧结构体
typedef struct {
uint32_t id; // CAN标识符
uint8_t is_extended; // 是否扩展帧(0=标准11位ID,1=扩展29位ID)
uint8_t is_remote; // 是否远程帧(0=数据帧, 1=远程帧)
uint8_t is_error; // 是否错误帧(0=正常帧, 1=错误帧)
uint8_t dlc; // 数据长度(0-8)
uint8_t data[8]; // 数据字节
uint64_t timestamp; // 时间戳(微秒)
} CanFrame;
// CAN滤波器结构体
typedef struct {
uint32_t id; // 滤波器ID
uint32_t mask; // 滤波器掩码
uint8_t is_extended; // 是否扩展帧格式
} CanFilter;
// CAN句柄
typedef struct CanHandle* CanHandle_t;
/**
* 打开CAN设备
*
* @param interface_name 接口名称 (如"can0")
* @param bitrate CAN波特率 (如125000, 250000, 500000, 1000000)
* @return CAN句柄,失败返回NULL
*/
CanHandle_t can_open(const char* interface_name, uint32_t bitrate);
/**
* 关闭CAN设备
*
* @param handle CAN句柄
* @return 0表示成功,非0表示失败
*/
int can_close(CanHandle_t handle);
/**
* 开始CAN通信
*
* @param handle CAN句柄
* @return 0表示成功,非0表示失败
*/
int can_start(CanHandle_t handle);
/**
* 停止CAN通信
*
* @param handle CAN句柄
* @return 0表示成功,非0表示失败
*/
int can_stop(CanHandle_t handle);
/**
* 发送CAN帧
*
* @param handle CAN句柄
* @param frame 要发送的CAN帧
* @return 0表示成功,非0表示失败
*/
int can_send(CanHandle_t handle, const CanFrame* frame);
/**
* 接收CAN帧
*
* @param handle CAN句柄
* @param frame 接收到的CAN帧
* @param timeout_ms 超时时间(毫秒),0表示非阻塞,负数表示一直等待
* @return 0表示成功,1表示超时,负数表示错误
*/
int can_receive(CanHandle_t handle, CanFrame* frame, int timeout_ms);
/**
* 设置CAN滤波器
*
* @param handle CAN句柄
* @param filters 滤波器数组
* @param num_filters 滤波器数量
* @return 0表示成功,非0表示失败
*/
int can_set_filters(CanHandle_t handle, const CanFilter* filters, int num_filters);
/**
* 获取CAN总线状态
*
* @param handle CAN句柄
* @param tx_error 发送错误计数器
* @param rx_error 接收错误计数器
* @param bus_status 总线状态(0=正常, 1=警告, 2=被动错误, 3=总线关闭)
* @return 0表示成功,非0表示失败
*/
int can_get_status(CanHandle_t handle, uint8_t* tx_error, uint8_t* rx_error, uint8_t* bus_status);
/**
* 设置CAN总线的比特率
*
* @param handle CAN句柄
* @param bitrate 比特率(bps)
* @return 0表示成功,非0表示失败
*/
int can_set_bitrate(CanHandle_t handle, uint32_t bitrate);
/**
* 获取最后一个错误消息
*
* @return 错误消息字符串
*/
const char* can_get_last_error(void);
#endif /* CAN_H */
c
/**
* can.c - CAN总线通信接口实现 (基于SocketCAN)
*
* 提供与CAN总线设备通信的基本功能
*/
#include "can.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
#include <fcntl.h>
// 定义CAN句柄结构体
struct CanHandle {
int socket; // CAN套接字
char interface_name[32]; // 接口名称
struct sockaddr_can addr; // 套接字地址
struct ifreq ifr; // 接口请求
uint32_t bitrate; // 比特率
int is_started; // 是否已启动
};
// 最后一个错误消息
static char lastErrorMessage[256] = {0};
// 设置最后一个错误消息
static void set_last_error(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(lastErrorMessage, sizeof(lastErrorMessage), format, args);
va_end(args);
}
// 打开CAN设备
CanHandle_t can_open(const char* interface_name, uint32_t bitrate) {
if (!interface_name) {
set_last_error("接口名称为空");
return NULL;
}
// 分配句柄
CanHandle_t handle = (CanHandle_t)malloc(sizeof(struct CanHandle));
if (!handle) {
set_last_error("内存分配失败");
return NULL;
}
// 初始化句柄
memset(handle, 0, sizeof(struct CanHandle));
strncpy(handle->interface_name, interface_name, sizeof(handle->interface_name) - 1);
handle->bitrate = bitrate;
handle->is_started = 0;
// 创建原始CAN套接字
handle->socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (handle->socket < 0) {
set_last_error("创建CAN套接字失败: %s", strerror(errno));
free(handle);
return NULL;
}
// 获取接口索引
strncpy(handle->ifr.ifr_name, interface_name, IFNAMSIZ - 1);
if (ioctl(handle->socket, SIOCGIFINDEX, &handle->ifr) < 0) {
set_last_error("获取接口索引失败: %s", strerror(errno));
close(handle->socket);
free(handle);
return NULL;
}
// 设置地址
memset(&handle->addr, 0, sizeof(struct sockaddr_can));
handle->addr.can_family = AF_CAN;
handle->addr.can_ifindex = handle->ifr.ifr_ifindex;
// 设置非阻塞模式
int flags = fcntl(handle->socket, F_GETFL, 0);
if (flags < 0) {
set_last_error("获取套接字标志失败: %s", strerror(errno));
close(handle->socket);
free(handle);
return NULL;
}
if (fcntl(handle->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
set_last_error("设置非阻塞模式失败: %s", strerror(errno));
close(handle->socket);
free(handle);
return NULL;
}
// 启用接收错误帧
int recv_err_frames = 1;
if (setsockopt(handle->socket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&recv_err_frames, sizeof(recv_err_frames)) < 0) {
set_last_error("启用错误帧接收失败: %s", strerror(errno));
close(handle->socket);
free(handle);
return NULL;
}
// 设置比特率 (这通常需要使用ip命令或定制驱动程序,这里只是保存值)
handle->bitrate = bitrate;
return handle;
}
// 关闭CAN设备
int can_close(CanHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
if (handle->is_started) {
can_stop(handle);
}
if (handle->socket >= 0) {
close(handle->socket);
}
free(handle);
return 0;
}
// 开始CAN通信
int can_start(CanHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
if (handle->is_started) {
return 0; // 已经启动
}
// 绑定套接字到CAN接口
if (bind(handle->socket, (struct sockaddr*)&handle->addr, sizeof(handle->addr)) < 0) {
set_last_error("绑定套接字失败: %s", strerror(errno));
return -1;
}
handle->is_started = 1;
return 0;
}
// 停止CAN通信
int can_stop(CanHandle_t handle) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
if (!handle->is_started) {
return 0; // 已经停止
}
// 关闭并重新打开套接字
close(handle->socket);
handle->socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (handle->socket < 0) {
set_last_error("重新创建CAN套接字失败: %s", strerror(errno));
handle->is_started = 0;
return -1;
}
// 重新设置非阻塞模式
int flags = fcntl(handle->socket, F_GETFL, 0);
if (flags >= 0) {
fcntl(handle->socket, F_SETFL, flags | O_NONBLOCK);
}
// 重新启用接收错误帧
int recv_err_frames = 1;
setsockopt(handle->socket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&recv_err_frames, sizeof(recv_err_frames));
handle->is_started = 0;
return 0;
}
// 发送CAN帧
int can_send(CanHandle_t handle, const CanFrame* frame) {
if (!handle || !frame) {
set_last_error("无效的参数");
return -1;
}
if (!handle->is_started) {
set_last_error("CAN接口未启动");
return -1;
}
// 检查数据长度
if (frame->dlc > 8) {
set_last_error("无效的数据长度: %d", frame->dlc);
return -1;
}
// 准备CAN帧
struct can_frame can_frame;
memset(&can_frame, 0, sizeof(struct can_frame));
// 设置ID和标志
if (frame->is_extended) {
can_frame.can_id = frame->id | CAN_EFF_FLAG;
} else {
can_frame.can_id = frame->id & CAN_SFF_MASK;
}
if (frame->is_remote) {
can_frame.can_id |= CAN_RTR_FLAG;
}
if (frame->is_error) {
can_frame.can_id |= CAN_ERR_FLAG;
}
// 设置数据长度和数据
can_frame.can_dlc = frame->dlc;
memcpy(can_frame.data, frame->data, frame->dlc);
// 发送帧
ssize_t nbytes = write(handle->socket, &can_frame, sizeof(struct can_frame));
if (nbytes != sizeof(struct can_frame)) {
set_last_error("发送CAN帧失败: %s", strerror(errno));
return -1;
}
return 0;
}
// 接收CAN帧
int can_receive(CanHandle_t handle, CanFrame* frame, int timeout_ms) {
if (!handle || !frame) {
set_last_error("无效的参数");
return -1;
}
if (!handle->is_started) {
set_last_error("CAN接口未启动");
return -1;
}
// 准备select超时
fd_set readfds;
struct timeval tv, *tvp;
FD_ZERO(&readfds);
FD_SET(handle->socket, &readfds);
if (timeout_ms >= 0) {
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
tvp = &tv;
} else {
// 无限等待
tvp = NULL;
}
// 等待数据可读
int ret = select(handle->socket + 1, &readfds, NULL, NULL, tvp);
if (ret < 0) {
set_last_error("select失败: %s", strerror(errno));
return -1;
} else if (ret == 0) {
// 超时
return 1;
}
// 读取CAN帧
struct can_frame can_frame;
struct timeval timestamp;
ssize_t nbytes = read(handle->socket, &can_frame, sizeof(struct can_frame));
if (nbytes < 0) {
set_last_error("读取CAN帧失败: %s", strerror(errno));
return -1;
}
if (nbytes < (ssize_t)sizeof(struct can_frame)) {
set_last_error("接收到不完整的CAN帧");
return -1;
}
// 获取时间戳
ioctl(handle->socket, SIOCGSTAMP, ×tamp);
// 填充输出帧
if (can_frame.can_id & CAN_EFF_FLAG) {
frame->id = can_frame.can_id & CAN_EFF_MASK;
frame->is_extended = 1;
} else {
frame->id = can_frame.can_id & CAN_SFF_MASK;
frame->is_extended = 0;
}
frame->is_remote = (can_frame.can_id & CAN_RTR_FLAG) ? 1 : 0;
frame->is_error = (can_frame.can_id & CAN_ERR_FLAG) ? 1 : 0;
frame->dlc = can_frame.can_dlc;
memcpy(frame->data, can_frame.data, can_frame.can_dlc);
// 设置时间戳 (微秒)
frame->timestamp = (uint64_t)timestamp.tv_sec * 1000000 + timestamp.tv_usec;
return 0;
}
// 设置CAN滤波器
int can_set_filters(CanHandle_t handle, const CanFilter* filters, int num_filters) {
if (!handle || (!filters && num_filters > 0)) {
set_last_error("无效的参数");
return -1;
}
// 如果没有滤波器,则接收所有帧
if (num_filters == 0) {
struct can_filter rfilter[1];
rfilter[0].can_id = 0;
rfilter[0].can_mask = 0;
if (setsockopt(handle->socket, SOL_CAN_RAW, CAN_RAW_FILTER,
&rfilter, sizeof(rfilter)) < 0) {
set_last_error("设置CAN滤波器失败: %s", strerror(errno));
return -1;
}
return 0;
}
// 设置自定义滤波器
struct can_filter* rfilters = (struct can_filter*)malloc(
num_filters * sizeof(struct can_filter));
if (!rfilters) {
set_last_error("内存分配失败");
return -1;
}
for (int i = 0; i < num_filters; i++) {
if (filters[i].is_extended) {
rfilters[i].can_id = filters[i].id | CAN_EFF_FLAG;
rfilters[i].can_mask = filters[i].mask | CAN_EFF_FLAG;
} else {
rfilters[i].can_id = filters[i].id & CAN_SFF_MASK;
rfilters[i].can_mask = filters[i].mask & CAN_SFF_MASK;
}
}
if (setsockopt(handle->socket, SOL_CAN_RAW, CAN_RAW_FILTER,
rfilters, num_filters * sizeof(struct can_filter)) < 0) {
set_last_error("设置CAN滤波器失败: %s", strerror(errno));
free(rfilters);
return -1;
}
free(rfilters);
return 0;
}
// 获取CAN总线状态
int can_get_status(CanHandle_t handle, uint8_t* tx_error, uint8_t* rx_error, uint8_t* bus_status) {
if (!handle || !tx_error || !rx_error || !bus_status) {
set_last_error("无效的参数");
return -1;
}
if (!handle->is_started) {
set_last_error("CAN接口未启动");
return -1;
}
// 获取接口状态
struct ifreq ifr;
struct can_berr_counter berr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, handle->interface_name, IFNAMSIZ - 1);
// 获取错误计数器
ifr.ifr_data = (void*)&berr;
if (ioctl(handle->socket, SIOCGCANBSTATS, &ifr) < 0) {
// 如果不支持SIOCGCANBSTATS,尝试其他方法
*tx_error = 0;
*rx_error = 0;
*bus_status = 0;
return 0;
}
*tx_error = berr.txerr;
*rx_error = berr.rxerr;
// 确定总线状态
if (*tx_error >= 255 || *rx_error >= 255) {
*bus_status = 3; // 总线关闭
} else if (*tx_error >= 128 || *rx_error >= 128) {
*bus_status = 2; // 被动错误
} else if (*tx_error >= 96 || *rx_error >= 96) {
*bus_status = 1; // 警告
} else {
*bus_status = 0; // 正常
}
return 0;
}
// 设置CAN总线的比特率
int can_set_bitrate(CanHandle_t handle, uint32_t bitrate) {
if (!handle) {
set_last_error("无效的句柄");
return -1;
}
// 在Linux环境中,通常需要使用ip命令设置CAN接口参数
// 例如: ip link set can0 type can bitrate 500000
// 这里我们只保存比特率值,需要通过外部命令实际设置接口
char command[128];
snprintf(command, sizeof(command),
"ip link set %s down && ip link set %s type can bitrate %u && ip link set %s up",
handle->interface_name, handle->interface_name, bitrate, handle->interface_name);
int result = system(command);
if (result != 0) {
set_last_error("设置比特率失败: 命令返回 %d", result);
return -1;
}
handle->bitrate = bitrate;
return 0;
}
// 获取最后一个错误消息
const char* can_get_last_error(void) {
return lastErrorMessage;
}
3.4 SPI 设备通信实例
c
/**
* spi_device.h - SPI设备通信接口
*
* 基于C语言的SPI通信接口,支持Linux/Unix
*/
#ifndef SPI_DEVICE_H
#define SPI_DEVICE_H
#include <stdint.h>
// SPI传输模式
typedef enum {
SPI_MODE_0 = 0, // CPOL=0, CPHA=0
SPI_MODE_1 = 1, // CPOL=0, CPHA=1
SPI_MODE_2 = 2, // CPOL=1, CPHA=0
SPI_MODE_3 = 3 // CPOL=1, CPHA=1
} SpiMode;
// SPI设备句柄
typedef struct SpiDevice* SpiDevice_t;
/**
* 打开SPI设备
*
* @param device_path 设备路径 (例如 "/dev/spidev0.0")
* @param mode SPI模式 (0-3)
* @param speed_hz 时钟频率 (Hz)
* @param bits_per_word 每个字的位数 (通常为8)
* @param lsb_first 是否LSB优先 (0=MSB, 1=LSB)
* @return SPI设备句柄,失败返回NULL
*/
SpiDevice_t spi_open(const char* device_path, SpiMode mode,
uint32_t speed_hz, uint8_t bits_per_word,
int lsb_first);
/**
* 关闭SPI设备
*
* @param device SPI设备句柄
*/
void spi_close(SpiDevice_t device);
/**
* 执行SPI全双工传输
*
* @param device SPI设备句柄
* @param tx_buffer 发送缓冲区
* @param rx_buffer 接收缓冲区
* @param length 缓冲区长度
* @return 成功返回0,失败返回负数
*/
int spi_transfer(SpiDevice_t device, const uint8_t* tx_buffer,
uint8_t* rx_buffer, size_t length);
/**
* 执行SPI发送操作 (无接收)
*
* @param device SPI设备句柄
* @param buffer 发送缓冲区
* @param length 数据长度
* @return 成功返回0,失败返回负数
*/
int spi_write(SpiDevice_t device, const uint8_t* buffer, size_t length);
/**
* 执行SPI接收操作 (发送0)
*
* @param device SPI设备句柄
* @param buffer 接收缓冲区
* @param length 数据长度
* @return 成功返回0,失败返回负数
*/
int spi_read(SpiDevice_t device, uint8_t* buffer, size_t length);
/**
* 设置SPI模式
*
* @param device SPI设备句柄
* @param mode SPI模式 (0-3)
* @return 成功返回0,失败返回负数
*/
int spi_set_mode(SpiDevice_t device, SpiMode mode);
/**
* 设置SPI时钟频率
*
* @param device SPI设备句柄
* @param speed_hz 时钟频率 (Hz)
* @return 成功返回0,失败返回负数
*/
int spi_set_speed(SpiDevice_t device, uint32_t speed_hz);
/**
* 设置SPI每个字的位数
*
* @param device SPI设备句柄
* @param bits_per_word 每个字的位数 (通常为8)
* @return 成功返回0,失败返回负数
*/
int spi_set_bits_per_word(SpiDevice_t device, uint8_t bits_per_word);
/**
* 设置SPI位序
*
* @param device SPI设备句柄
* @param lsb_first 是否LSB优先 (0=MSB, 1=LSB)
* @return 成功返回0,失败返回负数
*/
int spi_set_bit_order(SpiDevice_t device, int lsb_first);
/**
* 获取最后的错误消息
*
* @return 错误消息字符串
*/
const char* spi_get_error(void);
#endif /* SPI_DEVICE_H */
c
/**
* spi_device.c - SPI设备通信接口实现
*
* 基于Linux SPI设备驱动的实现
*/
#include "spi_device.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
// 最大错误消息长度
#define MAX_ERROR_MSG_LEN 256
// SPI设备结构体
struct SpiDevice {
int fd; // 文件描述符
uint32_t speed_hz; // 速度 (Hz)
uint8_t bits_per_word; // 每个字的位数
uint8_t mode; // SPI模式
uint8_t lsb_first; // LSB优先标志
char device_path[64]; // 设备路径
};
// 全局错误消息
static char error_message[MAX_ERROR_MSG_LEN] = {0};
// 设置错误消息
static void set_error(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(error_message, MAX_ERROR_MSG_LEN - 1, format, args);
va_end(args);
}
// 打开SPI设备
SpiDevice_t spi_open(const char* device_path, SpiMode mode,
uint32_t speed_hz, uint8_t bits_per_word,
int lsb_first) {
// 参数检查
if (!device_path) {
set_error("设备路径为空");
return NULL;
}
// 分配设备结构体
SpiDevice_t device = (SpiDevice_t)malloc(sizeof(struct SpiDevice));
if (!device) {
set_error("内存分配失败");
return NULL;
}
// 初始化结构体
memset(device, 0, sizeof(struct SpiDevice));
strncpy(device->device_path, device_path, sizeof(device->device_path) - 1);
device->speed_hz = speed_hz;
device->bits_per_word = bits_per_word;
device->mode = (uint8_t)mode;
device->lsb_first = lsb_first ? 1 : 0;
// 打开SPI设备
device->fd = open(device_path, O_RDWR);
if (device->fd < 0) {
set_error("无法打开SPI设备 '%s': %s", device_path, strerror(errno));
free(device);
return NULL;
}
// 配置SPI模式
uint8_t spi_mode = device->mode;
if (device->lsb_first) {
spi_mode |= SPI_LSB_FIRST;
}
if (ioctl(device->fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
set_error("设置SPI模式失败: %s", strerror(errno));
close(device->fd);
free(device);
return NULL;
}
// 配置位数
if (ioctl(device->fd, SPI_IOC_WR_BITS_PER_WORD, &device->bits_per_word) < 0) {
set_error("设置SPI位数失败: %s", strerror(errno));
close(device->fd);
free(device);
return NULL;
}
// 配置速度
if (ioctl(device->fd, SPI_IOC_WR_MAX_SPEED_HZ, &device->speed_hz) < 0) {
set_error("设置SPI速度失败: %s", strerror(errno));
close(device->fd);
free(device);
return NULL;
}
return device;
}
// 关闭SPI设备
void spi_close(SpiDevice_t device) {
if (device) {
if (device->fd >= 0) {
close(device->fd);
}
free(device);
}
}
// 执行SPI全双工传输
int spi_transfer(SpiDevice_t device, const uint8_t* tx_buffer,
uint8_t* rx_buffer, size_t length) {
if (!device || !tx_buffer || !rx_buffer || length == 0) {
set_error("无效的参数");
return -1;
}
// 创建传输结构
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx_buffer,
.rx_buf = (unsigned long)rx_buffer,
.len = length,
.speed_hz = device->speed_hz,
.delay_usecs = 0,
.bits_per_word = device->bits_per_word,
};
// 执行传输
int ret = ioctl(device->fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 0) {
set_error("SPI传输失败: %s", strerror(errno));
return -2;
}
return 0;
}
// 执行SPI发送操作 (无接收)
int spi_write(SpiDevice_t device, const uint8_t* buffer, size_t length) {
if (!device || !buffer || length == 0) {
set_error("无效的参数");
return -1;
}
// 分配临时接收缓冲区
uint8_t* rx_buffer = (uint8_t*)malloc(length);
if (!rx_buffer) {
set_error("内存分配失败");
return -3;
}
// 执行传输
int ret = spi_transfer(device, buffer, rx_buffer, length);
// 释放临时缓冲区
free(rx_buffer);
return ret;
}
// 执行SPI接收操作 (发送0)
int spi_read(SpiDevice_t device, uint8_t* buffer, size_t length) {
if (!device || !buffer || length == 0) {
set_error("无效的参数");
return -1;
}
// 分配临时发送缓冲区
uint8_t* tx_buffer = (uint8_t*)malloc(length);
if (!tx_buffer) {
set_error("内存分配失败");
return -3;
}
// 填充发送缓冲区为0
memset(tx_buffer, 0, length);
// 执行传输
int ret = spi_transfer(device, tx_buffer, buffer, length);
// 释放临时缓冲区
free(tx_buffer);
return ret;
}
// 设置SPI模式
int spi_set_mode(SpiDevice_t device, SpiMode mode) {
if (!device) {
set_error("无效的设备句柄");
return -1;
}
// 构建SPI模式标志
uint8_t spi_mode = (uint8_t)mode;
if (device->lsb_first) {
spi_mode |= SPI_LSB_FIRST;
}
// 设置模式
if (ioctl(device->fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
set_error("设置SPI模式失败: %s", strerror(errno));
return -2;
}
// 更新设备结构
device->mode = (uint8_t)mode;
return 0;
}
// 设置SPI时钟频率
int spi_set_speed(SpiDevice_t device, uint32_t speed_hz) {
if (!device) {
set_error("无效的设备句柄");
return -1;
}
// 设置速度
if (ioctl(device->fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) < 0) {
set_error("设置SPI速度失败: %s", strerror(errno));
return -2;
}
// 更新设备结构
device->speed_hz = speed_hz;
return 0;
}
// 设置SPI每个字的位数
int spi_set_bits_per_word(SpiDevice_t device, uint8_t bits_per_word) {
if (!device) {
set_error("无效的设备句柄");
return -1;
}
// 设置位数
if (ioctl(device->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) {
set_error("设置SPI位数失败: %s", strerror(errno));
return -2;
}
// 更新设备结构
device->bits_per_word = bits_per_word;
return 0;
}
// 设置SPI位序
int spi_set_bit_order(SpiDevice_t device, int lsb_first) {
if (!device) {
set_error("无效的设备句柄");
return -1;
}
// 构建新的模式标志
uint8_t spi_mode = device->mode;
if (lsb_first) {
spi_mode |= SPI_LSB_FIRST;
} else {
spi_mode &= ~SPI_LSB_FIRST;
}
// 设置模式
if (ioctl(device->fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
set_error("设置SPI位序失败: %s", strerror(errno));
return -2;
}
// 更新设备结构
device->lsb_first = lsb_first ? 1 : 0;
return 0;
}
// 获取最后的错误消息
const char* spi_get_error(void) {
return error_message;
}
4. 综合应用示例
4.1 嵌入式传感器数据采集系统
c
/**
* sensor_system.h - 嵌入式传感器数据采集系统接口
*
* 硬件协同设计示例:软件与传感器硬件接口的协同设计
*/
#ifndef SENSOR_SYSTEM_H
#define SENSOR_SYSTEM_H
#include <stdint.h>
#include <time.h>
// 传感器类型定义
typedef enum {
SENSOR_TYPE_TEMPERATURE = 0,
SENSOR_TYPE_HUMIDITY = 1,
SENSOR_TYPE_PRESSURE = 2,
SENSOR_TYPE_ACCEL = 3,
SENSOR_TYPE_GYRO = 4,
SENSOR_TYPE_MAGNETIC = 5,
SENSOR_TYPE_LIGHT = 6,
SENSOR_TYPE_PROXIMITY = 7,
SENSOR_TYPE_GAS = 8,
SENSOR_TYPE_COUNT // 总数
} SensorType;
// 传感器数据结构体
typedef struct {
SensorType type; // 传感器类型
uint32_t sensor_id; // 传感器ID
double value[3]; // 传感器值 (最多3个轴)
uint8_t value_count; // 实际值的数量
struct timespec timestamp; // 时间戳
} SensorData;
// 传感器配置结构体
typedef struct {
uint32_t sample_rate; // 采样率 (Hz)
uint32_t range; // 量程
uint32_t resolution; // 分辨率
uint8_t enabled; // 启用标志
} SensorConfig;
// 系统配置结构体
typedef struct {
uint8_t use_i2c; // 使用I2C接口
uint8_t use_spi; // 使用SPI接口
char i2c_device[64]; // I2C设备路径
char spi_device[64]; // SPI设备路径
uint32_t i2c_addr; // I2C设备地址
uint32_t spi_speed; // SPI时钟速度
uint8_t log_enabled; // 启用日志
char log_file[128]; // 日志文件路径
} SystemConfig;
// 传感器系统句柄
typedef struct SensorSystem* SensorSystem_t;
/**
* 初始化传感器系统
*
* @param config 系统配置
* @return 传感器系统句柄,失败返回NULL
*/
SensorSystem_t sensor_system_init(const SystemConfig* config);
/**
* 关闭传感器系统
*
* @param system 传感器系统句柄
*/
void sensor_system_close(SensorSystem_t system);
/**
* 添加传感器
*
* @param system 传感器系统句柄
* @param type 传感器类型
* @param config 传感器配置
* @return 成功返回传感器ID,失败返回-1
*/
int sensor_system_add_sensor(SensorSystem_t system, SensorType type,
const SensorConfig* config);
/**
* 配置传感器
*
* @param system 传感器系统句柄
* @param sensor_id 传感器ID
* @param config 传感器配置
* @return 成功返回0,失败返回负值
*/
int sensor_system_configure_sensor(SensorSystem_t system, uint32_t sensor_id,
const SensorConfig* config);
/**
* 启用传感器
*
* @param system 传感器系统句柄
* @param sensor_id 传感器ID
* @param enabled 1=启用,0=禁用
* @return 成功返回0,失败返回负值
*/
int sensor_system_enable_sensor(SensorSystem_t system, uint32_t sensor_id,
uint8_t enabled);
/**
* 读取传感器数据
*
* @param system 传感器系统句柄
* @param sensor_id 传感器ID
* @param data 传感器数据输出缓冲区
* @return 成功返回0,失败返回负值
*/
int sensor_system_read_sensor(SensorSystem_t system, uint32_t sensor_id,
SensorData* data);
/**
* 启动数据采集
*
* @param system 传感器系统句柄
* @return 成功返回0,失败返回负值
*/
int sensor_system_start_acquisition(SensorSystem_t system);
/**
* 停止数据采集
*
* @param system 传感器系统句柄
* @return 成功返回0,失败返回负值
*/
int sensor_system_stop_acquisition(SensorSystem_t system);
/**
* 设置数据回调函数
*
* @param system 传感器系统句柄
* @param callback 回调函数指针
* @param user_data 用户数据
* @return 成功返回0,失败返回负值
*/
int sensor_system_set_data_callback(SensorSystem_t system,
void (*callback)(const SensorData* data, void* user_data),
void* user_data);
/**
* 获取最后的错误消息
*
* @return 错误消息字符串
*/
const char* sensor_system_get_error(void);
/**
* 获取传感器数量
*
* @param system 传感器系统句柄
* @return 传感器数量
*/
uint32_t sensor_system_get_sensor_count(SensorSystem_t system);
/**
* 获取系统状态
*
* @param system 传感器系统句柄
* @param is_running 运行状态标志
* @param active_sensors 活动传感器数量
* @param sample_rate 当前平均采样率
* @return 成功返回0,失败返回负值
*/
int sensor_system_get_status(SensorSystem_t system, uint8_t* is_running,
uint32_t* active_sensors, double* sample_rate);
#endif /* SENSOR_SYSTEM_H */
c
/**
* sensor_system.c - 嵌入式传感器数据采集系统实现
*
* 硬件协同设计示例:软件与传感器硬件接口的协同设计
*/
#include "sensor_system.h"
#include "i2c.h"
#include "spi_device.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <stdarg.h>
// 最大错误消息长度
#define MAX_ERROR_MSG_LEN 256
// 最大传感器数量
#define MAX_SENSORS 32
// 传感器设备结构体
typedef struct {
SensorType type; // 传感器类型
uint32_t sensor_id; // 传感器ID
SensorConfig config; // 传感器配置
uint8_t is_i2c; // 是否使用I2C接口
uint8_t i2c_addr; // I2C设备地址
uint8_t reg_addr; // 寄存器地址
uint8_t active; // 激活标志
} SensorDevice;
// 传感器系统结构体
struct SensorSystem {
SystemConfig config; // 系统配置
I2cHandle_t i2c_handle; // I2C句柄
SpiDevice_t spi_handle; // SPI句柄
SensorDevice sensors[MAX_SENSORS]; // 传感器设备数组
uint32_t sensor_count; // 传感器数量
uint8_t is_running; // 运行标志
pthread_t acquisition_thread; // 采集线程
pthread_mutex_t lock; // 互斥锁
void (*data_callback)(const SensorData* data, void* user_data); // 数据回调
void* callback_user_data; // 回调用户数据
FILE* log_file; // 日志文件
};
// 全局错误消息
static char error_message[MAX_ERROR_MSG_LEN] = {0};
// 设置错误消息
static void set_error(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(error_message, MAX_ERROR_MSG_LEN - 1, format, args);
va_end(args);
}
// 写日志
static void write_log(SensorSystem_t system, const char* format, ...) {
if (!system || !system->config.log_enabled || !system->log_file) {
return;
}
// 获取当前时间
time_t now;
struct tm timeinfo;
char timestamp[64];
time(&now);
localtime_r(&now, &timeinfo);
strftime(timestamp, sizeof(timestamp), "[%Y-%m-%d %H:%M:%S] ", &timeinfo);
// 写入时间戳
fputs(timestamp, system->log_file);
// 写入日志消息
va_list args;
va_start(args, format);
vfprintf(system->log_file, format, args);
va_end(args);
// 写入换行并刷新
fputs("\n", system->log_file);
fflush(system->log_file);
}
// 数据采集线程函数
static void* acquisition_thread_func(void* arg) {
SensorSystem_t system = (SensorSystem_t)arg;
SensorData data;
write_log(system, "数据采集线程启动");
while (system->is_running) {
// 获取当前时间
clock_gettime(CLOCK_REALTIME, &data.timestamp);
// 遍历所有传感器
for (uint32_t i = 0; i < system->sensor_count; i++) {
// 如果传感器已激活
if (system->sensors[i].active) {
// 读取传感器数据
if (sensor_system_read_sensor(system, system->sensors[i].sensor_id, &data) == 0) {
// 调用回调函数
if (system->data_callback) {
system->data_callback(&data, system->callback_user_data);
}
// 记录日志
if (system->config.log_enabled && system->log_file) {
write_log(system, "传感器 %u 数据: 类型=%d, 值=[%.3f, %.3f, %.3f]",
data.sensor_id, data.type,
data.value[0], data.value[1], data.value[2]);
}
}
}
}
// 简单延时 (实际应用中应该使用更精确的定时机制)
usleep(10000); // 10ms
}
write_log(system, "数据采集线程停止");
return NULL;
}
// 读取I2C传感器数据
static int read_i2c_sensor(SensorSystem_t system, SensorDevice* sensor, SensorData* data) {
if (!system || !sensor || !data || !system->i2c_handle) {
set_error("无效的参数");
return -1;
}
// 设置I2C从设备地址
if (i2c_set_slave_address(system->i2c_handle, sensor->i2c_addr, 0) != 0) {
set_error("设置I2C从设备地址失败");
return -2;
}
// 根据传感器类型确定要读取的数据大小
uint8_t data_size = 2; // 默认读取2字节
switch (sensor->type) {
case SENSOR_TYPE_TEMPERATURE:
case SENSOR_TYPE_HUMIDITY:
case SENSOR_TYPE_PRESSURE:
case SENSOR_TYPE_LIGHT:
case SENSOR_TYPE_PROXIMITY:
case SENSOR_TYPE_GAS:
data_size = 2; // 单值传感器通常为2字节
data->value_count = 1;
break;
case SENSOR_TYPE_ACCEL:
case SENSOR_TYPE_GYRO:
case SENSOR_TYPE_MAGNETIC:
data_size = 6; // 3轴传感器通常为6字节(每轴2字节)
data->value_count = 3;
break;
default:
set_error("不支持的传感器类型: %d", sensor->type);
return -3;
}
// 分配读取缓冲区
uint8_t* buffer = (uint8_t*)malloc(data_size);
if (!buffer) {
set_error("内存分配失败");
return -4;
}
// 从I2C设备读取数据
int ret = i2c_read_reg8(system->i2c_handle, sensor->reg_addr, buffer, data_size);
if (ret < 0) {
set_error("I2C读取失败: %s", i2c_get_last_error());
free(buffer);
return -5;
}
// 解析数据
if (data->value_count == 1) {
// 单值传感器
int16_t raw_value = (buffer[0] << 8) | buffer[1];
// 根据传感器类型进行转换
switch (sensor->type) {
case SENSOR_TYPE_TEMPERATURE:
// 假设温度传感器: raw / 16.0 度
data->value[0] = raw_value / 16.0;
break;
case SENSOR_TYPE_HUMIDITY:
// 假设湿度传感器: raw / 10.0 %
data->value[0] = raw_value / 10.0;
break;
case SENSOR_TYPE_PRESSURE:
// 假设压力传感器: raw * 0.1 hPa
data->value[0] = raw_value * 0.1;
break;
case SENSOR_TYPE_LIGHT:
// 假设光传感器: raw lux
data->value[0] = raw_value;
break;
case SENSOR_TYPE_PROXIMITY:
// 假设接近传感器: raw mm
data->value[0] = raw_value;
break;
case SENSOR_TYPE_GAS:
// 假设气体传感器: raw ppm
data->value[0] = raw_value;
break;
default:
data->value[0] = raw_value;
}
} else if (data->value_count == 3) {
// 3轴传感器
int16_t raw_x = (buffer[0] << 8) | buffer[1];
int16_t raw_y = (buffer[2] << 8) | buffer[3];
int16_t raw_z = (buffer[4] << 8) | buffer[5];
// 根据传感器类型进行转换
switch (sensor->type) {
case SENSOR_TYPE_ACCEL:
// 假设加速度传感器: raw * 0.001 g
data->value[0] = raw_x * 0.001;
data->value[1] = raw_y * 0.001;
data->value[2] = raw_z * 0.001;
break;
case SENSOR_TYPE_GYRO:
// 假设陀螺仪传感器: raw * 0.01 deg/s
data->value[0] = raw_x * 0.01;
data->value[1] = raw_y * 0.01;
data->value[2] = raw_z * 0.01;
break;
case SENSOR_TYPE_MAGNETIC:
// 假设磁力计传感器: raw * 0.1 uT
data->value[0] = raw_x * 0.1;
data->value[1] = raw_y * 0.1;
data->value[2] = raw_z * 0.1;
break;
default:
data->value[0] = raw_x;
data->value[1] = raw_y;
data->value[2] = raw_z;
}
}
// 设置传感器类型和ID
data->type = sensor->type;
data->sensor_id = sensor->sensor_id;
// 释放缓冲区
free(buffer);
return 0;
}
// 读取SPI传感器数据
static int read_spi_sensor(SensorSystem_t system, SensorDevice* sensor, SensorData* data) {
if (!system || !sensor || !data || !system->spi_handle) {
set_error("无效的参数");
return -1;
}
// 根据传感器类型确定要读取的数据大小
uint8_t data_size = 2; // 默认读取2字节
switch (sensor->type) {
case SENSOR_TYPE_TEMPERATURE:
case SENSOR_
c
case SENSOR_TYPE_HUMIDITY:
case SENSOR_TYPE_PRESSURE:
case SENSOR_TYPE_LIGHT:
case SENSOR_TYPE_PROXIMITY:
case SENSOR_TYPE_GAS:
data_size = 2; // 单值传感器通常为2字节
data->value_count = 1;
break;
case SENSOR_TYPE_ACCEL:
case SENSOR_TYPE_GYRO:
case SENSOR_TYPE_MAGNETIC:
data_size = 6; // 3轴传感器通常为6字节(每轴2字节)
data->value_count = 3;
break;
default:
set_error("不支持的传感器类型: %d", sensor->type);
return -3;
}
// 分配读取缓冲区
uint8_t* rx_buffer = (uint8_t*)malloc(data_size + 1); // +1用于寄存器地址
uint8_t* tx_buffer = (uint8_t*)malloc(data_size + 1);
if (!rx_buffer || !tx_buffer) {
set_error("内存分配失败");
if (rx_buffer) free(rx_buffer);
if (tx_buffer) free(tx_buffer);
return -4;
}
// 设置寄存器地址(读取命令)
tx_buffer[0] = sensor->reg_addr | 0x80; // 最高位设为1表示读操作
memset(tx_buffer + 1, 0, data_size); // 填充0
// 通过SPI传输
int ret = spi_transfer(system->spi_handle, tx_buffer, rx_buffer, data_size + 1);
if (ret < 0) {
set_error("SPI传输失败: %s", spi_get_error());
free(rx_buffer);
free(tx_buffer);
return -5;
}
// 解析数据(跳过第一个字节,它是寄存器地址)
if (data->value_count == 1) {
// 单值传感器
int16_t raw_value = (rx_buffer[1] << 8) | rx_buffer[2];
// 根据传感器类型进行转换
switch (sensor->type) {
case SENSOR_TYPE_TEMPERATURE:
// 假设温度传感器: raw / 16.0 度
data->value[0] = raw_value / 16.0;
break;
case SENSOR_TYPE_HUMIDITY:
// 假设湿度传感器: raw / 10.0 %
data->value[0] = raw_value / 10.0;
break;
case SENSOR_TYPE_PRESSURE:
// 假设压力传感器: raw * 0.1 hPa
data->value[0] = raw_value * 0.1;
break;
case SENSOR_TYPE_LIGHT:
// 假设光传感器: raw lux
data->value[0] = raw_value;
break;
case SENSOR_TYPE_PROXIMITY:
// 假设接近传感器: raw mm
data->value[0] = raw_value;
break;
case SENSOR_TYPE_GAS:
// 假设气体传感器: raw ppm
data->value[0] = raw_value;
break;
default:
data->value[0] = raw_value;
}
} else if (data->value_count == 3) {
// 3轴传感器
int16_t raw_x = (rx_buffer[1] << 8) | rx_buffer[2];
int16_t raw_y = (rx_buffer[3] << 8) | rx_buffer[4];
int16_t raw_z = (rx_buffer[5] << 8) | rx_buffer[6];
// 根据传感器类型进行转换
switch (sensor->type) {
case SENSOR_TYPE_ACCEL:
// 假设加速度传感器: raw * 0.001 g
data->value[0] = raw_x * 0.001;
data->value[1] = raw_y * 0.001;
data->value[2] = raw_z * 0.001;
break;
case SENSOR_TYPE_GYRO:
// 假设陀螺仪传感器: raw * 0.01 deg/s
data->value[0] = raw_x * 0.01;
data->value[1] = raw_y * 0.01;
data->value[2] = raw_z * 0.01;
break;
case SENSOR_TYPE_MAGNETIC:
// 假设磁力计传感器: raw * 0.1 uT
data->value[0] = raw_x * 0.1;
data->value[1] = raw_y * 0.1;
data->value[2] = raw_z * 0.1;
break;
default:
data->value[0] = raw_x;
data->value[1] = raw_y;
data->value[2] = raw_z;
}
}
// 设置传感器类型和ID
data->type = sensor->type;
data->sensor_id = sensor->sensor_id;
// 释放缓冲区
free(rx_buffer);
free(tx_buffer);
return 0;
}
// 初始化传感器系统
SensorSystem_t sensor_system_init(const SystemConfig* config) {
if (!config) {
set_error("无效的系统配置");
return NULL;
}
// 分配系统结构体
SensorSystem_t system = (SensorSystem_t)malloc(sizeof(struct SensorSystem));
if (!system) {
set_error("内存分配失败");
return NULL;
}
// 初始化结构体
memset(system, 0, sizeof(struct SensorSystem));
memcpy(&system->config, config, sizeof(SystemConfig));
// 初始化互斥锁
if (pthread_mutex_init(&system->lock, NULL) != 0) {
set_error("初始化互斥锁失败");
free(system);
return NULL;
}
// 打开I2C设备(如果需要)
if (config->use_i2c) {
system->i2c_handle = i2c_open(config->i2c_device);
if (!system->i2c_handle) {
set_error("打开I2C设备失败: %s", i2c_get_last_error());
pthread_mutex_destroy(&system->lock);
free(system);
return NULL;
}
}
// 打开SPI设备(如果需要)
if (config->use_spi) {
system->spi_handle = spi_open(config->spi_device, SPI_MODE_0,
config->spi_speed, 8, 0);
if (!system->spi_handle) {
set_error("打开SPI设备失败: %s", spi_get_error());
if (system->i2c_handle) {
i2c_close(system->i2c_handle);
}
pthread_mutex_destroy(&system->lock);
free(system);
return NULL;
}
}
// 打开日志文件(如果需要)
if (config->log_enabled && config->log_file[0] != '\0') {
system->log_file = fopen(config->log_file, "a");
if (!system->log_file) {
set_error("打开日志文件失败: %s", strerror(errno));
// 不将此视为致命错误,继续初始化
}
}
// 写入初始日志
write_log(system, "传感器系统初始化");
return system;
}
// 关闭传感器系统
void sensor_system_close(SensorSystem_t system) {
if (!system) {
return;
}
// 确保停止采集
if (system->is_running) {
sensor_system_stop_acquisition(system);
}
// 写入关闭日志
write_log(system, "传感器系统关闭");
// 关闭日志文件
if (system->log_file) {
fclose(system->log_file);
system->log_file = NULL;
}
// 关闭I2C设备
if (system->i2c_handle) {
i2c_close(system->i2c_handle);
system->i2c_handle = NULL;
}
// 关闭SPI设备
if (system->spi_handle) {
spi_close(system->spi_handle);
system->spi_handle = NULL;
}
// 销毁互斥锁
pthread_mutex_destroy(&system->lock);
// 释放系统结构体
free(system);
}
// 添加传感器
int sensor_system_add_sensor(SensorSystem_t system, SensorType type,
const SensorConfig* config) {
if (!system || !config) {
set_error("无效的参数");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查是否已达到最大传感器数量
if (system->sensor_count >= MAX_SENSORS) {
pthread_mutex_unlock(&system->lock);
set_error("已达到最大传感器数量 (%d)", MAX_SENSORS);
return -2;
}
// 添加新传感器
SensorDevice* sensor = &system->sensors[system->sensor_count];
sensor->type = type;
sensor->sensor_id = system->sensor_count;
memcpy(&sensor->config, config, sizeof(SensorConfig));
// 设置接口类型
if (system->config.use_i2c) {
sensor->is_i2c = 1;
sensor->i2c_addr = (uint8_t)system->config.i2c_addr;
} else {
sensor->is_i2c = 0;
}
// 设置默认寄存器地址(根据传感器类型)
switch (type) {
case SENSOR_TYPE_TEMPERATURE:
sensor->reg_addr = 0x00;
break;
case SENSOR_TYPE_HUMIDITY:
sensor->reg_addr = 0x01;
break;
case SENSOR_TYPE_PRESSURE:
sensor->reg_addr = 0x02;
break;
case SENSOR_TYPE_ACCEL:
sensor->reg_addr = 0x10;
break;
case SENSOR_TYPE_GYRO:
sensor->reg_addr = 0x20;
break;
case SENSOR_TYPE_MAGNETIC:
sensor->reg_addr = 0x30;
break;
case SENSOR_TYPE_LIGHT:
sensor->reg_addr = 0x40;
break;
case SENSOR_TYPE_PROXIMITY:
sensor->reg_addr = 0x50;
break;
case SENSOR_TYPE_GAS:
sensor->reg_addr = 0x60;
break;
default:
sensor->reg_addr = 0x00;
}
// 设置激活状态
sensor->active = config->enabled;
// 更新传感器计数
uint32_t sensor_id = system->sensor_count;
system->sensor_count++;
pthread_mutex_unlock(&system->lock);
// 写入日志
write_log(system, "添加传感器: ID=%u, 类型=%d, 启用=%d",
sensor_id, type, config->enabled);
return sensor_id;
}
// 配置传感器
int sensor_system_configure_sensor(SensorSystem_t system, uint32_t sensor_id,
const SensorConfig* config) {
if (!system || !config) {
set_error("无效的参数");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查传感器ID是否有效
if (sensor_id >= system->sensor_count) {
pthread_mutex_unlock(&system->lock);
set_error("无效的传感器ID: %u", sensor_id);
return -2;
}
// 更新传感器配置
memcpy(&system->sensors[sensor_id].config, config, sizeof(SensorConfig));
// 更新激活状态
system->sensors[sensor_id].active = config->enabled;
pthread_mutex_unlock(&system->lock);
// 写入日志
write_log(system, "配置传感器: ID=%u, 启用=%d, 采样率=%u",
sensor_id, config->enabled, config->sample_rate);
return 0;
}
// 启用传感器
int sensor_system_enable_sensor(SensorSystem_t system, uint32_t sensor_id,
uint8_t enabled) {
if (!system) {
set_error("无效的系统句柄");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查传感器ID是否有效
if (sensor_id >= system->sensor_count) {
pthread_mutex_unlock(&system->lock);
set_error("无效的传感器ID: %u", sensor_id);
return -2;
}
// 更新激活状态
system->sensors[sensor_id].active = enabled ? 1 : 0;
system->sensors[sensor_id].config.enabled = enabled ? 1 : 0;
pthread_mutex_unlock(&system->lock);
// 写入日志
write_log(system, "%s传感器: ID=%u", enabled ? "启用" : "禁用", sensor_id);
return 0;
}
// 读取传感器数据
int sensor_system_read_sensor(SensorSystem_t system, uint32_t sensor_id,
SensorData* data) {
if (!system || !data) {
set_error("无效的参数");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查传感器ID是否有效
if (sensor_id >= system->sensor_count) {
pthread_mutex_unlock(&system->lock);
set_error("无效的传感器ID: %u", sensor_id);
return -2;
}
// 获取传感器引用
SensorDevice* sensor = &system->sensors[sensor_id];
// 确保传感器处于激活状态
if (!sensor->active) {
pthread_mutex_unlock(&system->lock);
set_error("传感器未激活: %u", sensor_id);
return -3;
}
// 根据接口类型读取传感器数据
int ret;
if (sensor->is_i2c) {
ret = read_i2c_sensor(system, sensor, data);
} else {
ret = read_spi_sensor(system, sensor, data);
}
pthread_mutex_unlock(&system->lock);
return ret;
}
// 启动数据采集
int sensor_system_start_acquisition(SensorSystem_t system) {
if (!system) {
set_error("无效的系统句柄");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查是否已经在运行
if (system->is_running) {
pthread_mutex_unlock(&system->lock);
set_error("数据采集已经在运行");
return -2;
}
// 检查是否有激活的传感器
int has_active_sensor = 0;
for (uint32_t i = 0; i < system->sensor_count; i++) {
if (system->sensors[i].active) {
has_active_sensor = 1;
break;
}
}
if (!has_active_sensor) {
pthread_mutex_unlock(&system->lock);
set_error("没有激活的传感器");
return -3;
}
// 设置运行标志
system->is_running = 1;
// 创建采集线程
int ret = pthread_create(&system->acquisition_thread, NULL,
acquisition_thread_func, system);
if (ret != 0) {
system->is_running = 0;
pthread_mutex_unlock(&system->lock);
set_error("创建采集线程失败: %s", strerror(ret));
return -4;
}
pthread_mutex_unlock(&system->lock);
// 写入日志
write_log(system, "启动数据采集");
return 0;
}
// 停止数据采集
int sensor_system_stop_acquisition(SensorSystem_t system) {
if (!system) {
set_error("无效的系统句柄");
return -1;
}
pthread_mutex_lock(&system->lock);
// 检查是否正在运行
if (!system->is_running) {
pthread_mutex_unlock(&system->lock);
set_error("数据采集未在运行");
return -2;
}
// 清除运行标志
system->is_running = 0;
// 保存线程ID
pthread_t thread_id = system->acquisition_thread;
pthread_mutex_unlock(&system->lock);
// 等待线程结束
pthread_join(thread_id, NULL);
// 写入日志
write_log(system, "停止数据采集");
return 0;
}
// 设置数据回调函数
int sensor_system_set_data_callback(SensorSystem_t system,
void (*callback)(const SensorData* data, void* user_data),
void* user_data) {
if (!system) {
set_error("无效的系统句柄");
return -1;
}
pthread_mutex_lock(&system->lock);
// 更新回调函数和用户数据
system->data_callback = callback;
system->callback_user_data = user_data;
pthread_mutex_unlock(&system->lock);
// 写入日志
write_log(system, "设置数据回调函数: %p", callback);
return 0;
}
// 获取最后的错误消息
const char* sensor_system_get_error(void) {
return error_message;
}
// 获取传感器数量
uint32_t sensor_system_get_sensor_count(SensorSystem_t system) {
if (!system) {
return 0;
}
return system->sensor_count;
}
// 获取系统状态
int sensor_system_get_status(SensorSystem_t system, uint8_t* is_running,
uint32_t* active_sensors, double* sample_rate) {
if (!system) {
set_error("无效的系统句柄");
return -1;
}
pthread_mutex_lock(&system->lock);
// 获取运行状态
if (is_running) {
*is_running = system->is_running;
}
// 计算激活的传感器数量
if (active_sensors) {
*active_sensors = 0;
for (uint32_t i = 0; i < system->sensor_count; i++) {
if (system->sensors[i].active) {
(*active_sensors)++;
}
}
}
// 计算平均采样率
if (sample_rate) {
*sample_rate = 0.0;
uint32_t count = 0;
for (uint32_t i = 0; i < system->sensor_count; i++) {
if (system->sensors[i].active) {
*sample_rate += system->sensors[i].config.sample_rate;
count++;
}
}
if (count > 0) {
*sample_rate /= count;
}
}
pthread_mutex_unlock(&system->lock);
return 0;
}
4.2 电机控制系统
cpp
/**
* motor_control.h - 电机控制系统接口
*
* 硬件协同设计示例:软件与电机驱动硬件的协同设计
*/
#ifndef MOTOR_CONTROL_H
#define MOTOR_CONTROL_H
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
namespace motor_control {
// 前向声明
class MotorControllerImpl;
// 电机类型
enum class MotorType {
DC, // 直流电机
BLDC, // 无刷直流电机
STEPPER, // 步进电机
SERVO // 伺服电机
};
// 电机控制模式
enum class ControlMode {
POSITION, // 位置控制
VELOCITY, // 速度控制
TORQUE, // 力矩控制
OPEN_LOOP // 开环控制
};
// 电机配置结构体
struct MotorConfig {
std::string name; // 电机名称
MotorType type; // 电机类型
double max_velocity; // 最大速度 (rpm)
double max_acceleration; // 最大加速度 (rpm/s)
double max_torque; // 最大力矩 (Nm)
double gear_ratio; // 齿轮比
bool reverse_direction; // 反向标志
// 特定电机类型配置
union {
struct {
double max_current; // 最大电流 (A)
} dc;
struct {
uint8_t pole_pairs; // 极对数
bool hall_sensors; // 是否使用霍尔传感器
} bldc;
struct {
uint32_t steps_per_rev; // 每转步数
uint8_t microstepping; // 微步细分
} stepper;
struct {
double min_angle; // 最小角度 (度)
double max_angle; // 最大角度 (度)
double center_angle; // 中心角度 (度)
} servo;
};
};
// PID控制器参数
struct PIDParams {
double kp; // 比例系数
double ki; // 积分系数
double kd; // 微分系数
double ff; // 前馈系数
double imax; // 积分限幅
};
// 电机状态
struct MotorStatus {
double position; // 位置 (取决于电机类型: 度/弧度/步)
double velocity; // 速度 (rpm)
double current; // 电流 (A)
double voltage; // 电压 (V)
double temperature; // 温度 (°C)
bool is_moving; // 是否运动中
bool is_calibrated; // 是否已校准
bool error_state; // 错误状态
uint32_t error_code; // 错误代码
ControlMode mode; // 当前控制模式
};
/**
* 电机控制器类
*/
class MotorController {
public:
/**
* 构造函数
*
* @param interface_name 接口名称 (如 "/dev/ttyUSB0", "can0")
* @param interface_type 接口类型 (如 "uart", "can", "spi")
*/
MotorController(const std::string& interface_name,
const std::string& interface_type);
/**
* 析构函数
*/
~MotorController();
/**
* 初始化电机控制器
*
* @return 成功返回true,失败返回false
*/
bool initialize();
/**
* 添加电机
*
* @param config 电机配置
* @return 成功返回电机ID,失败返回-1
*/
int add_motor(const MotorConfig& config);
/**
* 配置电机
*
* @param motor_id 电机ID
* @param config 电机配置
* @return 成功返回true,失败返回false
*/
bool configure_motor(int motor_id, const MotorConfig& config);
/**
* 设置PID参数
*
* @param motor_id 电机ID
* @param mode 控制模式
* @param params PID参数
* @return 成功返回true,失败返回false
*/
bool set_pid_params(int motor_id, ControlMode mode, const PIDParams& params);
/**
* 设置电机模式
*
* @param motor_id 电机ID
* @param mode 控制模式
* @return 成功返回true,失败返回false
*/
bool set_motor_mode(int motor_id, ControlMode mode);
/**
* 使能/禁用电机
*
* @param motor_id 电机ID
* @param enable 使能标志
* @return 成功返回true,失败返回false
*/
bool enable_motor(int motor_id, bool enable);
/**
* 设置位置目标
*
* @param motor_id 电机ID
* @param position 目标位置
* @param velocity_limit 可选的速度限制
* @param acceleration_limit 可选的加速度限制
* @return 成功返回true,失败返回false
*/
bool set_position(int motor_id, double position,
double velocity_limit = 0,
double acceleration_limit = 0);
/**
* 设置速度目标
*
* @param motor_id 电机ID
* @param velocity 目标速度 (rpm)
* @param acceleration_limit 可选的加速度限制
* @return 成功返回true,失败返回false
*/
bool set_velocity(int motor_id, double velocity,
double acceleration_limit = 0);
/**
* 设置力矩目标
*
* @param motor_id 电机ID
* @param torque 目标力矩 (Nm)
* @return 成功返回true,失败返回false
*/
bool set_torque(int motor_id, double torque);
/**
* 设置开环输出
*
* @param motor_id 电机ID
* @param duty_cycle 占空比 (-1.0 to 1.0)
* @return 成功返回true,失败返回false
*/
bool set_duty_cycle(int motor_id, double duty_cycle);
/**
* 获取电机状态
*
* @param motor_id 电机ID
* @return 电机状态结构体
*/
MotorStatus get_motor_status(int motor_id);
/**
* 校准电机
*
* @param motor_id 电机ID
* @return 成功返回true,失败返回false
*/
bool calibrate_motor(int motor_id);
/**
* 停止电机
*
* @param motor_id 电机ID
* @param emergency 是否紧急停止
* @return 成功返回true,失败返回false
*/
bool stop_motor(int motor_id, bool emergency = false);
/**
* 停止所有电机
*
* @param emergency 是否紧急停止
* @return 成功返回true,失败返回false
*/
bool stop_all_motors(bool emergency = false);
/**
* 获取最后的错误消息
*
* @return 错误消息
*/
std::string get_last_error() const;
/**
* 获取电机数量
*
* @return 电机数量
*/
int get_motor_count() const;
private:
// 私有实现 (PIMPL模式)
std::unique_ptr<MotorControllerImpl> impl_;
// 禁止拷贝和赋值
MotorController(const MotorController&) = delete;
MotorController& operator=(const MotorController&) = delete;
};
} // namespace motor_control
#endif /* MOTOR_CONTROL_H */
cpp
/**
* motor_control.cpp - 电机控制系统实现
*
* 硬件协同设计示例:软件与电机驱动硬件的协同设计
*/
#include "motor_control.h"
#include <cstring>
#include <thread>
#include <chrono>
#include <mutex>
#include <algorithm>
#include <cmath>
#include <fstream>
#include <sstream>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
namespace motor_control {
// 最大电机数量
constexpr int MAX_MOTORS = 16;
// 电机结构体
struct Motor {
MotorConfig config; // 电机配置
MotorStatus status; // 电机状态
PIDParams pid_position; // 位置PID参数
PIDParams pid_velocity; // 速度PID参数
PIDParams pid_torque; // 力矩PID参数
// 目标值
double target_position; // 目标位置
double target_velocity; // 目标速度
double target_torque; // 目标力矩
double target_duty_cycle; // 目标占空比
// 限制
double velocity_limit; // 速度限制
double acceleration_limit; // 加速度限制
// 状态
bool is_enabled; // 是否使能
bool is_configured; // 是否已配置
};
// PID控制器结构体
class PIDController {
public:
PIDController() {
reset();
}
void configure(const PIDParams& params) {
kp = params.kp;
ki = params.ki;
kd = params.kd;
ff = params.ff;
imax = params.imax;
reset();
}
void reset() {
previous_error = 0.0;
integral = 0.0;
last_time = std::chrono::steady_clock::now();
}
double update(double setpoint, double process_variable) {
auto now = std::chrono::steady_clock::now();
std::chrono::duration<double> time_diff = now - last_time;
double dt = time_diff.count();
// 防止dt过小导致不稳定
if (dt < 0.001) {
dt = 0.001;
}
// 计算误差
double error = setpoint - process_variable;
// 微分项 (使用误差变化率)
double derivative = 0.0;
if (dt > 0) {
derivative = (error - previous_error) / dt;
}
// 积分项 (使用误差累积)
integral += error * dt;
// 积分限幅
if (imax > 0) {
integral = std::min(std::max(integral, -imax), imax);
}
// PID输出
double output = kp * error + ki * integral + kd * derivative + ff * setpoint;
// 更新状态
previous_error = error;
last_time = now;
return output;
}
private:
double kp = 0.0;
double ki = 0.0;
double kd = 0.0;
double ff = 0.0;
double imax = 0.0;
double previous_error = 0.0;
double integral = 0.0;
std::chrono::steady_clock::time_point last_time;
};
// 电机控制器实现类
class MotorControllerImpl {
public:
MotorControllerImpl(const std::string& interface_name,
const std::string& interface_type)
: interface_name_(interface_name),
interface_type_(interface_type),
initialized_(false),
running_(false),
motor_count_(0),
fd_(-1)
{
// 初始化电机数组
for (int i = 0; i < MAX_MOTORS; i++) {
motors_[i] = {};
motors_[i].is_configured = false;
motors_[i].is_enabled = false;
// 设置默认PID参数
motors_[i].pid_position = {0.1, 0.01, 0.001, 0.0, 10.0};
motors_[i].pid_velocity = {0.01, 0.001, 0.0, 0.0, 10.0};
motors_[i].pid_torque = {0.5, 0.05, 0.0, 0.0, 10.0};
// 创建PID控制器
position_controllers_[i].configure(motors_[i].pid_position);
velocity_controllers_[i].configure(motors_[i].pid_velocity);
torque_controllers_[i].configure(motors_[i].pid_torque);
}
}
~MotorControllerImpl() {
// 停止控制线程
if (running_) {
running_ = false;
if (control_thread_.joinable()) {
control_thread_.join();
}
}
// 关闭接口
if (fd_ >= 0) {
close(fd_);
fd_ = -1;
}
}
bool initialize() {
// 检查是否已初始化
if (initialized_) {
last_error_ = "已经初始化";
return false;
}
// 根据接口类型打开相应设备
if (interface_type_ == "uart" || interface_type_ == "serial") {
if (!open_uart_interface()) {
return false;
}
} else if (interface_type_ == "can") {
if (!open_can_interface()) {
return false;
}
} else if (interface_type_ == "spi") {
if (!open_spi_interface()) {
return false;
}
} else {
last_error_ = "不支持的接口类型: " + interface_type_;
return false;
}
// 启动控制线程
running_ = true;
control_thread_ = std::thread(&MotorControllerImpl::control_loop, this);
initialized_ = true;
return true;
}
int add_motor(const MotorConfig& config) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查是否已初始化
if (!initialized_) {
last_error_ = "控制器未初始化";
return -1;
}
// 检查是否已达到最大电机数量
if (motor_count_ >= MAX_MOTORS) {
last_error_ = "已达到最大电机数量";
return -1;
}
// 查找是否已存在同名电机
for (int i = 0; i < motor_count_; i++) {
if (motors_[i].config.name == config.name) {
last_error_ = "电机名称已存在: " + config.name;
return -1;
}
}
// 添加新电机
int motor_id = motor_count_;
motors_[motor_id].config = config;
motors_[motor_id].is_configured = true;
// 初始化状态
motors_[motor_id].status.position = 0.0;
motors_[motor_id].status.velocity = 0.0;
motors_[motor_id].status.current = 0.0;
motors_[motor_id].status.voltage = 0.0;
motors_[motor_id].status.temperature = 0.0;
motors_[motor_id].status.is_moving = false;
motors_[motor_id].status.is_calibrated = false;
motors_[motor_id].status.error_state = false;
motors_[motor_id].status.error_code = 0;
motors_[motor_id].status.mode = ControlMode::POSITION;
// 初始化目标值
motors_[motor_id].target_position = 0.0;
motors_[motor_id].target_velocity = 0.0;
motors_[motor_id].target_torque = 0.0;
motors_[motor_id].target_duty_cycle = 0.0;
// 初始化限制
motors_[motor_id].velocity_limit = config.max_velocity;
motors_[motor_id].acceleration_limit = config.max_acceleration;
// 增加电机计数
motor_count_++;
return motor_id;
}
bool configure_motor(int motor_id, const MotorConfig& config) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 保存旧配置的一些值
bool was_enabled = motors_[motor_id].is_enabled;
ControlMode old_mode = motors_[motor_id].status.mode;
// 更新配置
motors_[motor_id].config = config;
// 恢复状态
motors_[motor_id].is_enabled = was_enabled;
motors_[motor_id].status.mode = old_mode;
// 设置限制
motors_[motor_id].velocity_limit = config.max_velocity;
motors_[motor_id].acceleration_limit = config.max_acceleration;
return true;
}
bool set_pid_params(int motor_id, ControlMode mode, const PIDParams& params) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 根据模式更新PID参数
switch (mode) {
case ControlMode::POSITION:
motors_[motor_id].pid_position = params;
position_controllers_[motor_id].configure(params);
break;
case ControlMode::VELOCITY:
motors_[motor_id].pid_velocity = params;
velocity_controllers_[motor_id].configure(params);
break;
case ControlMode::TORQUE:
motors_[motor_id].pid_torque = params;
torque_controllers_[motor_id].configure(params);
break;
default:
last_error_ = "不支持开环模式的PID参数";
return false;
}
return true;
}
bool set_motor_mode(int motor_id, ControlMode mode) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 检查模式是否支持
if (mode == ControlMode::POSITION && motors_[motor_id].config.type == MotorType::DC) {
last_error_ = "直流电机不支持位置控制模式";
return false;
}
// 更新模式
motors_[motor_id].status.mode = mode;
// 根据电机类型进行特定处理
switch (motors_[motor_id].config.type) {
case MotorType::DC:
// 重置PID控制器
if (mode == ControlMode::VELOCITY) {
velocity_controllers_[motor_id].reset();
} else if (mode == ControlMode::TORQUE) {
torque_controllers_[motor_id].reset();
}
break;
case MotorType::BLDC:
// 重置所有PID控制器
position_controllers_[motor_id].reset();
velocity_controllers_[motor_id].reset();
torque_controllers_[motor_id].reset();
break;
case MotorType::STEPPER:
// 步进电机特殊处理
if (mode == ControlMode::TORQUE) {
last_error_ = "步进电机不支持力矩控制模式";
return false;
}
break;
case MotorType::SERVO:
// 伺服电机仅支持位置控制
if (mode != ControlMode::POSITION) {
last_error_ = "伺服电机仅支持位置控制模式";
return false;
}
break;
}
return true;
}
bool enable_motor(int motor_id, bool enable) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 更新使能状态
motors_[motor_id].is_enabled = enable;
// 如果禁用,重置控制器和目标值
if (!enable) {
position_controllers_[motor_id].reset();
velocity_controllers_[motor_id].reset();
torque_controllers_[motor_id].reset();
motors_[motor_id].target_duty_cycle = 0.0;
}
// 发送使能命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = enable ? 0x01 : 0x00; // 使能命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送使能命令失败";
return false;
}
return true;
}
bool set_position(int motor_id, double position,
double velocity_limit, double acceleration_limit) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 检查电机是否使能
if (!motors_[motor_id].is_enabled) {
last_error_ = "电机未使能: " + std::to_string(motor_id);
return false;
}
// 检查电机是否支持位置控制
if (motors_[motor_id].config.type == MotorType::DC) {
last_error_ = "直流电机不支持位置控制";
return false;
}
// 对于伺服电机,检查位置是否在限制范围内
if (motors_[motor_id].config.type == MotorType::SERVO) {
double min_angle = motors_[motor_id].config.servo.min_angle;
double max_angle = motors_[motor_id].config.servo.max_angle;
if (position < min_angle || position > max_angle) {
last_error_ = "位置超出伺服电机范围: " +
std::to_string(position) + " [" +
std::to_string(min_angle) + ", " +
std::to_string(max_angle) + "]";
return false;
}
}
// 设置目标位置
motors_[motor_id].target_position = position;
// 设置速度和加速度限制(如果提供)
if (velocity_limit > 0) {
motors_[motor_id].velocity_limit = std::min(velocity_limit,
motors_[motor_id].config.max_velocity);
}
if (acceleration_limit > 0) {
motors_[motor_id].acceleration_limit = std::min(acceleration_limit,
motors_[motor_id].config.max_acceleration);
}
// 设置控制模式为位置模式
motors_[motor_id].status.mode = ControlMode::POSITION;
// 发送位置命令到硬件
uint8_t command_buffer[16] = {0};
command_buffer[0] = 0x10; // 位置控制命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
// 编码位置值(4字节浮点数)
float pos_float = static_cast<float>(position);
std::memcpy(&command_buffer[2], &pos_float, sizeof(float));
// 编码速度限制(4字节浮点数)
float vel_float = static_cast<float>(motors_[motor_id].velocity_limit);
std::memcpy(&command_buffer[6], &vel_float, sizeof(float));
// 编码加速度限制(4字节浮点数)
float acc_float = static_cast<float>(motors_[motor_id].acceleration_limit);
std::memcpy(&command_buffer[10], &acc_float, sizeof(float));
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送位置命令失败";
return false;
}
return true;
}
bool set_velocity(int motor_id, double velocity, double acceleration_limit) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 检查电机是否使能
if (!motors_[motor_id].is_enabled) {
last_error_ = "电机未使能: " + std::to_string(motor_id);
return false;
}
// 检查电机是否为伺服电机(不支持速度控制)
if (motors_[motor_id].config.type == MotorType::SERVO) {
last_error_ = "伺服电机不支持速度控制";
return false;
}
// 限制速度
velocity = std::min(std::max(velocity, -motors_[motor_id].config.max_velocity),
motors_[motor_id].config.max_velocity);
// 方向反转处理
if (motors_[motor_id].config.reverse_direction) {
velocity = -velocity;
}
// 设置目标速度
motors_[motor_id].target_velocity = velocity;
// 设置加速度限制(如果提供)
if (acceleration_limit > 0) {
motors_[motor_id].acceleration_limit = std::min(acceleration_limit,
motors_[motor_id].config.max_acceleration);
}
// 设置控制模式为速度模式
motors_[motor_id].status.mode = ControlMode::VELOCITY;
// 发送速度命令到硬件
uint8_t command_buffer[12] = {0};
command_buffer[0] = 0x20; // 速度控制命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
// 编码速度值(4字节浮点数)
float vel_float = static_cast<float>(velocity);
std::memcpy(&command_buffer[2], &vel_float, sizeof(float));
// 编码加速度限制(4字节浮点数)
float acc_float = static_cast<float>(motors_[motor_id].acceleration_limit);
std::memcpy(&command_buffer[6], &acc_float, sizeof(float));
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送速度命令失败";
return false;
}
return true;
}
bool set_torque(int motor_id, double torque) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 检查电机是否使能
if (!motors_[motor_id].is_enabled) {
last_error_ = "电机未使能: " + std::to_string(motor_id);
return false;
}
// 检查电机类型是否支持力矩控制
if (motors_[motor_id].config.type == MotorType::STEPPER ||
motors_[motor_id].config.type == MotorType::SERVO) {
last_error_ = "电机类型不支持力矩控制";
return false;
}
// 限制力矩
torque = std::min(std::max(torque, -motors_[motor_id].config.max_torque),
motors_[motor_id].config.max_torque);
// 方向反转处理
if (motors_[motor_id].config.reverse_direction) {
torque = -torque;
}
// 设置目标力矩
motors_[motor_id].target_torque = torque;
// 设置控制模式为力矩模式
motors_[motor_id].status.mode = ControlMode::TORQUE;
// 发送力矩命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = 0x30; // 力矩控制命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
// 编码力矩值(4字节浮点数)
float torque_float = static_cast<float>(torque);
std::memcpy(&command_buffer[2], &torque_float, sizeof(float));
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送力矩命令失败";
return false;
}
return true;
}
bool set_duty_cycle(int motor_id, double duty_cycle) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 检查电机是否使能
if (!motors_[motor_id].is_enabled) {
last_error_ = "电机未使能: " + std::to_string(motor_id);
return false;
}
// 限制占空比
duty_cycle = std::min(std::max(duty_cycle, -1.0), 1.0);
// 方向反转处理
if (motors_[motor_id].config.reverse_direction) {
duty_cycle = -duty_cycle;
}
// 设置目标占空比
motors_[motor_id].target_duty_cycle = duty_cycle;
// 设置控制模式为开环模式
motors_[motor_id].status.mode = ControlMode::OPEN_LOOP;
// 发送占空比命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = 0x40; // 开环控制命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
// 编码占空比值(4字节浮点数)
float duty_float = static_cast<float>(duty_cycle);
std::memcpy(&command_buffer[2], &duty_float, sizeof(float));
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送占空比命令失败";
return false;
}
return true;
}
MotorStatus get_motor_status(int motor_id) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
MotorStatus empty_status = {};
empty_status.error_state = true;
empty_status.error_code = 0xFFFF;
return empty_status;
}
// 返回状态副本
return motors_[motor_id].status;
}
bool calibrate_motor(int motor_id) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 发送校准命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = 0xA0; // 校准命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送校准命令失败";
return false;
}
// 更新校准状态
motors_[motor_id].status.is_calibrated = true;
return true;
}
bool stop_motor(int motor_id, bool emergency) {
std::lock_guard<std::mutex> lock(mutex_);
// 检查电机ID是否有效
if (motor_id < 0 || motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
last_error_ = "无效的电机ID: " + std::to_string(motor_id);
return false;
}
// 发送停止命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = emergency ? 0xF0 : 0xF1; // 紧急停止或正常停止
command_buffer[1] = (uint8_t)motor_id; // 电机ID
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送停止命令失败";
return false;
}
// 更新电机状态
motors_[motor_id].target_velocity = 0.0;
motors_[motor_id].target_torque = 0.0;
motors_[motor_id].target_duty_cycle = 0.0;
motors_[motor_id].status.is_moving = false;
// 如果是紧急停止,则禁用电机
if (emergency) {
motors_[motor_id].is_enabled = false;
}
return true;
}
bool stop_all_motors(bool emergency) {
std::lock_guard<std::mutex> lock(mutex_);
// 发送停止所有电机命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = emergency ? 0xFC : 0xFD; // 紧急停止所有或正常停止所有
bool result = send_command(command_buffer, sizeof(command_buffer));
if (!result) {
last_error_ = "发送停止所有电机命令失败";
return false;
}
// 更新所有电机状态
for (int i = 0; i < motor_count_; i++) {
if (motors_[i].is_configured) {
motors_[i].target_velocity = 0.0;
motors_[i].target_torque = 0.0;
motors_[i].target_duty_cycle = 0.0;
motors_[i].status.is_moving = false;
// 如果是紧急停止,则禁用电机
if (emergency) {
motors_[i].is_enabled = false;
}
}
}
return true;
}
std::string get_last_error() const {
return last_error_;
}
int get_motor_count() const {
return motor_count_;
}
private:
// 控制循环线程函数
void control_loop() {
while (running_) {
// 更新电机状态
update_motor_status();
// 执行控制逻辑
for (int i = 0; i < motor_count_; i++) {
if (motors_[i].is_configured && motors_[i].is_enabled) {
update_motor_control(i);
}
}
// 控制周期 (1000 Hz)
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
// 更新电机状态
void update_motor_status() {
std::lock_guard<std::mutex> lock(mutex_);
// 接收状态数据
uint8_t buffer[64] = {0};
int bytes_read = receive_data(buffer, sizeof(buffer));
if (bytes_read > 0) {
// 解析状态数据
parse_status_data(buffer, bytes_read);
}
}
// 解析状态数据
void parse_status_data(const uint8_t* data, int size) {
// 检查数据有效性
if (size < 2) {
return;
}
// 根据命令类型解析数据
uint8_t cmd_type = data[0];
if (cmd_type == 0x80) { // 电机状态数据
// 检查数据大小
if (size < 18) {
return;
}
// 获取电机ID
uint8_t motor_id = data[1];
// 检查ID是否有效
if (motor_id >= motor_count_ || !motors_[motor_id].is_configured) {
return;
}
// 解析状态数据
float position, velocity, current, voltage, temperature;
// 位置 (字节2-5)
std::memcpy(&position, &data[2], sizeof(float));
// 速度 (字节6-9)
std::memcpy(&velocity, &data[6], sizeof(float));
// 电流 (字节10-13)
std::memcpy(¤t, &data[10], sizeof(float));
// 电压 (字节14-17)
std::memcpy(&voltage, &data[14], sizeof(float));
// 温度 (字节18-21)
if (size >= 22) {
std::memcpy(&temperature, &data[18], sizeof(float));
} else {
temperature = 0.0f;
}
// 其他状态标志 (字节22)
uint8_t flags = 0;
if (size >= 23) {
flags = data[22];
}
// 更新电机状态
motors_[motor_id].status.position = position;
motors_[motor_id].status.velocity = velocity;
motors_[motor_id].status.current = current;
motors_[motor_id].status.voltage = voltage;
motors_[motor_id].status.temperature = temperature;
// 解析状态标志
motors_[motor_id].status.is_moving = (flags & 0x01) != 0;
motors_[motor_id].status.is_calibrated = (flags & 0x02) != 0;
motors_[motor_id].status.error_state = (flags & 0x04) != 0;
// 错误代码 (字节23-24)
if (size >= 25 && motors_[motor_id].status.error_state) {
motors_[motor_id].status.error_code = (data[23] << 8) | data[24];
} else {
motors_[motor_id].status.error_code = 0;
}
}
}
// 更新电机控制
void update_motor_control(int motor_id) {
// 根据控制模式执行控制逻辑
switch (motors_[motor_id].status.mode) {
case ControlMode::POSITION:
update_position_control(motor_id);
break;
case ControlMode::VELOCITY:
update_velocity_control(motor_id);
break;
case ControlMode::TORQUE:
update_torque_control(motor_id);
break;
case ControlMode::OPEN_LOOP:
// 开环控制由set_duty_cycle直接处理
break;
}
}
// 位置控制逻辑
void update_position_control(int motor_id) {
// 获取当前位置和目标位置
double current_position = motors_[motor_id].status.position;
double target_position = motors_[motor_id].target_position;
// 计算位置误差
double position_error = target_position - current_position;
// 检查是否在位置容差范围内
const double position_tolerance = 0.01; // 位置容差
if (std::abs(position_error) < position_tolerance) {
// 已到达目标位置
motors_[motor_id].status.is_moving = false;
return;
}
// 计算位置控制器输出(目标速度)
double target_velocity = position_controllers_[motor_id].update(
target_position, current_position);
// 限制速度
target_velocity = std::min(std::max(target_velocity, -motors_[motor_id].velocity_limit),
motors_[motor_id].velocity_limit);
// 更新目标速度
motors_[motor_id].target_velocity = target_velocity;
// 继续执行速度控制
update_velocity_control(motor_id);
}
// 速度控制逻辑
void update_velocity_control(int motor_id) {
// 获取当前速度和目标速度
double current_velocity = motors_[motor_id].status.velocity;
double target_velocity = motors_[motor_id].target_velocity;
// 计算速度误差
double velocity_error = target_velocity - current_velocity;
// 检查是否在速度容差范围内
const double velocity_tolerance = 0.1; // 速度容差
if (std::abs(velocity_error) < velocity_tolerance &&
motors_[motor_id].status.mode == ControlMode::VELOCITY) {
// 已达到目标速度
motors_[motor_id].status.is_moving = (std::abs(target_velocity) > velocity_tolerance);
} else {
// 未达到目标速度
motors_[motor_id].status.is_moving = true;
}
// 计算速度控制器输出(目标力矩)
double target_torque = velocity_controllers_[motor_id].update(
target_velocity, current_velocity);
// 限制力矩
target_torque = std::min(std::max(target_torque, -motors_[motor_id].config.max_torque),
motors_[motor_id].config.max_torque);
// 更新目标力矩
motors_[motor_id].target_torque = target_torque;
// 继续执行力矩控制
update_torque_control(motor_id);
}
// 力矩控制逻辑
void update_torque_control(int motor_id) {
// 获取当前力矩和目标力矩
double current_torque = motors_[motor_id].status.current * 0.1; // 假设电流与力矩成正比
double target_torque = motors_[motor_id].target_torque;
// 计算力矩控制器输出(目标占空比)
double target_duty_cycle = torque_controllers_[motor_id].update(
target_torque, current_torque);
// 限制占空比
target_duty_cycle = std::min(std::max(target_duty_cycle, -1.0), 1.0);
// 更新目标占空比
motors_[motor_id].target_duty_cycle = target_duty_cycle;
// 发送占空比命令到硬件
uint8_t command_buffer[8] = {0};
command_buffer[0] = 0x40; // 开环控制命令
command_buffer[1] = (uint8_t)motor_id; // 电机ID
// 编码占空比值(4字节浮点数)
float duty_float = static_cast<float>(target_duty_cycle);
std::memcpy(&command_buffer[2], &duty_float, sizeof(float));
send_command(command_buffer, sizeof(command_buffer));
}
// 打开UART接口
bool open_uart_interface() {
// 打开串口设备
fd_ = open(interface_name_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd_ < 0) {
last_error_ = "无法打开串口设备: " + interface_name_ + " - " + strerror(errno);
return false;
}
// 配置串口参数
struct termios tty;
memset(&tty, 0, sizeof(tty));
// 获取当前配置
if (tcgetattr(fd_, &tty) != 0) {
last_error_ = "获取串口参数失败: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
// 设置波特率
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
// 设置控制模式
tty.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器控制线
tty.c_cflag &= ~CSIZE; // 清除位大小标志
tty.c_cflag |= CS8; // 8位数据位
tty.c_cflag &= ~PARENB; // 无奇偶校验
tty.c_cflag &= ~CSTOPB; // 1个停止位
tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控制
// 设置输入模式
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
// 设置输出模式
tty.c_oflag &= ~OPOST;
// 设置本地模式
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
// 设置超时
tty.c_cc[VMIN] = 0; // 非阻塞读
tty.c_cc[VTIME] = 1; // 100ms超时
// 应用设置
if (tcsetattr(fd_, TCSANOW, &tty) != 0) {
last_error_ = "设置串口参数失败: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
// 清空缓冲区
tcflush(fd_, TCIOFLUSH);
return true;
}
// 打开CAN接口
bool open_can_interface() {
// 创建套接字
fd_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (fd_ < 0) {
last_error_ = "无法创建CAN套接字: " + std::string(strerror(errno));
return false;
}
// 指定CAN接口
struct ifreq ifr;
strcpy(ifr.ifr_name, interface_name_.c_str());
if (ioctl(fd_, SIOCGIFINDEX, &ifr) < 0) {
last_error_ = "无法获取CAN接口索引: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
// 绑定套接字
struct sockaddr_can addr;
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(fd_, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
last_error_ = "无法绑定CAN套接字: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
// 设置非阻塞模式
int flags = fcntl(fd_, F_GETFL, 0);
if (flags < 0) {
last_error_ = "无法获取套接字标志: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
if (fcntl(fd_, F_SETFL, flags | O_NONBLOCK) < 0) {
last_error_ = "无法设置非阻塞模式: " + std::string(strerror(errno));
close(fd_);
fd_ = -1;
return false;
}
return true;
}
// 打开SPI接口
bool open_spi_interface() {
// SPI接口需要用户自行实现,这里仅占位
last_error_ = "SPI接口尚未实现";
return false;
}
// 发送命令
bool send_command(const uint8_t* data, size_t size) {
if (fd_ < 0) {
last_error_ = "设备未打开";
return false;
}
if (interface_type_ == "uart" || interface_type_ == "serial") {
// 发送UART数据
ssize_t bytes_written = write(fd_, data, size);
if (bytes_written < static_cast<ssize_t>(size)) {
last_error_ = "UART发送失败: " + std::string(strerror(errno));
return false;
}
// 刷新输出缓冲区
tcdrain(fd_);
} else if (interface_type_ == "can") {
// 检查数据大小(CAN帧有限制)
if (size > 8) {
last_error_ = "CAN数据过大";
return false;
}
// 准备CAN帧
struct can_frame frame;
memset(&frame, 0, sizeof(frame));
// 设置ID(假设使用标准ID)
frame.can_id = 0x100; // 基本ID
// 设置数据长度
frame.can_dlc = size;
// 复制数据
memcpy(frame.data, data, size);
// 发送CAN帧
ssize_t bytes_written = write(fd_, &frame, sizeof(frame));
if (bytes_written < static_cast<ssize_t>(sizeof(frame))) {
last_error_ = "CAN发送失败: " + std::string(strerror(errno));
return false;
}
} else if (interface_type_ == "spi") {
// SPI发送需要用户自行实现
last_error_ = "SPI接口尚未实现";
return false;
}
return true;
}
// 接收数据
int receive_data(uint8_t* buffer, size_t max_size) {
if (fd_ < 0) {
last_error_ = "设备未打开";
return -1;
}
if (interface_type_ == "uart" || interface_type_ == "serial") {
// 从UART接收数据
ssize_t bytes_read = read(fd_, buffer, max_size);
if (bytes_read < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 无数据可读
return 0;
}
last_error_ = "UART接收失败: " + std::string(strerror(errno));
return -1;
}
return bytes_read;
} else if (interface_type_ == "can") {
// 接收CAN帧
struct can_frame frame;
memset(&frame, 0, sizeof(frame));
ssize_t bytes_read = read(fd_, &frame, sizeof(frame));
if (bytes_read < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 无数据可读
return 0;
}
last_error_ = "CAN接收失败: " + std::string(strerror(errno));
return -1;
}
if (bytes_read != sizeof(frame)) {
last_error_ = "接收到不完整的CAN帧";
return -1;
}
// 检查数据大小
if (frame.can_dlc > max_size) {
last_error_ = "接收缓冲区太小";
return -1;
}
// 复制数据
memcpy(buffer, frame.data, frame.can_dlc);
return frame.can_dlc;
} else if (interface_type_ == "spi") {
// SPI接收需要用户自行实现
last_error_ = "SPI接口尚未实现";
return -1;
}
return 0;
}
private:
std::string interface_name_; // 接口名称
std::string interface_type_; // 接口类型
bool initialized_; // 初始化标志
bool running_; // 运行标志
int motor_count_; // 电机数量
int fd_; // 文件描述符
std::string last_error_; // 最后一个错误消息
Motor motors_[MAX_MOTORS]; // 电机数组
PIDController position_controllers_[MAX_MOTORS]; // 位置PID控制器
PIDController velocity_controllers_[MAX_MOTORS]; // 速度PID控制器
PIDController torque_controllers_[MAX_MOTORS]; // 力矩PID控制器
std::thread control_thread_; // 控制线程
std::mutex mutex_; // 互斥锁
};
// MotorController 类方法的实现,委托给 MotorControllerImpl
MotorController::MotorController(const std::string& interface_name,
const std::string& interface_type)
: impl_(new MotorControllerImpl(interface_name, interface_type)) {
}
MotorController::~MotorController() = default;
bool MotorController::initialize() {
return impl_->initialize();
}
int MotorController::add_motor(const MotorConfig& config) {
return impl_->add_motor(config);
}
bool MotorController::configure_motor(int motor_id, const MotorConfig& config) {
return impl_->configure_motor(motor_id, config);
}
bool MotorController::set_pid_params(int motor_id, ControlMode mode, const PIDParams& params) {
return impl_->set_pid_params(motor_id, mode, params);
}
bool MotorController::set_motor_mode(int motor_id, ControlMode mode) {
return impl_->set_motor_mode(motor_id, mode);
}
bool MotorController::enable_motor(int motor_id, bool enable) {
return impl_->enable_motor(motor_id, enable);
}
bool MotorController::set_position(int motor_id, double position,
double velocity_limit,
double acceleration_limit) {
return impl_->set_position(motor_id, position, velocity_limit, acceleration_limit);
}
bool MotorController::set_velocity(int motor_id, double velocity,
double acceleration_limit) {
return impl_->set_velocity(motor_id, velocity, acceleration_limit);
}
bool MotorController::set_torque(int motor_id, double torque) {
return impl_->set_torque(motor_id, torque);
}
bool MotorController::set_duty_cycle(int motor_id, double duty_cycle) {
return impl_->set_duty_cycle(motor_id, duty_cycle);
}
MotorStatus MotorController::get_motor_status(int motor_id) {
return impl_->get_motor_status(motor_id);
}
bool MotorController::calibrate_motor(int motor_id) {
return impl_->calibrate_motor(motor_id);
}
bool MotorController::stop_motor(int motor_id, bool emergency) {
return impl_->stop_motor(motor_id, emergency);
}
bool MotorController::stop_all_motors(bool emergency) {
return impl_->stop_all_motors(emergency);
}
std::string MotorController::get_last_error() const {
return impl_->get_last_error();
}
int MotorController::get_motor_count() const {
return impl_->get_motor_count();
}
} // namespace motor_control
5. 结语
以上代码示例展示了通过 C/C++ 与硬件协同设计的多种实现方式,涵盖了从底层驱动到应用层的各个方面。这些实例可以作为硬件协同设计的参考,开发者可以根据自己的具体需求进行修改和扩展。
关键实践要点:
- 硬件抽象层:通过标准接口封装底层硬件,提供统一的编程模型
- 内存映射I/O:直接操作硬件寄存器进行高效控制
- 多线程处理:使用线程分离数据采集、处理和控制逻辑
- 错误处理:完善的错误检查和报告机制
- 跨平台考虑:尽可能使用标准库和跨平台API
这些示例演示了软件如何与硬件紧密协作,共同实现系统功能。实际应用中,可能需要根据具体硬件规格进行适当调整。