В данном уроке мы попробуем с помощью библиотеки LL поработать с интерфейсом USART (Universal synchronous asynchronous receiver transmitter) контроллера STM32F4.
Модуль USART у контроллера линейки STM32F4 практически ничем не отличается от аналогичного в контроллере STM32F1, поэтому изучать нам аппаратную составляющую не придётся и инициализация происходит таким же образом.
В регистрах также почти нет изменений, лишь некоторые, о которых я вкратце сейчас расскажу.
В регистре SR бит NE (Noise error flag) изменил свою аббревиатуру на NF (Noise detected flag), сохранив при этом весь функционал
Также в регистре CR3 добавился бит ONEBIT (One sample bit method enable), который даёт возможность отключать шумовой фильтр
ONEBIT (One sample bit method enable): Бит метода выборки. Включает метод с одним битом выборки, в этом случае флаг обнаружения шума (NF) отключается
0 — метод с тремя битами выборки. Флаг обнаружения шума (NF) включен.
1 — метод с одним битом выборки. Флаг обнаружения шума (NF) отключен.
Вот и вся, в принципе разница.
Также нам значительно облегчает работу с шиной UART то, что нам не потребуется переходник на USB, ибо возможность передачи данных по USART в USB в нашей плате STM32F429I-Discovery поддерживается через ST-Link. Хотя говорят, что в старых версиях такой платы данной возможности нет, так что уточняйте, какая именно у вас плата.
С модулем USART контроллера STM32 мы также работали и с применением библиотеки LL, правда это было с серией STM32F1, но как выяснилась, данная шина у серии F1 работает точно так же и программируется тоже. Поэтому, раз уж мы так много всего знаем, то мы сразу объединим знания трёх уроков начиная с урока 161, и будем через USART не только передавать данные, но и принимать, и, мало того, используя при этом механизм прерываний.
А теперь мы смело можем перейти к проекту, который был сделан из проекта урока 209 с именем LL_SPI_ILI9341_DMA и получил новое имя — LL_USART.
Откроем наш проект в Cube MX и включим наш USART, предварительно ознакомившись со схемой
У нас включились необходимые ножки
Включим прерывания на USART1
Изменим приоритет данных прерываний на 1
Настроим также использование для USART библиотеки LL
Сгенерируем наш проект, открыв его затем в Cube IDE, затем откроем файл main.c и сначала подключим библиотеку для работы со строками, которая нам нужна будет для работы с функцией memset
1 2 |
#include "ll_spi_ili9341.h" #include "string.h" |
Объявим глобальный символьный массив и целочисленную переменную для флага приёма
1 2 3 |
uint32_t dma_spi_cnt=1; char rx_str[30]; uint8_t fl=0; |
Также добавим функцию передачи строки через USART, которую возьмём из проекта урока 209
1 2 3 4 5 6 7 8 9 10 11 12 |
//------------------------------------------------------- void USART_TX (uint8_t* dt, uint16_t sz) { uint16_t ind = 0; while (ind<sz) { while (!LL_USART_IsActiveFlag_TXE(USART1)) {} LL_USART_TransmitData8(USART1,*(uint8_t*)(dt+ind)); ind++; } } //------------------------------------------------------- |
В функции main() удалим объявление переменной j, которая нам не будет нужна
uint16_t i,j;
А переменную i сразу проинициализируем нулём
uint16_t i=0;
Объявим также символьный массив, который нужен будет для формирования строки для передачи через USART в терминальную программу
1 2 |
uint16_t i=0; char str1[30]; |
Из бесконечного цикла удалим весь пользовательский код.
Настроим цвет текста и фона, а также ориентацию экрана дисплея
1 2 3 4 5 |
TFT9341_FillScreen(TFT9341_BLACK); TFT9341_SetRotation(1); TFT9341_SetTextColor(TFT9341_YELLOW); TFT9341_SetBackColor(TFT9341_BLACK); TFT9341_SetFont(&Font24); |
Разрешим прерывания от USART1 по событию приёма байта и ошибки
1 2 3 |
TFT9341_SetFont(&Font24); LL_USART_EnableIT_RXNE(USART1); LL_USART_EnableIT_ERROR(USART1); |
После функции DMA1_Stream4_TransferComplete добавим функцию для обработки события окончания приёма байта из шины, в которой примем байт и запишем его в переменную, если это не перевод строки, то запишем его также в наш массив, проинкрементировав затем переменную позиции. А если это всё-таки перевод строки, то заполним пробелами последующие байты массива до 19-го и в 20-й запишем ноль, чтобы функциям работы со строками было понятно, что это окончание строки, обнулим счётчик и установим пользовательский флаг
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//----------------------------------------------- void USART1_RX_Callback(void) { static uint16_t cnt=0; uint8_t b = LL_USART_ReceiveData8(USART1); if(b != 0x0A) { rx_str[cnt] = b; cnt++; } else { memset(rx_str+cnt-1,' ',20-cnt-1); rx_str[20] = 0; cnt=0; fl=1; } } //----------------------------------------------- |
Добавим на данную функцию прототип в файле stm32f4xx_it.c
1 2 |
void DMA1_Stream4_TransferComplete(void); void USART1_RX_Callback(void); |
В функции-обработчике USART1_IRQHandler в случае установленного флага приёма байта вызовем нашу функцию, в других случаях прочитаем регистр DR
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* USER CODE BEGIN USART1_IRQn 1 */ if(LL_USART_IsActiveFlag_RXNE(USART1) && LL_USART_IsEnabledIT_RXNE(USART1)) { USART1_RX_Callback(); } else { if(LL_USART_IsActiveFlag_ORE(USART1)) { (void) USART1->DR; } else if(LL_USART_IsActiveFlag_FE(USART1)) { (void) USART1->DR; } else if(LL_USART_IsActiveFlag_NE(USART1)) { (void) USART1->DR; } } |
Прошу заметить, что не смотря на то, что флаг NE в официальной документации был переименован, в библиотеке он остался со старым именем. Думаю, что это никак не повлияет на работоспособность функции определения флага.
Вернёмся в функцию main() файла main.c и в бесконечном цикле в случае установленного пользовательского флага отобразим на дисплее принятый текст и сбросим флаг. Мы не будем ждать установленного флага, так как у нас циклы будут следовать друг за другом довольно часто
1 2 3 4 5 6 |
/* USER CODE BEGIN 3 */ if(fl) { TFT9341_String(10,100,rx_str); fl=0; } |
Затем передадим строку со счётчиком, который будет считать от 0 до 1023 циклически и добавим задержку в 100 милисекунд
1 2 3 4 5 6 7 |
fl=0; } if(i>1023) i=0; sprintf(str1,"String %04d\r\n",i); USART_TX((uint8_t*)str1,13); LL_mDelay(100); i++; |
Запустим терминальную программу, настроим также и передачу данных оттуда, благо, это делать мы давно умеем, соберём код, прошьём контроллер и увидим, что в терминальную программу благополучно приходят строки от нашего контроллера
Попробуем также передать из терминальной программы строку нашем контроллеру
На дисплее нашей платы строка успешно отобразилась
Попробуем передать строку покороче, чтобы проверить, что лишние символы на дисплее успешно забиваются пробелами
Всё отлично работает
Итак, на данном уроке, мы, объединив наши знания предыдущих уроков, смогли по шине USART контроллера STM32F1 передать данные, а также их принять, используя при этом механизм прерываний, с применением библиотеки LL.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь STM32F429I-DISCO
Смотреть ВИДЕОУРОК (нажмите на картинку)
Доброго здоровья всем!Всё отлично и понятно почти всё.Может подскажите где найти информацию как работать с компараторами микроконтроллера stm32.Не могу не где найти.
STM32F429I-DISC0 – отладочная плата. Нет VCP.Как можно установить VCP