Подписаться на получение новых статей на почту:

Stm32. Протокол USART на HAL. Шаг №84

Всем привет. В этой записи мы с Вами разберем и научимся работать с протоколом UART/USART в микроконтроллерах STM32, для дальнейшей работы с Wi-Fi модулем ESP8266. Отлаживать интерфейс будем на отладочной плате STM32Discovery на базе микроконтроллера STM32F303VCT6. Запустим уже настроенный программный комплекс CooCox CoIDE и STM32CubeMX. Используем библиотеки HAL.

Рассмотрим архитектуру. Читаем мануал. В нашем проце 3 USART , 2 UART и 12 каналов DMA (Direct Memory Access). Мы также в нашем проекте будем использовать прямой доступ к памяти, т.е. использовать передачу данных в Uart ,без участия процессора.

Uart_Usart

Именно в данной модели контроллера интерфейс UART4 может обслуживаться DMA.

Uart_DMA

Данные быстро перемещаются DMA без действий ЦП. Устройства STM32F303xB / C / D / E, STM32F398xC и STM32F398xE имеют два DMA контроллера с общими 12 каналами. Каждый из которых предназначен для управления запросами доступа к памяти от одного или нескольких периферийных устройств. У каждого есть арбитр для обработки приоритета между DMA запросами. Программируемое количество передаваемых данных: до 65535.

Вернемся к UART. USART предлагает очень широкий диапазон скорости в бодах используя программируемый генератор скорости передачи. Он поддерживает синхронную, асинхронную и многопроцессорная связь. Он также поддерживает LIN, протокол Smartcard и IrDA, а также CTS и RTS для управления потока данных. Просмотрим на каких ногах сидит наш uart, в данном случае нас интересует uart 4. В таблице описание ножек находим альтернативные функции. Рис. ниже.

pin-definitions

Теперь сконфигурируем контроллер в визуальном редакторе ST Cube MX. Создаем проект выбираем плату STM32Discovery. Активируем UART4 – асинхронный режим.

 

Cube_USART

Переходим на вкладку Configuration и настаиваем параметры UART4 Parametr Settings :скорость , длина слова, четность , стоп бит а также направление данных (прием и передача):

 

Settings UART

Во вкладке NVIC Settings разрешим глобальную переменную. Если ее не включить , то после передачи данных, UART будет висеть в постоянном занятом виде, т.к. флаг занятости сбрасывается в прерывании по передачи.

interrupt_uart

Переходим на вкладку DMA и настраиваем модуль. Нажимаем Add примерно также настраиваем.

CUBE_DMA

На этом настройка в Cube закончена. Генерируем код. Далее рассмотрим работу с библиотекой HAL. Ее применение как хорошо так и плохо.

Хорошо в том что происходит уменьшение порога для работы с микроконтроллерами, за счет того что Cube генерирует конфигурацию сам. А плохо в том что при неправильной работе какой либо функции придется “курить” мануалы, на фоне чего меркнет все хорошее.

Протестируем библиотеки, передавая информацию на терминал через usb-uart. Ниже пример использования.

usb_uart_stm32

Для начала необходимо знать, что настройка выводов UART находится в файле stm32f3xx_hal_msp.c в функции HAL_UART_MspInit. Сами же переопределения находятся в файле stm32f3xx_hal_gpio_ex.h. Они у нас уже сгенерированы, описывать их и здесь не будем. Мы их разберем в следующей статье используя для UART библиотеку CMSIS. Инициализация порта находится в файле main.c и содержит те данные которые мы задали в Cube.

Для передачи/приема информации используем функции из файла, который находится Drivers -> STM32F3xx_HAL_Driver-> Legacy ->stm32f3_hal_uart.h.

Все функции стандартные, поэтому неважно в какой IDE писать, в будущем мы не будем расписывать поиск функций. Здесь приведем один пример для наглядности.

HAL_UART_Transmit (UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_UART_Transmit_DMA (UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UART_Receive_IT (UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

Выше приведены три функции, которые мы используем в данной статье. Первая — передача, где UART_HandleTypeDef *huart – указатель на переменную UART, uint8_t *pData – массив данных ,uint16_t Size – размер передаваемой информации, uint32_t Timeout – время, по истечению которого функция перестает работать. Вторая — передача с использованием DMA, здесь нам тайм аут уже не требуется так используется прерывание. И третья прием по одному байту на прерываниях. Довольно легкое использование функций. Исходники выложены в конце статьи. Прописываем их в основной функции main. Ниже примеры кода.

1.HAL_UART_Transmit ();
int main (void) {
     uint8_t data[]="stm32";
     while (1) {
            HAL_UART_Transmit (&huart4, data, 5, 1000);//Передаем строку 
            HAL_GPIO_TogglePin (GPIOE, GPIO_PIN_8);//Включаем светодиод
            HAL_Delay (100);//Задержка
} ...........
transmit_uart

2. HAL_UART_Transmit_DMA ();
int main (void) {
    uint8_t data[]="stm32dma";
    while (1) {
         HAL_UART_Transmit_DMA (&huart4,data,9);
         HAL_GPIO_TogglePin (GPIOE, GPIO_PIN_8);
         HAL_Delay (2000);
}.........
transmit_dma_uart

3.HAL_UART_Receive_IT ();
int main (void) {
     uint8_t data[]="stm32"; //Строка для передачи
     uint8_t data_rec = 0;
     HAL_UART_Receive_IT (&huart4, &data_rec, 1);
     while (1) {
         if (huart4.RxXferCount == 0){//Счетчик считает обратный отсчет, при установке в 0 прием прекращается
               if (data_rec == '0')  { // В кавычках т.к. терминал работает в коде ANSII
                     HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8,GPIO_PIN_SET);//Включаем светодиод Led 8
                     HAL_Delay (500);
                }     
               else if (data_rec == '1')   {
                     HAL_GPIO_WritePin (GPIOE, GPIO_PIN_9,GPIO_PIN_SET);
                     HAL_Delay (500);
                }
               else if (data_rec == '2'){
                     HAL_GPIO_WritePin (GPIOE, GPIO_PIN_10,GPIO_PIN_SET);
                     HAL_Delay (500);
                }
               HAL_GPIO_TogglePin (GPIOE, GPIO_PIN_11);
               HAL_UART_Receive_IT (&huart4,&data_rec, 2);/*Еще раз записываем функцию в цикле, т.к. в ней сбрасывается флаг прерывания*/
        }
        HAL_UART_Transmit (&huart4, data, 5, 1000); 
        HAL_Delay (500);
    }
}
IMG_20180210_235753

Немного о коде. Считывать данные можно по окончанию приема, для чего мы берем одно из полей структуры UART (UART_HomdleTypeDef), в данном случае uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ — счетчик принятого, который отсчитывает в обратную сторону. У нас на рисунке, выше, видно при посылке в контроллер символа “2” загорается светодиод Led10 (Обведено красным). При выходе из обработчика прерывания в основной цикл, повторно при приеме символа, к сожалению обработчик не реагирует. Не будем копаться в библиотеке и в следующей записи организуем UART используя библиотеку CMSIS. По данной проблеме немного провел поиск в интернете. Действительно в данной модели и других наблюдается некорректная работа в прерываниях. Используя библиотеку HAL, хочется отметить, что после вызова любой из не блокирующих функций HAL_UART_Transmit_IT (), HAL_UART_Receive_IT (), HAL_UART_Transmit_DMA (), HAL_UART_Receive_DMA () в нормальном режиме необходимо дождаться пока она не отработает,  а в качестве признака завершения использовать callback функцию HAL_UART_TxCpltCallback (),  HAL_UART_RxCpltCallback (). Так как повторный вызов чтения или записи без корректного завершения предыдущего — гарантированный глюк с непонятным состоянием порта. Пример такой функции:

UART_HandleTypeDef huart; //Создание уарта
uint8_t rxed_byte; //Создание буфера
/*Задание параметров и инициализация UART через HAL_UART_Init (&huart);*/
Создаём свою callback функцию, где прописываем флаг.
void HAL_UART_RxCpltCallback (UART_HandleTypeDef *huart){
         FLAG = SET; }
При отработке функции  HAL_UART_Receive_IT (&huart, (uint8_t *) rxed_byte, 1), ждем конца отработки callback и установки Flag. Забираем из rxed_byte полученный байт, сбрасываем флаг, опять запускаем HAL_UART_Receive_IT.

Исходники.

Передача/прием UART используя HAL ( Скачали: 336 чел. ) 

В следующей записи мы рассмотрим прием/передачу по UART используя CMSIS. Так как данный протокол у нас будет основным в нашем проекте то мы должны с ним познакомится на уровне регистров. А также интегрируем библиотеку CMSIS в IDE Coocox без использования Cube На этом сегодня и остановимся. Всем пока.

Просмотрено 4239 раз.

Я на Google+

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

Ваш e-mail не будет опубликован.

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting