文章目录
- 1.前言
- 2.时序逆向分析
- 2.1协议分析
- 2.2卡带音频通道引出
- 3、PCB设计
- 4、程序设计
- 5、焊接调试
- 6、结语
1.前言
之前写过四篇关于车机增加音频输入的方法。
1、07宝来经典车机CD收音机(RC668)改装增加蓝牙播放音乐
2、全网首发!老大众奥迪碟盒通信协议破解,可以模拟数码碟盒,外接AUX蓝牙U盘等音频设备
3、全网首发!大众奥迪DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装
4、全网首发,克莱斯勒大捷龙jeep道奇DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装
5、全网首发!大众宝来高尔夫polo领驭迈腾帕萨特奥迪A4A6B6B7等老车机增加带蓝牙控制的AUX解码模块
早期老奔驰宝马奥迪高端车机他们的卡带机由于年代久远大部分都用不了,虽然他们不是一家,但是卡带部分用的都是一样的方案,这里以奥迪老A6卡带机为例,设计一套卡带通道激活模块,用于激活卡带通道,然后就可以把卡带音频引出转成AUX,接入自己喜欢的音源,奥迪卡带通道可以使用杜比音效,听重低音效果不错。
2.时序逆向分析
卡带机芯控制器原理图如下所示。
和主板通信的主要接口引脚是
ME/FE | 卡带正反面 |
---|---|
MONITOR | 保护监控 |
PLAY-SWITCH | 卡带播放 |
ENABLE-CC | 使能 |
GND | gnd |
CLOCK-CC | 时钟线 |
VCC 12V | 12V |
DATA-CC | 数据线 |
通过示波器和逻辑分析仪反复测试,卡带控制主要引脚为ENABLE-CC、CLOCK-CC、DATA-CC这个三个引脚有关。下面通过逻辑分析仪抓取3个引脚时序,破解协议。
关机状态 低电平
开机
按mode按钮切换到TAPE
REV按钮按下
FF 按钮按下
再按下FF按钮
抓取的波形太多了,综合分析结果如下
2.1协议分析
开机:进入非卡带 返回 f0 00 f0 00
开机 :进入卡带 箭头向上 : f0 00 f0 00 a8 aa db c2 df 56
先发f0 00 f0 00 然后发a8 然后 aa 然后 a8 aa db c2 df 56 a8发完拉低sw
开机 :进入卡带 箭头向下 : f0 f0 0 a8 aa db c2 ea e7 66
卡带机向上运行 关机 返回: 52 ea f0 00 先发52 后面为应答 F0后拉高SW
卡带机向下运行 关机 返回: 62 da f2 f0 00 先发62 后面为应答 F0后拉高SW
切换卡带机箭头向上 运行 返回:da d7 56
切换卡带机箭头向下 运行 返回:ea e7 66
切换功能机箭头向上 返回: 52 ea f0 00 先发52 后面为应答
切换功能机箭头向下 返回: 62 da f2 f0 00 先发62 后面为应答
FM 进入卡带机 箭头向上 :a8 aa db c2 df 56
FM 进入卡带机 箭头向下 :a8 aa db c2 ea e7 66
卡带机FF按钮 箭头向前快进按下 : c0 d2
在按下停止快进:c2 ea c2 f0 00 a8 aa db c2 df 56 先发c2 在发ea c2 在发后面
卡带机FR按钮 箭头向前快进按下 : c0 ea e2
在按下停止快进:c2 da c2 f0 00 a8 aa db c2 df 56 先发c2 在发da c2 在发后面
FF RF 一起按下 返回: 98 a8 aa db f0 00 先发98 在发a8 再发 aa db f0 00
2.2卡带音频通道引出
磁头AB面引出AUX
卡带机输入音频信号需要阻抗匹配
增益调节
3、PCB设计
根据上述原理,设计原理图PCB
卡带接口引出PCB板卡
卡带控制接口PCB板卡
4、程序设计
贴上核心程序代码
///ENABLE/
void GPIOA_IRQHandler(void)
{
static uint8_t preData = 0;
/* USER CODE BEGIN GPIOA_IRQn 0 */
/* EXTI line interrupt detected */
if (__HAL_GPIO_EXTI_GET_FLAG(TAPE_ENABLE_GPIO_PORT, TAPE_ENABLE_GPIO_PINS) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_FLAG(TAPE_ENABLE_GPIO_PORT, TAPE_ENABLE_GPIO_PINS);
if(HAL_GPIO_ReadPin(TAPE_ENABLE_GPIO_PORT, TAPE_ENABLE_GPIO_PINS) == GPIO_PIN_SET) //上升沿
{
LED_01(LED_ON);
TAPE_CLK_GPIO_Config();
if ((myTape.tsReceiveData[0] == 0xac) || (myTape.tsReceiveData[0] == 0xa8)) //
{
osal_set_event(tape_task_id, TAPE_PLAY_EVENT);
TAPE_ONOFF(TAPE_LOW);
}else
if ((myTape.tsReceiveData[0] == 0x52) || (myTape.tsReceiveData[0] == 0x62)) //关机
{
osal_set_event(tape_task_id, TAPE_STOP_EVENT);
}else
if (((myTape.tsReceiveData[0]&0xf0) == 0xf0)&&(preData==0xda))
{
osal_set_event(tape_task_id, TAPE_INIT_EVENT);
}
else
if ((myTape.tsReceiveData[0] ==0xd2||myTape.tsReceiveData[0] ==0xe2)&&(preData==0xc0)) //c0 d2 快进c0 e2
{
// TAPE_ONOFF(TAPE_HIGHT);
osal_set_event(tape_task_id, TAPE_FF_FAST_EVENT);
}
else
if ((myTape.tsReceiveData[0] ==0xea||myTape.tsReceiveData[0] ==0xda)&&(preData==0xc0)) //c0 ea 快进 c0 da
{
// TAPE_ONOFF(TAPE_HIGHT);
osal_set_event(tape_task_id, TAPE_FR_FAST_EVENT);
}
else
if ((myTape.tsReceiveData[0] ==0xe7)&&(preData==0xea)) //切换箭头向下
{
TAPE_MEFE(TAPE_HIGHT);
} else
if ((myTape.tsReceiveData[0] ==0xd7)&&(preData==0xda)) //切换箭头向上
{
TAPE_MEFE(TAPE_LOW);
}
preData = myTape.tsReceiveData[0];
osal_set_event(tape_task_id, TAPE_RECE_EVENT);
__HAL_GPIO_EXTI_CLEAR_FLAG(TAPE_ENABLE_GPIO_PORT, TAPE_ENABLE_GPIO_PINS); //清除中断标志位
// EXTI->IMR &= ~(EXTI_Line1); //关闭外部中断1
HAL_NVIC_DisableIRQ(TAPE_CLK_EXTI_IRQn);
__HAL_GPIO_EXTI_CLEAR_FLAG(TAPE_CLK_GPIO_PORT, TAPE_CLK_GPIO_PINS); //清除中断标志位
// SPI2_Buffer_Rx[0] = 0;
// SPI2_Buffer_Rx[1] = 0;
}else //下降沿
{
LED_01(LED_OFF);
TAPE_CLK_GPIO_EXIT_Config();
__HAL_GPIO_EXTI_CLEAR_FLAG(TAPE_CLK_GPIO_PORT, TAPE_CLK_GPIO_PINS); //清除中断标志位
HAL_NVIC_EnableIRQ(TAPE_CLK_EXTI_IRQn); //开启外部中断1
// EXTI->IMR |= EXTI_Line1;
myTape.tsRxinedx = 0;
}
}
__HAL_GPIO_EXTI_CLEAR_FLAG(TAPE_ENABLE_GPIO_PORT, TAPE_ENABLE_GPIO_PINS); //清除中断标志位
/* USER CODE END GPIOA_IRQn CLK 0 */
}
/**
* @brief 当前任务的事件回调处理函数
* @param task_id [任务ID]
* @param task_event [收到的本任务事件]
* @return uint16 [未处理的事件]
*/
uint16 tape_task_event_process(uint8 task_id, uint16 task_event)
{
if(task_event & TAPE_INIT_EVENT)
{
initTape();
myTape.tsStatus = 1;
return task_event ^ TAPE_INIT_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_RECE_EVENT)
{
printf(" %x\n",myTape.tsReceiveData[0]);
// if(SPI2_Buffer_Rx[0] == )
myTape.tsReceiveData[0] = 0;
myTape.tsReceiveData[1] = 0;
return task_event ^ TAPE_RECE_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_IDLE_EVENT)
{
printf(" %x\n",myTape.tsReceiveData[0]);
myTape.tsReceiveData[0] = 0;
myTape.tsReceiveData[1] = 0;
return task_event ^ TAPE_IDLE_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_PLAY_EVENT)
{
TAPE_ONOFF(TAPE_HIGHT);
HAL_Delay(300);
TAPE_ONOFF(TAPE_LOW);
HAL_Delay(337);
TAPE_ONOFF(TAPE_HIGHT);
HAL_Delay(77);
TAPE_ONOFF(TAPE_LOW);
osal_set_event(tape_task_id, TAPE_PLAYING_EVENT);
myTape.tsStatus = 1;
return task_event ^ TAPE_PLAY_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_PLAYING_EVENT)
{
TAPE_CLK(TAPE_LOW);
HAL_Delay(1);
TAPE_CLK(TAPE_HIGHT);
if(myTape.tsStatus == 1) //开机发送脉冲
{
osal_start_reload_timer(tape_task_id, TAPE_PLAYING_EVENT, 25 / TICK_PERIOD_MS);
}else if(myTape.tsStatus == 2) //快进发送脉冲
{
osal_start_reload_timer(tape_task_id, TAPE_PLAYING_EVENT, 2 / TICK_PERIOD_MS);
}
return task_event ^ TAPE_PLAYING_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_FF_FAST_EVENT)
{
sendTapeMsg(U_COMMEND_NEXT);
printf("FF \n");
myTape.tsStatus = 2;
return task_event ^ TAPE_FF_FAST_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_FR_FAST_EVENT)
{
sendTapeMsg(U_COMMEND_PRE);
printf("FR \n");
myTape.tsStatus = 2;
return task_event ^ TAPE_FR_FAST_EVENT; //处理完后需要清除事件位
}
if(task_event & TAPE_STOP_EVENT)
{
myTape.tsStatus = 0;
TapePowerOff();
return task_event ^ TAPE_STOP_EVENT; //处理完后需要清除事件位
}
return 0;
}
定义结构体 用于保存车机播放音乐相关信息。
/**
* @brief 当前任务的事件回调处理函数
* @param task_id [任务ID]
* @param task_event [收到的本任务事件]
* @return uint16 [未处理的事件]
*/
uint16 userApp_task_event_process(uint8 task_id, uint16 task_event)
{
if(task_event & SYS_EVENT_MSG) //判断是否为系统消息事件
{
osal_sys_msg_t *msg_pkt;
msg_pkt = (osal_sys_msg_t *)osal_msg_receive(task_id); //从消息队列获取一条消息
// uBUTTON_ProcessOSALMsg(task_id,msg_pkt);
uCommend_ProcessOSALMsg(task_id,msg_pkt);
// return unprocessed events
return (task_event ^ SYS_EVENT_MSG);
}
if(task_event & USERAPP_INIT_EVENT)
{
osal_start_reload_timer(userApp_task_id, USERAPP_EVENT, 500 / TICK_PERIOD_MS);
return task_event ^ USERAPP_INIT_EVENT; //处理完后需要清除事件位
}
if(task_event & BLE_UART_RX_EVENT)
{
BLE_UART_Rx.lenth = BLE_UART_Rx.u8RxCnt;
BLE_UART_Rx.flag = 1;
BLE_UART_Rx.u8RxCnt = 0;
return task_event ^ BLE_UART_RX_EVENT; //处理完后需要清除事件位
}
if(task_event & USERAPP_EVENT)
{
#ifndef WDEBUG
WDOG_Feed(); // 喂狗
#endif
return task_event ^ USERAPP_EVENT; //处理完后需要清除事件位
}
return 0;
}
5、焊接调试
根据原理图将电路板焊接好,下载程序。
将解码模块插入到卡带机上
开机上电,按mode键,进入卡带模式。
视频演示如下
https://live.csdn.net/v/325082
6、结语
有朋友反馈,找不到我,今打油诗一首
加流一壶真千金
微云澹日映寒流
信意麾毫无点误
KING_SONGING
唱奇腾怪可删修
歌咏康衢了此生
的然民仰如父母
国家涵养自建隆
王俭归来幕府非
有朋自远方来,不亦说乎