GPIO IN, OUT (ESP-IDF 環境 + C 言語)
プログラムの書き方
LED やスイッチを使う上でよく使われる関数については, ESP-IDF Programming Guide の API Reference の GPIO & RTC GPIO を参照して欲しい.
GPIO (IN) : L チカ
電子工作における hello world と言える L チカを実行する. まずはサンプルファイルをコピーし, 実行してみる.
$ cd ~/esp $ cp -r esp-idf/examples/get-started/blink . $ cd blink
サンプルでは, config menu で点灯させる LED の GPIO を指定するようになっている. その設定は, main/Kconfig.projbuild に書かれており, デフォルトで GPIO 5 が設定されている.
$ lv main/Kconfig.projbuild
menu "Example Configuration"
config BLINK_GPIO
int "Blink GPIO number"
range 0 34
default 5
help
GPIO number (IOxx) to blink on and off.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.
GPIOs 35-39 are input-only so cannot be used as outputs.
endmenu
main プログラムでは congig menu で設定された LED GPIO が CONFIG_BLINK_GPIO に 代入され, それがマクロで BLINK_GPIO に置き換えられている. プログラム中では BLINK_GPIO のレベルを 0, 1 に変化させることで LED の点灯を実現している.
$ lv main/blink.c
...(中略)....
#define BLINK_GPIO CONFIG_BLINK_GPIO
...(中略)....
printf("Turning off the LED\n");
gpio_set_level(BLINK_GPIO, 0);
...(後略)....
ビルド
make コマンドを実行する. プロジェクトのディレクトリで最初に make コマンドを実行した時には 以下の例のように config menu が表示される.
- Serial flasher config を選択し, Default serial port にデバイス名 (ここでは /dev/ttyUSB0) を入力する.

- Example Configuration を選択し, Blink GPIO number に LED の GPIO の番号 (ここでは 13) を入力する.

マイコンへの書き込み
マイコンに書き込むのは make flash コマンド, 標準出力を表示するのは make monitor コマンドである. まとめて make flash monitor としても良い.
$ make flash monitor Turning off the LED Turning on the LED Turning off the LED Turning on the LED Turning off the LED ....
上記のように標準出力に LED の点灯・消灯のメッセージが表示され, さらに実際に実習ボードの LED の 1 つが点灯することが確認できるであろう.
プログラムの修正と実行
デフォルトの blink.c は make menuconfig で設定された GPIO の LED を点灯させるもの となっている. それを修正して 1 つ目の LED (GPIO 13) を点灯させるプログラムに修正する.
$ cp main/blink.c main/blink.c.bk $ vi main/blink.c
エディタを使って以下のように書く.
1 #include <stdio.h>
2 #include "freertos/FreeRTOS.h"
3 #include "freertos/task.h"
4 #include "driver/gpio.h"
5
6 #define BLINK_GPIO 13
7
8 void app_main(void)
9 {
10 /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
11 gpio_pad_select_gpio(BLINK_GPIO);
12
13 /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
14 gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
15
16 while(1) {
17 /* Blink off (output low) */
18 printf("Turning off the LED\n");
19 gpio_set_level(BLINK_GPIO, 0);
20 vTaskDelay(1000 / portTICK_PERIOD_MS);
21
22 /* Blink on (output high) */
23 printf("Turning on the LED\n");
24 gpio_set_level(BLINK_GPIO, 1);
25 vTaskDelay(1000 / portTICK_PERIOD_MS);
26 }
27 }
- 4 行目: GPIO を利用する場合に driver/gpio.h を include する必要がある.
- 6 行目: LED の接続される GPIO を指定
- 11 行目: ピンの役割を GPIO モードに変更
- 14 行目: LED の接続されているピンを出力に設定.
- 19, 24 行目: LED の点灯・消灯. gpio_set_level の第二引数が 0 なら電圧を 0V に (= 消灯)
- 20, 25 行目: 1 秒 = 1000 ミリ秒だけ動作を止める. ESP-IDF 環境では, 待ち時間 (単位 ミリ秒) を portTICK_PERIOD_MS (FreeRTOS の割込み周期)で割り算した結果を vTaskDelay の引数に与える必要がある.
編集したのち, コンパイルとマイコンへの書き込みを行う. make flash すると LED の点滅が確認できるはずである.
$ make $ make flash
全ての LED を点灯させる.
LED を 1 つしか点灯できない. 実習ボードの全ての LED を点灯させてみよう. 実習基板には 8 つの LED があるが, それらの GPIO は 32,33,25,26,27,14,12,13 である.
1 #include <stdio.h>
2 #include "freertos/FreeRTOS.h"
3 #include "freertos/task.h"
4 #include "driver/gpio.h"
5
6 #define NUM 8
7
8 void app_main(void)
9 {
10 int BLINK_GPIO[NUM] = {32,33,25,26,27,14,12,13};
11 int i;
12
13 /* 初期化 */
14 for (i = 0; i < NUM; i++){
15 /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
16 gpio_pad_select_gpio(BLINK_GPIO[i]);
17
18 /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
19 gpio_set_direction(BLINK_GPIO[i], GPIO_MODE_OUTPUT);
20 }
21
22 while(1) {
23 for (i = 0; i < NUM; i++){
24 /* Blink off (output low) */
25 gpio_set_level(BLINK_GPIO[i], 0);
26 vTaskDelay(1000 / portTICK_PERIOD_MS);
27
28 /* Blink on (output high) */
29 gpio_set_level(BLINK_GPIO[i], 1);
30 vTaskDelay(1000 / portTICK_PERIOD_MS);
31 }
32 }
33 }
編集したのち, コンパイルとマイコンへの書き込みを行う.
$ make $ make flash

上記の操作で全ての LED が点灯することが確認できたと思う. 念のために, gpio_pad_select_gpio が必要であることを確認してみる. gpio_pad_select_gpio をコメントアウトして実行するとどうなるであろうか?
1 #include <stdio.h>
2 #include "freertos/FreeRTOS.h"
3 #include "freertos/task.h"
4 #include "driver/gpio.h"
5
6 #define NUM 8
7
8 void app_main(void)
9 {
10 int BLINK_GPIO[NUM] = {32,33,25,26,27,14,12,13};
11 int i;
12
13 /* 初期化 */
14 for (i = 0; i < NUM; i++){
15 /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
16// gpio_pad_select_gpio(BLINK_GPIO[i]);
17
18 /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
19 gpio_set_direction(BLINK_GPIO[i], GPIO_MODE_OUTPUT);
20 }
21
22 while(1) {
23 for (i = 0; i < NUM; i++){
24 /* Blink off (output low) */
25 gpio_set_level(BLINK_GPIO[i], 0);
26 vTaskDelay(1000 / portTICK_PERIOD_MS);
27
28 /* Blink on (output high) */
29 gpio_set_level(BLINK_GPIO[i], 1);
30 vTaskDelay(1000 / portTICK_PERIOD_MS);
31 }
32 }
33 }
改めてコンパイルとマイコンへの書き込みを行う.
$ make $ make flash

そうすると, LED が 5 個しか点灯しないことが確認できるはずである. ESP32 の Pin Description (データシート の 2.2 節を参照) を見ると, 各ピンに様々な役割があることがわかる. 上記のように, 初期化プロセスで各ピンを GPIO モードに切り替えることを忘れる, 思った通りの動作をさせられないことになる.
GPIO (OUT) : スイッチ
スイッチと LED を連動させたプログラムを書く. 以下のようなプログラムを書くと, SW4 を ON/OFF した時に LED1 が点灯/消灯する.
1 #include <stdio.h>
2 #include "freertos/FreeRTOS.h"
3 #include "freertos/task.h"
4 #include "driver/gpio.h"
5
6 #define buttonPin 19
7 #define ledPin 13
8
9 void app_main(void)
10 {
11 /* LED の初期化 */
12 gpio_pad_select_gpio(ledPin);
13 gpio_set_direction(ledPin, GPIO_MODE_OUTPUT);
14
15 /* スイッチの初期化*/
16 gpio_pad_select_gpio(buttonPin);
17 gpio_set_direction(buttonPin, GPIO_MODE_INPUT);
18 gpio_set_pull_mode(buttonPin, GPIO_PULLUP_ONLY); //PULLUP が必要
19
20 while(1) {
21 int buttonState = gpio_get_level(buttonPin);
22
23 if (buttonState == 1) {
24 gpio_set_level(ledPin, 1); // turn LED on:
25 } else {
26 gpio_set_level(ledPin, 0); // turn LED off:
27 }
28 }
29 }
- 6 行目: スイッチの接続される GPIO を指定.
- 16~18 行目: スイッチの接続されているピンを入力に設定
- GPIO をインプットモードにする. PULLUP しないといけない.
- 21 行目: スイッチの入力値を取得
- 23-24 行目: スイッチが入っていたら LED を ON に.
- 25~26 行目: スイッチが入ってなければ LED を OFF に.