Давно назревала ситуация изменить немного библиотеку. Раньше я подключал 4-х, 8-ми выводные интерфейсы к строго определённым выводам. Это накладывало некоторые ограничения на написание драйверов для дисплеев. Приходилось заниматься ногодрыжеством. Решил положить этому конец и немного модернизировать библиотеку. Изменения коснулись файлов gpio_main.* и IO_Digital.*.
В чём суть изменения? Возьмём LCD1602, подключенный по 8-ми битному интерфейсу. Его можно было подключить только так:
Или только так:
Сейчас можно будет подключить начиная с любого вывода:
Единственное условие, выводы должны идти подряд. Я не стал делать выводы вразнобой и на разные порты как это делают на Arduino. У STM достаточно периферии и возможности переназначить её на нужные выводы, чтобы обращать внимание на разные мелочи.
Теперь об изменениях. В gpio_main.h описываются две функции:
// Работа с данными с разрядностью от 2-х до 16-ти. void _DigitalWrite(GPIO_TypeDef *GPIOx_Set, uint16_t Data, uint8_t FirstPin, uint16_t PinMask); // Запись 16-ти разрядных данных uint16_t _DigitalRead(GPIO_TypeDef *GPIOx_Set, uint8_t FirstPin, uint16_t PinMask); // Чтение 16-ти разрядных данных
Первая пишет слово нужной разрядности, вторая читает слово нужной разрядности. Обоим функциям передаются:
- порт
- номер первого (младшего бита)
- маска для выделения нужных бит
В _DigitalWrite()
кроме этого передаются данные, а _DigitalRead()
возвращает 16-ти битное значение, в разрядах которого будут готовые данные для использования в программе. Если первый пин не нулевой, то считанные данные будут сдвинуты так, что мы всё равно получим их в таком виде, будто наш интерфейс начинается с нулевого пина. Так же организована и запись в порт. Запись в порт изменит только указанные пины и не затронет другие.
Реализация в gpio_main.cpp:
void _DigitalWrite(GPIO_TypeDef *GPIOx_Set, uint16_t Data, uint8_t FirstPin, uint16_t PinMask) { GPIOx_Set->ODR &= ~PinMask; // Сбрасываем выводы соответствующие пулу наших выводов GPIOx_Set->ODR |= ((Data << FirstPin) & PinMask); // Выводим } uint16_t _DigitalRead(GPIO_TypeDef *GPIOx_Set, uint8_t FirstPin, uint16_t PinMask) { return ((GPIOx_Set->IDR & PinMask) >> FirstPin); }
Как видно, ничего особенного в этих функциях нет. В IO_Digital.h тоже нет ничего особенного. Изменились немного конструкторы и добавились четыре функции:
IO_Digital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, bool IO, uint8_t PULL); // Инициализация порта IO_Digital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, bool Edge); // Инициализация порта на выход с предустановкой его в одно из состояний IO_Digital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint8_t Size, bool IO, uint8_t PULL);// Инициализировать последовательность выводов порта GPIOx, начиная с GPIO_Pin, количество Size void digitalWriteByte(uint16_t Data); uint16_t digitalReadByte(void); // Дополнительные функции, используемые в двунаправленных интерфейсах void setInput(void); // Переводит ранее проинициализированные выводы на вход void setOutput(void); // Переводит ранее проинициализированные выводы на выход
В конструкторе, инициализирующем параллельный вывод, добавилась переменная Size
, в которой нужно указать сколько бит будем использовать. В GPIO_Pin
указываем самый младший бит интерфейса.
Например, инициализация порта для третьего рисунка будет выглядеть следующим образом:
IO_Digital Parallel(GPIOB, GPIO_PIN_3, 8, Output, No_Pull); // Инициализируем 8 выводов с B3 по B10 на выход
А запись в него:
Parallel.digitalWriteByte(0x03); // Выводим 0х03 на параллельный выход
И чтение:
uint8_t Temp = (uint8_t) digitalReadByte();
Мы задали переменную Temp
8-ми битовой беззнаковой, так как в этом случае у нас считывается всего 8 бит.
Так как при написании интерфейсов дисплеев и другой периферии с параллельным интерфейсом у нас выводы могут быть настроены как на выход, так и на вход, введены ещё две функции setInput()
и setOutput()
, переинициализирующие порты. Они обращаются к известной нам функции _SetPin()
из файла gpio_main.*. Конечно, повторять полную переинициализацию выводов как-то не комильфо, но это упрощает код, независимый от ядра МК. Да и скорость переинициализации довольно высока, дисплей простаивать не будет. Если посмотреть функции в IO_Digital.*, можно увидеть, что они практически ничего не делают, просто обращаются к функциям из gpio_main.*. Сделано так только для того, чтобы работа с портами была независима от периферии GPIO МК. Так как gpio_main.* зависима от типа МК, а IO_Digital.* нет.
Расписывать как и что делается не буду. Там всё просто, и можно всё понять из комментариев. И не забывайте, защиты от дурака нет. И после каждой статьи или правки библиотек, нужно скачивать данные с Яндекс Диска.
Пример работы с параллельным интерфейсом лежит в каталоге WorkDevel\Developer\Tests MK\F407F407VExx_GPIO_Multi.
Библиотеки и примеры на Яндекс Диске и архивом WorkDevel.
Тема на форуме - перейти.
Спасибо за материалы!
Что-то я никак не мог собрать, оказалось сглупил - скачал только файлы проекта, без библиотек, так что надо быть внимательнее )
Это здорово, если мои материалы могут Вам чем то помочь.
У меня довольно большие планы по этим библиотекам.
Не хватает времени приводить их в удобоваримое состояние.