ソフト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の章に入っていきたいと思います。
ようやく、
会社の実機に近いところまで
繋がってきた気がしています。

コメント