STM32. UART, Прием данных, не зная размера данных. UART_IT_IDLE. Работа с прерываниями. Урок 9.

Поделиться
HTML-код
  • Опубликовано: 22 окт 2024

Комментарии • 21

  • @jorchick
    @jorchick 4 года назад

    Ух ты, мой коммент был упомянут. Я на прошлой неделе разбирался с блютуз протоколом BMS, и поскольку не знал размерность пакетов, пришлось разобраться в IDLE. Все делал также. Я не стал использовать RxCpltCallback, просто увеличив размер буффера.

  • @ebjikkolu4757
    @ebjikkolu4757 3 года назад +6

    Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback .
    С помощью этого всего ,микроконтроллер будет принимать весь пакет ,ни больше, ни меньше ,плюс подскажет о количестве принятых байт .Если указанный буффер будет меньше принятого пакета, то функция начнет перезаписывать буффер сначала .
    Функционал базируется как раз на проверке таймингов между байтами(если задержка минимальна-то пакет еще продолжается, если задержка больше- пакет закончен ,грубо говоря) ,быть может инженеры подсмотрели принципы реализации именно тут, как знать..)

  • @МихаилТиунов-с7д
    @МихаилТиунов-с7д 4 года назад +3

    Ещё раз модифицировал код. Теперь в переменной Recieved - количество принятых байт. Изначально мне не было нужно, но подумал - вдруг кому пригодится.
    Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS):
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE
    HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA
    (или HAL_UART_Receive_IT, если без DMA)
    Обработчик прерываний USART:
    void USART1_IRQHandler(void)
    {
    /* USER CODE BEGIN USART1_IRQn 0 */
    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */
    if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE
    {
    __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
    HAL_UART_DMAStop(&huart1); //Останавливаем DMA
    Recived = Rx_BuffSize - DMA1_Channel5->CNDTR; //В переменной Recived - количество принятых байт
    HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
    }
    /* USER CODE END USART1_IRQn 1 */
    }
    Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)

  • @МихаилТиунов-с7д
    @МихаилТиунов-с7д 4 года назад +1

    Олег, когда вы включаете для USART разрешение на обработку глобальных прерываний, Cube создает в файле stm32f1xx_it.c процедуру void USART1_IRQHandler(void), в которой происходит вызов процедуры HAL_UART_IRQHandler(&huart1), в которой Вы и делали правку, вызывающую вашу HAL_UART_IDLE_Callback. Правильнее обработку прерывания делать именно в USART1_IRQHandler и тогда не возникнет проблемы удаления кода кубом при следующих изменениях в проекте.

    • @Solderingironspb
      @Solderingironspb  4 года назад

      Хм...спасибо, попробую)

    • @МихаилТиунов-с7д
      @МихаилТиунов-с7д 4 года назад +1

      @@Solderingironspb У меня сделан прием через DMA выглядит вот так
      void USART1_IRQHandler(void)
      {
      /* USER CODE BEGIN USART1_IRQn 0 */
      /* USER CODE END USART1_IRQn 0 */
      HAL_UART_IRQHandler(&huart1);
      /* USER CODE BEGIN USART1_IRQn 1 */
      if(huart1.Instance->SR & 0x10) //Проверяем что прерывание произошло по IDLE
      {
      __HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE); //Отключаем прерывания
      __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
      HAL_UART_DMAStop(&huart1); //Останавливаем DMA
      __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание
      HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
      Recived = 1; //По этому флагу у меня обрабатывается пакет запроса
      в главном цикле
      }
      /* USER CODE END USART1_IRQn 1 */
      }

    • @МихаилТиунов-с7д
      @МихаилТиунов-с7д 4 года назад +1

      @@Solderingironspb Кстати - разрешаю сделать ролик об этом с использованием моего кода. Сам в своё время долго искал как это сделать. Таких роликов на ютюбе нет.

    • @Solderingironspb
      @Solderingironspb  4 года назад +2

      Такой информации не то, что на ютубе нет, ее и в сети-то фиг найдешь...

    • @МихаилТиунов-с7д
      @МихаилТиунов-с7д 4 года назад +2

      @@Solderingironspb И я об этом. Собственно - очень тебе благодарен. Благодаря тебе пошел в нужном направлении и сделал. Весь проект прислать не могу - у меня там целое большое изделие. Но ролик такой, считаю, надо сделать. Готов ответить на все вопросы, подключиться и согласовать до публикации.

  • @МихаилТиунов-с7д
    @МихаилТиунов-с7д 4 года назад +1

    Еще поэкспериментировал. Оказывается отключать прерывания перед сбросом флага IDLE , а затем, включать нет необходимости. Конечный код прекрасно работает и выглядит вот так:
    Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS):
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE
    HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA
    (или HAL_UART_Receive_IT, если без DMA)
    Обработчик прерываний USART:
    void USART1_IRQHandler(void)
    {
    /* USER CODE BEGIN USART1_IRQn 0 */
    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */
    if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE
    {
    __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
    HAL_UART_DMAStop(&huart1); //Останавливаем DMA
    (или HAL_UART_Abort_IT если без DMA)
    HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA

    (или HAL_UART_Receive_IT, если без DMA)
    Recived = 1; //По этому флагу у меня обрабатывается пакет запроса
    в главном цикле (или в задаче FreeRTOS).
    }
    /* USER CODE END USART1_IRQn 1 */
    }
    Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)

  • @WZombie47
    @WZombie47 3 года назад

    я ничего не понял. idle это режим простоя. каким образом добавили новый флаг прерываний в стм? или это обработка флага который там есть? а почему его не было?
    Почему длина принимаемого буфера равна 20 - принятые байты? это ж если 5 байтов придет то буфер будет 15 а зачем нам 15 если у нас 5 байт пришло и нам нужен буфер 5

  • @АлексейСлесаревич
    @АлексейСлесаревич 4 года назад

    Здравствуйте, скажите пожалуйста, урок по SPI планируется? И если да, то скоро ли?

    • @Solderingironspb
      @Solderingironspb  4 года назад +1

      Здравствуйте. И по spi и по i2c планируются уроки. Только для начала нужно эти темы самому освоить. Сейчас с али едут датчики BME280(на них буду пробовать осваивать i2c). Тему с spi начну наверное с каких-нибудь 7сегментных индикаторов с микросхемой от maxim. Все будет)

    • @АлексейСлесаревич
      @АлексейСлесаревич 4 года назад

      @@SolderingironspbПонял, благодарю. Ещё интересует тема встроенных часов реального времени, надеюсь по ним тоже в планах

    • @Solderingironspb
      @Solderingironspb  4 года назад +1

      и по ним, и по работе с энкодером, и по замеру времени в микросекундах. Тем много. Все освоим, надеюсь)

  • @edmelectronics4110
    @edmelectronics4110 2 года назад +1

    Другой, боле простой пример прием данных не зная их размер: ruclips.net/video/mXT3Hjae64s/видео.html

    • @Solderingironspb
      @Solderingironspb  2 года назад +1

      Здравствуйте) Данные функции появились уже после того, как я выложил данное видео. Раньше их в HAL не было. Даже человек тут в комментариях писал: "Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback ."