PIC16F1938で5ch PWM制御 完成編|CCP1~5 + Timer2/4/6を実装

ソフトPWMから始まり、
ハードPWM、ADC、EEPROM、UIまで追加して、
ようやく5ch PWM制御がひとつの形になりました。

今回は今までChatGPTにかなりお世話になっていたので、
総集編として一人で書くことに注力し、
かなり時間がかかってしまいました。

添削はしっかりChatGPTにしてもらい、
血だらけにしてもらいながら、
修正しなんとか形になりました。

そして、実際にやってみると、

「思ったより簡単に動かない」

場面ばかりでした。

特に、
ANSELBの設定漏れやADCチャンネルのズレ、
press_time++による長押し判定の不安定さなど、

“動かない理由を探す時間”

の方にも時間を要しました。

ですが、その分かなり理解は深まりました。

今回の回路

コードと動き

まず、前回同様にグローバルにADCON0のCHSをセットしました。

c

#define VOL1_CH 0b00000
#define VOL2_CH 0b00001
#define VOL3_CH 0b00010
#define VOL4_CH 0b00011
#define VOL5_CH 0b00100

本当は上記のようにしないといけなかったのに、
1つずつズレてしまっていたので、
つぎの様な動きになりました。

このズレてしまっているのは、
上のコードの様に
直すことでVolのナンバーに対してLEDが
光ってくれました。

しかし、

c

//sw_now ・・・スイッチの現在の状態表示用変数
//press_time・・スイッチに押されている時間をなんとなくカウントする変数
//long_press・・長押し判定かどうかのフラグ

if (sw_now == 0) {
            if (press_time < 1000) {
                press_time++;
            }
            if (press_time > 50) {
                long_press = 1;
            }
}

前回同様にこのコードでとりあえずスイッチの短押し、長押しを
判定させるようにしていました。
※この段階ではTimer0は未実装です。

それで動かした動画は無いのですが、
短押しをとても早くしないといけなくて大変でした。
この数字をいろいろといじって、
調整はしました。

結局press_timeが加算されるのは
whileが1周すればというあいまいな時間の
はかり方なので、
やはり、Timer0を実装することにしました。


プリスケーラ → 1:8
TMR0 → 5

の条件でTimer0のオーバーフローで
1msを作り、
1秒以下で短押し判定、
1秒を超えたら長押し判定
にしようと試みました。

c

void __interrupt() isr(void)
{
    if(INTCONbits.TMR0IF)
    {
        TMR0 = 5;
        INTCONbits.TMR0IF = 0;
        
        if(sw_pressed && press_time < 10000){
            press_time++;
        }
    }
}

void main(void) {

    ...

    while (1) {
        unsigned char sw_now = PORTBbits.RB4;
        static unsigned char sw_prev = 1;
        
        if ((sw_prev == 1) && (sw_now == 0)) {
            press_time = 0;
            long_press = 0;
            sw_pressed = 1;
            for (char i = 0; i < 5; i++) {
                ui_level[i] = Stored_offset[i];
                ui_start[i] = Stored_offset[i];
                ui_dir[i] = 1;
            }   
        }

        if (sw_now == 0) {
            if (press_time > 1000) long_press = 1;

            for (char i = 0; i < 5; i++) {
                if (long_press) {
                    if (ui_dir[i] > 0) {
                        if (ui_level[i] < 1023 - 4) {
                            ui_level[i] += 1;
                        } else {
                            ui_level[i] = 1023;
                            ui_dir[i] = -1;
                        }
                    } else {
                        if (ui_level[i] > ui_start[i] + 4) {
                            ui_level[i] -= 1;
                        } else {
                            ui_level[i] = ui_start[i];
                            ui_dir[i] = 1;
                        }
                    }
                }
            }
        }

        if ((sw_prev == 0) && (sw_now == 1)) {
            sw_pressed = 0;
            if (long_press == 0) {
                for (char i = 0; i < 5; i++) {
                    Stored_offset[i] = Read_ADC(ch[i]);
                    EEPROM_Write(i, (unsigned char) (Stored_offset[i] >> 2));
                }
            }
            press_time = 0;
            long_press = 0;
        }
        sw_prev = sw_now;
    }
}

これもうまく1秒ではなく、
それよりもかなり早い時間判定となってしまっていました。

そのため、結局は、

c

if (press_time > 2500) long_press = 1;

にすることにしました。
下の動画は、いろいろと試行錯誤している中で撮ったものです。
動作としてはOKです。

今回の学び

ソフトPWMから始まり、
ハードPWM、ADC、EEPROM、UIまで追加して、
ようやく5ch PWM制御がひとつの形になりました。

実際にやってみると、

「思ったより簡単に動かない」

場面ばかりでした。

特に、

・ANSELBの設定漏れ
・ADCチャンネル定義のズレ
・VDD未接続
・Main Project違い
・press_time++ の不安定な長押し判定

など、

“動かない理由を探す時間”

の方が圧倒的に長かった気がします。

ですが、その分かなり理解は深まりました。

特に今回、

「時間は処理回数ではなく、
基準を作って管理するもの」

という考え方に変わったことは
大きな収穫でした。

Timer0 を使って、
より安定した長押し判定へ進めみたいと思っていますが、

とりあえず区切りをつけて、
次回からは、
UARTの章に入っていきたいと思います。

ようやく、
会社の実機に近いところまで
繋がってきた気がしています。

コメント

タイトルとURLをコピーしました