以前製作したWindowsXP用の赤外線リモコンのRaspberryPi?への引越しです。
最近、プリンターポートありのPCが少なくなっているので、どうするか検討していましたが、RaspberryPi?を最近さわりはじめたので、こちらに引越しさせることにしました。
時間精度や、制御方法などの基本を調査し、Windws版のTCPサーバ機能を実現する予定です。
単純にLEDチカチカのTPを125usで制御してみます。125us(8K)はWindows版リモコンのサンプリング周期です。
#include <bcm2835.h> #include <stdio.h> // Blinks on RPi Plug P1 pin 11 (which is GPIO pin 17) #define PIN RPI_GPIO_P1_11 int main(int argc, char **argv) { if (!bcm2835_init()) return 1; // Set the pin to be an output bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); // Blink while (1) { // Turn it on bcm2835_gpio_write(PIN, HIGH); // wait a bit bcm2835_delayMicroseconds( 125LL ); // turn it off bcm2835_gpio_write(PIN, LOW); // wait a bit bcm2835_delayMicroseconds( 125LL ); } bcm2835_close(); return 0; }
実行した結果がこれです。
250usに対して誤差は500ns以下ですので、シリアル通信として、レシーブマージンは十分に確保できます。
RaspberryPi?のPWM機能については、使用したことがないため、改めて確認しました。
まずは、bcm2835ライブラリですがPWM関係はvoid bcm2835_pwm_set_clock (uint32_t divisor) void bcm2835_pwm_set_mode (uint8_t channel, uint8_t markspace, uint8_t enabled) void bcm2835_pwm_set_range (uint8_t channel, uint32_t range) void bcm2835_pwm_set_data (uint8_t channel, uint32_t data)
があります。つまり
- ライブラリ初期化(bcm2835_init())
- ピンの機能設定(bcm2835_gpio_fsel())
- PWMクロック設定( bcm2835_pwm_set_clock())
- PWMモード設定(bcm2835_pwm_set_mode())
- PWMレンジ設定(bcm2835_pwm_set_range())
- PWMスタート/ストップ設定(bcm2835_pwm_set_data())
でよさそうです。
クロックソースは 19.2MHzが使用されるようで、最終的にここで指定した分周比が出力のクロックとなります。
ただし分周の指定は以下の中からしか選べないようです。typedef enum { BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, BCM2835_PWM_CLOCK_DIVIDER_512 = 512, BCM2835_PWM_CLOCK_DIVIDER_256 = 256, BCM2835_PWM_CLOCK_DIVIDER_128 = 128, BCM2835_PWM_CLOCK_DIVIDER_64 = 64, BCM2835_PWM_CLOCK_DIVIDER_32 = 32, BCM2835_PWM_CLOCK_DIVIDER_16 = 16, BCM2835_PWM_CLOCK_DIVIDER_8 = 8, BCM2835_PWM_CLOCK_DIVIDER_4 = 4, BCM2835_PWM_CLOCK_DIVIDER_2 = 2, BCM2835_PWM_CLOCK_DIVIDER_1 = 1 } bcm2835PWMClockDivider;
モードは2つあり、
- バランスモード:RANGEパルス数に対して全体としてDATAパルス数になるようにクロックパルスの組み合わせを発生させる。
- マークスペースモード:DATAクロック数の幅の間HIGHを出力して、RANGE-DATAクロック数の間LOWを出力する。
今回の用途では、Duty=50%の波形としたいので。マークスペースモードを選択します。
では、どのようにこの2つを設定するかですが、38KHzにするためには
19200 / 76 = 252.63157894736842105263157894737
これでON/OFFを繰り返せば言い訳ですが、実際には、256がもっとも近い値になります
19200 / 256 = 75 KHz (37.5KHz)
が設定可能となります。受光器のフィルタは上記の誤差では影響はないものと考えます。
次にRANGEとDATAですが、ON/OFFが一回ですので
Range = 2
Data = 1
でよいはずです
#include <bcm2835.h> #include <stdio.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> // PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18) // in alt fun 5. // Note that this is the _only_ PWM pin available on the RPi IO headers #define PIN RPI_GPIO_P1_12 // and it is controlled by PWM channel 0 #define PWM_CHANNEL 0 // This controls the max range of the PWM signal #define RANGE 2 int kbhit(void) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if (ch != EOF) { ungetc(ch, stdin); return 1; } return 0; } int main(int argc, char **argv) { if (!bcm2835_init()) return 1; // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5); // Clock divider is set to 256. bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_256); // set Mark-Space mode and enable bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); while(!kbhit()) { bcm2835_delay(50); bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); bcm2835_delay(50); bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 0); } bcm2835_close(); return 0; }
問題ありません。
つづく。
お疲れ様でした。