인터럽트를 사용하여 두 개의 ESP8266 PWM 위상을 동기화했습니다.

이것은 ESP8266 Advent Calendar 2015의 14 일째 기사입니다.

안녕하세요 kerokero입니다. 프로그램을 쓰거나 전자 공작하거나 고양이에게 놀고있는 삼촌입니다. Qiita는 첫 게시물입니다. ESP8266에서 외부 인터럽트를 사용해 보았으므로, 참고가 되면이라고 생각 투고합니다.

배경



현재 ESP8266(ESP-WROOM-02)을 사용하여 철도 모형 레이아웃(직류 2선식)의 무선화를 하고 있습니다.

이런 느낌의 것을



가능한지 확인하는 모습
サーバー経由でブラウザとやりとりしている様子

그렇지만, PWM 제어에서는, 다른 신호원이 만드는 PWM 전압 사이를 통과하는 경우, 양측의 위상이 없으면 실효 전압이 일시적으로 올라 버리기 때문에 움직임이 멍청합니다.


실제 움직임은 이런 느낌입니다. 섹션 경계(검은 조인트 부분)에서 가속하고 있는 것을 알 수 있습니다.

位相が揃っていないと

다음은 「그렇다면 위상을 맞추어 보자」라고 시도해 보았던 보고입니다.

어떻게 할까



자신의 섹션에 자신 이외가 내고 있는 전압이 검출된 것을 계기로 인터럽트를 걸어 그 파형에 동기시킵니다.
통상, 철도 모형의 동력차(N게이지)는 복수축의 양측의 바퀴로 집전하고 있기 때문에, 열차가 자구간과 이웃의 구간을 오버랩할 때, 이웃의 구간에 걸리는 전압을 검출한다 수 있습니다. 다만, 이것은 이웃 구간과 자신의 구간의 PWM 파형의 OR이므로, 여기로부터 자신의 PWM 신호를 마이너스 해 줍니다. (아래 그림)

(손으로 그릴까 ...)

지금까지의 신호 생성 부분은 로직 회로로 만들었습니다.

선로의 전압 파형을 검출하는 신호(상단의 회로)에서 자신의 PWM을 조금 뻗은 신호(중단)를 뺍니다(중단의 우단의 인버터+하단의 회로)

그러면 「옆의 구간만이 ON인 상태」를 나타내는 신호를 추출할 수 있으므로, 이것을 ESP8266의 인터럽트에 사용합니다.

ESP8266의 인터럽트는 RAISING(LOW→HIGH), FALLING(HIGH→LOW), CHANGE(둘 다)의 3가지 방법이 가능하지만 이번에는 CHANGE로 걸었습니다. 그 부분의 코드를 싣습니다 (Arduino로 쓰고 있습니다. VisualStudio에 VisualMicro 플러그인을 넣어 사용하고 있습니다).

인터럽트 루틴 중에서는 「옆의 구간만이 ON인 상태」가 된 이유가 「「둘 다 ON 상태」로부터 「자신이 OFF가 되었다」 때문」인가 「「둘 다 OFF 상태」로부터 「옆이 ON이 되었기 때문」인지를 판정해, 거기에 응해 PWM의 카운터 타이머를 리스타트 시키고 있습니다, 관련하는 곳만 빼낸 것을 아래에 올립니다. 타이머 재설정은 core_esp8266_wiring_pwm.c의 pwm_start_timer() 복사본입니다.
//setup()の中
    attachInterrupt(13, sync,  CHANGE);//割り込みを設定する

volatile long up = 0;//割り込み発生回数の調査用
volatile long dn = 0;//〃
volatile short adj = 0;//タイミング調整用(実行中に変化させながら様子を見たところ、120くらいがちょうどよいようです)
bool resetWithFALLING = false;
//割り込み処理(位相同期)
void sync() {
    if (rest > 0) {//ちょっと間引き
        rest--;
        return;
    }
    detachInterrupt(13);//再入を防ぐため割り込みをやめる
    Feeder *f = Feeders->get(0);
    short duty = f->getAnalogValue();//(上の行とあわせてGPIO14に設定している値のこと)
    int isRAISING = digitalRead(13) == 1;
    if (isRAISING) {
        up++;
        if (digitalRead(14) == HIGH) {//me delay
            resetWithFALLING = true;
        }
        else {
            timer1_disable();
            delayMicroseconds(1000 - duty - adj);
            timer1_write(1);
            timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
            rest = 5;
        }
    }
    else {//FALLING
        dn++;
        if (resetWithFALLING) {
            timer1_disable();
            timer1_write(1);
            timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
            resetWithFALLING = false;
        }
    }
    attachInterrupt(13, sync, CHANGE);//割り込みを許可する
}

volatile short rest = 0;
//loop()かonTimer()の中
    rest = 0;//割り込み間引き用カウンタをクリアする

상기의 코드로 어떻게든 움직이고 있습니다만, 인터럽트 검출을 ON으로 한 상태라면 10분에 1회 정도 떨어집니다. (왜인지 알 수있는 사람을 알려주세요 ...)

잘 움직였다?



위의 때때로 떨어지는 건을 제외하고는(^^;; 일단 움직였습니다.동기한 모습과 파형을 올리네요.

位相同期してみた結果

位相同期してみた結果(波形)

전체 시스템 정보



이번은 ESP8266에 관계있는 부분만 꺼내서 썼습니다만, 시스템 전체에 대해서는 대단히 조금씩 쓰기 시작한 곳이므로, 흥미가 있는 분은 봐 주세요→. 맑은 가끔 흐린 곳에 의해 고양이

좋은 웹페이지 즐겨찾기