ESP32 Урок 46. ULP. GPIO. Подключаем кнопку



Продолжаем работу с сопроцессором ULP (ultra-low-power processor или процессор со сверхнизким потреблением).

И также мы продолжаем работать с портом GPIO. Только на данном уроке мы попытаемся получить значение уровня на ножке GPIO, настроенной на вход. Мы оставим и светодиод, который мы на прошлом уроке подключили к ножке GPIO4 катодом и а анодом к питанию 3,3 вольта, а также воспользуемся кнопкой, уже присутствующей на плате и подключенной к GPIO0. Поэтому схема наша не изменится

 

 

Посмотрим, как на схеме подключена кнопка к GPIO0

 

 

Мы видим, что ножка GPIO0 постоянно подтянута к питанию, а кнопка при нажатии притягивает её к общему проводу. Поэтому при написании кода нужно об этом помнить.

Проект мы создадим на основе проекта прошлого урока с именем ULP_FSM_BLINK и назовём его ULP_FSM_BUTTON.

Откроем проект в Espressif IDE и для начала в файле main.c в функции init_ulp_program изменим имя ножки для светодиода, а также объявим ещё ножку, к которой подключена кнопка

 

gpio_num_t gpio_led_num = GPIO_NUM_4, gpio_button_num = GPIO_NUM_0;

 

Здесь также, соответственно, изменим имя

 

rtc_gpio_init(gpio_led_num);
rtc_gpio_set_direction(gpio_led_num, RTC_GPIO_MODE_OUTPUT_ONLY);

 

Настроим ножку кнопки

 

 

Перейдём в файл ulp_assembly_source_file.S и изменим время задержки на 10 милисекунд, чтобы при погружении в сон у нас сразу светодиод потухал

 

move r3, stackEnd

//delay(10 ms)
move r0, 10

 

Изменение уровня и следующую задержку убираем, чтобы светодиод у нас не горел перед тем, как мы начнём отслеживать уровень на ножке

 

GPIO_LOW

//delay(1 sec)
move r0, 1000
psr
jump delay_ms

 

Добавим метку

 

 

Добавим ещё задержку на 10 милисекунд, чтобы наши циклы не повторялись слишком часто

 

 

Теперь нам надо будет прочитать уровень ножки GPIO.

Для этого мы воспользуемся макросом READ_RTC_REG

 

 

Данный макрос считывает до 16 бит из rtc_reg[low_bit + bit_width — 1 : low_bit] в R0.

То есть в регистр r0 записывается число из регистрового поля, объявленного в параметре 2 шириной, объявленной в параметре 3 из регистра, объявленного в параметре 1.

Прочитаем 11 бит из поля RTCIO_RTC_GPIO_IN_NEXT регистра RTCIO_RTC_GPIO_IN_REG

 

 

 

11 бит мы читаем, так как ножке GPIO0 соответствует ножка 11 в RTC

 

 

Добавим переход

 

 

 

В случае единицы идём на метку, так как единица у нас будет при высоком уровне ножки, значит кнопка притянута к шине питания (не нажата).

При нажатии у нас кнопка притянется к земле и мы выйдем из цикла, так как наше условие будет ложным. В данном случае мы зажжём светодиод, подождём секунду и погасим его

 

 

А далее по коду у нас 4-секундная задержка и возврат из спящего режима (пробуждение).

Соберём код, прошьём контроллер, включим терминал.

Мы ушли в спящий режим и больше из него не выходим

 

 

Нажмём и отпустим кнопку и наш светодиод при нажатии кнопки тут же зажжётся

 

 

Через секунду светодиод погаснет и ещё через четыре секунды мы вернемся из спящего режима, после чего опять уйдём в него

 

 

Если мы опять нажмём кнопку, то цикл повторится.

Интересно было бы после отслеживания нажатия отследить затем и отжатие. Но в этом ничего сложного нет и урок не об этом. Есть у меня задумка куда интереснее.

Раз уж у нас так быстро получилось отследить уровень на ножке, то давайте реализуем вот какую идею. А вдруг у нас светодиод будет подключен не к GPIO4, а также кнопка не к GPIO0. Нам придётся тогда менять номера ножек не только в их объявлении, но также смотреть в таблицу и просчитывать, какие ножки соответствует другим ножкам в RTC. Хотелось бы как-то это всё автоматизировать, чтобы нам нужно было бы поменять номера ножек только в их объявлении.

Оказалась эта задача не такая уж и лёгкая. В сети очень мало информации на этот счёт. Самое тяжёлое то, что макросы READ_RTC_REG и WRITE_RTC_REG не умеют работать ни с переменными, ни с регистрами общего назначения, а работают только с константами. Но реализовать идею всё же удалось.

Давайте сначала вычислим программно соответствие ножкам GPIO ножек RTC GPIO.

 

 

Возвращаемся в функцию init_ulp_program файла main.c и помощью специальной функции найдём номер ножки для каждой из двух наших ножек в RTC

 

 

Так как наши регистровые поля RTC_GPIO_OUT_DATA_W1TC_SRTC_GPIO_OUT_DATA_W1TS_S и RTC_GPIO_IN_NEXT_S в соответствующих им регистрах все располагаются с бита 14, то объявим переменную для номера бита, соответствующую пока что ножке светодиода

 

 

Макрос WRITE_RTC_REG на самом деле использует команду REG_WR

 

Перейдём в файл ulp_assembly_source_file.S, объявим после секции bss секцию data и добавим туда метку с шаблоном команды записи в регистр, который устанавливает уровни ножек, установив высокий уровень в ножку под номером 0. Только после команды не забываем добавить команду возврата по адресу вызова

 

 

Теперь наша задача вместо +0 записать другое значение.

Идём обратно в функцию init_ulp_program файла main.c и, используя описание команды а также операцию сдвигов, установим соответствующий бит в команде

 

 

В файле ulp_assembly_source_file.S добавим также команду записи в регистр сброса уровня ножек, также команду считывания поля регистра

 

 

Возвращаемся опять в функцию init_ulp_program файла main.c и также занесём значение нужного бита и во вторую команду записи регистра

 

 

Также вычислим номер бита для чтения ножки и занесём его в команду чтения регистра

 

 

В файле ulp_assembly_source_file.S теперь можем удалить макросы установки уровней на ножке

 

.macro GPIO_LOW
WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + 10, 1, 1)
.endm

.macro GPIO_HIGH
WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + 10, 1, 1)
.endm

 

Удалим вызов макроса GPIO_HIGH в двух местах кода и вместо этого в этих местах вызовем наши новые команды

 

  psr
  jump set_led_pin

 

А вместо вызова макроса GPIO_LOW вызовем также соответствующую команду

 

  psr
  jump clear_led_pin

 

Вместо строки

 

READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + 11, 1)

 

вызовем также соответствующую команду

 

  psr
  jump get_button_pin

 

Соберём код, прошьём контроллер, чтобы убедиться, что у нас также всё работает.

Давайте теперь проверим, что у нас при изменении ножек будет по-прежнему всё работать как надо.

Перебросим провод с ножки GPIO4 на ножку GPIO13

 

 

Изменим номер ножке в функции init_ulp_program файла main.c

 

gpio_num_t gpio_led_num = GPIO_NUM_13, gpio_button_num = GPIO_NUM_0;

 

Соберём код, прошьём контроллер и убедимся, что программа наша также успешно работает.

Теперь подключим внешнюю кнопку к GPIO4, соблюдая ту же схему, как и подключена внутренняя кнопка, то есть предварительно подключив ножку GPIO4 к шине питания через резистор 10 килоом

 

 

Изменим номер в объявлении

 

gpio_num_t gpio_led_num = GPIO_NUM_13, gpio_button_num = GPIO_NUM_4;

Соберём код, прошьём контроллер и проверим работоспособность нашего кода

 

 

Итак, на данном уроке нам удалось при помощи сопроцессора ULP поработать с ножкой порта GPIO, настроенной на вход, тем самым отследив уровень на ней, изменяемый с помощью кнопки, а также в ходе написания кода мы научились вносить изменения в команды.

Всем спасибо за внимание!

 

Данная статья в Дзен.

 

 

Предыдущий урок Программирование МК ESP32 Следующий урок

 

Исходный код

 

 

Недорогие отладочные платы ESP32 можно купить здесь Недорогие отладочные платы ESP32

Недорогие отладочные платы ESP32/ESP32-C3/ESP32-S3 можно купить здесь Недорогие отладочные платы ESP32

Логический анализатор 16 каналов можно приобрести здесь

 

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

ESP32 ULP. GPIO. Подключаем кнопку

 

Смотреть ВИДЕОУРОК в Дзен (нажмите на картинку)

ESP32 ULP. GPIO. Подключаем кнопку

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*