极客巢V5A收音机(咕咕机)

极客巢V5A收音机是一款多功能、DIY友好的嵌入式收音机产品,它具备以下核心特性:

  • 全波段接收: 支持调频 (FM)、调幅 (AM)、短波 (SW)、单边带 (SSB)、航空波段等多种无线电波段。
  • 网络收音机 (固件升级): 通过刷固件的方式,可以扩展支持网络收音机功能,接收互联网上的音频流。
  • 用户友好界面: 配备显示屏和按键/旋钮,提供直观的操作界面。
  • 可扩展性: 预留硬件接口和软件架构,方便用户进行功能扩展和定制。
  • 商业化产品: 已经商业化,意味着需要考虑产品的稳定性、可靠性和用户体验。

系统架构设计

针对极客巢V5A收音机的需求,我将采用分层架构的设计模式,这种架构模式能够有效地组织代码,提高代码的可维护性、可扩展性和可重用性。系统架构主要分为以下几个层次:

  1. 硬件抽象层 (HAL - Hardware Abstraction Layer)
  2. 板级支持包 (BSP - Board Support Package)
  3. 操作系统层 (OS - Operating System)
  4. 中间件层 (Middleware)
  5. 应用层 (Application)

1. 硬件抽象层 (HAL)

HAL层是系统架构的最底层,直接与硬件交互。它向上层提供统一的、抽象的硬件接口,屏蔽底层硬件的差异性。HAL层的主要职责包括:

  • 初始化硬件外设: 例如,GPIO、SPI、I2C、UART、ADC、DAC、LCD控制器、音频编解码器、射频芯片等。
  • 提供硬件操作接口: 例如,GPIO的读写操作、SPI/I2C的通信操作、ADC/DAC的采样和输出、LCD的显示控制、音频编解码器的音频数据传输、射频芯片的频率设置和模式切换等。
  • 中断管理: 处理硬件中断,并将中断事件传递给上层。

HAL层代码示例 (hal_layer.h 和 hal_layer.c)

hal_layer.h

#ifndef HAL_LAYER_H
#define HAL_LAYER_H

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

// GPIO 定义
typedef enum {
   
    GPIO_PIN_0,
    GPIO_PIN_1,
    GPIO_PIN_2,
    // ... 更多GPIO引脚定义
    GPIO_PIN_MAX
} GPIO_PinTypeDef;

typedef enum {
   
    GPIO_MODE_INPUT,
    GPIO_MODE_OUTPUT
} GPIO_ModeTypeDef;

typedef enum {
   
    GPIO_STATE_RESET,
    GPIO_STATE_SET
} GPIO_StateTypeDef;

// SPI 定义
typedef enum {
   
    SPI_INSTANCE_1,
    SPI_INSTANCE_2,
    SPI_INSTANCE_MAX
} SPI_InstanceTypeDef;

typedef enum {
   
    SPI_MODE_MASTER,
    SPI_MODE_SLAVE
} SPI_ModeTypeDef;

typedef struct {
   
    SPI_InstanceTypeDef Instance;
    SPI_ModeTypeDef Mode;
    uint32_t BaudRate;
    // ... 其他SPI配置参数
} SPI_InitTypeDef;

// 函数声明

// GPIO 函数
void HAL_GPIO_Init(GPIO_PinTypeDef Pin, GPIO_ModeTypeDef Mode);
void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, GPIO_StateTypeDef State);
GPIO_StateTypeDef HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin);

// SPI 函数
bool HAL_SPI_Init(SPI_InitTypeDef *SPI_InitStruct);
bool HAL_SPI_Transmit(SPI_InstanceTypeDef Instance, uint8_t *pData, uint16_t Size);
bool HAL_SPI_Receive(SPI_InstanceTypeDef Instance, uint8_t *pData, uint16_t Size);

// I2C 函数 (示例,根据实际硬件添加)
// ...

// UART 函数 (示例,根据实际硬件添加)
// ...

// ADC 函数 (示例,根据实际硬件添加)
// ...

// DAC 函数 (示例,根据实际硬件添加)
// ...

// LCD 控制器函数 (示例,根据实际硬件添加)
// ...

// 音频编解码器函数 (示例,根据实际硬件添加)
// ...

// 射频芯片函数 (示例,根据实际硬件添加)
// ...

#endif // HAL_LAYER_H

hal_layer.c

#include "hal_layer.h"

// 硬件相关的头文件,例如 STM32 的头文件
// #include "stm32xxx.h" // 假设使用 STM32 平台

// GPIO 函数实现
void HAL_GPIO_Init(GPIO_PinTypeDef Pin, GPIO_ModeTypeDef Mode) {
   
    //  根据 Pin 和 Mode 配置 GPIO 寄存器
    //  例如,配置 GPIO 的方向、上下拉电阻、速度等
    //  具体实现需要参考硬件平台的 GPIO 寄存器定义和操作方法
    //  这里仅为示例,实际代码会更复杂
    if (Mode == GPIO_MODE_OUTPUT) {
   
        // 设置为输出模式
        // ... 硬件寄存器操作
    } else if (Mode == GPIO_MODE_INPUT) {
   
        // 设置为输入模式
        // ... 硬件寄存器操作
    }
}

void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, GPIO_StateTypeDef State) {
   
    //  根据 Pin 和 State 控制 GPIO 输出高低电平
    //  例如,控制 LED 灯的亮灭
    if (State == GPIO_STATE_SET) {
   
        // 设置为高电平
        // ... 硬件寄存器操作
    } else {
   
        // 设置为低电平
        // ... 硬件寄存器操作
    }
}

GPIO_StateTypeDef HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin) {
   
    //  读取 GPIO 引脚的电平状态
    //  返回 GPIO_STATE_SET (高电平) 或 GPIO_STATE_RESET (低电平)
    // ... 硬件寄存器操作
    //  假设读取到的电平状态为 level
    GPIO_StateTypeDef level = GPIO_STATE_RESET; // 示例,实际读取硬件状态
    if (/* level is high */ 1) {
    // 示例条件,根据实际硬件判断高电平条件
        level = GPIO_STATE_SET;
    }
    return level;
}

// SPI 函数实现
bool HAL_SPI_Init(SPI_InitTypeDef *SPI_InitStruct) {
   
    //  根据 SPI_InitStruct 配置 SPI 寄存器
    //  例如,配置 SPI 的时钟频率、模式、数据位宽、极性、相位等
    //  具体实现需要参考硬件平台的 SPI 寄存器定义和操作方法
    //  这里仅为示例
    if (SPI_InitStruct->Instance == SPI_INSTANCE_1) {
   
        // 初始化 SPI1
        // ... 硬件寄存器操作配置 SPI1
        return true; // 初始化成功
    } else if (SPI_InitStruct->Instance == SPI_INSTANCE_2) {
   
        // 初始化 SPI2
        // ... 硬件寄存器操作配置 SPI2
        return true; // 初始化成功
    } else {
   
        return false; // 不支持的 SPI 实例
    }
}

bool HAL_SPI_Transmit(SPI_InstanceTypeDef Instance, uint8_t *pData, uint16_t Size) {
   
    //  通过指定的 SPI 实例发送数据
    //  将 pData 指向的数据发送 Size 个字节
    //  需要处理 SPI 的发送 FIFO、状态寄存器等
    //  这里仅为示例
    if (Instance == SPI_INSTANCE_1) {
   
        // 使用 SPI1 发送数据
        for (uint16_t i = 0; i < Size; i++) {
   
            // 等待发送缓冲区空
            // ... 硬件寄存器操作,等待 TXE 标志位
            // 发送数据
            // ... 硬件寄存器操作,写入数据到数据寄存器
        }
        return true; // 发送成功
    } else if (Instance == SPI_INSTANCE_2) {
   
        // 使用 SPI2 发送数据
        // ... SPI2 发送实现
        return true; // 发送成功
    } else {
   
        return false; // 不支持的 SPI 实例
    }
}

bool HAL_SPI_Receive(SPI_InstanceTypeDef Instance, uint8_t *pData, uint16_t Size) {
   
    //  通过指定的 SPI 实例接收数据
    //  接收 Size 个字节的数据,存储到 pData 指向的缓冲区
    //  需要处理 SPI 的接收 FIFO、状态寄存器等
    //  这里仅为示例
    if (Instance == SPI_INSTANCE_1) {
   
        // 使用 SPI1 接收数据
        for (uint16_t i = 0; i < Size; i++) {
   
            // 等待接收缓冲区非空
            // ... 硬件寄存器操作,等待 RXNE 标志位
            // 接收数据
            // ... 硬件寄存器操作,从数据寄存器读取数据
            pData[i] = /* 读取到的数据 */;
        }
        return true; // 接收成功
    } else if (Instance == SPI_INSTANCE_2) {
   
        // 使用 SPI2 接收数据
        // ... SPI2 接收实现
        return true; // 接收成功
    } else {
   
        return false; // 不支持的 SPI 实例
    }
}

// ... 其他 HAL 函数的实现 (I2C, UART, ADC, DAC, LCD, 音频编解码器, 射频芯片)
// ...  这些函数的实现方式类似,都需要直接操作硬件寄存器
// ...  具体实现需要参考硬件平台的手册和寄存器定义

2. 板级支持包 (BSP)

BSP层构建在HAL层之上,它针对具体的硬件平台进行定制,提供更高级别的、与硬件平台相关的驱动和服务。BSP层的主要职责包括:

  • 系统时钟初始化: 配置系统时钟,为各个模块提供时钟源。
  • 外设驱动初始化: 初始化板载外设,例如,LCD屏幕、按键、旋钮、音频接口、射频模块等。 这层会调用 HAL 层的函数来初始化和配置硬件。
  • 提供板级功能接口: 例如,LCD屏幕的初始化和显示、按键的扫描和事件处理、旋钮的编码值读取、音频接口的输入输出控制、射频模块的初始化和控制等。

BSP层代码示例 (bsp_layer.h 和 bsp_layer.c)

bsp_layer.h

#ifndef BSP_LAYER_H
#define BSP_LAYER_H

#include "hal_layer.h"

// LCD 驱动定义
typedef struct {
   
    uint16_t Width;
    uint16_t Height;
    // ... 其他 LCD 相关参数
} LCD_InitTypeDef;

// 按键定义
typedef enum {
   
    BUTTON_KEY1,
    BUTTON_KEY2,
    BUTTON_KEY3,
    // ... 更多按键定义
    BUTTON_KEY_MAX
} Button_TypeDef;

// 旋钮定义 (假设是编码器)
typedef enum {
   
    ENCODER_1,
    ENCODER_2,
    ENCODER_MAX
} Encoder_TypeDef;

// 音频接口定义 (简化示例)
typedef enum {
   
    AUDIO_OUTPUT_SPEAKER,
    AUDIO_OUTPUT_HEADPHONE
} AudioOutput_TypeDef;

// 射频模块定义 (简化示例)
typedef enum {
   
    RF_MODULE_SI4735, // 假设使用 SI4735 芯片
    // ... 其他射频模块类型
    RF_MODULE_MAX
} RFModule_TypeDef;


// 函数声明

// 系统时钟初始化
void BSP_SystemClock_Init(void);

// LCD 驱动函数
bool BSP_LCD_Init(LCD_InitTypeDef *LCD_InitStruct);
void BSP_LCD_DisplayString(uint16_t x, uint16_t y, const char *str);
void BSP_LCD_ClearScreen(uint16_t color);
void BSP_LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color);

// 按键驱动函数
void BSP_Button_Init(Button_TypeDef Button);
bool BSP_Button_IsPressed(Button_TypeDef Button);

// 旋钮驱动函数
void BSP_Encoder_Init(Encoder_TypeDef Encoder);
int32_t BSP_Encoder_GetValue(Encoder_TypeDef Encoder);

// 音频接口函数
bool BSP_Audio_OutputSelect(AudioOutput_TypeDef Output);
bool BSP_Audio_SetVolume(uint8_t volume); // 0-100%

// 射频模块函数
bool BSP_RFModule_Init(RFModule_TypeDef Module);
bool BSP_RFModule_SetFrequency(RFModule_TypeDef Module, float frequency_MHz);
bool BSP_RFModule_SetMode(RFModule_TypeDef Module, const char *mode_str); // 例如 "FM", "AM", "SSB"
float BSP_RFModule_GetSignalStrength(RFModule_TypeDef Module);

#endif // BSP_LAYER_H

bsp_layer.c

#include "bsp_layer.h"

//  宏定义,根据实际硬件平台定义
#define LCD_SPI_INSTANCE        SPI_INSTANCE_1
#define LCD_CS_PIN              GPIO_PIN_0 // 假设 LCD CS 引脚
#define LCD_RS_PIN              GPIO_PIN_1 // 假设 LCD RS 引脚
#define LCD_RESET_PIN           GPIO_PIN_2 // 假设 LCD RESET 引脚

#define BUTTON1_PIN             GPIO_PIN_3 // 假设 Button 1 引脚
#define BUTTON2_PIN             GPIO_PIN_4 // 假设 Button 2 引脚
#define BUTTON3_PIN             GPIO_PIN_5 // 假设 Button 3 引脚

#define ENCODER1_PIN_A          GPIO_PIN_6 // 假设 Encoder 1 A 相引脚
#define ENCODER1_PIN_B          GPIO_PIN_7 // 假设 Encoder 1 B 相引脚

#define AUDIO_OUTPUT_CTRL_PIN   GPIO_PIN_8 // 假设音频输出切换控制引脚

#define RF_MODULE_SPI_INSTANCE  SPI_INSTANCE_2
#define RF_MODULE_CS_PIN        GPIO_PIN_9 // 假设 RF 模块 CS 引脚
#define RF_MODULE_RESET_PIN     GPIO_PIN_10 // 假设 RF 模块 RESET 引脚


// 系统时钟初始化
void BSP_SystemClock_Init(void) {
   
    //  配置系统时钟,例如使用外部晶振、内部RC振荡器等
    //  并配置 PLL 倍频,设置 CPU 主频、外设时钟频率
    // ...  具体实现根据硬件平台和时钟树配置
    //  示例代码,假设使用外部晶振 8MHz,倍频到 72MHz
    // ...  配置 RCC 寄存器
}

// LCD 驱动函数
bool BSP_LCD_Init(LCD_InitTypeDef *LCD_InitStruct) {
   
    //  LCD 初始化
    //  1. 初始化 LCD 控制器 SPI 接口
    SPI_InitTypeDef spi_init;
    spi_init.Instance = LCD_SPI_INSTANCE;
    spi_init.Mode = SPI_MODE_MASTER;
    spi_init.BaudRate = /*  根据 LCD 规格设置 SPI 频率  */ 10000000; // 10MHz
    // ... 其他 SPI 配置
    if (!HAL_SPI_Init(&spi_init)) {
   
        return false; // SPI 初始化失败
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式程序员小刘

很高兴文章有帮助到你

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

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

打赏作者

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

抵扣说明:

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

余额充值