GPIO IN, OUT (ESP-IDF 環境 + C 言語)

プログラムの書き方

GPIO で使われる関数については, ESP-IDF Programming GuideAPI ReferenceGPIO & RTC GPIO を参照して欲しい.

以下に最低限使う必要のある関数を挙げる.

//ヘッダファイルの読み込み
#include "driver/gpio.h" 

// ピン番号の型 gpio_num_t 
gpio_num_t  pin = 13;

// ピンのリセット
gpio_reset_pin( pin );

// ピンの入力の指定
gpio_set_direction(pin, GPIO_MODE_INPUT);
gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY); //内部的にプルアップ

// ピンの入力値. 戻り値は 0 or 1
gpio_get_level(pin);

// ピンの出力の指定
gpio_set_direction(pin, GPIO_MODE_OUTPUT);

// ピンの出力.第 2 引数は 0 or 1
gpio_set_level(pin, 0);
gpio_set_level(pin, 1);

Lチカの例題

電子工作における hello world と言える L チカを実行する.

プロジェクトの準備

サンプルプロジェクトをコピーする.

$ cd ~/esp

$ cp -r esp-idf/examples/get-started/sample_project ./blink

$ cd blink

プログラムの作成

このサンプルプロジェクトのメインファイルは main ディレクトリ以下の main.c であるので, そのファイルを編集する.エディタとして,vi, emacs, gedit, code などが使える.

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

void app_main(void)
{
   // LED ピン
   gpio_num_t pin = 13;                       // ピン番号
   gpio_reset_pin(pin);                       // ピンのリセット
   gpio_set_direction(pin, GPIO_MODE_OUTPUT); // ピンを出力で利用

   while(1) {
      gpio_set_level(pin, 0);                 // ピンの値を0に
      vTaskDelay(1000 / portTICK_PERIOD_MS);  // 1 秒の待ち

      gpio_set_level(pin, 1);                 // ピンの値を1に
      vTaskDelay(1000 / portTICK_PERIOD_MS);  // 1 秒の待ち
   }
}

なお,上記プログラム中の vTaskDelay(1000 / portTICK_PERIOD_MS); の行は, 1 秒 = 1000 ミリ秒だけ動作を止めるという命令である. ESP-IDF 環境では, 待ち時間 (単位 ミリ秒) を portTICK_PERIOD_MS (FreeRTOS の割込み周期)で割り算した結果を vTaskDelay の引数に与える必要がある.

1 番目の LED が定期的に点灯・消灯することを確認されたい.

ビルドとマイコンへの書き込み

idf.py build コマンドを実行する.

$ idf.py build

マイコンに書き込むのは idf.py flash コマンド, 標準出力を表示するのは idf.py monitor コマンドである. まとめて idf.py flash monitor としても良い.

$ idf.py flash monitor

実習ボードの左端の LED が点灯することが確認できるであろう.

monitor を終了するのは Ctrl-] である.

レポート課題 1: GPIO

実施方法

[1] 目的:

  • GPIO のプログラムにおいて,入力 (gpio_get_level 関数) で得られる数字とGPIO の出力 (gpio_set_level 関数) の引数で与える数字が,LED およびスイッチの挙動とどのような関係になっているか理解する.さらに,それらの数字が回路図とどのような関係になっているか理解する.

[2] 使用する機器:

  • マイコンボード
  • LED (マイコンボード上の LED を利用.左端の LED 以外を使うこと)
  • タクトスイッチ

[3] 機器の接続方法

  • タクトスイッチをケーブルで接続すること
    • 黒色のケーブル (GND) を GND のピンに接続
    • 赤色のケーブル (VCC) を適当なピンに接続 → 実験ボードのピン配置参照

[3] プログラム:

  • 以下のプログラムの穴埋め (4 箇所, <穴1>~<穴4>) を行い,「ボタンを押すと LED が点灯する」プログラムを完成させること.

    #include <stdio.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "driver/gpio.h"
    
    void app_main(void)
    {
       // LED ピン
       gpio_num_t pin = <穴1>;                     // ピン番号
       gpio_reset_pin(pin);                        // ピンのリセット
       gpio_set_direction(pin, GPIO_MODE_OUTPUT);  // ピンを出力で利用
    
       //スイッチピン
       gpio_num_t pin2 = <穴2>;                    // ピン番号
       gpio_reset_pin(pin2);                       // ピンのリセット
       <穴3>;                                      // ピンを入力で利用
       <穴4>;                                      // 入力で使うピンを内部的にプルアップ
    
       while(1) {
          if (gpio_get_level(pin2) == <穴5>)      //スイッチの ON/OFF の判断
          {
             gpio_set_level(pin, 0);                 //ピンの値を0に
          }
          else if (gpio_get_level(pin2) == <穴6>) //スイッチの ON/OFF の判断
          {
             gpio_set_level(pin, 1);                 //ピンの値を1に
          }
          vTaskDelay(1000 / portTICK_PERIOD_MS);  //1秒の待ち
       }
    }

レポートのまとめ方

以下の内容を記述すること.

  • 実験の目的
  • 実験方法
    • 利用する機器の一覧
    • 機器の接続方法
      • タクトスイッチをマイコンボードのどのピンに接続したか明記すること
  • 実験設定
    • プログラムの穴埋め部に何を入れたかまとめて示すこと.以下のような表形式で示すこと(表には表番号を付すこと).
      • 書き方の例:「作成したプログラムは実験手順書に書かれているサンプルプログラムを元にした.サンプルプログラム中の<穴1>~<穴6>に入れた数字を表 X に示す.」
      • プログラム全部をレポートで示す必要はありません.

穴1穴2穴3穴4穴5穴6
........................

  • 実験結果
    • 作成したプログラムを実行したときに,何が起きたか説明すること.但し,以下に示すような表を作成し,その表を引用する形で説明文を書くこと.
      • スイッチのボタンを押したとき・押していないときに,LED が点灯・消灯のどちらになったかを示すこと.
      • スイッチのボタンを押したとき・押していないときに,gpio_get_level の戻り値がどうなっていたかを示すこと.
      • LED が点灯・消灯するときに,gpio_set_level の引数をどうしていたかを示すこと.

スイッチgpio_get_level の戻り値LEDgpio_set_levelの引数
ON0 or 1X 番目の LED が点灯 or 消灯0 or 1
OFF0 or 1X 番目の LED が点灯or 消灯0 or 1

  • 議論
    • おそらく実験結果は,スイッチの ON/OFF と gpio_get_level の戻り値 (0 or 1) との関係が直感的でないと思われる.その理由を以下の回路図を元に議論をしなさい.なお,回路図はレポートに書いて図番号を付し,その図番号を引用する形で説明文を書くこと.なお,今回スイッチに使うピンは PULL_UP 抵抗内蔵であるので,回路図的にはマイコンの中に抵抗が存在する形となる.
      • PULL_UP 回路 (PULL_UP 抵抗) の役割は?
      • なぜスイッチ ON のときに gpio_get_level の戻り値 が (0 or 1) なのか?
      • なぜスイッチ OFF のときに gpio_get_level の戻り値 が (0 or 1) なのか?