Ala が 2026年05月10日22時08分27秒 に編集
初版
タイトルの変更
UIAPduino タクトスイッチ押下で点灯
タグの変更
LED
PlatformIO
UIAPduino
VSCode
ch32fun
メイン画像の変更
記事種類の変更
セットアップや使用方法
Lチカの変更
ライセンスの変更
(MIT) The MIT License
本文の変更
# はじめに 本記事は [UIAPduinoでLチカ(内臓LEDと外付けLED)](https://elchika.com/article/9af19d24-6628-4378-807f-0b341d24c243/) でLED点灯まではできていることを前提とします。 > 次の拡張としてはスイッチ押下で点灯とかやってみようかなと思っています。 上記記載していた通り、拡張してみたので投稿します。 # ボタンLED ゴールとしては、ボタン(タクトスイッチ)を押している間だけLEDが光るようにします。  ## 1. 構成 * 外付けLED … D2 / PC0 - D2 / PC0 → 抵抗 → LED → GND * ボタン … D7 / PC5 - D7 / PC5 → ボタン → GND   画像出典:UIAP「UIAPduino Pro Micro CH32V003 V1.4」ピン配置図 License: Creative Commons Attribution 4.0 International https://www.uiap.jp/uiapduino/pro-micro/ch32v003/v1dot4#with-ch32fun-development-environment ボタンは D7 と GND を押したときだけつながるように内部プルアップにします。 つまり、ボタンを押していない間が HIGH、 押している間は LOW とします。 ## 2. ボタン(タクトスイッチ) について 以下を参考にしました。 [【分解】タクトスイッチの構造と使い方を徹底解説 #4](https://note.com/shingo_shirogane/n/n01f0484907a9) 左右の端子で接続が切れており、ボタンが押されることで左右の端子がつながります。 よってボタンを押した場合にのみGNDの線につながるように配置します。 ## 3. コード ```c #include "ch32fun.h" #include <stdio.h> // LEDピン定義 D2 / PC0 #define LED_PIN PC0 // ボタンピン定義: D7 / PC5 #define BUTTON_PIN PC5 int main() { SystemInit(); // GPIOを有効化 funGpioInitAll(); // LED_PINを出力に設定 funPinMode( LED_PIN, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP ); // BUTTON_PINを入力に設定 // プルアップにする funPinMode( BUTTON_PIN, GPIO_CNF_IN_PUPD ); funDigitalWrite( BUTTON_PIN, FUN_HIGH ); while(1) { // ボタンが押されているかをチェック if ( funDigitalRead( BUTTON_PIN ) == FUN_LOW ) { // D2 を HIGH に設定して LED を点灯 funDigitalWrite( LED_PIN, FUN_HIGH ); } else { // D2 を LOW に設定して LED を消灯 funDigitalWrite( LED_PIN, FUN_LOW ); } Delay_Ms( 10 ); } } ``` ## 4. コード解説 ### プルアップにする GPIO の入力モード設定としてプルアップ、プルダウンの設定が可能です。 [ch32fun のサンプル](https://github.com/cnlohr/ch32fun/blob/cfffff6d6bd9bd97d7348d044a1de145f4548072/examples_x035/timers_sync_ext_trigger/timers_sync_ext_trigger.c#L46) でも使われているように `funPinMode( <ピン>, GPIO_CFGLR_IN_PUPD )` 、 `funDigitalWrite( <ピン>, FUN_HIGH )` でプルアップ設定が可能です。 ボタンを押した場合は、 D7 / PC5 → タクトスイッチ → GND とつながり、 D7 は LOW になります。 ただし **押していないとき** は D7 はどこにもつながっていない状態となり、浮いてしまい不安定な状態となるため「何も押していないときは HIGH になる」 ようにします。 ### 1行目 ```c funPinMode(BUTTON_PIN, GPIO_CNF_IN_PUPD); ``` BUTTON_PIN を入力ピンにして、 Pull-Up / Pull-Down を使えるモードにしています。 ### 2行目 ```c funDigitalWrite( BUTTON_PIN, FUN_HIGH ); ``` BUTTON_PIN は入力であるため、この状態で `FUN_HIGH` を書き込むと「内部プルアップを有効」にできるようです。 ## 5. さらに詳細 プルアップ等の設定、関数仕様とかドキュメントがあれば知りたいのですが、基本豊富にあるサンプルコードなどを参考にしてねという感じなんですかね? 見当たらなかったので以下は理解した内容です。 ```c #define funPinMode( pin, mode ) { GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf<<(4*((pin)&0xf))))) | ((mode)<<(4*((pin)&0xf))); } #define funDigitalWrite( pin, value ) do{ GpioOf( pin )->BSHR = 1<<((!(value))*16 + ((pin) & 0xf)); }while(0) ``` それぞれ、 `CFGLR` と `BSHR` レジスタを操作しているためリファレンスマニュアルを確認します。 CH32V003 のリファレンスマニュアルがこちら。7章に GPIO の説明があります。 https://www.wch-ic.com/downloads/CH32V003RM_PDF.html ### GPIOx_CFGLR `GPIOx_CFGLR` というポートコンフィグレーションレジスタで各ピンごとに、 ``` CNFy[1:0] MODEy[1:0] ``` という4ビットで設定となります。上位2ビットで入力/出力の種類、下位2ビットで入力か出力(速度選択)かを設定しています。 先ほど1行目で設定していた `GPIO_CNF_IN_PUPD` は 0x08 の値のため Mode = 00b が **入力モード** で、CNF = 10b のときに **With pull-up and pull-down mode** となっています。  ### GPIOx_BSHR こちらは説明をみると、 **BRy** はこれらのビットに「1」を書き込むと対応する OUTDR のビットが 「0 」にクリアされます。 「0」を書き込むとなんの影響もない。 **BSy** はこれらのビットに「1」を書き込むと対応する OUTDR のビットが 「1」になります。 「0」を書き込むとなんの影響もない。  `funDigitalWrite` は `1<<((!(value))*16 + ((pin) & 0xf))` のようにして、 BSy, BRy の切り替えを行って書き込んでいるんですね。 よって、実際に何を書き込んでいるかは OUTDR をさらに次にあげる確認します。 ### GPIOx_OUTDR の ODRy ビット 2行目の `funDigitalWrite( BUTTON_PIN, FUN_HIGH );` はプルアップ/プルダウン入力モードのときに、プルアップするかプルダウンするかを選択するものになります。説明をいかに翻訳します。 ``` For output modes. (y=0-7), the data output by the port. These data can only be operated in 16-bit form. the I/O port outputs the values of these registers externally. For modes with drop-down inputs. 1: Pull-up input; 0: Pull-down input. 出力モードの場合。 (y=0-7)、ポートから出力されるデータ。これらのデータは 16ビット形式でのみ処理可能です。 I/Oポートは これらのレジスタの値を外部に出力します。 ドロップダウン入力を持つモードの場合。 1: プルアップ入力 0: プルダウン入力 ``` よって、2行目で設定している `FUN_HIGH` は 0x01 であるため、プルアップ入力を設定していることになります。  以上より、入力モード(プルアップ/プルダウンモード)の上でプルアップ入力を設定となります。 # 最後に 想像以上にch32fun で動作させる場合、 example を参考に手直しすればトライアンドエラーでもいけはしますが理解するにはレジスタの知識が要るなと思いました。 実際とりあえずサンプル参考に動かしてみてから後から何やっているのかを調べる感じになってました(本当ならちゃんと理解してから動かした方がいい気はしますが)。