#include "mp3_driver.h" #include "elog.h" #include /* 外部UART句柄声明 */ extern UART_HandleTypeDef huart3; /** * @brief 计算MP3命令校验和 * @param cmd 命令数组(不包含校验位) * @param len 数据长度 * @return 校验和(高位在前,低位在后) * @note 校验算法:从版本号开始,到数据结束,所有字节相加后取反再加1 */ static void MP3_CalcChecksum(const uint8_t *cmd, uint8_t len, uint8_t *high, uint8_t *low) { uint16_t sum = 0; // 从版本号(索引1)开始累加,到数据结束 for (uint8_t i = 1; i < len; i++) { sum += cmd[i]; } // 取反加1 (即0x10000 - sum) sum = 0x10000 - sum; // 高位在前,低位在后 *high = (sum >> 8) & 0xFF; *low = sum & 0xFF; } /** * @brief 发送MP3命令 * @param cmd 命令数组 * @param len 命令长度 * @return HAL状态 */ static HAL_StatusTypeDef MP3_SendCommand(const uint8_t *cmd, uint16_t len) { return HAL_UART_Transmit(&huart3, (uint8_t *)cmd, len, 100); } /** * @brief MP3模块初始化 * @return HAL状态 */ HAL_StatusTypeDef MP3_Init(void) { elog_d("MP3", "开始初始化MP3模块..."); // 命令1:开启声音 (0x06 - 0x00 - 0x00 - 0x1E) // 0x1E = 30, 表示音量为30 uint8_t init_cmd1[] = {0x7E, 0xFF, 0x06, 0x06, 0x00, 0x00, 0x1E, 0xFE, 0xD7, 0xEF}; uint8_t high1, low1; MP3_CalcChecksum(init_cmd1, 7, &high1, &low1); init_cmd1[7] = high1; init_cmd1[8] = low1; HAL_StatusTypeDef ret1 = MP3_SendCommand(init_cmd1, sizeof(init_cmd1)); elog_d("MP3", "开启声音命令返回值: %d", ret1); // 延时等待模块响应 HAL_Delay(100); // 命令2:选择TF卡作为音源 (0x09 - 0x00 - 0x00 - 0x02) uint8_t init_cmd2[] = {0x7E, 0xFF, 0x06, 0x09, 0x00, 0x00, 0x02, 0xFE, 0xF0, 0xEF}; uint8_t high2, low2; MP3_CalcChecksum(init_cmd2, 7, &high2, &low2); init_cmd2[7] = high2; init_cmd2[8] = low2; HAL_StatusTypeDef ret2 = MP3_SendCommand(init_cmd2, sizeof(init_cmd2)); elog_d("MP3", "选择TF卡命令返回值: %d", ret2); if (ret1 == HAL_OK && ret2 == HAL_OK) { elog_i("MP3", "MP3模块初始化完成"); return HAL_OK; } else { elog_e("MP3", "MP3模块初始化失败"); return HAL_ERROR; } } /** * @brief 按索引播放指定曲目 * @param index 曲目索引 (1-9999) * @return HAL状态 */ HAL_StatusTypeDef MP3_Play(uint16_t index) { if (index == 0 || index > 9999) { elog_e("MP3", "无效的曲目索引: %d", index); return HAL_ERROR; } // 构建播放命令:0x7E 0xFF 0x06 0x12 0x00 high(索引) low(索引) checksum1 checksum2 0xEF uint8_t play_cmd[10]; play_cmd[0] = MP3_HEADER; play_cmd[1] = MP3_VERSION; play_cmd[2] = MP3_LENGTH; play_cmd[3] = MP3_CMD_PLAY_INDEX; play_cmd[4] = 0x00; play_cmd[5] = (index >> 8) & 0xFF; // 索引高字节 play_cmd[6] = index & 0xFF; // 索引低字节 // 计算校验和 uint8_t high, low; MP3_CalcChecksum(play_cmd, 7, &high, &low); play_cmd[7] = high; play_cmd[8] = low; play_cmd[9] = MP3_FOOTER; // 发送命令 HAL_StatusTypeDef ret = MP3_SendCommand(play_cmd, sizeof(play_cmd)); if (ret == HAL_OK) { elog_d("MP3", "播放曲目 %d", index); } else { elog_e("MP3", "播放曲目 %d 失败", index); } return ret; } /** * @brief 停止播放 * @return HAL状态 */ HAL_StatusTypeDef MP3_Stop(void) { // 构建停止命令:0x7E 0xFF 0x06 0x16 0x00 0x00 0x00 checksum1 checksum2 0xEF uint8_t stop_cmd[10]; stop_cmd[0] = MP3_HEADER; stop_cmd[1] = MP3_VERSION; stop_cmd[2] = MP3_LENGTH; stop_cmd[3] = MP3_CMD_STOP; stop_cmd[4] = 0x00; stop_cmd[5] = 0x00; stop_cmd[6] = 0x00; // 计算校验和 uint8_t high, low; MP3_CalcChecksum(stop_cmd, 7, &high, &low); stop_cmd[7] = high; stop_cmd[8] = low; stop_cmd[9] = MP3_FOOTER; HAL_StatusTypeDef ret = MP3_SendCommand(stop_cmd, sizeof(stop_cmd)); if (ret == HAL_OK) { elog_d("MP3", "停止播放"); } else { elog_e("MP3", "停止播放失败"); } return ret; } /** * @brief 暂停播放 * @return HAL状态 */ HAL_StatusTypeDef MP3_Pause(void) { // 构建暂停命令:0x7E 0xFF 0x06 0x0E 0x00 0x00 0x00 checksum1 checksum2 0xEF uint8_t pause_cmd[10]; pause_cmd[0] = MP3_HEADER; pause_cmd[1] = MP3_VERSION; pause_cmd[2] = MP3_LENGTH; pause_cmd[3] = MP3_CMD_PAUSE; pause_cmd[4] = 0x00; pause_cmd[5] = 0x00; pause_cmd[6] = 0x00; // 计算校验和 uint8_t high, low; MP3_CalcChecksum(pause_cmd, 7, &high, &low); pause_cmd[7] = high; pause_cmd[8] = low; pause_cmd[9] = MP3_FOOTER; HAL_StatusTypeDef ret = MP3_SendCommand(pause_cmd, sizeof(pause_cmd)); if (ret == HAL_OK) { elog_d("MP3", "暂停播放"); } else { elog_e("MP3", "暂停播放失败"); } return ret; } /** * @brief 设置音量 * @param volume 音量值 (0-30) * @return HAL状态 */ HAL_StatusTypeDef MP3_SetVolume(uint8_t volume) { if (volume > 30) { volume = 30; // 最大音量30 } // 构建音量设置命令:0x7E 0xFF 0x06 0x06 0x00 0x00 volume checksum1 checksum2 0xEF uint8_t vol_cmd[10]; vol_cmd[0] = MP3_HEADER; vol_cmd[1] = MP3_VERSION; vol_cmd[2] = MP3_LENGTH; vol_cmd[3] = MP3_CMD_SET_VOLUME; vol_cmd[4] = 0x00; vol_cmd[5] = 0x00; vol_cmd[6] = volume; // 计算校验和 uint8_t high, low; MP3_CalcChecksum(vol_cmd, 7, &high, &low); vol_cmd[7] = high; vol_cmd[8] = low; vol_cmd[9] = MP3_FOOTER; HAL_StatusTypeDef ret = MP3_SendCommand(vol_cmd, sizeof(vol_cmd)); if (ret == HAL_OK) { elog_d("MP3", "设置音量: %d", volume); } else { elog_e("MP3", "设置音量失败"); } return ret; } /** * @brief 设置音源 * @param source 音源类型 (1=U盘, 2=SD卡/TF卡) * @return HAL状态 */ HAL_StatusTypeDef MP3_SetSource(uint8_t source) { if (source != MP3_SOURCE_U_DISK && source != MP3_SOURCE_SD_CARD) { elog_e("MP3", "无效的音源类型: %d", source); return HAL_ERROR; } // 构建音源设置命令:0x7E 0xFF 0x06 0x09 0x00 0x00 source checksum1 checksum2 0xEF uint8_t source_cmd[10]; source_cmd[0] = MP3_HEADER; source_cmd[1] = MP3_VERSION; source_cmd[2] = MP3_LENGTH; source_cmd[3] = MP3_CMD_SET_SOURCE; source_cmd[4] = 0x00; source_cmd[5] = 0x00; source_cmd[6] = source; // 计算校验和 uint8_t high, low; MP3_CalcChecksum(source_cmd, 7, &high, &low); source_cmd[7] = high; source_cmd[8] = low; source_cmd[9] = MP3_FOOTER; HAL_StatusTypeDef ret = MP3_SendCommand(source_cmd, sizeof(source_cmd)); if (ret == HAL_OK) { elog_d("MP3", "设置音源: %d", source); } else { elog_e("MP3", "设置音源失败"); } return ret; }