RapberryPi-赤外線リモコン

以前製作した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;
}

実行した結果がこれです。

125usx2-period.jpg

250usに対して誤差は500ns以下ですので、シリアル通信として、レシーブマージンは十分に確保できます。

RaspberryPi?のPWM機能の確認

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)

があります。つまり

  1. ライブラリ初期化(bcm2835_init())
  2. ピンの機能設定(bcm2835_gpio_fsel())
  3. PWMクロック設定( bcm2835_pwm_set_clock())
  4. PWMモード設定(bcm2835_pwm_set_mode())
  5. PWMレンジ設定(bcm2835_pwm_set_range())
  6. 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つあり、

  1. バランスモード:RANGEパルス数に対して全体としてDATAパルス数になるようにクロックパルスの組み合わせを発生させる。
  2. マークスペースモード: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;
}

問題ありません。

つづく。

お疲れ様でした。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS