PSoCで455kHzの赤外線PCM信号を出す回路とソフトについて説明します。
赤丸でかこったPWM8_1ユーザーモジュールで信号を発生します。PWM8_1のクロックには48MHz(SYSCLK*2)を入力し、Enableは常時PWM信号を生成するようにHighにします。PWM8_1の周期は105、compare値(PWM信号のDuty)には0を設定します。出力はCompareOutの信号を38kHzのPPM信号とORして出力します。

ソフトはこんな感じです。
全部のチャンネルのデータを受信するごとにTXBUFにPCM信号(ON/OFF情報)をセットしてから呼び出しています。
TXBUFには48μsごとに赤外線をONにするか、OFFにするかを表す情報を格納します。
ONにする場合はON時のPWM信号のcompare値(35)を入れておき、OFFにする場合はcompare値(0)を入れておきます。データの末尾には終わりを表すための0xFFを入れておきます。48μsごとに「PWM8_1_WritePulseWidth(tmp);」を行ってPWM信号のDutyを変化させています。
やりたくはなかったのですが、48μsごとの割込みでは処理できなかったため、ソフトでタイミングを取るようにしました。(CPUを24MHzで動かせば大丈夫かもしれないのですが、そうするとI2Cで接続したLCDが制御できないため。)
void Send_Pulse(void)
{
static BYTE tmp;
TX_SND_count = 0;
tmp = TXBUF[TX_SND_count];
while(tmp != 0xff){
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
asm("nop");
PWM8_1_WritePulseWidth(tmp);
TX_SND_count++;
tmp = TXBUF[TX_SND_count];
};
}
TXBUFにはこのようなデータが入っています。
TXBUF[] = {35,35,35,35,35,35,35,35,35,0,35,0,35,0xFF};
上記は「9ビットON,1ビットOFF,1ビットON,1ビットOFF,終了」を表しています。実際にはプロポから入力されたデータや選択されているバンドなどに従って生成されたデータを入れておきます。
実際の送信データ設定処理はこんなふうになりました。
CONFIG_ROM[PCM455CH]はバンド(チャンネル)の情報、txCH_Data[]はプロポから入力されたPPM信号のパルス周期(1100μsが0x00、1900μsが0xFF)が入っています。
下記ではラダー(txCH_Data[3])とスロットル(txCH_Data[2])のデータを各8ビット送信しています。
//PCM2用の送信データ設定処理
void PCM2_data_set(void)
{
int i;
unsigned int tmp;
unsigned int mask;
TX_SET_count = 0; //0.048ms * 9 ON
TXBUF_SET1(); //1
TXBUF_SET1(); //2
TXBUF_SET1(); //3
TXBUF_SET1(); //4
TXBUF_SET1(); //5
TXBUF_SET1(); //6
TXBUF_SET1(); //7
TXBUF_SET1(); //8
TXBUF_SET1(); //9
TXBUF_SET0(); //0.048ms OFF
TXBUF_SET1(); //0.048ms ON
TXBUF_SET0(); //0.048ms OFF (2ch)
switch(CONFIG_ROM[PCM455CH]){
case Ch_A : TXBUF_SET0();TXBUF_SET0();TXBUF_SET0();parity = 0;break;
case Ch_B : TXBUF_SET0();TXBUF_SET0();TXBUF_SET1();parity = 1;break;
case Ch_C : TXBUF_SET0();TXBUF_SET1();TXBUF_SET0();parity = 1;break;
case Ch_D : TXBUF_SET0();TXBUF_SET1();TXBUF_SET1();parity = 2;break;
case Ch_E : TXBUF_SET1();TXBUF_SET0();TXBUF_SET0();parity = 1;break;
case Ch_F : TXBUF_SET1();TXBUF_SET0();TXBUF_SET1();parity = 2;break;
case Ch_G : TXBUF_SET1();TXBUF_SET1();TXBUF_SET0();parity = 2;break;
case Ch_H : TXBUF_SET1();TXBUF_SET1();TXBUF_SET1();parity = 3;break;
};
TXBUF_SET0(); //0.048ms OFF
for(i=2;i<=3;i++){
tmp = txCH_Data[i];
mask = 0x80;
while (mask != 0){
if ((tmp & mask) != 0){
TXBUF_SET1();
parity++;
}
else {
TXBUF_SET0();
};
mask = mask >> 1;
};
TXBUF_SET0(); //0.048ms OFF
};
if (pairing_req > 0){
pairing_req--;
TXBUF_SET1(); //0.048ms OFF
parity++;
}
else {
TXBUF_SET0(); //0.048ms OFF
};
if (resv_req > 0){
resv_req--;
TXBUF_SET1(); //0.048ms OFF
parity++;
}
else {
TXBUF_SET0(); //0.048ms OFF
};
//parityには1だったビットの数が入っている。偶数だったらパリティビットが1
if ((parity & 0x01)==0){
TXBUF_SET1();
}
else {
TXBUF_SET0();
};
TXBUF_SETE();
}
void TXBUF_SET(char c)
{
if (TX_SET_count < TXBUF_SIZE){
TXBUF[TX_SET_count] = c;
TX_SET_count++;
};
}
void TXBUF_SET1(void)
{
TXBUF_SET(IR_PWM16_CNT); //IR_PWM16_CNT=35
}
void TXBUF_SET0(void)
{
TXBUF_SET(0);
}
void TXBUF_SETE(void)
{
TXBUF_SET(0xff);
}
<10月18日追記>
上記のPSoCの内部回路ですが、ひとつ前の版のものです。IRラジコン☆プログラム倉庫にアップしてあるプロジェクトのものとは一部異なります。やっていることは変わりませんが、ユーザーモジュールの配置などが変わっています。
最近のコメント