2016-05-20 19 views
2

Я использую stm32f0 MCU.Почему прерывание передачи UART не работает в этом случае?

У меня есть простой код эхо-сигнала UART, в котором каждый полученный байт будет передан. Я тестировал, что он работает. Вот;

uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0; 
//Interrupt callback routine 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{ 
    if (huart->Instance == USART1) //current UART 
    { 
     HAL_UART_Transmit(&huart1, &Rx_data[0], 1, tx_timeout);   
     HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte 
    } 
} 

Мне не нравится код, даже если он работает. Во-первых, tx_timeout равно 0, и большинство примеров кода отличны от нуля. Я не знаю побочного эффекта. Во-вторых, HAL_UART_Transmit() является блокирующим вызовом, и не рекомендуется использовать блокирующие вызовы внутри прерывания. Итак, я решил использовать прерывание для передачи uart HAL_UART_Transmit_IT() вместо блокирующего вызова. Вот модифицированный код;

uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0; 
//Interrupt callback routine 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{ 
    if (huart->Instance == USART1) //current UART 
    { 
     HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1);   
     HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte 
    } 
} 

Однако, он не работает должным образом. Мой компьютер передает ASCII 12345678 в stm32. Если все работает должным образом, ПК должен получать 12345678 обратно. Однако вместо этого ПК получает 1357. Что не так с этим кодом, который использует HAL_UART_Transmit_IT()?

ответ

8

Первое:

Как было описано в ответах на ваш previous question нулевой тайм-аут только исключает ожидание государства флага. Если вы откроете код HAL_UART_Transmit - вы увидите, что при отправке 1 байта без тайм-аута никакое состояние блокировки не будет!

Второе:

Это не истинный метод для отправки/приема одного байта из функций огромный HAL и их обратных вызовов. Я предполагаю: следующий ваш вопрос будет «как я должен выполнять синтаксический анализ там?». И я надеюсь, что вы не будете вставлять функцию разбора в обратный вызов IRQ!

Как правило, вам нужны буферы. И полезно использовать циклический буфер.

mxconstants.h:

/* USER CODE BEGIN Private defines */ 

/* Buffer's length must be select according to real messages frequency */ 
#define RXBUF_LEN   128 // must be power of 2 
#define TXBUF_LEN   128 // must be power of 2 
#define RXBUF_MSK   (RXBUF_LEN-1) 
#define TXBUF_MSK   (TXBUF_LEN-1) 

/* USER CODE END Private defines */ 

main.c:

uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN]; 
/* xx_i - counter of input bytes (tx - pushed for transmit, rx - received) 
    xx_o - counter of output bytes (tx - transmitted, rx - parsed) 
    xx_e - counter of echoed bytes */ 
volatile uint16_t rx_i = 0, tx_o = 0; 
uint16_t rx_o = 0, rx_e = 0, tx_i = 0; 
volatile uint8_t tx_busy = 0; 

void transmit(uint8_t byte) 
{ 
    tx_buf[TXBUF_MSK & tx_i] = byte; 
    tx_i++; 
    tx_busy = 1; 
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); 
} 

void main(void) 
{ 
    /* Initialization code */ 
    /* ... */ 
    /* Enable usart 1 receive IRQ */ 
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); 
    for (;;) { 
     /* Main cycle */ 
     while (rx_i != rx_e) { 
      /* echo here */ 
      transmit(rx_buf[RXBUF_MSK & rx_e]); 
      rx_e++; 
     } 
     while (rx_i != rx_o) { 
      /* parse here */ 
      /* ... */ 
      rx_o++; 
     } 
     /* Power save 
     while (tx_busy); 
     HAL_UART_DeInit(&huart1); 
     */ 
    } 
} 

stm32f0xx_it.c:

extern uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN]; 
extern volatile uint16_t rx_i, tx_o; 
extern uint16_t rx_o, rx_e, tx_i; 
extern volatile uint8_t tx_busy; 

void USART1_IRQHandler(void) 
{ 
    /* USER CODE BEGIN USART1_IRQn 0 */ 
    if((__HAL_UART_GET_IT(&huart1, UART_IT_RXNE) != RESET) && 
     (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE) != RESET)) 
    { 
     rx_buf[rx_i & RXBUF_MSK] = (uint8_t)(huart1.Instance->RDR & 0x00FF); 
     rx_i++; 
     /* Clear RXNE interrupt flag */ 
     __HAL_UART_SEND_REQ(&huart1, UART_RXDATA_FLUSH_REQUEST); 
    } 
    if((__HAL_UART_GET_IT(&huart1, UART_IT_TXE) != RESET) && 
     (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TXE) != RESET)) 
    { 
     if (tx_i == tx_o) { 
      __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE); 
      __HAL_UART_ENABLE_IT(&huart1, UART_IT_TC); 
     } else { 
      huart1.Instance->TDR = (uint8_t)(tx_buf[TXBUF_MSK & tx_o] & (uint8_t)0xFF); 
      tx_o++; 
     } 
    } 
    if((__HAL_UART_GET_IT(&huart1, UART_IT_TC) != RESET) && 
     (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TC) != RESET)) 
    { 
     tx_busy = 0; 
     __HAL_UART_DISABLE_IT(&huart1, UART_IT_TC); 
    } 
    /* And never call default handler */ 
    return; 
    /* USER CODE END USART1_IRQn 0 */ 

    HAL_UART_IRQHandler(&huart1); 

    /* USER CODE BEGIN USART1_IRQn 1 */ 
    /* USER CODE END USART1_IRQn 1 */ 
} 

И третий !!!

И об этом:

Почему HAL_UART_Transmit_IT не поможет/работать?

Потому что это слишком медленно! И если вы пытаетесь подсчитать HAL_BUSY результаты:

uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0; 
//Interrupt callback routine 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{ 
    static uint32_t hal_busy_counter = 0; 
    if (huart->Instance == USART1) //current UART 
    { 
     if (HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1) == HAL_BUSY) { 
      hal_busy_counter++; 
     }   
     HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte 
    } 
} 

Когда вы приостановите MCU отладчик после обмена данными - вы будете удивлены: он будет равен кол-пропущенных символов.

+0

Буфер, входные и выходные счетчики (напр.'uint8_t rx_buf [RXBUF_LEN]; volatile uint16_t rx_i; uint16_t rx_o; ') - это реализация механизма очереди. – imbearr

+0

Замечательный ответ. Upvoted. Я хотел бы кое-что подтвердить с вами. Использование HAL_UART_Transmit() с нулевым временем ожидания означает, что HAL_UART_Transmit() становится неблокирующим? Любой возможный побочный эффект? Если это так, я думаю, что решение будет достаточно хорошим. – user781486

+0

Никаких побочных эффектов при текущей версии HAL. Но этот обработчик IRQ слишком велик. Когда вы будете использовать это решение в большом проекте, где IRART USART может остаться, пока работает другой обработчик IRQ, вы снова можете пропустить байты! – imbearr