我将为您详细阐述 MMDVM_HS_Dual_Hat 双工板嵌入式系统的代码设计架构,并提供相应的 C 代码示例。我们将从需求分析出发,逐步深入到系统实现、测试验证和维护升级,力求构建一个可靠、高效、可扩展的嵌入式平台。
关注微信公众号,提前获取相关推文

项目背景与需求分析
项目背景:
MMDVM (Multi-Mode Digital Voice Modem) 是一个开源项目,旨在提供一个多模式数字语音调制解调器,用于业余无线电通信。MMDVM_HS_Dual_Hat 双工板是在此基础上开发的一款硬件产品,它具备以下关键特性:
- 双工通信: 支持同时发射和接收,实现全双工或半双工模式的通信。
- 多模式支持: 能够处理多种数字语音模式,如 D-STAR, DMR, Fusion (C4FM), P25 等。
- 高性能: 采用高速处理器和优化的硬件设计,确保实时、低延迟的通信性能。
- 可扩展性: 硬件和软件设计应具备良好的扩展性,方便添加新的功能和模式。
- 易用性: 提供友好的配置和管理界面,方便用户使用和维护。
需求分析:
基于项目背景和 MMDVM_HS_Dual_Hat 双工板的特性,我们可以提炼出以下核心需求:
- 实时通信: 系统必须能够实时处理音频数据,进行调制解调,保证语音通信的流畅性。
- 多模式支持: 需要支持多种数字语音模式,并能够方便地扩展新的模式。
- 双工操作: 实现同时发射和接收功能,支持双工通信模式。
- 硬件抽象: 代码需要与底层硬件解耦,方便移植和维护。
- 资源管理: 有效管理系统资源,包括 CPU、内存、外设等,确保系统稳定运行。
- 可配置性: 提供灵活的配置选项,允许用户自定义系统参数,如通信模式、频率、信道等。
- 错误处理: 具备完善的错误处理机制,能够检测并处理各种异常情况,保证系统可靠性。
- 可维护性和可升级性: 代码结构清晰,模块化设计,方便维护和升级。
代码设计架构
为了满足以上需求,并构建一个可靠、高效、可扩展的系统平台,我建议采用分层架构和模块化设计相结合的代码架构。这种架构将系统划分为不同的层次和模块,每个层次和模块负责特定的功能,层与层之间通过清晰的接口进行通信,模块之间保持低耦合高内聚。
分层架构:
我将系统架构分为以下几个层次,从底层硬件到上层应用,逐层抽象和封装:
硬件抽象层 (HAL - Hardware Abstraction Layer):
- 功能: 封装底层硬件操作,提供统一的硬件访问接口,隐藏硬件差异。
- 模块:
- GPIO 驱动: 控制 GPIO 引脚的输入输出,用于控制外围设备,如 LED、按键、射频芯片控制等。
- SPI 驱动: 实现 SPI 通信协议,用于与射频芯片、Codec 芯片等进行数据交换。
- I2C 驱动: 实现 I2C 通信协议,用于与传感器、EEPROM 等进行数据交换。
- UART 驱动: 实现 UART 通信协议,用于调试输出、串口控制等。
- ADC/DAC 驱动: 控制模数转换器 (ADC) 和数模转换器 (DAC),用于音频信号的采集和输出。
- 定时器驱动: 提供定时器功能,用于任务调度、时间管理等。
- 中断控制器驱动: 管理中断请求,处理硬件中断事件。
设备驱动层 (Device Driver Layer):
- 功能: 基于 HAL 层提供的接口,实现对具体硬件设备的驱动,提供设备的功能性接口。
- 模块:
- 射频收发器驱动: 控制射频收发芯片,实现信号的调制、解调、发射和接收。例如,常见的射频芯片如 ADF7021, STM32WB 系列集成射频等。
- 音频 Codec 驱动: 控制音频编解码芯片,实现音频信号的 AD/DA 转换、音频处理等。例如,常见的 Codec 芯片如 CS4270, TLV320AIC3104 等。
- 电源管理驱动: 控制电源管理芯片,实现电源的开关、电压调节、功耗管理等。
- LED 驱动: 控制 LED 灯的亮灭、闪烁等,用于状态指示。
- 按键驱动: 检测按键的按下和释放,用于用户输入。
MMDVM 协议层 (MMDVM Protocol Layer):
- 功能: 实现 MMDVM 协议栈,处理数字语音模式的编码、解码、调制、解调、同步、帧处理等核心功能。
- 模块:
- 模式识别模块: 识别不同的数字语音模式 (D-STAR, DMR, Fusion, P25 等)。
- 调制解调模块: 实现各种数字调制解调算法 (FSK, GMSK, 4FSK, etc.)。
- 编码解码模块: 实现语音编码和解码算法 (AMBE++, Codec2, etc.)。
- 同步模块: 实现位同步、帧同步、载波同步等,确保可靠的通信。
- 帧处理模块: 处理 MMDVM 协议帧的封装、解析、校验等。
- 协议状态机: 管理 MMDVM 通信协议的状态流程。
应用逻辑层 (Application Logic Layer):
- 功能: 实现系统的核心应用逻辑,包括通信控制、模式切换、参数配置、用户界面等。
- 模块:
- 通信控制模块: 负责管理通信流程,包括发射、接收、信道切换、功率控制等。
- 模式管理模块: 负责切换不同的数字语音模式,加载和配置相应的协议模块。
- 配置管理模块: 负责加载、保存和管理系统配置参数,例如频率、信道、模式、呼叫组等。
- 用户界面模块 (可选): 如果需要用户界面 (例如,通过串口、Web 界面等),则负责处理用户输入,显示系统状态。
- 状态监控模块: 监控系统运行状态,例如 CPU 负载、内存使用率、射频状态等。
操作系统层 (OS Layer - Real-Time Operating System, RTOS):
- 功能: 提供任务调度、资源管理、同步机制等,支持多任务并发执行,提高系统实时性和响应性。
- 选择: 可以选择轻量级的 RTOS,例如 FreeRTOS, RT-Thread, uC/OS 等。RTOS 不是必需的,对于简单的应用也可以采用裸机系统,但 RTOS 能显著提高系统的复杂度和可维护性,尤其是在处理实时通信和多任务并发的场景下。
模块化设计:
在每个层次内部,进一步采用模块化设计,将功能划分为独立的模块,模块之间通过接口进行交互。例如:
- MMDVM 协议层: 可以针对每种数字语音模式 (D-STAR, DMR, Fusion, P25) 设计独立的模块,每个模块实现该模式的调制解调、编码解码等功能。这样可以方便地添加新的模式,只需要开发新的模式模块即可。
- 设备驱动层: 可以针对不同的射频芯片、Codec 芯片设计独立的驱动模块,方便更换硬件平台。
数据流:
系统的数据流大致如下:
- 接收路径: 射频收发器接收射频信号 -> 射频收发器驱动 -> HAL SPI 接口 -> 微处理器 -> MMDVM 协议层 (解调、解码、帧处理) -> 应用逻辑层 (处理语音数据) -> 音频 Codec 驱动 -> HAL DAC 接口 -> 音频 Codec -> 音频输出 (扬声器/耳机)。
- 发射路径: 音频输入 (麦克风) -> 音频 Codec -> 音频 Codec 驱动 -> HAL ADC 接口 -> 微处理器 -> 应用逻辑层 (获取语音数据) -> MMDVM 协议层 (编码、调制、帧封装) -> 射频收发器驱动 -> HAL SPI 接口 -> 微处理器 -> 射频收发器 -> 射频信号发射。
C 代码实现框架
以下是一个基于上述架构的 C 代码实现框架示例,这只是一个框架,并非完整的、可直接编译运行的代码,目的是展示代码结构和关键接口。我将尽量详细展开,并包含一些关键模块的示例代码。
(1) 硬件抽象层 (HAL)
hal.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| #ifndef HAL_H #define HAL_H
#include <stdint.h> #include <stdbool.h>
typedef enum { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_MAX } GPIO_PinTypeDef;
typedef enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG } GPIO_ModeTypeDef;
typedef enum { GPIO_PULL_NONE, GPIO_PULLUP, GPIO_PULLDOWN } GPIO_PullTypeDef;
typedef enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH } GPIO_SpeedTypeDef;
typedef struct { GPIO_PinTypeDef Pin; GPIO_ModeTypeDef Mode; GPIO_PullTypeDef Pull; GPIO_SpeedTypeDef Speed; } GPIO_InitTypeDef;
typedef enum { SPI_MODE_MASTER, SPI_MODE_SLAVE } SPI_ModeTypeDef;
typedef enum { SPI_POLARITY_LOW, SPI_POLARITY_HIGH } SPI_PolarityTypeDef;
typedef enum { SPI_PHASE_1EDGE, SPI_PHASE_2EDGE } SPI_PhaseTypeDef;
typedef enum { SPI_DATASIZE_8BIT, SPI_DATASIZE_16BIT } SPI_DataSizeTypeDef;
typedef struct { SPI_ModeTypeDef Mode; SPI_PolarityTypeDef Polarity; SPI_PhaseTypeDef Phase; SPI_DataSizeTypeDef DataSize; uint32_t BaudRatePrescaler; } SPI_InitTypeDef;
void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct); void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, bool PinState); bool HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin);
void HAL_SPI_Init(SPI_InitTypeDef *SPI_InitStruct); void HAL_SPI_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout); void HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t Timeout); uint8_t HAL_SPI_TransmitReceive(uint8_t TxData, uint32_t Timeout);
void HAL_TIM_DelayMs(uint32_t Delay);
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn); void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
#endif
|
hal_stm32f4xx.c (示例,针对 STM32F4 系列)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include "hal.h" #include "stm32f4xx_hal.h"
void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct) { GPIO_InitTypeDefTypeDef hal_gpio_init; hal_gpio_init.Pin = GPIO_InitStruct->Pin; HAL_GPIO_Init(GPIOx, &hal_gpio_init); }
void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, bool PinState) { HAL_GPIO_WritePin(GPIOx, Pin, PinState ? GPIO_PIN_SET : GPIO_PIN_RESET); }
bool HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin) { return HAL_GPIO_ReadPin(GPIOx, Pin) == GPIO_PIN_SET; }
void HAL_SPI_Init(SPI_InitTypeDef *SPI_InitStruct) { SPI_InitTypeDefTypeDef hal_spi_init; hal_spi_init.Mode = SPI_InitStruct->Mode == SPI_MODE_MASTER ? SPI_MODE_MASTER : SPI_MODE_SLAVE; HAL_SPI_Init(SPIx, &hal_spi_init); }
void HAL_SPI_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout) { HAL_SPI_Transmit(SPIx, pData, Size, Timeout); }
void HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t Timeout) { HAL_SPI_Receive(SPIx, pData, Size, Timeout); }
uint8_t HAL_SPI_TransmitReceive(uint8_t TxData, uint32_t Timeout) { uint8_t RxData; HAL_SPI_TransmitReceive(SPIx, &TxData, &RxData, 1, Timeout); return RxData; }
void HAL_TIM_DelayMs(uint32_t Delay) { HAL_Delay(Delay); }
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn) { HAL_NVIC_EnableIRQ(IRQn); }
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn) { HAL_NVIC_DisableIRQ(IRQn); }
|
(2) 设备驱动层 (Device Driver)
rf_transceiver_driver.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #ifndef RF_TRANSCEIVER_DRIVER_H #define RF_TRANSCEIVER_DRIVER_H
#include <stdint.h> #include <stdbool.h>
typedef enum { RF_TRANSCEIVER_STATE_IDLE, RF_TRANSCEIVER_STATE_RX, RF_TRANSCEIVER_STATE_TX } RF_TransceiverStateTypeDef;
typedef struct { uint32_t frequency; uint8_t power_level; } RF_TransceiverConfigTypeDef;
typedef struct { RF_TransceiverStateTypeDef state; RF_TransceiverConfigTypeDef config; } RF_TransceiverHandleTypeDef;
bool RF_Transceiver_Init(RF_TransceiverHandleTypeDef *hTransceiver); bool RF_Transceiver_SetFrequency(RF_TransceiverHandleTypeDef *hTransceiver, uint32_t frequency); bool RF_Transceiver_SetPowerLevel(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t power_level); bool RF_Transceiver_SetMode(RF_TransceiverHandleTypeDef *hTransceiver, RF_TransceiverStateTypeDef mode); bool RF_Transceiver_TransmitData(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t *pData, uint16_t Size); bool RF_Transceiver_ReceiveData(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t *pData, uint16_t Size, uint32_t Timeout); RF_TransceiverStateTypeDef RF_Transceiver_GetState(RF_TransceiverHandleTypeDef *hTransceiver);
#endif
|
rf_transceiver_adf7021.c (示例,针对 ADF7021 射频芯片)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| #include "rf_transceiver_driver.h" #include "hal.h"
#define ADF7021_REG_CTRL1 0x01 #define ADF7021_REG_FREQ_MSB 0x02
static uint8_t ADF7021_ReadReg(uint8_t reg_addr); static void ADF7021_WriteReg(uint8_t reg_addr, uint8_t reg_value);
bool RF_Transceiver_Init(RF_TransceiverHandleTypeDef *hTransceiver) { SPI_InitTypeDef spi_init; spi_init.Mode = SPI_MODE_MASTER; spi_init.Polarity = SPI_POLARITY_LOW; spi_init.Phase = SPI_PHASE_1EDGE; spi_init.DataSize = SPI_DATASIZE_8BIT; spi_init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; HAL_SPI_Init(&spi_init);
ADF7021_WriteReg(ADF7021_REG_CTRL1, 0x12);
hTransceiver->state = RF_TRANSCEIVER_STATE_IDLE; return true; }
bool RF_Transceiver_SetFrequency(RF_TransceiverHandleTypeDef *hTransceiver, uint32_t frequency) { uint32_t freq_reg_value = ; ADF7021_WriteReg(ADF7021_REG_FREQ_MSB, (freq_reg_value >> 16) & 0xFF);
hTransceiver->config.frequency = frequency; return true; }
bool RF_Transceiver_SetPowerLevel(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t power_level) { ADF7021_WriteReg(, power_level); hTransceiver->config.power_level = power_level; return true; }
bool RF_Transceiver_SetMode(RF_TransceiverHandleTypeDef *hTransceiver, RF_TransceiverStateTypeDef mode) { if (mode == RF_TRANSCEIVER_STATE_RX) { ADF7021_WriteReg(, ); hTransceiver->state = RF_TRANSCEIVER_STATE_RX; } else if (mode == RF_TRANSCEIVER_STATE_TX) { ADF7021_WriteReg(, ); hTransceiver->state = RF_TRANSCEIVER_STATE_TX; } else if (mode == RF_TRANSCEIVER_STATE_IDLE) { ADF7021_WriteReg(, ); hTransceiver->state = RF_TRANSCEIVER_STATE_IDLE; } return true; }
bool RF_Transceiver_TransmitData(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t *pData, uint16_t Size) { for (uint16_t i = 0; i < Size; i++) { ADF7021_WriteReg(, pData[i]); } return true; }
bool RF_Transceiver_ReceiveData(RF_TransceiverHandleTypeDef *hTransceiver, uint8_t *pData, uint16_t Size, uint32_t Timeout) { for (uint16_t i = 0; i < Size; i++) { pData[i] = ADF7021_ReadReg(); } return true; }
RF_TransceiverStateTypeDef RF_Transceiver_GetState(RF_TransceiverHandleTypeDef *hTransceiver) { return hTransceiver->state; }
static uint8_t ADF7021_ReadReg(uint8_t reg_addr) { uint8_t tx_buf[2] = {reg_addr | 0x80, 0x00}; uint8_t rx_buf[2]; HAL_SPI_TransmitReceive(tx_buf, rx_buf, 2, HAL_MAX_DELAY); return rx_buf[1]; }
static void ADF7021_WriteReg(uint8_t reg_addr, uint8_t reg_value) { uint8_t tx_buf[2] = {reg_addr & 0x7F, reg_value}; HAL_SPI_Transmit(tx_buf, 2, HAL_MAX_DELAY); }
|
audio_codec_driver.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #ifndef AUDIO_CODEC_DRIVER_H #define AUDIO_CODEC_DRIVER_H
#include <stdint.h> #include <stdbool.h>
typedef enum { AUDIO_CODEC_SAMPLE_RATE_8K, AUDIO_CODEC_SAMPLE_RATE_16K, } AudioCodecSampleRateTypeDef;
typedef enum { AUDIO_CODEC_BIT_DEPTH_16BIT, AUDIO_CODEC_BIT_DEPTH_24BIT, } AudioCodecBitDepthTypeDef;
typedef struct { AudioCodecSampleRateTypeDef sample_rate; AudioCodecBitDepthTypeDef bit_depth; } AudioCodecConfigTypeDef;
typedef struct { AudioCodecConfigTypeDef config; } AudioCodecHandleTypeDef;
bool AudioCodec_Init(AudioCodecHandleTypeDef *hCodec); bool AudioCodec_SetConfig(AudioCodecHandleTypeDef *hCodec, AudioCodecConfigTypeDef *config); bool AudioCodec_StartRecord(AudioCodecHandleTypeDef *hCodec); bool AudioCodec_StopRecord(AudioCodecHandleTypeDef *hCodec); bool AudioCodec_StartPlayback(AudioCodecHandleTypeDef *hCodec); bool AudioCodec_StopPlayback(AudioCodecHandleTypeDef *hCodec); bool AudioCodec_ReadData(AudioCodecHandleTypeDef *hCodec, uint8_t *pData, uint16_t Size, uint32_t Timeout); bool AudioCodec_WriteData(AudioCodecHandleTypeDef *hCodec, uint8_t *pData, uint16_t Size, uint32_t Timeout);
#endif
|
audio_codec_cs4270.c (示例,针对 CS4270 音频 Codec 芯片)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #include "audio_codec_driver.h" #include "hal.h"
#define CS4270_REG_POWER_CTRL 0x02 #define CS4270_REG_DAC_CTRL 0x04
static uint8_t CS4270_ReadReg(uint8_t reg_addr); static void CS4270_WriteReg(uint8_t reg_addr, uint8_t reg_value);
bool AudioCodec_Init(AudioCodecHandleTypeDef *hCodec) {
CS4270_WriteReg(CS4270_REG_POWER_CTRL, 0x01); CS4270_WriteReg(CS4270_REG_DAC_CTRL, 0x03);
return true; }
bool AudioCodec_SetConfig(AudioCodecHandleTypeDef *hCodec, AudioCodecConfigTypeDef *config) { hCodec->config = *config; return true; }
bool AudioCodec_StartRecord(AudioCodecHandleTypeDef *hCodec) { return true; }
bool AudioCodec_StopRecord(AudioCodecHandleTypeDef *hCodec) { return true; }
bool AudioCodec_StartPlayback(AudioCodecHandleTypeDef *hCodec) { return true; }
bool AudioCodec_StopPlayback(AudioCodecHandleTypeDef *hCodec) { return true; }
bool AudioCodec_ReadData(AudioCodecHandleTypeDef *hCodec, uint8_t *pData, uint16_t Size, uint32_t Timeout) { return true; }
bool AudioCodec_WriteData(AudioCodecHandleTypeDef *hCodec, uint8_t *pData, uint16_t Size, uint32_t Timeout) { return true; }
static uint8_t CS4270_ReadReg(uint8_t reg_addr) { return 0; }
static void CS4270_WriteReg(uint8_t reg_addr, uint8_t reg_value) { }
|
(3) MMDVM 协议层 (MMDVM Protocol)
mmdvm_protocol.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #ifndef MMDVM_PROTOCOL_H #define MMDVM_PROTOCOL_H
#include <stdint.h> #include <stdbool.h>
typedef enum { MMDVM_MODE_DSTAR, MMDVM_MODE_DMR, MMDVM_MODE_FUSION, MMDVM_MODE_P25, MMDVM_MODE_MAX } MMDVM_ModeTypeDef;
typedef struct { MMDVM_ModeTypeDef mode; } MMDVM_ConfigTypeDef;
typedef struct { MMDVM_ConfigTypeDef config; } MMDVM_HandleTypeDef;
bool MMDVM_Init(MMDVM_HandleTypeDef *hMmdvm, MMDVM_ConfigTypeDef *config); bool MMDVM_SetMode(MMDVM_HandleTypeDef *hMmdvm, MMDVM_ModeTypeDef mode); bool MMDVM_ProcessRxData(MMDVM_HandleTypeDef *hMmdvm, uint8_t *pData, uint16_t Size); bool MMDVM_GetTxData(MMDVM_HandleTypeDef *hMmdvm, uint8_t *pData, uint16_t Size);
#endif
|
mmdvm_protocol_core.c (MMDVM 协议核心逻辑,模式无关部分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include "mmdvm_protocol.h" #include "modulation.h" #include "encoding.h"
bool MMDVM_Init(MMDVM_HandleTypeDef *hMmdvm, MMDVM_ConfigTypeDef *config) { hMmdvm->config = *config; return true; }
bool MMDVM_SetMode(MMDVM_HandleTypeDef *hMmdvm, MMDVM_ModeTypeDef mode) { hMmdvm->config.mode = mode; return true; }
bool MMDVM_ProcessRxData(MMDVM_HandleTypeDef *hMmdvm, uint8_t *pData, uint16_t Size) { uint8_t demodulated_data[Size]; Modulation_Demodulate(hMmdvm->config.mode, pData, Size, demodulated_data);
uint8_t decoded_audio_data[Size]; Encoding_Decode(hMmdvm->config.mode, demodulated_data, Size, decoded_audio_data);
return true; }
bool MMDVM_GetTxData(MMDVM_HandleTypeDef *hMmdvm, uint8_t *pData, uint16_t Size) {
uint8_t encoded_data[Size]; Encoding_Encode(hMmdvm->config.mode, pData, Size, encoded_data);
Modulation_Modulate(hMmdvm->config.mode, encoded_data, Size, pData);
return true; }
|
(4) 应用逻辑层 (Application Logic)
app_logic.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #ifndef APP_LOGIC_H #define APP_LOGIC_H
#include <stdint.h> #include <stdbool.h> #include "mmdvm_protocol.h" #include "audio_codec_driver.h" #include "rf_transceiver_driver.h"
bool AppLogic_Init(void); void AppLogic_Run(void); void AppLogic_HandleRxAudioData(uint8_t *pData, uint16_t Size); void AppLogic_GetTxAudioData(uint8_t *pData, uint16_t Size);
#endif
|
app_logic.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include "app_logic.h" #include "mmdvm_protocol.h" #include "audio_codec_driver.h" #include "rf_transceiver_driver.h" #include "hal.h"
MMDVM_HandleTypeDef hMmdvm; AudioCodecHandleTypeDef hCodec; RF_TransceiverHandleTypeDef hTxTransceiver; RF_TransceiverHandleTypeDef hRxTransceiver;
bool AppLogic_Init(void) {
AudioCodec_Init(&hCodec); RF_Transceiver_Init(&hTxTransceiver); RF_Transceiver_Init(&hRxTransceiver);
MMDVM_ConfigTypeDef mmdvm_config; mmdvm_config.mode = MMDVM_MODE_DMR; MMDVM_Init(&hMmdvm, &mmdvm_config);
return true; }
void AppLogic_Run(void) { uint8_t rx_rf_buffer[128]; uint8_t tx_audio_buffer[128]; uint8_t rx_audio_buffer[128]; uint8_t tx_rf_buffer[128];
AudioCodec_StartRecord(&hCodec); AudioCodec_StartPlayback(&hCodec);
RF_Transceiver_SetMode(&hRxTransceiver, RF_TRANSCEIVER_STATE_RX);
while (1) { if (RF_Transceiver_ReceiveData(&hRxTransceiver, rx_rf_buffer, sizeof(rx_rf_buffer), 10)) { MMDVM_ProcessRxData(&hMmdvm, rx_rf_buffer, sizeof(rx_rf_buffer)); }
if (AudioCodec_ReadData(&hCodec, tx_audio_buffer, sizeof(tx_audio_buffer), 10)) { MMDVM_GetTxData(&hMmdvm, tx_rf_buffer, sizeof(tx_rf_buffer));
RF_Transceiver_SetMode(&hTxTransceiver, RF_TRANSCEIVER_STATE_TX); RF_Transceiver_TransmitData(&hTxTransceiver, tx_rf_buffer, sizeof(tx_rf_buffer)); RF_Transceiver_SetMode(&hTxTransceiver, RF_TRANSCEIVER_STATE_IDLE); }
HAL_TIM_DelayMs(1); } }
void AppLogic_HandleRxAudioData(uint8_t *pData, uint16_t Size) { AudioCodec_WriteData(&hCodec, pData, Size, HAL_MAX_DELAY); }
void AppLogic_GetTxAudioData(uint8_t *pData, uint16_t Size) { AudioCodec_ReadData(&hCodec, pData, Size, HAL_MAX_DELAY); }
|
(5) main.c (主程序)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include "app_logic.h"
int main(void) {
AppLogic_Init();
AppLogic_Run();
return 0; }
|
项目中采用的各种技术和方法
- 分层架构: 将系统划分为 HAL, 设备驱动层, MMDVM 协议层, 应用逻辑层, OS 层,提高代码的可维护性、可移植性和可扩展性。
- 模块化设计: 在每个层次内部,进一步划分为独立的模块,例如 MMDVM 协议层可以分为 D-STAR 模块、DMR 模块等,设备驱动层可以分为 ADF7021 驱动、CS4270 驱动等,提高代码的复用性和灵活性。
- 硬件抽象层 (HAL): 隔离硬件差异,方便代码移植到不同的硬件平台,降低硬件更换带来的软件修改成本。
- 设备驱动: 封装硬件设备的具体操作细节,向上层提供统一的功能性接口,简化上层应用开发。
- 实时操作系统 (RTOS - 可选): 使用 RTOS (例如 FreeRTOS) 可以更好地管理系统资源,实现多任务并发执行,提高系统的实时性和响应性,尤其适用于需要处理实时通信和多任务并发的嵌入式系统。
- 状态机: 在 MMDVM 协议层,可以使用状态机来管理复杂的协议流程,例如连接建立、数据传输、断开连接等状态的切换。
- 中断驱动: 充分利用硬件中断,提高系统的实时响应能力,例如射频收发器接收到数据、音频 Codec 数据就绪等事件可以通过中断通知 CPU 进行处理。
- 环形缓冲区 (Ring Buffer): 在音频数据处理、射频数据处理等场景中,可以使用环形缓冲区来提高数据处理效率,避免数据丢失。
- 异步通信: 在 HAL 层和设备驱动层,可以考虑使用异步通信方式 (例如,DMA - Direct Memory Access) 来提高数据传输效率,降低 CPU 负载。
- 错误处理机制: 在代码中加入完善的错误处理机制,例如参数校验、异常检测、错误日志记录、错误恢复等,提高系统的健壮性和可靠性。
- 代码注释和文档: 编写清晰的代码注释,并编写相应的系统设计文档、API 文档等,方便代码维护和团队协作。
- 版本控制 (Git): 使用 Git 进行代码版本控制,方便代码管理、协作开发、版本回溯等。
- 单元测试和集成测试: 进行充分的单元测试和集成测试,验证代码的正确性和稳定性。
- 代码审查: 进行代码审查,提高代码质量,发现潜在的 Bug 和设计缺陷。
总结
以上代码框架和技术方法是构建 MMDVM_HS_Dual_Hat 双工板嵌入式系统的一个良好起点。实际项目开发中,还需要根据具体的硬件平台、MMDVM 模式需求、性能要求等进行详细设计和优化。例如,针对不同的数字语音模式,需要实现相应的调制解调算法、编码解码算法、协议处理逻辑等。对于双工板,需要仔细设计双工通信的流程和资源管理,避免冲突和干扰。此外,还需要进行大量的实践验证和测试,才能最终构建一个可靠、高效、可扩展的 MMDVM 嵌入式系统平台。
希望这份详细的架构说明和代码框架能够帮助您理解 MMDVM_HS_Dual_Hat 双工板嵌入式系统的开发思路。如果您有任何疑问或需要更深入的探讨,请随时提出。