ニトリのエレクターシェルフもどき(まがいもの)(パクリ)であるスチールラックに洋折釘(ネジ)を取り付ける為の台座?を造形しました。
3Dプリンター | Ender-3 V3 SE |
ノズル径 | 0.3mm(社外品)Amazon |
スライサー | Creality Print v6.0.0.1078 |
フィラメント | eSUN PETG 白 Amazon |
3DCAD | Onshape(無料サブスクリプション) |
この記事を書いた私は素人です。しかもデバッグの環境構築は初めてなので、誤りに気付かず書いている場合があるかも知れません。注意して下さい。
前記事の続きから、デバッグの環境を整えました。
↓ 配線が蜘蛛の巣状態で見苦しいけど、一応デバッグ中でブレークポイントで停止中です。
私の開発環境
pico-setup-windowsからダウンロードした
pico-setup-windows-0.3.5-x64.exe と
VSCode用のRaspberry Pi Pico拡張機能を使用。
VSCode C/C++ | Windows 11 |
ピコプローブ | Raspberry Pi Pico |
デバッグ対象 | Raspberry Pi Pico W |
ピコプローブとなるPicoにインストールする debugprobe_on_pico.uf2 を得るには。そしてインストール。uf2ファイルをPicoにインストールする手順は省きます。この記事を読む貴方は承知でしょうから。
↓ Raspberry Pi 公式サイトの Pico-series Microcontrollers ページにある Debugging using another Pico-series device の説明文で You can find the latest release of the firmware in the debugprobe GitHub repository. にリンクされたページに行くと debugprobe_on_pico.uf2 をダウンロード出来る。
↓ Pico同士のデバッグ用配線
↓ ピコプローブにUSBケーブルを差し込み(BOOTSELボタンは押さない)Windowsに認識された事を、デバイスマネージャーで確認。
さて、ピコプローブとデバッグ対象のPicoが配線されたら、いよいよデバッグです。
↓ 1、2、3の順に選択
1 | Picoアイコン |
2 | Debug Project |
3 | Pico Debug(Cortex-Debug) |
↓ デバッグが始まるとmain関数の最初の所で自動停止? 問題があるから停止した?
↓ 赤字で「warning: なんとか、かんとか」って警告されるけど、Continue (F5)ボタンを押すと先に正常に?進める。
このデバッグ環境を利用する New Pico Project を作る場合は以下の通り。
New Pico Project
Name | SSD1331_test |
Board type | Pico W |
Location | c:\Users\JM1LXS\Documents\LXS_Pico |
Select Pico SDK version | v2.1.0 |
Features | SPI |
Stdio support | Console over UART |
Pico wireless options | Pico W onboard LED |
Code generation options | Use project name as entry point file name |
Generate C++ code | |
Debugger | DebugProbe (CMSIS-DAP) |
ソースコードに
printf(“TEST”\n);
を書いて置くとデバッグ中のシリアルモニターに、先程の文字を表示する事が出来る。またコード変更しても、USBケーブルの抜き差しやBOOTSELボタンやリセットボタンを押す必要が無くデバッグ出来る。
と言っても、初心者の私は良く分からずに、やっているだけだけど。
前回に続き、今回はロータリーエンコーダーを2個にしてみました。
複数のロータリーエンコーダーの同時読み取りは、switch-case分で対応出来ました。
その対応と言っても、人の指で2個のロータリーエンコーダーを普通にクルクル回す速さでの事です。モーターなどで機械的に高速で回した場合には対応出来ないかも。
「尚、私はロータリーエンコーダーを読み取るソースコードを書くのは始めたばかりだし、C言語も素人で、しかも初心者なので凄いソースコードは書けません。悪しからず」
この記事のソースコードや考えに誤り、非効率、プロならこんなソースコードは書かないとか、あるでしょうから先に言って置きます。
↓ 白色(PETG)の造形物は、私がOnshapeで設計、Ender-3 V3 SEで造形しました。
今は電子工作に3Dプリンターは、半田ごてくらいに必需品だと思う。無いなら自分で作ればいい。電子工作もその考えだし。3DCAD設計も楽しいしね。PC画面の3Dが現物になるんだから凄い。
↑↓ central_line の上下は0、x_speed(グラフ描画間隔)は1のロータリーエンコーダーで変化させる。
x_speedの値は待機時間。つまり、グラフ描画(左端から右端までの描画)後に、待機時間を設けて次のグラフ描画となる。オシロスコープで言う時間軸の変化みたいなもの。
↓ この関数で複数(2個)のロータリーエンコーダーの読み取りを行います。
void lxs_gpio_callback(uint gpio, uint32_t events)
↓ 次のソースコードは一部分ですが、core1で行うロータリーエンコーダーの読み取りに関係します。
// コールバック関数
// 1つ又は複数のロータリーエンコーダーを同時に回した時
// (割り込みが発生した時)に呼ばれる関数
// gpio の値でどのロータリーエンコーダーなのか特定出来る
void lxs_gpio_callback(uint gpio, uint32_t events) {
int lxs_clk;
// この関数実行中のみ点灯させて
// ロータリーエンコーダーの
// 立ち上がりや立ち下がりに
// 発生する割り込みを確認するLED
gpio_put(5, 1); // GP5のLED点灯
// 割り込みの禁止
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false);
sleep_ms(3); // 0.003秒 念の為のチャタリング対策
switch (gpio) {
// DT0 の割り込み ///////////////////////
case PIN_DT0: // 0のロータリーエンコーダー
// CLK0の状態を取得
lxs_clk = gpio_get(PIN_CLK0);
switch (events) {
// DT0 の立ち上がり割り込み
case GPIO_IRQ_EDGE_RISE: // 0x8u
if (lxs_clk == 1) { // #A 右回り
central_line--;
} else if (lxs_clk == 0) { // #C 左回り
central_line++;
}
break;
// DT0 の立ち下がり割り込み
case GPIO_IRQ_EDGE_FALL: // 0x4u
if (lxs_clk == 0) { // #B 右回り
central_line--;
} else if (lxs_clk == 1) { // #D 左回り
central_line++;
}
break;
// evetes値が12(0x0Cかな)とか意味不明の場合
default:
central_line = central_line;
break;
}
break;
// DT1 の割り込み ///////////////////////
case PIN_DT1: // 1のロータリーエンコーダー
// CLK1の状態を取得
lxs_clk = gpio_get(PIN_CLK1);
switch (events) {
// DT1 の立ち上がり割り込み
case GPIO_IRQ_EDGE_RISE: // 0x8u
if (lxs_clk == 1) { // #A 右回り
x_speed = x_speed + 10; // +10μ秒(+0.00001秒)
} else if (lxs_clk == 0) { // #C 左回り
x_speed = x_speed - 10;
}
break;
// DT1 の立ち下がり割り込み
case GPIO_IRQ_EDGE_FALL: // 0x4u
if (lxs_clk == 0) { // #B 右回り
x_speed = x_speed + 10;
} else if (lxs_clk == 1) { // #D 左回り
x_speed = x_speed - 10;
}
break;
// events値が12(0x0Cかな)とか意味不明の場合
default:
x_speed = x_speed;
break;
}
break;
default: // gpio の値が想定外の時
central_line = 45; // 初期値
x_speed = 920; // 初期値
break;
}
// 割り込み禁止の解除
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
gpio_put(5, 0); // GP5のLED消灯
}
void core1_entry() {
const uint LED_PIN = 25;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
// GPIOの初期化(ロータリーエンコーダー用)
gpio_init(PIN_CLK0); // GP4
gpio_init(PIN_DT0); // GP3
gpio_init(PIN_SW0); // GP2
gpio_init(PIN_CLK1); // GP12
gpio_init(PIN_DT1); // GP11
gpio_init(PIN_SW1); // GP10
// 立ち上がり、立ち下がりの割り込み確認用LED
gpio_init(5); // GP5
// 入出力設定
gpio_set_dir(PIN_CLK0, GPIO_IN);
gpio_set_dir(PIN_DT0, GPIO_IN);
gpio_set_dir(PIN_SW0, GPIO_IN);
gpio_set_dir(PIN_CLK1, GPIO_IN);
gpio_set_dir(PIN_DT1, GPIO_IN);
gpio_set_dir(PIN_SW1, GPIO_IN);
gpio_set_dir(5, GPIO_OUT);
// 内部プルダウン設定
gpio_pull_down(PIN_CLK0);
gpio_pull_down(PIN_DT0);
gpio_pull_down(PIN_SW0);
gpio_pull_down(PIN_CLK1);
gpio_pull_down(PIN_DT1);
gpio_pull_down(PIN_SW1);
// ヒステレリス設定(シュミットトリガ利用)念の為のチャタリング対策
gpio_set_input_hysteresis_enabled(PIN_CLK0, true);
gpio_set_input_hysteresis_enabled(PIN_DT0, true);
gpio_set_input_hysteresis_enabled(PIN_SW0, true);
gpio_set_input_hysteresis_enabled(PIN_CLK1, true);
gpio_set_input_hysteresis_enabled(PIN_DT1, true);
gpio_set_input_hysteresis_enabled(PIN_SW1, true);
// 割り込み用コールバック関数の登録
gpio_set_irq_enabled_with_callback(PIN_DT0, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &lxs_gpio_callback);
gpio_set_irq_enabled_with_callback(PIN_DT1, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &lxs_gpio_callback);
// 割り込み禁止の解除
gpio_set_irq_enabled(PIN_DT0, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
gpio_set_irq_enabled(PIN_DT1, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
// 基板実装LED(GP25)の点灯用ループ
while (true) {
if (gpio_get(PIN_CLK0) == 1) {
gpio_put(LED_PIN, 1);
//sleep_ms(2);
} else {
gpio_put(LED_PIN, 0);
//sleep_ms(2);
}
}
}
まぁ〜、このソースコード、C言語初心者の私にとっては趣味に使える。
でも、以下の事が、今後解決したらいいと思う。
【理解不能】
↓ 上記ソースコードの一部で、自分で書いて置きながら、私には理解出来ない事がある。割り込み用コールバック関数の登録で、ロータリーエンコーダーが2個だから2つ書いているけど、1つだけでも同様に動作する。なんで?
// 割り込み用コールバック関数の登録
gpio_set_irq_enabled_with_callback(PIN_DT0, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &lxs_gpio_callback);
gpio_set_irq_enabled_with_callback(PIN_DT1, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &lxs_gpio_callback);
【意味不明】
上記の理解不能な件に加えて、コールバック関数内で使用するeventsの値が意味不明なのがある。
それは、ロータリーエンコーダーを回している時(1クリックごとに)、私が想定するeventsの値は0x4uと0x8uなんだけど、12(多分0x0Cuかな)が頻繁に発生する。
この12とは? なに? エラーとかファールのコード?
ググり方が不味いのか、ググっても解決していない。
これは仕方ないので、その部分のソースコードで想定外の値の時は、ロータリーエンコーダーを回しても(1クリック分だけ)変化しない事にした。↓
// evetes値が12(0x0Cかな)とか意味不明の場合
default:
central_line = central_line;
break;
// events値が12(0x0Cかな)とか意味不明の場合
default:
x_speed = x_speed;
break;
AmazonでポチったロータリーエンコーダーHW-040を、Raspberry Pi Picoの割り込みとC言語で読み取る記事。ただ私は素人なので誤りが有るかも知れません。
開発環境
VSCode C/C++ | Windows 11 |
RP2040 | Raspberry Pi Pico |
↓ 目標はロータリーエンコーダーでcentral_lineを上下に動かす事。
↓ DTの立ち上がり割り込み、又は立ち下がり割り込みの時、CLKの値を読み取り右回り、又は左回りを判断して1クリック毎に central_line の値を変化させます。
尚、画像中の#A、#B、#C、#Dはソースコードにあるそれと一致します。
↓ ロータリーエンコーダーの読み取りはcore1で行い、ADCとOLEDの表示はcore0で行う。次のコードはcore1で処理する部分で、ロータリーエンコーダーの読み取りをGPIOの割り込みで処理します。尚、ソースコード中の#A、#B、#C、#Dは上記画像のそれと一致します。
// コールバック関数
// ロータリーエンコーダーを回した時(割り込み発生時)に呼ばれる関数
void lxs_gpio_callback(uint gpio, uint32_t events) {
int lxs_clk;
// この関数実行中のみ点灯させて
// ロータリーエンコーダーの
// 立ち上がり
// 立ち下がり を確認する為のLED
gpio_put(5, 1); // GP5のLED点灯
// 割り込みの禁止
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false);
sleep_ms(3); // 0.003秒 念の為のチャタリング対策
// CLKの状態を取得
lxs_clk = gpio_get(PIN_CLK);
// DTの立ち上がり割り込み
if (gpio == PIN_DT && events == GPIO_IRQ_EDGE_RISE) {
if (lxs_clk == 1) { // #A
central_line--;
} else if (lxs_clk == 0) { // #C
central_line++;
}
// DTの立ち下がり割り込み
} else if (gpio == PIN_DT && events == GPIO_IRQ_EDGE_FALL) {
if (lxs_clk == 0) { // #B
central_line--;
} else if (lxs_clk == 1) { // #D
central_line++;
}
}
// 割り込み禁止の解除
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
gpio_put(5, 0); // GP5のLED消灯
}
void core1_entry() {
const uint LED_PIN = 25;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
// GPIOの初期化(ロータリーエンコーダー用)
gpio_init(PIN_CLK); // GP4
gpio_init(PIN_DT); // GP3
gpio_init(PIN_SW); // GP2
// 立ち上がり、立ち下がりの割り込み確認用LED
gpio_init(5); // GP5
// 入出力設定
gpio_set_dir(PIN_CLK, GPIO_IN);
gpio_set_dir(PIN_DT, GPIO_IN);
gpio_set_dir(PIN_SW, GPIO_IN);
gpio_set_dir(5, GPIO_OUT);
// 内部プルダウン設定
gpio_pull_down(PIN_CLK);
gpio_pull_down(PIN_DT);
gpio_pull_down(PIN_SW);
// ヒステレリス設定(シュミットトリガ利用)念の為のチャタリング対策
gpio_set_input_hysteresis_enabled(PIN_CLK, true);
gpio_set_input_hysteresis_enabled(PIN_DT, true);
gpio_set_input_hysteresis_enabled(PIN_SW, true);
// 割り込み用コールバック関数の登録
gpio_set_irq_enabled_with_callback(PIN_DT, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &lxs_gpio_callback);
// 割り込み禁止の解除
gpio_set_irq_enabled(PIN_DT, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
// 基板実装LED(GP25)の点灯用ループ
while (true) {
if (gpio_get(PIN_CLK) == 1) {
gpio_put(LED_PIN, 1);
} else {
gpio_put(LED_PIN, 0);
}
}
}
↓ GP5に繋げた緑色のLEDは、ロータリーエンコーダーを回した時に呼ばれる関数 lxs_gpio_callback() の実行中だけ点灯。立ち上がり、立ち下がりの割り込みをLEDの点灯で分かる仕組み。