2016-05-20 15 views
2

Ich verwende Stm32f0 MCU.Warum funktioniert der UART-Sende-Interrupt in diesem Fall nicht?

Ich habe einen einfachen UART-Echo-Code, in dem jedes empfangene Byte übertragen wird. Ich habe getestet, dass es funktioniert. Hier ist es;

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 
    } 
} 

Ich fühle mich nicht wohl mit dem Code, obwohl es funktioniert. Erstens ist tx_timeout 0 und die meisten Codebeispiele sind nicht Null. Ich kenne den Nebeneffekt nicht. Zweitens ist HAL_UART_Transmit() ein blockierender Anruf, und es ist nicht ratsam, blockierende Anrufe innerhalb eines Interrupts zu verwenden. Also entschied ich mich, einen Interrupt für die Uart-Übertragung HAL_UART_Transmit_IT() anstelle eines blockierenden Anrufs zu verwenden. Hier ist der modifizierte Code;

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 
    } 
} 

Es funktioniert jedoch nicht wie erwartet. Mein PC überträgt ASCII 12345678 an stm32. Wenn die Dinge wie erwartet funktionieren, sollte der PC 12345678 zurück erhalten. Der PC empfängt jedoch stattdessen 1357. Was ist falsch an diesem Code, der HAL_UART_Transmit_IT() verwendet?

Antwort

8

Erstens:

Wie in Antworten auf Ihre previous question null Timeout beschrieben ausschließen nur Warten auf Flaggenstaat. Wenn Sie HAL_UART_Transmit Code öffnen - Sie sehen, dass, wenn Sie 1 Byte ohne Zeitüberschreitung senden, kein Blockierungszustand wird!

Zweitens:

Es ist nicht wahr Methode/senden ein Byte aus einer riesigen HAL Funktionen erhalten und ihre Rückrufe. Ich schätze: Als nächstes wird deine Frage "wie muss ich Parsen dort umsetzen?". Und ich hoffe, dass Sie Ihre Parse-Funktion nicht in IRQ Callback einfügen!

Also im Allgemeinen brauchen Sie Puffer. Und es ist eine gute Idee, einen zyklischen Puffer zu verwenden.

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 */ 
} 

Und drittens !!!

Und dazu:

Warum HAL_UART_Transmit_IT nicht helfen/Arbeit?

Weil es zu langsam ist! Und wenn Sie versuchen, HAL_BUSY Ergebnisse zu zählen:

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 
    } 
} 

Wenn Sie MCU Pause in Debugger nach dem Datenaustausch - Sie überrascht werden: es wird gleich der verpassten Zeichen zählen.

+0

Puffer, Eingangs- und Ausgangszähler (z.'uint8_t rx_buf [RXBUF_LEN]; flüchtig uint16_t rx_i; uint16_t rx_o; ') - ist die Implementierung des Warteschlangenmechanismus. – imbearr

+0

Wunderbare Antwort. Upvoted. Ich möchte etwas mit dir bestätigen. Wenn HAL_UART_Transmit() mit Null-Timeout verwendet wird, bedeutet dies, dass HAL_UART_Transmit() nicht blockiert wird? Jede mögliche Nebenwirkung? Wenn das der Fall ist, denke ich, dass diese Lösung gut genug wäre. – user781486

+0

Keine Nebenwirkungen in der aktuellen Version von HAL. Aber dieser IRQ-Handler ist immer noch zu groß. Wenn Sie diese Lösung in einem großen Projekt verwenden, in dem USART IRQ möglicherweise verbleibt, während ein anderer IRQ-Handler arbeitet, haben Sie möglicherweise wieder Bytes verpasst! – imbearr

Verwandte Themen