2017-04-10 185 views
0

我使用STM32F1(STM32F103C8T6),以開發使用FreeRTOS的一個項目線程啓動。UART發送UART後未能獲得在STM32 HAL庫

以下是我的GPIO以及USART1接口配置:

__GPIOA_CLK_ENABLE(); 
    __USART1_CLK_ENABLE(); 

    GPIO_InitTypeDef GPIO_InitStruct; 
    GPIO_InitStruct.Pin = GPIO_PIN_9; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; 
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

    GPIO_InitStruct.Pin = GPIO_PIN_10; 
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 
    GPIO_InitStruct.Pull = GPIO_NOPULL; 
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

    huart1.Instance = USART1; 
    huart1.Init.BaudRate = 9600;//115200; 
    huart1.Init.WordLength = UART_WORDLENGTH_8B; 
    huart1.Init.StopBits = UART_STOPBITS_1; 
    huart1.Init.Parity = UART_PARITY_NONE; 
    huart1.Init.Mode = UART_MODE_TX_RX; 
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; 
    HAL_UART_Init(&huart1); 

    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); 
    HAL_NVIC_EnableIRQ(USART1_IRQn); 

的問題是:爲什麼UART發送工作之前線程開始,但線程啓動後不或線程?我想從線程傳輸數據。即

int main(void) 
{ 
    Initializations(); 

    //THIS WORKS!! 
    uart_transmit_buffer[0] = 'H'; 
    uart_transmit_buffer[1] = 'R'; 
    uart_transmit_buffer[2] = '#'; 
    uint8_t nums_in_tr_buf = 0; 
    nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t); 
    state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000); 

    StartAllThreads(); 
    osKernelStart(); 

    for (;;); 
} 

static void A_Random_Thread(void const *argument) 
{ 
     for(;;) 
     { 
     if (conditionsMet()) //Executed once when a proper response received. 
     { 
      //BUT NOT THIS :(!! 
      uart_transmit_buffer[0] = 'H'; 
      uart_transmit_buffer[1] = 'R'; 
      uart_transmit_buffer[2] = '#'; 
      uint8_t nums_in_tr_buf = 0; 
      nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t); 
      state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000); 
     } 
     } 
} 

我確定沒有線程處於死鎖狀態。問題是UART_HAL_Transmit給出了HAL_BUSY狀態。

而且,我有專門的一個線程接收和UART RX解析信息,我懷疑這可能是問題的原因。以下是代碼:

static void UART_Receive_Thread(void const *argument) 
{ 
    uint32_t count; 
    (void) argument; 
    int j = 0, word_length = 0; 

    for (;;) 
    { 
      if (uart_line_ready == 0) 
      { 
        HAL_UART_Receive(&huart1, uart_receive_buffer, UART_RX_BUFFER_SIZE, 0xFFFF); 
        if (uart_receive_buffer[0] != 0) 
        { 
          if (uart_receive_buffer[0] != END_OF_WORD_CHAR) 
          { 
            uart_line_buffer[k] = uart_receive_buffer[0]; 
            uart_receive_buffer[0] = 0; 
            k++; 
          } 
          else 
          { 
            uart_receive_buffer[0] = 0; 
            uart_line_ready = 1; 
            word_length = k; 
            k = 0; 
          } 
        } 
      } 
      if (uart_line_ready == 1) 
      { 
        //osThreadSuspend(OLEDThreadHandle); 
        for (j = 0; j <= word_length; j++) 
        { 
          UART_RECEIVED_COMMAND[j] = uart_line_buffer[j]; 
        } 
        for (j = 0; j <= word_length; j++) 
        { 
          uart_line_buffer[j] = 0; 
        } 
        uart_line_ready = 0; 

        RECEIVED_COMMAND = ParseReceivedCommand(UART_RECEIVED_COMMAND); 
        if (RECEIVED_COMMAND != _ID_) 
        { 
          AssignReceivedData (word_length); //Results in uint8_t * RECEIVED_DATA 
        } 
        //osThreadResume(OLEDThreadHandle); 
      } 
      //Should be no delay in order not to miss any data.. 
    } 
} 

另一個原因,我懷疑可能與系統的中斷問題(也請注意初始化部分,我配置NVIC):

void USART1_IRQHandler(void) 
{ 
    HAL_UART_IRQHandler(&huart1); 
} 

任何幫助或對此問題的指導將受到高度讚賞。提前致謝。

+1

實際上,您並未使用中斷,只是在NVIC中啓用UART IRQ,但它也必須位於外設。 'HAL_UART_Receive_IT'做到了'HAL_UART_Receive'沒有。進行測試,在其中不啓動UART接收線程。 –

+0

我的意思是說,沒有UART接收線程它的作品。問題是如何克服這個問題?你是否建議使用HAL_UART_Receive_IT而不是HAL_UART_Receive? – mozcelikors

+0

不,這只是一個與IRQ無關的說法。例如,您的線程可能會嘗試同時使用UART並以BUSY狀態接管。嘗試通過信號量或互斥鎖來保護UART的使用。 –

回答

1

原來,這個問題是事做阻擋語句。 由於UART_Receive_Thread內部有HAL_UART_Receive和被阻塞的線程,直到被接收的東西,這導致在一個繁忙的HAL(因此,HAL_BUSY狀態)。

溶液使用無阻塞語句不改變任何東西。 即,使用HAL_UART_Receive_ITHAL_UART_Transmit_IT同時並忽略阻斷語句的工作。

感謝導致這種解決方案的所有建議。

1

使用FreeRTOS操作系統,你必須中斷優先級設置爲5或以上,因爲低於5被保留用於操作系統。 因此改變你的代碼的優先級設置爲:

HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); 
+0

感謝您的幫助提示,但不幸的是,這並沒有解決我的問題。 – mozcelikors

1

從我所看到的HAL_UART_Transmit將與F4 HAL(。5.0),如果不是因爲__HAL_LOCK(huart)工作過。 RX線程會鎖定句柄,然後TX線程會嘗試鎖定並返回HAL_BUSY。 HAL_UART_Transmit_ITHAL_UART_Receive_IT在發送/接收期間不鎖定手柄。

這可能會導致State成員出現問題,因爲它是由幫助函數UART_Receive_ITUART_Transmit_IT非原子更新的。雖然我不認爲這會影響手術。

您可以修改該功能以允許同時進行接收和發送。每次他們發佈HAL的新版本時,你都必須更新它。

問題是ST HAL並不意味着要與RTOS一起使用。它在宏__HAL_LOCK的定義中這樣說。重新定義它以使用RTOS的互斥體也值得嘗試。與HAL_Delay()一樣使用RTOS的線程休眠功能。

一般來說,雖然在線程中通過阻塞函數發送應該沒問題,但我不會在線程中使用阻塞函數接收數據。你必然會遇到這樣的超限錯誤。

同樣,如果在接收中斷中進行了太多處理,您可能會遇到溢出錯誤。我更喜歡使用DMA進行接收,如果我已經用完了DMA流,則會使用中斷。中斷只將數據複製到緩衝區,與DMA相似。然後使用線程processRxData來處理實際數據。