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]