Проблема флага IDLE с uart?

void USART2_IRQHandler(void)
 
{
 
 /* USER CODE BEGIN USART2_IRQn 0 */
 
  /* UART IDLE Interrupt */
 
    if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) == SET)  
 
    {
 
     __HAL_UART_CLEAR_IDLEFLAG(&huart2);
 print("time %d",timeCounter");
receivedDataFlag = 1;

 
}
 
}

Когда я использую эту функцию, проверьте состояния ожидания линии и определите, получены данные или нет. Но это прерывание срабатывает во время передачи. Как я могу разделить приемную линию данных в режиме ожидания и прием в режиме ожидания?

Я хочу инициировать простое получение линии данных, как я могу это сделать? Какой еще регистр мне посмотреть?

Я получаю очень интересный результат,

Отправитель отправляет каждые 100 мс данные на мое устройство;

Если я использую только функции приема DMA; время возврата 10, 110, 220 330 (состояния простоя работают)

Но если я получил, то после передачи данных с помощью uart эти значения времени возвращают 10,13,15, ... средняя функция передачи изменяет состояние ожидания линии, как это возможно? Связан ли UART_FLAG_IDLE только с rx?

РЕДАКТИРОВАТЬ: Кстати, я использую rs485, поэтому, когда я начинаю передачу, я устанавливаю режим передатчика tranceiver, поэтому режим приемника на стороне отправителя, поэтому мой MCU решает IDLE в этом состоянии? это возможно? Как я могу защитить эту ситуацию?

Когда я запускаю режим передачи после получения данных, то завершается обратный вызов, Когда я вызываю HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE); прерывание функции IDLE срабатывает каждые 5 мс, но тайм-аут отправки данных 100 мс

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
 

  HAL_UART_DMAStop(&huart2);
  dmaTransmitCompletedFlag = 1;
  RS485_Set_Receive_Mode();
  HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE);
  waitForTransmittingData = 0;

}
Никогда не выполняйте вызовы функций из ISR! Вы только что отправили все регистры, используемые в ISR, и теперь делаете это снова. printf увеличивает количество используемых регистров, а задержка от функции в ISR расточительна. Установите свой флаг. В вашем программном обеспечении проверьте флаг, обработайте его и напечатайте сообщение.
@StainlessSteelRat Вы серьезно относитесь к тому, что сказали? Вызов функций из ISR — это нормально. STM32 HAL уже делает это. Это STM32, поэтому в ISR регистры в любом случае помещаются в стек аппаратно для контекста ISR, штраф не больше, чем для обычного вызова функции. Кроме того, у STM32 может быть около 1 мегабайта оперативной памяти, так что это не проблема, даже на 8-килобайтном STM32. Что неправильно, так это вызывать тяжелую функцию, такую ​​​​как printf, в ISR, и, скорее всего, она не является реентерабельной, поэтому это самые большие проблемы.
Зависит от функции. Любой printf - это свинья и часть проблемы OP.
@StainlessSteelRat прав, что использование печати в прерывании является проблемой, поскольку драйвер потока stdio должен быть потокобезопасным. Чего по умолчанию нет для stm32.

Ответы (3)

Это прерывание используется как для передачи, так и для приема.

IDLE относится только к приему, это означает, что обнаружен хотя бы один полный кадр ожидания.

Использование печати в прерывании неразумно, особенно если печать использует тот же UART, для которого предназначено прерывание.

печать с использованием usart1, но это прерывание с использованием usart2, относится ли IDLE только к приему, как это возможно? Как мой таймер очень близко?
Кстати, я использую rs485, поэтому, когда я начинаю передачу, я устанавливаю режим передатчика трансивера, поэтому режим приемника на стороне отправителя, поэтому мой MCU решает IDLE в этом состоянии? это возможно?
во-вторых, предостережение против печати в прерывании. В дополнение к блокирующему характеру этой функции существует много накладных расходов и использования оперативной памяти, что еще больше увеличивает время выполнения. Наилучшая практика заключается в том, чтобы ваши обработчики были очень быстрыми и простыми, а более трудоемкие функции пропускались установкой флагов в обработчике и очисткой их в основном цикле. Если ваши обработчики работают слишком долго, вы получите «штормы прерываний», которые в основном блокируют ваш код.
@mathco Я не понимаю, почему вы спрашиваете, как это возможно, потому что так задумано. IDLE имеет отношение только к приему, он устанавливается, когда после приема кадра прием нового кадра не обнаружен в течение времени ожидания одного кадра. Если вы хотите, чтобы я процитировал для вас руководство, вы должны указать, какую именно модель микроконтроллера STM32 вы используете.
Я добавил некоторые детали в свой вопрос
Я до сих пор не понимаю вопроса. Если вы установите RS485 в режим передачи, мы не знаем, может ли STM32 принимать передаваемые данные или нет. Тем не менее, всякий раз, когда приемник видит кадр ожидания, он создает прерывание ожидания. Если вам не нужны прерывания простоя, прекратите их использовать. Но, как я уже сказал, нет проблем в том, как работают прерывания IDLE, проблема в том, что вы можете ожидать, что они будут работать иначе, чем они действительно работают, и то, как вы используете трансивер RS485, может повлиять на это. И вы никогда не упоминаете, какой именно микроконтроллер STM32 вы используете, чтобы никто не мог процитировать вам руководство. Отредактируйте тип STM32.

Это IRQ предназначено для USART2, но оно вызывается для каждого разрешенного прерывания , связанного с USART2. Это означает, что обработчик должен проверять и обрабатывать каждый разрешенный сигнал прерывания. Для STM32 USART включает в себя основные сигналы UART, управляемого прерываниями, такие как TXNE и RXNE, а также сигналы ошибок, IDLE и т. д.

Сигнал IDLE предназначен для кадрирования многобайтовых приемов (обычная проблема для USART, особенно в шумной среде). Он активируется, когда линия приема находится в состоянии высокого уровня (или «свободна») в течение некоторого времени устранения дребезга (определяемого настройками скорости передачи/передискретизации), после того как эта линия была активной (во время приема группы из одного или нескольких байтов). . Это полезно, потому что вы можете использовать его для сброса вашего приемного буфера обратно в индекс «0», чтобы следующий кадр был правильно выстроен (даже если в текущем кадре было получено слишком мало или слишком много байтов). Обычно вам приходится реализовывать такую ​​логику с помощью выделенного периферийного устройства таймера, но STM32 удобно упаковывает его в свои периферийные устройства USART (хотя это не поддерживается собственным драйвером HAL).

Если вы действительно хотите, чтобы только сигнал ожидания вызывал прерывание, вам нужно вручную отключить все остальные сигналы прерывания. Если вам нужен полезный приемник UART, управляемый прерываниями, я не советую вам это делать.

Из одного из ваших предыдущих вопросов я дал вам несколько ссылок, где это реализовано.

Исходный код

USART3_IRQHandler(void) {
    /* Check for IDLE line interrupt */
    if (LL_USART_IsEnabledIT_IDLE(USART3) && LL_USART_IsActiveFlag_IDLE(USART3)) {
        LL_USART_ClearFlag_IDLE(USART3);        /* Clear IDLE line flag */
        usart_rx_check();                       /* Check for data to process */
    }

    /* Implement other events when needed */
}
Я просмотрел весь исходный код по этой ссылке, прежде чем писать свой код, но срабатывает прерывание IDLE, когда трансивер RS485 запускает режим передачи, я не знаю, почему?
После этой функции триггер прерывания IDLE; void HAL_UART_TxCpltCallback (UART_HandleTypeDef huart) { HAL_UART_DMAStop (& huart2); dmaTransmitCompletedFlag = 1; RS485_Set_Receive_Mode(); HAL_UART_Receive_DMA(&huart2,(uint8_t )dma_rx_buf,DMA_BUF_SIZE); ждать передачи данных = 0; }