文章目录
- 前言
- 1、设计指标
- 2、PCB设计
- 3、程序设计
- 4、调试
- 4.1蓝牙控制AUX解码板
- 4.2自定义车机按钮控制其他高品质蓝牙音频模块
- 4.3小程序使用
- 5、模块与车机连接方法
- 6、结语
前言
之前写过四篇关于车机增加音频输入的方法。
1、07宝来经典车机CD收音机(RC668)改装增加蓝牙播放音乐
2、全网首发!老大众奥迪碟盒通信协议破解,可以模拟数码碟盒,外接AUX蓝牙U盘等音频设备
3、全网首发!大众奥迪DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装
4、全网首发,克莱斯勒大捷龙jeep道奇DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装
汽车使用寿命很长,而电子设备老化的速度很快,这就导致了10多年的老车还能在开10年,但是汽车上的电子设备基本都不能用了,比如听歌用的CD机,10年基本没有几个CD能正常工作了,为了解决老车不能听音乐,或者听音乐不方便的问题,所以设计了一款数码碟盒AUX解码模块,该模块能激活碟箱接口,通过碟箱接口接入自己喜欢的音源。保证原滋原味,音质的好坏取决于音源。
VWC-AB01 带蓝牙控制的AUX解码板
碟盒功能
产品型号 | 碟箱解码 | 开关机灯 | 蓝牙指示灯 | 蓝牙BLE | 原车按钮控制 | KEY | IO | OTA升级 | 12V供电 | 5V输出 |
---|---|---|---|---|---|---|---|---|---|---|
VWC-AX01 | ● | ● | ○ | ○ | ○ | ○ | ○ | ○ | ● | ○ |
VWC-AB01 | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● |
1、设计指标
模块规格如下:
输入电压 | 12VDC |
---|---|
工作电流 | 100mA |
工作温度 | -40℃~+80℃ |
频率响应 | 20HZ-20KHZ |
长x宽x高 | 如上图 |
2、PCB设计
AUX解码板碟箱音频接口直接引出,与控制端不共地,并且用模拟地对音频线进行包地处理,增加抗干扰能力。
带蓝牙控制的AUX解码板,红色部分为ble天线部分。
3、程序设计
贴上核心程序代码
/*捕捉中断*/
void ETM2_IRQHandler(void)
{
uint32_t nextVal;
uint32_t curVal = ETM2->CNT;
if(ETM2->SC & ETM_SC_TOF_MASK) //清除溢出标志位
{
ETM2->SC &= ~ETM_SC_TOF_MASK;
}
if(ETM2->CONTROLS[0].CnSC & ETM_CnSC_CHF_MASK )//输入信号边沿变化
{
ETM2->CONTROLS[0].CnSC &= ~ETM_CnSC_CHF_MASK;
if(RxInProgress == (VPW_RxStatus_t)Idle) // 产生下降沿
{
RxInProgress = (VPW_RxStatus_t)SOF;
VPW_RxBufPtr = 0;
// ResetRx();
if(VPW_TxBufPtr >1)
{
VPW_RxBufPtr = 0;
}
ETM2->CONTROLS[0].CnSC |= ETM_CnSC_ELSB_MASK; //切换到跳边沿检测
}
else if(RxInProgress == 1)
{
uint32_t width;
uint8_t symIdx;
width = GetPulseWidth(PrevCntrVal, curVal);
if(width > RX_SOF_MIN && width <= RX_SOF_MAX)
{
symIdx = SOF_IDX;
}
else if(width > RX_LONG_MIN && width <= RX_LONG_MAX)
{
symIdx = LONG_IDX;
}
else if(width > RX_SHORT_MIN && width <= RX_SHORT_MAX)
{
symIdx = SHORT_IDX;
}
else
{
ResetRx();
return;
}
VPW_RxBuf[VPW_RxBufPtr] = symIdx;
if(TxInProgress == 1) //正在发送
{
if(VPW_RxBuf[VPW_RxBufPtr] != VPW_TxBuf[VPW_RxBufPtr])
{
FinalizeTx();
}
}
if(VPW_RxBufPtr < sizeof(VPW_RxBuf) - 2)
{
VPW_RxBufPtr++;
}
SetTimerAlarm(239*48);
}
PrevCntrVal = curVal;
}
if(ETM2->CONTROLS[0].CnSC & ETM_CnSC_CHF_MASK )//输入信号上升沿
{
ETM2->CONTROLS[0].CnSC &= ~ETM_CnSC_CHF_MASK;
}
}
发送程序使用定时器0产生波形
/*****************************************************************************//*!
*
* @brief ETM1 回调函数
*
* @param none
*
* @return none
*
*****************************************************************************/
void ETM0_IRQHandler(void)
{
uint32_t nextVal;
ETM_ClrOverFlowFlag(ETM0); //清除溢出标志位
ETM_ClockSet(ETM0, ETM_CLOCK_NOCLOCK, ETM_CLOCK_PS_DIV16); //停止计数
nextVal = VPW_Symbols[VPW_TxBuf[VPW_TxBufPtr]];
if((VPW_TxBuf[VPW_TxBufPtr] == EOF_IDX)||(VPW_TxBufPtr>=(TX_BUFLEN*8)))
{
FinalizeTx();
}
else
{
ETM_SetModValue(ETM0,nextVal);
ETM0->CNT = 0;
ETM_ClockSet(ETM0, ETM_CLOCK_SYSTEMCLOCK, ETM_CLOCK_PS_DIV16); //开始计数
GPIO_Toggle(GPIOA,J1850_OUT_MASK);
}
VPW_TxBufPtr++;
}
定义结构体 用于保存车机播放音乐相关信息。
typedef struct
{
uint8_t rnd;
uint8_t scan;
uint8_t playing;
uint8_t cd_button;
uint8_t cd_power;
uint8_t cd_status;
uint8_t disc;
uint8_t track;
uint8_t minute;
uint8_t second;
uint8_t workSta; // 工作状态0 关机 1 待机 2工作
uint8_t BIDIstate; // pointer to the current state handler routine
uint8_t BIDIcount;
uint8_t staCount;
} CD_CHANFER_STRUCT;
自定义车机按钮程序
void bt_exButtonMessage(void)
{
if(mybtEx.fbutton_flag == 0)
{
if(mybtEx.frst == 1)
{
mybtEx.fbutton_flag = 1;
mybtEx.fbutton_value = U_BUTTON_RST;
tmos_start_task(userApp_task_id,USERAPP_EVENT,20 * TICK_PERIOD_MS);
}else
if(mybtEx.fpowerOn == 1)
{
mybtEx.fbutton_flag = 1;
bt_exPowerOn();
mybtEx.fbutton_value = U_BUTTON_POWER;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmPowerOn.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fpowerOff == 1)
{
mybtEx.fbutton_flag = 1;
bt_exPowerOff();
mybtEx.fbutton_value = U_BUTTON_POWER;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmPowerOff.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fPlay == 1)
{
mybtEx.fbutton_flag = 1;
mybtEx.fbutton_value = U_BUTTON_PLAY;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, 500 * TICK_PERIOD_MS);
}else
if(mybtEx.fnext == 1)
{
mybtEx.fbutton_flag = 1;
bt_exNext();
mybtEx.fbutton_value = U_BUTTON_NEXT;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmNext.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fpre == 1)
{
mybtEx.fbutton_flag = 1;
bt_exPre();
mybtEx.fbutton_value = U_BUTTON_PRE;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmPrev.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fmix == 1)
{
mybtEx.fbutton_flag = 1;
bt_exMix();
mybtEx.fbutton_value = U_BUTTON_MIX;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmMix.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd1 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd1();
mybtEx.fbutton_value = U_BUTTON_CD1;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd1.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd2 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd2();
mybtEx.fbutton_value = U_BUTTON_CD2;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd2.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd3 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd3();
mybtEx.fbutton_value = U_BUTTON_CD3;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd3.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd4 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd4();
mybtEx.fbutton_value = U_BUTTON_CD4;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd4.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd5 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd5();
mybtEx.fbutton_value = U_BUTTON_CD5;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd5.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.fcd6 == 1)
{
mybtEx.fbutton_flag = 1;
bt_exCd6();
mybtEx.fbutton_value = U_BUTTON_CD6;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmCd6.delayTime * TICK_PERIOD_MS);
}else
if(mybtEx.btPause == 1)
{
#ifdef WDEBUG
#endif
mybtEx.fbutton_flag = 1;
bt_exPlayPuse();
mybtEx.fbutton_value = U_BUTTON_PAUSE;
tmos_start_task(userApp_task_id, USERAPP_BUTTON_EVENT, btMapPWMCfg.wmPause.delayTime * TICK_PERIOD_MS);
}
}
}
微信小程序程序
4、调试
AUX解码板插碟机上,搭铁开机,即可工作,这里不做详细论述。视频演示
带蓝牙控制的大众奥迪老车机AUX解码模块
下面主要讲解下,蓝牙控制AUX解码板。
4.1蓝牙控制AUX解码板
现有AUX解码板只能解码不能用原车按钮控制,这样在开车的时候想要换歌曲,就需要操作手机或者其他设备,很不安全。为了解决这个问题,将解码板的主控换成带蓝牙5.3的单片机,既可以实现解码车机,又能实现原车按钮控制手机等数码产品上下一曲。
VWC-AB01 模组连接到车机上默认模式是AUX解码功能,当手机或其他电子设备连接蓝牙名称为:
VWCDC-SP-BLE蓝牙设备,如下图所示,手机端这时播放音乐,既可以通过车机原车按钮控制手机上下一曲播放蓝牙音乐了。
4.2自定义车机按钮控制其他高品质蓝牙音频模块
市面上的公版蓝牙模组控制方式,大体上分为两类控制,一类是IO高低电平时间控制,另外一类是ADC按键控制。这里以ADC按键为控制方式的蓝牙模组为例,讲解如何自定义车机按键功能,控制蓝牙音频模块。
ADC按键原理如下图所示,核心原理就是电阻串联分压,不同按键按下,就是不同电阻与固定值的22k上拉电阻串联分压,因为每个按键对应的电阻值不同,所以可以区分不同按键按下。
蓝牙音频模块和解码板连接图
根据上面原理,只要解码模块产生和按键按下相同的电压,和持续时间,就可以模拟对应按键功能了。比如下一曲对应的是0.96V,那么只要控制模块产生0.96v电压即可。那么怎么控制模块产生不同的电压呢?这里面要用到对应的微信小程序配置工具了。
4.3小程序使用
微信小程序搜索悦享行或者私聊博主发小程序
搜索连接VWCDC-SP-BLE,连接成功后显示如下界面,默认参数为输出3.3V 持续0.5s
根据上图可知上一曲、下一曲、暂停对应的电压值,根据实际情况设置即可,如下图所示,设置好按设置按钮,然后在读取设置参数,如果读回来的数据和写入的数据一致,那么设置成功。按对应的车机按键,模块就会输出设置的电压值和持续时间。
视频演示
支持小程序自定义大众奥迪车机按键功能的蓝牙控制AUX解码模块
5、模块与车机连接方法
AUX解码板连接方法
带蓝牙控制的AUX解码板连接方法
6、结语
有朋友反馈,找不到我,今打油诗一首
加流一壶真千金
微云澹日映寒流
信意麾毫无点误
KING_SONGING
唱奇腾怪可删修
歌咏康衢了此生
的然民仰如父母
国家涵养自建隆
王俭归来幕府非
有朋自远发来,不亦说乎!