STM Урок 14. HAL. USART. Прием данных

 

 

 

 

Урок 14

 

HAL. USART. Прием данных

 

 

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

Во-первых, нужно обрабатывать прерывание от USART, вы ведь не угадаем, когда именно нам принимать.

Во-вторых, где-то и как-то это надо отображать.

Вот тут-то на помощь нам приходит наш добрый и старый дисплей 20х4.

Подключим его по той же 4-битной схеме (нажмите на картинку для увеличения изображения)

 

image00_0500

 

В связи с этим новый проект USART_RECEIVE мы создадим из другого проекта — MYLCD80

Запускаем вновь созданный проект в CUBE, включаем аналогичным образом USART2 – Asynchronous.

Те же самые настройки. как и в проекте с передачей данных должны быть и в Configuration.

Только единственная разница, в USART в Configuration на USART2 включим прерывания

 

image01

 

Генерируем проект. Открываем его.

Добавляем файл lcd.c.

Собираем, прошиваем, смотрим, чтобы убедиться, что дисплей у нас работает.

Если дисплей работает, то мы работаем с кодом.

По дисплею оставляем в коде только это

 

/* USER CODE BEGIN 2 */

        LCD_ini();

  sprintf(str, "Stm32F407VG");

        LCD_String(str);

        LCD_SetPos(10, 2);

  sprintf(str, "ARM mc");

        LCD_String(str);

  /* USER CODE END 2 */

 

Остальное убираем, из бесконечного цикла также всё убираем, и уберем переменную i.

 

 

Добавим код в main()

 

  /* USER CODE BEGIN WHILE */

        str[8]=0;

        HAL_UART_Receive_IT(&huart2,(uint8_t*) str,8);

  while (1)

  {

                HAL_Delay(100);

                if(huart2.RxXferCount==0)

                {

                        LCD_SetPos(0, 3);

                        LCD_String(str);

                        str[8]=0;

                        HAL_UART_Receive_IT(&huart2,(uint8_t*) str,8);

                }

  /* USER CODE END WHILE */

 

Собираем, прошиваем, смотрим.

С терминальной программы пытаемся вводить символы (обязательно ровно по 8, ну, либо по-другому, но пока не наберется 8, на дисплей ничего не выведется)

 

image02

 

В будущих проектах мы обязательно вернемся к режиму приёма данных по USART с использованием прерываний, правда не очень скоро, но вернёмся.

 

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

 

 

Исходный код

 

 

Терминальная программа

 

STM32F4-DISCOVERY

Переходник USB-TTL лучше купить такой (сейчас у меня именно такой и он мне больше нравится)

 

 

Смотреть ВИДЕОУРОК

 

STM32 HAL. USART. Передача данных

11 комментариев на “STM Урок 14. HAL. USART. Прием данных
  1. Юриц:

    Можете показать пример как определять размер сообщеия автоматичемкт? 

  2. Владимир:

    Была у меня проблема приема пакета неизвестной длины. Один контроллер другому посылает команды по UART. У каждой команды свой набор параметров, и соответственно свой размер пакета передаваемых данных. Да и, кроме того, контроллер занят другими боле важными задачами, в том числе отработкой конвейера поступающих по UART команд. День потратил на поиск и отработку глюков, но нашёл решения. Может кому-то пригодится, ибо в уроке не все тонкости раскрыты.
    1. Приём Rx через прерывания.
    Функция HAL_UART_Receive_IT определяет буфер, в который ведётся запись, а также 2 параметра huart2.RxXferSize — это длина принимаемого пакета, и huart2.RxXferCount — счетчик принимаемых байт. Естественно, буфер должен быть готов принять пакет максимальной длины и функция HAL_UART_Receive_IT принимает именно его. А вот с более короткими пакетами надо немного включить мозг. После вызова функции HAL_UART_Receive_IT, переменные RxXferCount=RxXferSize (счётчик равен размеру ожидаемых данных). Но когда начинается прием данных, то RxXferCountInstance->CNDTR
    только вот условие if ((huart2.hdmarx->Instance->CNDTR)Instance->CNDTR;
    if (cnt < huart.RxXferSize)
    Вот так условие заработало.
    функция HAL_UART_AbortReceive(&huart2) работает и для режима приема по прерываниям, и для режима приема через DMA.

    3. Ну вот если надо принять пакет вообще никак не известной заранее длины, то в режиме прерываний надо использовать таймауты (определять интервал времени между принятыми байтами, не забывая вычищать буфер), а в режиме DMA есть такой момент
    if(hdma_usart2_rx.State==HAL_DMA_STATE_READY_HALF_MEM0) — есть загрузка половины пакета – вычищаем буфер, потом HAL_UART_AbortReceive(&huart2); HAL_UART_Receive_DMA(&huart2, (uint8_t*) str, максимальный_размер_пакета)

    P.S. я очень плохо знаю язык си, и еще хуже знаю STM32 и KeiluVision5. Не кидайтесь тапками если чё не так. Просто потратил много времени на решение данной задачи, а на технических форумах все специалисты пишут что HAL==кал, и все равно надо изучать ReferenceManual на контроллер и CMSIS. По крайней мере, благодаря видеоурокам Владимира, я понял, как начать, а потом отследить через Watch1 и найти решение именно для моей задачи. Надеюсь, кому-нибудь мой комментарий сэкономит время.

  3. Владимир:

    некорректно ушел комментарий. дублирую пункты:
    1. Приём Rx через прерывания.
    Функция HAL_UART_Receive_IT определяет буфер, в который ведётся запись, а также 2 параметра huart2.RxXferSize — это длина принимаемого пакета, и huart2.RxXferCount — счетчик принимаемых байт. Естественно, буфер должен быть готов принять пакет максимальной длины и функция HAL_UART_Receive_IT принимает именно его. А вот с более короткими пакетами надо немного включить мозг. После вызова функции HAL_UART_Receive_IT, переменные RxXferCount=RxXferSize (счётчик равен размеру ожидаемых данных). Но когда начинается прием данных, то RxXferCount<RxXferSize. Если выполняется это условие, то смотрим первый байт в буфере приёма str[0] и определяем какая должна быть длина пакета. Далее проверяем весь ли пакет принят?
    if (длина_пакета==(RxXferSize-RxXferCount)) если нет, то ничего не делаем (в следующем цикле проверим), а если да, то переписываем принятый пакет в другую переменную для последующей обработки команды, а вот с UART'ом следующий порядок действий такой:
    HAL_UART_AbortReceive(&huart2); //внеплановое завершение приёма по правилам HAL
    HAL_UART_Receive_IT(&huart2, str, размер_максимального_пакета); //запуск приёма следующего пакета

    • Исходный кот:

      Hu is длина пакета?
      Откуда я знаю, какой длины пакет придет? Вернее, Я ЭТО знаю, а, как узнает про это устройство, когда у него только две линии Rx и Tx?

    • Исходный кот:

      На GPIO вешать ничего нельзя… Так бы можно было бы оттырить прино 6 GPIO, все равно их полно и болтаются они как …в проруби. Но, По ТХ, работаем только по Rx и Tx!Команды не более 30 символов

  4. Владимир:

    2. Приём в Rx через DMA.
    Ну суть та же, только счётчик принятых данных не huart2.RxXferCount, а huart2.hdmarx->Instance->CNDTR
    только вот условие if ((huart2.hdmarx->Instance->CNDTR)Instance->CNDTR;
    if (cnt < huart.RxXferSize)
    Вот так условие заработало.
    функция HAL_UART_AbortReceive(&huart2) работает и для режима приема по прерываниям, и для режима приема через DMA.

    • Владимир:

      Блин, да что так все криво-то отправляется?
      2. Приём в Rx через DMA.
      Ну суть та же, только счётчик принятых данных не huart2.RxXferCount, а huart2.hdmarx->Instance->CNDTR
      только вот условие if ((huart2.hdmarx->Instance->CNDTR)Instance->CNDTR;
      if (cnt < huart.RxXferSize)
      Вот так условие заработало.
      функция HAL_UART_AbortReceive(&huart2) работает и для режима приема по прерываниям, и для режима приема через DMA.

  5. Владимир:

    Капец какой-то, посылаю одно, на сайте другое… дубль 3:
    2. Приём в Rx через DMA.
    Ну суть та же, только счётчик принятых данных не huart2.RxXferCount, а huart2.hdmarx->Instance->CNDTR
    только вот условие
    if ((huart2.hdmarx->Instance->CNDTR)Instance->CNDTR;
    if (cnt < huart.RxXferSize)
    Вот так условие заработало.
    функция HAL_UART_AbortReceive(&huart2) работает и для режима приема по прерываниям, и для режима приема через DMA.

  6. Исходный кот:

    Ребята, надо, чтобы, терминал v 1.9b получал пакеты произвольной длины(желательно, по прерываниям. то есть, я ввожу то что мне надо и нажимаю SEND). Я так понял, HAL для этого совершенно не годится? Перепробовал все, принимает совершенно не то что нужно. Плюс, символы '$' и '#' не обрабатываются. Вместо них . Весь код по книге, только, размер уменьшен до одного символа и вместо LCD HAL_UART_Transmit_IT(…). Ведь, по — идее, функция, HAL_UART_Receive_IT(…) должна взять первый символ и послать его HAL_UART_Transmit_IT, очистить буфер, перейти ко второму символу и также нередать его в верхнюю часть терминала? Или я ошибаюсь?

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

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

*