STM Урок 161. LL. USART. Передача данных. Часть 2
В предыдущей части нашего занятия мы познакомились с блок-схемой шины USART в контроллере STM32F1, а также познакомились с регистрами данной шины и с их битами по-отдельности.
Думаю, на этой ноте можно уже смело переходить к практической части нашего урока. Работать на данном уроке с шиной USART мы будем пока только на передачу, без всяких прерываний и DMA.
Начнем со схемы. Контроллер у нас будет STM32F103C8T6, расположенный на недорогой отладочной плате. Также для мониторинга мы подключим к нему индикатор с драйвером MAX7219, которым мы также постоянно пользуемся. Подключим мы его к шине SPI2, ножки мы увидим, когда будем настраивать шину в Cube MX

Для работы с интерфейсом USART мы подключим переходник USB-TTL к шине USART1, не забывая, что ножка RX переходника подключается к ножке TX контроллера, а ножка TX, наоборот, — к RX

Также для оценки процесса обмена подключим к шине USART логический анализатор

Подключим к ПК, анализатор, переходник и программатор

Перейдём к проекту. Создадим новый проект в Cube MX и выберем наш контроллер

Выберем программатор

Подключим кварцевый резонатор

Произведём настройки тактирования в Clock Configuration
Включим USART1 для работы в асинхронном режиме, настройки все оставим по умолчанию

Посмотрим, какие ножки у нас включились для шины USART1

Для работы с драйвером индикатора включим шину SPI2 произведём её некоторые настройки

Посмотрим, какие ножки контроллера работают с шиной SPI2, а также включим ещё одну на выход для линии SS

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

Далее перейдём в раздел Project Manager и задействуем на всё библиотеку LL
Придумаем имя нашему проекту и выберем среду программирования

Соберём проект и откроем его в Keil. Файлы для работы с драйвером индикатора max7219.c и max7219.h возьмём, например из проекта прошлого урока LL_SPI_MASTER_DMA и скопируем их в соответствующие папки нового проекта.
Подключим файл max7219.c к дереву проекта, настроим программатор на автоперезагрузку и уберём оптимизацию.
Подключим библиотеку для драйвера индикатора, а также ещё одну стандартную библиотеку, в файле main.c
|
1 2 3 |
/* USER CODE BEGIN Includes */ #include <stdio.h> #include "max7219.h" |
А теперь в соответствии с традицией посмотрим, как нам проектогенератор сгенерировал инициализацию шины USART1.
Для этого зайдём в тело функции MX_SPI2_Init и посмотрим, что там происходит.
Как обычно, сначала включается тактирование, также настраиваются ножки шины, а затем данными заполняется структура USART_InitStruct, поля которой затем используется для настройки битов тех или иных регистров шины.
Далее уже вызывается более низкоуровневая функция LL_USART_Init, параметрами которой служат USART1 и вышеназванная структура.
Проследуем в тело данной функции, в которой, как обычно, сначала идёт проверка наличия параметров.
В условие включения 9-битного режима передачи мы не попадаем, а попадаем в ELSE. где сначала отключаются биты M, PCE, PS, TE и RE регистра CR1 с помощью второго параметра макроса MODIFY_REG, а в третьем параметре мы настраиваем биты с помощью полей нашей переданной структуры. В нашем случае включатся только биты TE и RE, так как мы включаем шину и на передачу и на приём, хотя приёмом пользоваться пока не будем.
Далее с помощью функции LL_USART_SetStopBitsLength настраивается количество стоповых бит. Так как у нас 1 стоповый бит, то у нас соответствующее битовое поле STOP регистра CR2 будет нулевое.
Затем с помощью функции LL_USART_SetHWFlowCtrl настраиваются биты RTSE и CTSE регистра CR3, отвечающие за управление аппаратным потоком, а так как мы им не будем управлять, то данные биты просто сбросятся.
Затем идёт настройка скорости обмена по шине.
Сначала с помощью функции LL_RCC_GetSystemClocksFreq заполняются поля структуры rcc_clocks типа LL_RCC_ClocksTypeDef, в которые заносятся частоты тактирования различных видов периферии контроллера. Так как у нас включен USART1, то нас будет интересовать поле PCLK2_Frequency, которое заполнится значением частоты PCLK2. Значение данного поля затем присваивается переменной periphclk, которой мы затем и пользуемся в расчётах делителя. Значение данной переменной затем передаётся в качестве параметра функции LL_USART_SetBaudRate, которой в качестве третьего параметра также передаётся и значение битрейта, которое нам желательно получить.
Войдём в тело этой функции и посмотрим, как настраивается битрейт.
Здесь регистру BRR присваивается возвращённое значение ещё одной функции (а вернее макроса) __LL_USART_DIV_SAMPLING16, преобразованный в 16-битное значение. В данную функцию передаются те же параметры.
Здесь стоит задача — получить значение делителя — его целую и дробную часть и уложить в регистр BRR.
Делитель рассчитывается по той же формуле, только для этого надо его из неё выразить

Вот этим и занимается наш макрос. Только разбирать, как здесь всё происходит мы не будем, так как здесь используется ещё ряд вспомогательных макросов, чтобы избежать работы с плавающей точкой.
На этом наша функция LL_USART_Init заканчивается, поэтому вернёмся в функцию MX_USART1_UART_Init, в которой дальше с помощью функции LL_USART_ConfigAsyncMode сбрасываются биты LINEN и CLKEN в регистре CR2, а также сбрасываются биты SCEN, IREN и HDSEL, назначение которых мы теперь уже знаем.
Затем при помощи функции LL_USART_Enable устанавливается бит UE регистра CR1, который включит нашу шину.
На этом инициализация закончена. Можно приступать к написанию кода.
Объявим глобальный строковый массив
|
1 2 |
/* USER CODE BEGIN PV */ char str1[30]; |
В функции main() произведём инициализацию драйвера индикатора, проверим его, выведя на него число, подождём 2 секунды и очистим индикатор
|
1 2 3 4 5 6 7 8 |
/* USER CODE BEGIN 2 */ LL_mDelay(100); LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_12); LL_SPI_Enable(SPI2); Init_7219(); Number_7219(87654321); LL_mDelay(2000); Clear_7219(); |
Добавим функцию. которая будет заниматься передачей в шину USART байтов в определённом количестве
|
1 2 3 4 |
/* USER CODE BEGIN 0 */ void USART_TX (uint8_t* dt, uint16_t sz) { } |
Займёмся телом функции. Добавим целочисленную переменную для перемещения указателя по массиву
|
1 2 3 |
void USART_TX (uint8_t* dt, uint16_t sz) { uint16_t ind = 0; |
Добавим цикл, в котором будем следить за окончанием массива
|
1 2 3 4 |
uint16_t ind = 0; while (ind<sz) { } |
В данном цикле дождёмся установки флага TXE в регистре SR
|
1 2 3 |
while (ind<sz) { while (!LL_USART_IsActiveFlag_TXE(USART1)) {} |
Запишем передаваемый байт в регистр DR, тем самым шина получит команду передавать данные и затем увеличим индекс
|
1 2 3 |
while (!LL_USART_IsActiveFlag_TXE(USART1)) {} LL_USART_TransmitData8(USART1,*(uint8_t*)(dt+ind)); ind++; |
Вот, в принципе, и вся функция.
Вернёмся в функцию main() и добавим переменную для счёта
|
1 2 |
/* USER CODE BEGIN 1 */ uint16_t i=0; |
В бесконечном цикле сначала сбросим счётчик по достижению какого-нибудь порога
|
1 2 |
/* USER CODE BEGIN 3 */ if(i>1023) i=0; |
Сформируем строку со значением счётчика и передадим её в шину USART
|
1 2 3 |
if(i>1023) i=0; sprintf(str1,"String %04drn",i); USART_TX((uint8_t*)str1,13); |
Отобразим значение счётчика на индикаторе, немного подождём и увеличим значение счётчика на 1
|
1 2 3 4 |
USART_TX((uint8_t*)str1,13); NumberR_7219(i); LL_mDelay(100); i++; |
Вот и весь наш код. Зная теорию, намного легче его писать.
Соберём код, прошьём контроллер. Посмотрим сначала результат работы кода на светодиодном индикаторе

Индикатор исправно отсчитывает циферки.
Далее настроим терминальную программу, и посмотрим, как приходят строки в ПК

Также давайте посмотрим, как отображается трафик в программе логического анализа. Для этого включим 2 канала. Затем добавим следующий анализатор

Настроим анализатор

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

Установим триггер на канал 0

Вот так передаётся наша строка
Также мы видим, что передача байтов идёт непрерывно, без каких-либо пропусков
Итак, на данном уроке мы изучили подробно аппаратную реализацию шины USART в контроллере STM32, и, используя библиотеку LL закрепили свои знания на практике.
Всем спасибо за внимание!
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Индикатор светодиодный семиразрядный с драйвером MAX7219
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)







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