ESP8266 Урок 20. FreeRTOS. Переходник для LCD 20×4

 

 

 

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

А на данном уроке мы, используя данную операционную систему, попробуем подключить к нашему контроллеру символьный дисплей разрешением в 4 строки по 20 символов с использованием шины I2C через специальный переходник.

С данным переходником мы знакомы, мы его уже подключали в уроке 10, а также смогли переопределить ножки SDA и SCL в уроке 18.

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

Схему оставим с переопределёнными контактами из урока 18, хотя бы для того, чтобы не мигал постоянно при обмене по I2C светодиод

 

 

Проект за основу мы возьмём из прошлого урока с именем UART_TX_RTOS и назовём его I2C_LCD2004_RTOS.

Откроем наш проект в Eclipse и начнём добавлять в проект файлы для работы с переходником.

Чтобы нам полностью не писать данные файлы, добавим их из проекта урока 18 с именем I2C_LCD2004_REMAP. Также мы, благодаря тому, что будем эти файлы изменять, заодно и узнаем их отличие для операционной системы. Это файлы с именами i2c_user.h, lcd.h, i2c_user.c и lcd.c. Скопируем их в соответствующие папки нового проекта inc и src.

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

Начнем с файла i2c_user.h.

Первым делом удалим подключение данной библиотеки, так как такой в SDK RTOS нет

 

#include "osapi.h"

 

Вместо неё подключим сразу несколько

 

 

Вот эти макросы также слегка изменятся, поэтому сначала удалим их

 

#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \

gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_HIGH_SCL_LOW() \

gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_LOW_SCL_HIGH() \

gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_LOW_SCL_LOW() \

gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

 

И теперь они примут следующий вид

 

 

В файле lcd.h также удалим подключение данной библиотеки

 

#include "osapi.h"

 

А вместо неё подключим вот эту

 

 

Переходим в файл i2c_user.c, в котором удалим подключение вот этих заголовочных файлов

 

#include "osapi.h"

#include "gpio.h"

 

А подключим мы теперь здесь вот этот заголовочный файл

 

 

Удалим вот эти прототипы, с прерываниями тут будет немного по-другому

 

void ets_isr_mask(unsigned intr);

void ets_isr_unmask(unsigned intr);

 

Поэтому теперь в теле функции i2c_mas_gpio_init удалим вызов данного макроса

 

ETS_GPIO_INTR_DISABLE();

 

А макрос будет здесь такой, которым мы запретим все прерывания

 

 

Аналогично поступим и с разрешением прерываний в конце тела функции, удалив вызов вот этого макроса

 

ETS_GPIO_INTR_ENABLE();

 

А вместо него здесь будет вот такой

 

 

Переходим в файл lcd.c, в котором мы для начала удалим подключение данной библиотеки

 

#include "i2c_user.h"

 

Во всех местах использования функции ets_delay_us в качестве задержки мы будем использовать функцию os_delay_us, так что изменим её имя.

В функции LCD_ini вот эту задержку

 

os_delay_us(100000);

 

разобьём на две

 

os_delay_us(50000);

os_delay_us(50000);

 

 

так как использовать мы здесь в качестве аргумента можем только 16-разрядные величины.

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

В файле main.h подключим наши библиотеки

 

 

Перейдём в main.c, в котором в функции user_rf_cal_sector_set исправим вычитаемое, почему-то у нас здесь ошибка

 

case FLASH_SIZE_4M_MAP_256_256:

rf_cal_sec = 128 - 5;

 

Добавим ещё две глобальных переменных перемен типа структуры, так как мы создадим целых 4 задачи

 

pData dt1, dt2, dt3, dt4;

 

В функции user_init() инициализируем наш переходник и дисплей, а также подготовим заголовки строк, соответствующие номерам наших задач

 

 

Уменьшим задержку в первых двух переменных структуры, а также инициализируем остальные две переменные

 

dt1.del = 300; dt1.num_task = 1;

dt2.del = 400; dt2.num_task = 2;

dt3.del = 500; dt3.num_task = 3;

dt4.del = 600; dt4.num_task = 4;

 

Создадим ещё две задачи, также используя для них одну и ту же функцию задачи

 

 

Можно, казалось бы, уже приступить к изменению тела функции задачи, но для того, чтобы дисплей нормально работал и отзывался из всех задач и во избежание коллизий желательно передавать строки в него посредством очереди. С очередями мы знакомы, поэтому быстро сейчас этот вопрос решим.

Объявим глобальную переменную очереди

 

 

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

 

 

Первое поле структуры – номер задачи, а второе – счётчик.

 

 

Для работы с дисплеем мы создадим отдельную приёмную задачу. Добавим для неё функцию

 

 

В user_init() создадим очередь на 10 элементов типа структуры

 

 

Создадим также и задачу, у которой будет самый высокий приоритет, чтобы остальные задачи не приостановили её в какой-нибудь момент, что будет чревато искажением вывода информации на дисплей

 

 

Сначала давайте изменим код функции передающей задачи task1, так как у нас там пока вывод информации производится в UART, а нам надо в дисплей. Создадим переменную структуры очереди

 

 

Вместо переменной cnt мы здесь теперь будем использовать одноимённое поле переменной структуры, поэтому данную переменную удалим

 

uint32 cnt=0;

 

а аналогичное поле инициализируем

 

 

Инициализируем также и номер задачи в следующем поле

 

 

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

 

char str01[20];

 

Объявим переменную состояния

 

 

Вот эти строки в бесконечном цикле также удалим

 

snprintf(str01, sizeof(str01), "Task%d: %7lu", pdt->num_task, cnt);

os_printf("%s\n", str01);

 

Отправим указатель на наши данные в очередь

 

 

Если вдруг вернётся плохой статус, отчитаемся об этом в UART

 

 

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

 

xReceivedData.cnt++;

if(xReceivedData.cnt>=10000000) xReceivedData.cnt=0;

 

С функцией передачи закончили, переходим к приёмной функции vRecvTask, в которой сначала также объявим переменную статуса

 

 

Затем объявим символьный массив

 

 

Создадим переменную типа структуры очереди

 

 

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

 

 

Попытаемся забрать элемент (указатель на данные) из очереди

 

 

Таймаут здесь в 10 секунд, я думаю, этого вполне достаточно для того, чтобы дождаться данных.

И далее, если мы получили данные из очереди, то выведем на дисплей следующие строки, содержащие наши данные

 

 

От номера задачи мы отняли единицу, так как строки нумеруются с нуля, а задачи – с единицы.

В противном случае отправим в UART сообщение, что мы не дождались данных

 

 

Соберём код, прошьём контроллер и посмотрим результат работы на дисплее

 

 

Если проверить состояние в терминальной программе, то мы там ничего не увидим, то есть никакие строки туда не приходят, значит у нас всё работает правильно, все задачи выполняться успевают, все данные передаются и принимаются.

Таким образом, на данному уроке нам удалось подключить символьный дисплей с переходником к нашему контроллеру, используя при этом операционную систему реального времени FreeRTOS, что, думаю в дальнейшем нам обязательно пригодится для мониторинга за состоянием программы. Пока, конечно, функция задачи работы с дисплеем у нас не универсальная, так как мы в неё передавали не строки, а специфические данные, но, тем не менее, мы настроили работу дисплея в условиях операционной системы.

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

 

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

 

Исходный код

 

 

Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU

Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266

Дисплей LCD 20×4 можно приобрести здесь Дисплей LCD 20×4

Дисплей LCD 16×2

Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004

 

 

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

 

ESP8266 FreeRTOS. Переходник для LCD 20?4

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

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

*