前回得られたリモコンの信号を再生して、シーリングライトが点灯するか確認したいと思います。
信号をキャプチャした前回の記事はこちらです。
38kHzを生成する
PadaukマイコンPFS122には、周期波形やPWMを生成できるTimer2カウンターが内蔵されています。このうちMode0という周期波形を生成するモードを使い38kHzを生成しようと思います。
Timer2の入力クロックには、8MHzのIHRCを使います。プリスケーラは使用せず、Upper bound Registerに210を設定すると、出力周波数は38kHzになります。
右下のデマルチプレクサは、どこのポートに出力するか、またはしないのか(Disable)を設定できます。このため、PA3に出力するように設定すると38kHzがPA3から出力し、Disableを設定すると出力が止まるということができます。
回路図
マイコンにはPFS122を使います。PadaukマイコンのIOの出力電流は数mAととても弱いので、直接LEDを接続すると明るく光りません。できるだけ明るく光って欲しいので、MOS-FETを使ってLEDを駆動します。
電源に使うコイン電池は、内部抵抗が大きく電流をたくさん取り出すと電圧が下がってしまいます。少しでも緩和するために、抵抗の後にコンデンサを取り付けました。LEDがOFFの時に充電され、LEDがONの時にコンデンサの電気も一緒に使うことでLEDに流れる電流を増やします。
スイッチ入力は、IOをプルアップに設定できるため、スイッチだけ接続してあります。
プログラム
#include <pdk/device.h> #include <stdint.h> #include "auto_sysclock.h" #include "startup.h" #include "delay.h" #define IR_OUT 3 #define T2_BOUND 210 #define LED_PIN 5 #define LED_OFF() PA |= (1 << LED_PIN) #define LED_ON() PA &= ~(1 << LED_PIN) #define SW_PIN 4 #define SW_STATES() ( PA & (1 << SW_PIN) ) == 0 #define SW_PRESS 1 #define SW_RELEASE 0 #define T_TIME 375 //us #define IR_ON() TM2C = (uint8_t)(TM2C_CLK_IHRC | TM2C_MODE_PERIOD | TM2C_OUT_PA3) #define IR_OFF() TM2C = (uint8_t)(TM2C_CLK_IHRC | TM2C_MODE_PERIOD | TM2C_OUT_DISABLE) const uint8_t payload_power[] = { 0xff, 0x08, 0xa2, 0x88, 0x8a, 0x8a, 0x8a, 0xa2, 0xaa, 0xa8, 0x88, 0x8a, 0x28, 0x8a, 0xaa, 0xa8, 0x88, 0x88, 0x88, 0x80 }; const uint8_t payload_power_length = sizeof(payload_power); const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; void main() { //Timer2 PAC |= ( 1 << IR_OUT); TM2C = (uint8_t)(TM2C_CLK_IHRC | TM2C_MODE_PERIOD | TM2C_OUT_DISABLE); TM2S = (uint8_t)(TM2S_SCALE_NONE | TM2S_PRESCALE_NONE | TM2S_PWM_RES_8BIT); TM2B = T2_BOUND; //for LED PAC |= ( 1 << LED_PIN); LED_OFF(); //for SWtich PAC &= ~(1 << SW_PIN); PAPH |= ( 1 << SW_PIN); //pullup PADIER |= ( 1 << SW_PIN); //input while(1) { //Waiting for the press of the button while(SW_STATES() != SW_PRESS); { __wdreset(); //kick WDT } LED_ON();//Transmit the code for(uint8_t i=0 ; i<payload_power_length ; i++) { for(uint8_t j=0; j<8 ; j++) { if( ( payload_power[i] & mask[j] ) != 0 ) { IR_ON(); }else{ IR_OFF(); } _delay_us(T_TIME); __wdreset(); //kick WDT } } LED_OFF(); //Waiting for the release of the button _delay_ms(40); while(SW_STATES() == SW_PRESS) { __wdreset(); //kick WDT } _delay_ms(40); } } // Startup code - Setup/calibrate system clock unsigned char STARTUP_FUNCTION(void) { // Initialize the system clock (CLKMD register) with the IHRC, ILRC, or EOSC clock source and correct divider. // The AUTO_INIT_SYSCLOCK() macro uses F_CPU (defined in the Makefile) to choose the IHRC or ILRC clock source and divider. // Alternatively, replace this with the more specific PDK_SET_SYSCLOCK(...) macro from pdk/sysclock.h PDK_USE_FACTORY_IHRCR_16MHZ(); PDK_USE_FACTORY_BGTR(); AUTO_INIT_SYSCLOCK(); // Insert placeholder code to tell EasyPdkProg to calibrate the IHRC or ILRC internal oscillator. // The AUTO_CALIBRATE_SYSCLOCK(...) macro uses F_CPU (defined in the Makefile) to choose the IHRC or ILRC oscillator. // Alternatively, replace this with the more specific EASY_PDK_CALIBRATE_IHRC(...) or EASY_PDK_CALIBRATE_ILRC(...) macro from easy-pdk/calibrate.h AUTO_CALIBRATE_SYSCLOCK(2800); return 0; // Return 0 to inform SDCC to continue with normal initialization. }
スイッチが押されると、電源ボタンを押した時のデータ(payload_power)が送信されるプログラムです。
とりあえず、Timer2で38kHzの信号が生成できているかオシロスコープで確認してみます。
綺麗な38kHzが生成できていました。
続いて、送信データの時間長が元のリモコンの送信時間長と同じ66msになるように、1bitあたりの周期を調節し16行目に設定します。
これで、リモコンの電源ボタンと同じ波形が出力されるはずです。
実験
スイッチを押すと...
おおおおお。シーリングライトが点灯しました。
もう一度押すと、消灯します。
リモコンのコピーが成功しました!
さて次回は
次回は、マイコンをスリープさせて、スイッチが押された時のみ動作するように、プログラムを改良したいと思います。
2025.4.17 追加 続きはこちらです。
コメント