15年ほど乗っている我が家の車の、FMラジオ(いわゆるカーステレオってやつです。純正ご用達品)の感度がなぜか下がって来たようで、家の近くの街乗りでノイズが混じるようになってきたのが気になっていました。スマホの音を車載Audioに入力できないかなと、以前FMトランスミッタでやってみて、音が悪すぎで断念。カーステレオに増設用のI/Fがあることはわかっていたのですが、なかなか手を出さずに今日まで来ました。
だんだん聞こえが悪くなってきて、じゃ、やるか、と色々と調べていたら、2012年ころにshiozokuさんが同じようなことをやってたのを発見。いろいろと調べてゆくと、うちの同じカーステレオの拡張I/Fも見つかり、比べてみると同じ系列のカーステレオのようだとわかりました。
ここまでわかればなんとかなるだろうと、回路を作って、ソフト(shiozokuさんはAVRで作られたようですが、PIC用に修正)を作ってみました。以下それの備忘録です。
動作についての説明と、ソフトウェア、ハードウェア(制御部/アナログ部)について記述します。
動作概要:
うちの車のカーステレオは、松下さんのモデルNo.RM-A51SAQというTC24というセレナに乗っているものです。これにはAUX入力用のコネクタがあって、そこへ外部からのAUX_ONというレベル信号(+12V)を与えてやると、AUXモード(LCDにAUXと表示される)に遷移します。また外部へのRADIO_ONというレベル信号が出力されており、カーステレオの本体機能が動作するとレベル信号(+12V)が出力されます。この時、外部の装置は、AUX_ON信号をReset(OFF/0V)する必要があります。AUX_ONをResetしないとAUXモードから抜けられない状態、RADIOが聞けない状態になります。つまり外部からのAUX_ON信号が優先されるようです。
shiozokuさんのソフトは、上記のRADIO_ON信号を監視していて、カーステレオ機能がONの状態と、AUXモードが電源OFFを挟んで交互に動作するようになっていて、本体の電源ボタンの押下によってそれが切り替わる、つまり外部にボタンが必要ないことになります。例えばカーステレオがOnの状態で、電源ボタンを二度押すと、OFF状態を経由してAUXモードになります。AUXモードで、電源ボタンを二度押すと、OFF状態を経由してカーステレオが動作します。また、おまけで、AUXモードの時に、ラジオのボタンなどを押すとカーステレオ側の機能が優先されて切り替わります。純正っぽい。
ソフトウェア:
ソフトウェアは、AVR用のものをPIC用に一部追加、修正しました。
ソフトの内部では、mode_stateで状態を管理していて、外部からのイベントでmode_statusを遷移させます。
- MAIN_OFF:カーステレオの電源が切れている状態
- MAIN_RADIO:カーステレオ本体側が動作している状態
- MAIN_AUXSW:前の状態がカーステレオ本体が動作していて、その後電源がOFFになり、次に電源が入った時にはAUXに切り替える状態
- MAIN_AUX:外部装置が動作している状態、AUXモード
これをforとswitchで回しています。
shiozokuさんとの差分:
shiozokuさんの方ではモードをEEPROMに記憶していますが、面倒なので、スキップ。カーステレオ本体側で、電源が切れた時のカーステレオの動作モードを覚えている(RADIOがONかOFFかだけ。AUXは忘れる、、)ので、本装置が起動時にRADIO_ONを監視していて、RADIO_ONであればそのモードに強制的に遷移させています。逆に、AUXモードで電源が切れた場合は、MAIN_OFF状態にしてあるので、次に電源ボタンが押されるとカーステレオが起動します。
開発環境:
MPLAB X IDE/5.35, XC8/2.20, C99
2021/4/12写真入れ替え(状態遷移追加)
ハードウェア(制御部分):
ハードウェアは、PIC12F675(8pin)を用いました。扱う信号線が少ないのと、単に手元にあったから、という理由です。これも古いPICです。
RADIO_ONという12Vのレベル信号入力と、AUX_ONという12Vのレベル信号出力、電源12V(ACC:アクセサリからとりました)、が外部とのI/Fになります。
RADIO_ONは、12Vを抵抗で5V相当に分圧して直接PICのPortに入力しています。車の電源は15V位になることがあるので、2:1にしてあります。12Vになっても4VあればHigh判定してくれます。
AUX_ONは、PICのPort出力を2SC1815と2SA1015のコンプリメンタリの石を使ってドライブしています。
電源は、PIC用に5Vのレギュレータを入れてあります。
ICEのコネクタをつけようかと思って回路図に記載はしていますが、PICが8pinなので、外せばいいやと面倒になったので基板上には実装していません。
ハードウェア(アナログ部分):
アナログ部分は、スマホの音声出力を直接カーステレオのAUX入力に入れても音が小さい、ということで、OpeAMPを使って増幅しています。OpeAMPはこれまた古い、手元にあったML307Sという8pinで1chを二個使いました。
回路はマルツさんの「■オペアンプ 単電源1段アンプの設計手順 」というのを参考にして、手元にあった部品とにらめっこして作成してあります。反転増幅になっていますが、聞いてもわからんと思うのでそのままにしてあります。片電源なので、+端子には12/2Vに分圧して加えてあります。
ゲインの調整は、現地調整でカーステレオのラジオとスマホの音量を比較して、入力側10kΩを固定として、最終的には120kΩとしました。この抵抗、後(現地?)で変えると思ったので、アクセスしやすいように、OpeAMPの上にしてあります。正解でした。交換するときに抵抗の根本で切って、そこに半田付けしました。大丈夫だろうとは思いますが、OpeAMPが発熱すると抵抗値が変わって増幅度が変わるのも嫌なので、多少物理的に浮かせてあります。右半分が制御部分ですPICとトランジスタが2個、5Vのレギュレータです。左上がLとRの2ch分のアナログ回路です。
結言:
ということで割と順調に作ることができました。shirozokuさんに感謝します。
車で動作させた(エンジンOFFで)ところうまくいったので、喜んでいましたが、後で出かけたときにつけてみたら、オールタネータノイズがとてつもなくでかかったので、電源にチョークコイルを入れたり、ヘッドホンプラグへのケーブルを太くしたりしましたがだめ。あとは感でコンデンサを電源周りに入れたりして当たって、最終的に12/2V(12Vを2分圧して、中点をOpeAMPの+に加えるところ)とGNDの間に10μFの電解コンデンサを入れたところ、ぴたっと止まりました。こういうところは難しいところですね。(上下の写真は最後のオルタネータノイズ取りのコンデンサは入っていない版です。最終状態の写真を取り忘れました、、、。)
あと、ハードウェアの写真で、左下の部分に「空地」がありますが、Bluetoothのレシーバでも載せようかと思って空けてあります。大陸にOrderしたので、到着したらまた発掘作業からやってみたいと思います。
お決まりですが、本記事は自分の備忘録です。なんの動作保証もしませんし、接続先の装置、システム等への影響、故障などを起こさせる可能性もあります。もし万が一これを見てやってみる方(古い装置なのでまずいないとは思いますが)は、すべて自己責任でお願いいたします。
/* ************************************************** * ファイル名 main.c for CarRadio_AUX_control Project * 作成者 tomoaric * 作成日 2021/4/4 * 更新日 * バージョン 1.0 * 開発環境: * MPLAB X IDE/5.35, XC8/2.20, C99 * 使用PIC: * PIC12F675 * クロック 4MHz(INTIO) * 概要 * CarRadioのDIN8pin経由でRadio/AUXを電源ボタンのOn/Off/Onで切り替える * 電源ボタンを二度押しで、RadioとAUXを、全Off経由で切り替える * Raio_On時に、電源ボタン押下→Off、電源ボタン押下→AUX_On、 * AUX_On時に、電源ボタン押下→Off、電源ボタン押下→Radio_On * となる * 割り込み未使用 * 使用ポート: * 1:VSS(+5V) 2ICE * 2:GP5 Radio_On In * 3:GP4 /AUX_On Out * 4:/MCLR 2ICE * 5:LED for test purpose... * 6:ICSCLK 2ICE * 7:ICSDAT 2ICE * 8:VDD(GND) 2ICE * * Analog部分は、 * https://www.marutsu.co.jp/contents/shop/marutsu/mame/102.html * の辺りを見て作成。 * * 本プログラムは以下の記事をもとにして作成しています。 * shiozokuさんに感謝します。 * http://shiozoku.blogspot.com/2012/01/aux.html * * コメントは処理を理解するために、追加してあります。 * */ #include \<xc.h\> // CONFIG #pragma config FOSC = INTRCIO // Oscillator Selection bits @12F675 set to 4MHz #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-Up Timer Enable bit (PWRT enabled) #pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD) #pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled) #pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #define _XTAL_FREQ 4000000 //for __delay operation... #define Radio_On GP5 //Input #define AUX_On GP4 //Output #define LED GP2 //Output for test purpose #define TRUE 1 #define FALSE 0 #define ON 1 #define OFF 0 #define MAIN_OFF 0 #define MAIN_RADIO 1 #define MAIN_AUXSW 2 #define MAIN_AUX 3 #define initial_WAIT 3000 #define WAIT 200 //AUX_On signal control to the RADIO // "AUX_On = On" -> request changing AUX mode to the RADIO void AUXON_Set(unsigned int on_off) { if(on_off==ON) { AUX_On = ON; // LED = ON; } else{ AUX_On = OFF; // LED = OFF; } } // Raio_On signal check int RADIOON_Get() { return Radio_On; } // pic initialize static void pic_init() { // OSCCON = 0b01110000; //内部周波数8MHz // OSCCON = 0b01110000; //111:内部周波数8MHz,101:2M,110:4M // ポートの設定 1=input TRISIO = 0b00100000; // GP4:out, GP5:in GPIO = 0; // アナログの設定 ANSEL = 0b00000000; //do not use any Aanalog input CMCON = 0x07; // コンパレータ未使用 } // ==================== メイン処理 =========================== void main() { // unsigned char once_flag=TRUE; //eepromを使う場合 unsigned int once_flag=FALSE; //eepromを使わない場合 unsigned int mode_state; //once_flagは、初めて「MAIN_RADIOとMAIN_AUX」になったときにセット //次のloop回でEEPROMに覚えさせる pic_init(); // Radioが立ち上がるのを待つ __delay_ms(initial_WAIT); // eepromを使わない設定として、電源ON時にRADIO側が前の状態を記憶しているので // それに従う。この場合、電源OFF時にAUXだった場合(MAIN_AUX)は、MAIN_OFFとする。 // RADIO_On信号をチェックして、On(ラジオ動作中)だったら、そのモードにする // それ以外はState:MAIN_OFF、AUX_OnはOFFとする if (RADIOON_Get()==ON) mode_state=MAIN_RADIO; else{ mode_state=MAIN_OFF; AUXON_Set(OFF); __delay_ms(WAIT); } // 前回状態復帰 // ReadEEPROM(0,&mode_state); // if(mode_state==MAIN_AUX) AUXON_Set(ON); for(;;){ switch(mode_state) { case MAIN_OFF: //電源OFFの状態 if(RADIOON_Get()==ON) //RadioがOnになった(2個めの矢印) { mode_state=MAIN_RADIO; once_flag=TRUE; } else //電源がOFFのままだけど、一度ONになったかの判断 { if(once_flag) { // WriteEEPROM(0,mode_state); once_flag=FALSE; } } break; case MAIN_RADIO: //ラジオが付いている状態 if(RADIOON_Get()==ON) //まだラジオのまま { if(once_flag) { // WriteEEPROM(0,mode_state); once_flag=FALSE; } } else //ラジオがついているから消えた状態に遷移(3個めの矢印) { mode_state=MAIN_AUXSW; once_flag=TRUE; } break; case MAIN_AUXSW: //一回ラジオがOnになって、消された状態 //AUXへの切り替えを待っている状態 if(RADIOON_Get()==ON) //一旦ラジオが消されて、再度ついた!(4つ目の矢印) //AUXへ遷移させる { mode_state=MAIN_AUX; AUXON_Set(ON); __delay_ms(WAIT); } break; case MAIN_AUX: //AUXになっている状態 if(RADIOON_Get()==ON) //AUX状態で、ラジオがONになった(1個めの矢印) //AUXOnをOFFにして、全部消す { mode_state=MAIN_OFF; AUXON_Set(OFF); __delay_ms(WAIT); } else //AUX状態が継続 { if(once_flag) { // WriteEEPROM(0,mode_state); once_flag=FALSE; } } break; default: mode_state = MAIN_OFF; } __delay_ms(WAIT); } }