canooee 发表于 2026-1-15 15:44:25

FRDM-MCXN947 多场景语音控制功耗测量系统

# FRDM-MCXN947 多场景语音控制功耗测量系统

## 一、项目简介

感谢与非网和得捷举办的活动,本项目是基于 FRDM-MCXN947 的​**语音控制型多场景功耗测量系统**​,核心逻辑调整为:通过语音指令触发不同功能模块(物体识别、风扇转动、屏幕显示),并精准测量每个模块独立工作及组合工作时的功耗数据。所有外设(摄像头、3.5 英寸 LCD、风扇、语音模块)均直接连接 FRDM-MCXN947 开发板,系统可自动采集、显示、播报各语音指令对应的功耗表现,最终输出多维度的功耗对比数据。

### 核心调整亮点

1. ​**语音触发场景化**​:通过语音指令(如 “启动物体识别”“打开风扇”“屏幕显示数据”)精准触发单一 / 组合功能;
2. ​**功耗精准测量**​:针对 “物体识别(摄像头)”“风扇转动”“屏幕显示” 三大核心场景,分别测量独立功耗 + 组合功耗;
3. ​**数据可视化对比**​:LCD 屏分区域展示不同语音指令对应的功耗数值、对比曲线;
4. ​**全链路闭环**​:语音指令→功能触发→功耗采集→数据显示→语音播报→数据存储,形成完整闭环。

## 二、系统框图

!(https://www.eefocus.com/forum/data/attachment/forum/202601/15/154323u2b2daa2babcxbc3.png)



查看代码

```
graph TD
    A --> A1[主控单元-Cortex-M9]
    A --> A2[电源管理模块]
    A --> A3
   
    %% 核心外设(均直连开发板)
    B[语音模块SYN6288] --> B1
    B1 --> A3
    B --> B2[语音识别算法层]
    B --> B3[语音指令解析]
    B3 --> A1
   
    C[摄像头模块OV5640] --> C1
    C1 --> A3
    C --> C2[物体识别算法层]
    C2 --> A1
   
    D --> D1
    D1 --> A3
    D --> D2[功耗数据显示层]
   
    E[风扇模块] --> E1
    E1 --> A3
    E --> E2[转速调节层]
   
    %% 功耗采集模块(直连开发板电源回路)
    F[高精度功耗采集模块] --> F1[电流采样电阻(0.1Ω)]
    F1 --> A3(ADC0)
    F --> F2[电压采样电路]
    F2 --> A3(ADC1)
    F --> F3[功耗计算层]
    F3 --> A1
   
    %% 数据流向(核心调整)
    B[语音指令] --> A1[指令解析]
    A1 --> C[触发物体识别]
    A1 --> D[触发屏幕显示]
    A1 --> E[触发风扇转动]
    F[功耗采集] --> A1[数据计算]
    A1 --> D[功耗数据显示]
    A1 --> B[功耗语音播报]
    A1 --> G
   
    %% 供电链路(均由开发板供电)
    H --> A
    A --> B/C/D/E/F/G
```
## 三、核心代码实现

### 1. 核心调整说明

* 新增​**语音指令解析模块**​,支持 3 类核心指令识别;
* 新增​**场景化功耗测量逻辑**​,针对物体识别 / 风扇转动 / 屏幕显示单独测量;
* 优化​**功耗数据存储结构**​,区分单一功能 / 组合功能功耗;
* 保留所有外设直连开发板的驱动逻辑,确保硬件适配性。

### 2. 完整优化代码

c

运行

```
#include "fsl_common.h"
#include "fsl_gpio.h"
#include "fsl_adc.h"
#include "fsl_uart.h"
#include "fsl_pwm.h"
#include "lcd_ili9488.h"
#include "camera_ov5640.h"
#include "voice_syn6288.h"
#include "fatfs_sd.h"

// ====================== 核心配置(外设均直连开发板)======================
// ADC功耗采集(直连开发板电源回路)
#define ADC_CHANNEL_CURRENT 0U    // 电流采样ADC通道(直连开发板电流回路)
#define ADC_CHANNEL_VOLTAGE 1U    // 电压采样ADC通道(直连开发板电源端)
#define SAMPLE_RESISTOR 0.1f   // 高精度采样电阻(0.1Ω)
#define ADC_REF_VOLTAGE 3.3f      // ADC参考电压
#define ADC_RESOLUTION 4096.0f    // 12位ADC分辨率

// 语音指令定义(核心触发场景)
typedef enum {
    CMD_NONE = 0,
    CMD_OBJECT_RECOG = 1,// 语音指令:"启动物体识别"
    CMD_FAN_RUN = 2,       // 语音指令:"打开风扇"
    CMD_LCD_DISPLAY = 3,   // 语音指令:"显示功耗数据"
    CMD_COMBINED = 4       // 语音指令:"全部启动"(组合场景)
} VoiceCmd_t;

// 功耗场景定义(对应语音指令)
typedef enum {
    SCENE_IDLE = 0,            // 空闲场景(无功能运行)
    SCENE_OBJECT_RECOG = 1,    // 物体识别场景(仅摄像头工作)
    SCENE_FAN = 2,             // 风扇场景(仅风扇转动)
    SCENE_LCD = 3,             // 屏幕场景(仅LCD显示)
    SCENE_COMBINED = 4,      // 组合场景(所有功能运行)
    SCENE_MAX
} PowerScene_t;

// 功耗数据结构体(按场景存储)
typedef struct {
    PowerScene_t scene;
    char scene_name;       // 场景名称
    float voltage;             // 电压(V)
    float current;             // 电流(mA)
    float power;               // 功耗(mW)
    uint32_t duration;         // 运行时长(ms)
} PowerData_t;

// ====================== 全局变量 ======================
PowerData_t g_powerData;// 各场景功耗数据
VoiceCmd_t g_currentCmd = CMD_NONE;// 当前识别的语音指令
PowerScene_t g_currentScene = SCENE_IDLE;
uint8_t g_fan_pwm_duty = 50;         // 风扇PWM占空比(50%)

// ====================== 函数声明 ======================
void System_Init(void);
void Voice_Recog_Process(void);       // 语音指令识别处理
void Scene_Switch(PowerScene_t scene); // 场景切换(触发对应功能)
void Power_Measure_Scene(PowerScene_t scene); // 场景功耗测量
void LCD_Show_Power_Compare(void);   // LCD显示多场景功耗对比
void Voice_Report_Power_Scene(PowerScene_t scene); // 语音播报场景功耗
void Object_Recog_Run(void);         // 物体识别功能(仅摄像头)
void Fan_Control(uint8_t duty);      // 风扇控制(仅风扇)
void LCD_Display_Only(void);         // 仅LCD显示功能

// ====================== 主函数 ======================
int main(void)
{
    // 1. 系统初始化(所有外设直连开发板)
    System_Init();
   
    // 2. 初始化功耗数据结构体
    g_powerData = (PowerData_t){SCENE_IDLE, "空闲场景", 0, 0, 0, 0};
    g_powerData = (PowerData_t){SCENE_OBJECT_RECOG, "物体识别", 0, 0, 0, 0};
    g_powerData = (PowerData_t){SCENE_FAN, "风扇转动", 0, 0, 0, 0};
    g_powerData = (PowerData_t){SCENE_LCD, "屏幕显示", 0, 0, 0, 0};
    g_powerData = (PowerData_t){SCENE_COMBINED, "全部启动", 0, 0, 0, 0};
   
    // 3. 初始界面显示
    LCD_Clear(WHITE);
    LCD_ShowString(10, 10, "FRDM-MCXN947 功耗测量", BLACK, WHITE, 24);
    LCD_ShowString(10, 40, "语音指令:等待中...", BLACK, WHITE, 16);
    Voice_SendString("系统已就绪,请说出指令:启动物体识别、打开风扇、显示功耗数据、全部启动");

    // 4. 主循环(语音指令→场景切换→功耗测量→显示播报)
    while(1)
    {
      // 步骤1:语音指令识别
      Voice_Recog_Process();
      
      // 步骤2:根据指令切换场景
      if(g_currentCmd != CMD_NONE)
      {
            switch(g_currentCmd)
            {
                case CMD_OBJECT_RECOG:
                  g_currentScene = SCENE_OBJECT_RECOG;
                  break;
                case CMD_FAN_RUN:
                  g_currentScene = SCENE_FAN;
                  break;
                case CMD_LCD_DISPLAY:
                  g_currentScene = SCENE_LCD;
                  break;
                case CMD_COMBINED:
                  g_currentScene = SCENE_COMBINED;
                  break;
                default:
                  g_currentScene = SCENE_IDLE;
                  break;
            }
            
            // 步骤3:切换场景并测量功耗
            Scene_Switch(g_currentScene);
            Power_Measure_Scene(g_currentScene);
            
            // 步骤4:LCD显示多场景功耗对比
            LCD_Show_Power_Compare();
            
            // 步骤5:语音播报当前场景功耗
            Voice_Report_Power_Scene(g_currentScene);
            
            // 步骤6:数据存储到SD卡
            SD_Save_PowerData(&g_powerData);
            
            // 重置指令,等待下一次语音触发
            g_currentCmd = CMD_NONE;
      }
      
      // 延时防抖
      SDK_DelayAtLeastUs(1000, SDK_GetCoreSysClkFreq());
    }
}

// ====================== 核心函数实现 ======================
/**
* @brief 系统初始化(所有外设直连FRDM-MCXN947)
* - 语音模块:UART1(直连开发板UART引脚)
* - 摄像头:SPI2+I2C(直连开发板SPI/I2C引脚)
* - LCD屏:SPI3(直连开发板SPI引脚)
* - 风扇:PWM0+GPIO(直连开发板PWM/GPIO引脚)
* - ADC:直连开发板ADC0/ADC1引脚(功耗采集)
*/
void System_Init(void)
{
    // 1. 时钟初始化
    CLOCK_EnableClock(kCLOCK_Gpio0);
    CLOCK_EnableClock(kCLOCK_Gpio1);
    CLOCK_EnableClock(kCLOCK_Adc0);
    CLOCK_EnableClock(kCLOCK_Pwm0);
   
    // 2. ADC初始化(功耗采集,直连开发板电源回路)
    adc_config_t adcConfig;
    ADC_GetDefaultConfig(&adcConfig);
    ADC_Init(ADC0, &adcConfig);
    ADC_EnableChannel(ADC0, ADC_CHANNEL_CURRENT, true);
    ADC_EnableChannel(ADC0, ADC_CHANNEL_VOLTAGE, true);
   
    // 3. UART初始化(语音模块,直连开发板UART1)
    uart_config_t uartConfig;
    UART_GetDefaultConfig(&uartConfig);
    uartConfig.baudRate_Bps = 9600;
    uartConfig.parityMode = kUART_ParityDisabled;
    UART_Init(UART1, &uartConfig, CLOCK_GetUartClkFreq(UART1));
   
    // 4. PWM初始化(风扇驱动,直连开发板PWM0)
    pwm_config_t pwmConfig;
    PWM_GetDefaultConfig(&pwmConfig);
    PWM_Init(PWM0, kPWM_Module_0, &pwmConfig);
    PWM_SetTimerPeriod(PWM0, kPWM_Module_0, 1000); // 1kHz频率
    PWM_SetDutyCycle(PWM0, kPWM_Module_0, kPWM_Channel_0, g_fan_pwm_duty);
   
    // 5. 外设初始化(均直连开发板)
    LCD_Init();                // LCD屏初始化(SPI直连)
    Camera_Init();             // 摄像头初始化(SPI/I2C直连)
    Voice_Init();            // 语音模块初始化(UART直连)
    SD_Init();               // SD卡初始化(SPI直连)
   
    // 6. GPIO初始化(外设使能,直连开发板GPIO)
    gpio_pin_config_t gpioConfig = {kGPIO_DigitalOutput, 0};
    GPIO_PinInit(GPIO1, 10, &gpioConfig); // 摄像头使能引脚
    GPIO_PinInit(GPIO1, 11, &gpioConfig); // LCD使能引脚
}

/**
* @brief 语音指令识别处理(核心:解析语音模块返回的指令)
* 语音模块接收到指令后,通过UART向开发板返回对应指令码
*/
void Voice_Recog_Process(void)
{
    uint8_t recv_buf = {0};
    uint32_t recv_len = 0;
   
    // 读取语音模块返回的数据(UART1)
    if(UART_ReadBlocking(UART1, recv_buf, sizeof(recv_buf), &recv_len) == kStatus_Success)
    {
      // 解析语音指令(示例:语音模块返回"CMD1"=物体识别,"CMD2"=风扇,"CMD3"=LCD,"CMD4"=全部)
      if(strstr((char*)recv_buf, "CMD1") != NULL)
      {
            g_currentCmd = CMD_OBJECT_RECOG;
      }
      else if(strstr((char*)recv_buf, "CMD2") != NULL)
      {
            g_currentCmd = CMD_FAN_RUN;
      }
      else if(strstr((char*)recv_buf, "CMD3") != NULL)
      {
            g_currentCmd = CMD_LCD_DISPLAY;
      }
      else if(strstr((char*)recv_buf, "CMD4") != NULL)
      {
            g_currentCmd = CMD_COMBINED;
      }
      else
      {
            g_currentCmd = CMD_NONE;
            Voice_SendString("指令识别失败,请重新说出");
      }
    }
}

/**
* @brief 场景切换(触发对应功能,仅运行目标外设)
* @param scene 目标功耗场景
*/
void Scene_Switch(PowerScene_t scene)
{
    // 第一步:关闭所有外设(初始状态)
    Camera_StopCapture();    // 关闭摄像头
    PWM_StopTimer(PWM0, kPWM_Module_0); // 关闭风扇
    LCD_DisplayOff();      // 关闭LCD显示
   
    // 第二步:根据场景启动对应外设(直连开发板)
    switch(scene)
    {
      case SCENE_IDLE:
            LCD_ShowString(10, 40, "场景:空闲(无功能)", BLACK, WHITE, 16);
            break;
            
      case SCENE_OBJECT_RECOG:
            LCD_ShowString(10, 40, "场景:物体识别(仅摄像头)", BLACK, WHITE, 16);
            Object_Recog_Run(); // 仅启动摄像头进行物体识别
            break;
            
      case SCENE_FAN:
            LCD_ShowString(10, 40, "场景:风扇转动(仅风扇)", BLACK, WHITE, 16);
            Fan_Control(g_fan_pwm_duty); // 仅启动风扇
            break;
            
      case SCENE_LCD:
            LCD_ShowString(10, 40, "场景:屏幕显示(仅LCD)", BLACK, WHITE, 16);
            LCD_Display_Only(); // 仅启动LCD显示
            break;
            
      case SCENE_COMBINED:
            LCD_ShowString(10, 40, "场景:全部启动(组合)", BLACK, WHITE, 16);
            Object_Recog_Run(); // 摄像头
            Fan_Control(g_fan_pwm_duty); // 风扇
            LCD_Display_Only(); // LCD
            break;
            
      default:
            break;
    }
}

/**
* @brief 场景功耗测量(精准测量当前场景的功耗)
* @param scene 目标场景
*/
void Power_Measure_Scene(PowerScene_t scene)
{
    uint32_t adc_volt = 0, adc_curr = 0;
    float voltage = 0.0f, current = 0.0f, power = 0.0f;
    uint32_t start_time = SDK_GetTimeCount();
   
    // 连续采样10次取平均值(提高精度)
    for(uint8_t i=0; i<10; i++)
    {
      // 1. 采集电压(直连开发板电源端ADC1)
      ADC_StartConversion(ADC0, ADC_CHANNEL_VOLTAGE);
      while(!ADC_GetChannelConversionResult(ADC0, ADC_CHANNEL_VOLTAGE, &adc_volt));
      voltage += (adc_volt * ADC_REF_VOLTAGE) / ADC_RESOLUTION;
      
      // 2. 采集电流(通过采样电阻电压计算,直连开发板电流回路ADC0)
      ADC_StartConversion(ADC0, ADC_CHANNEL_CURRENT);
      while(!ADC_GetChannelConversionResult(ADC0, ADC_CHANNEL_CURRENT, &adc_curr));
      current += ((adc_curr * ADC_REF_VOLTAGE) / ADC_RESOLUTION) / SAMPLE_RESISTOR * 1000;
      
      SDK_DelayAtLeastUs(100, SDK_GetCoreSysClkFreq());
    }
   
    // 计算平均值
    voltage /= 10.0f;
    current /= 10.0f;
    power = voltage * current; // 功耗=电压×电流(mW)
   
    // 保存到场景功耗数据
    g_powerData.voltage = voltage;
    g_powerData.current = current;
    g_powerData.power = power;
    g_powerData.duration = SDK_GetTimeCount() - start_time;
}

/**
* @brief LCD显示多场景功耗对比(核心可视化)
* 分区域显示:物体识别/风扇转动/屏幕显示/组合场景的功耗对比
*/
void LCD_Show_Power_Compare(void)
{
    char buf;
    uint16_t y_start = 70;
   
    // 清空显示区域
    LCD_Fill(10, y_start, 310, 470, WHITE);
   
    // 1. 显示物体识别场景功耗
    sprintf(buf, "物体识别:%.2f V%.2f mA%.2f mW",
            g_powerData.voltage,
            g_powerData.current,
            g_powerData.power);
    LCD_ShowString(10, y_start, buf, RED, WHITE, 16);
   
    // 2. 显示风扇转动场景功耗
    y_start += 30;
    sprintf(buf, "风扇转动:%.2f V%.2f mA%.2f mW",
            g_powerData.voltage,
            g_powerData.current,
            g_powerData.power);
    LCD_ShowString(10, y_start, buf, BLUE, WHITE, 16);
   
    // 3. 显示屏幕显示场景功耗
    y_start += 30;
    sprintf(buf, "屏幕显示:%.2f V%.2f mA%.2f mW",
            g_powerData.voltage,
            g_powerData.current,
            g_powerData.power);
    LCD_ShowString(10, y_start, buf, GREEN, WHITE, 16);
   
    // 4. 显示组合场景功耗
    y_start += 30;
    sprintf(buf, "全部启动:%.2f V%.2f mA%.2f mW",
            g_powerData.voltage,
            g_powerData.current,
            g_powerData.power);
    LCD_ShowString(10, y_start, buf, BLACK, WHITE, 16);
   
    // 5. 绘制功耗对比柱状图(简化版)
    uint16_t bar_x = 50;
    // 物体识别功耗柱(红色)
    LCD_DrawFillRect(bar_x, 200 - (uint16_t)(g_powerData.power/2),
                     bar_x+20, 200, RED);
    // 风扇功耗柱(蓝色)
    bar_x += 40;
    LCD_DrawFillRect(bar_x, 200 - (uint16_t)(g_powerData.power/2),
                     bar_x+20, 200, BLUE);
    // LCD功耗柱(绿色)
    bar_x += 40;
    LCD_DrawFillRect(bar_x, 200 - (uint16_t)(g_powerData.power/2),
                     bar_x+20, 200, GREEN);
    // 组合功耗柱(黑色)
    bar_x += 40;
    LCD_DrawFillRect(bar_x, 200 - (uint16_t)(g_powerData.power/2),
                     bar_x+20, 200, BLACK);
}

/**
* @brief 语音播报当前场景功耗
* @param scene 当前场景
*/
void Voice_Report_Power_Scene(PowerScene_t scene)
{
    char voice_buf = {0};
   
    // 拼接播报字符串
    sprintf(voice_buf, "%s的功耗为:电压%.2f伏,电流%.2f毫安,功耗%.2f毫瓦",
            g_powerData.scene_name,
            g_powerData.voltage,
            g_powerData.current,
            g_powerData.power);
   
    // 发送到语音模块播报
    Voice_SendString(voice_buf);
}

/**
* @brief 物体识别功能(仅摄像头工作,直连开发板)
*/
void Object_Recog_Run(void)
{
    GPIO_PinWrite(GPIO1, 10, 1); // 开启摄像头使能(直连GPIO1_10)
    Camera_StartCapture();       // 启动摄像头采集
    Camera_Object_Recognition();// 物体识别算法(简化版)
}

/**
* @brief 风扇控制(仅风扇工作,直连开发板PWM)
* @param duty PWM占空比(0-100)
*/
void Fan_Control(uint8_t duty)
{
    PWM_SetDutyCycle(PWM0, kPWM_Module_0, kPWM_Channel_0, duty);
    PWM_StartTimer(PWM0, kPWM_Module_0); // 启动风扇(直连PWM0)
}

/**
* @brief 仅LCD显示功能(仅LCD工作,直连开发板SPI)
*/
void LCD_Display_Only(void)
{
    GPIO_PinWrite(GPIO1, 11, 1); // 开启LCD使能(直连GPIO1_11)
    LCD_DisplayOn();             // 仅启动LCD显示
}
```

## 四、效果演示

## 五、项目文档

页: [1]
查看完整版本: FRDM-MCXN947 多场景语音控制功耗测量系统