從0開始搭建基於ARM GCC的軟件系統03——printf重定向

如何讓printf語句從指定的端口打印信息,本章節爲你解鎖……
 
一、直接上代碼說明
我使用的AliOS Things Developer Kit,硬件上使用LPUART1(PB10/PB11)作爲串口輸出。
也可以根據具體情況配置其它UART。
 
UART_HandleTypeDef hlpuart1;

//初始化串口LPUART1
void MX_LPUART1_UART_Init(void)
{
    hlpuart1.Instance = LPUART1;
    hlpuart1.Init.BaudRate = 115200;
    hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
    hlpuart1.Init.StopBits = UART_STOPBITS_1;
    hlpuart1.Init.Parity = UART_PARITY_NONE;
    hlpuart1.Init.Mode = UART_MODE_TX_RX;
    hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    //hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    //hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if (HAL_UART_Init(&hlpuart1) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
}

//重寫HAL_UART_MspInit
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    if(uartHandle->Instance==LPUART1)
    {
        /* USER CODE BEGIN LPUART1_MspInit 0 */
        __HAL_RCC_GPIOB_CLK_ENABLE(); //特別注意,我參考的alios thing中代碼,沒有這句,導致串口沒有輸出,這裏添加這句後就OK了

        /* USER CODE END LPUART1_MspInit 0 */
        /* LPUART1 clock enable */
        __HAL_RCC_LPUART1_CLK_ENABLE();

        /**LPUART1 GPIO Configuration    
        PB10     ------> LPUART1_RX
        PB11     ------> LPUART1_TX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* LPUART1 interrupt Init */
        HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(LPUART1_IRQn);
        /* USER CODE BEGIN LPUART1_MspInit 1 */

        /* USER CODE END LPUART1_MspInit 1 */
    }
}

// 重寫write函數, printf時最終會調用這個函數。這裏類似keil ARMCC中的fputc函數
int _write(int file, char *ptr, int len)
{
    int i=0;
    
    for (i = 0; i < len; i++)
    {
        while (!(LPUART1->ISR & USART_ISR_TXE))
        {
        }
        LPUART1->TDR = ptr[i];
    }
    return len;
}

// main函數實現
int main(void)
{

    HAL_Init();

    /* Configure the System clock to have a frequency of 80 MHz */
    SystemClock_Config();

    /* Add your application code here
     */
    MX_LPUART1_UART_Init();
    
    /* Infinite loop */
    while (1)
    {
        printf("Hello world!\n");
        fflush(stdout); //如果printf函數最後不添加"\n",信息不會打印出來,所以這裏需要添加這一句

        /* Insert delay 500 ms */
        HAL_Delay(500);
    }
}

// 以下爲系統初始化代碼,保證系統能運行即可,與printf重定向無關,僅供參考
/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow :
  *            System Clock source            = PLL (MSI)
  *            SYSCLK(Hz)                     = 80000000
  *            HCLK(Hz)                       = 80000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 1
  *            APB2 Prescaler                 = 1
  *            MSI Frequency(Hz)              = 4000000
  *            PLL_M                          = 1
  *            PLL_N                          = 40
  *            PLL_R                          = 2
  *            PLL_P                          = 7
  *            PLL_Q                          = 4
  *            Flash Latency(WS)              = 4
  * @param  None
  * @retval None
  */
static void SystemClock_Config(void)
{

    RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  /* MSI is enabled after System reset, activate PLL with MSI as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 40;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLP = 7;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    /* Initialization Error */
    while(1);
  }
  
  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
     clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    /* Initialization Error */
    while(1);
  }
}

 

二、Makefile注意事項
需要用到一些lib。libc.a\libgcc.a等
在使用 arm gcc 編譯鏈接的過程可能會出現錯誤undefined reference to  `_sbrk'   `_close'  `_fstat'  `_read' `_write' 。
添加以下鏈接參數:
-std=gun99
--specs=nano.specs //使用靜態庫 libc_nano.a
--specs=nosys.specs //使用靜態庫 libnosys.a
 
我使用的編譯參數參考如下:
# 使用了編譯優化和硬件浮點數
CFLAGS += -mcpu=$(CPU) -mthumb -Wall
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -Os
CFLAGS += -ffunction-sections -fdata-sections -std=c99

LFLAGS += -mcpu=$(CPU) -mthumb
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
LFLAGS += -Wl,--gc-sections
# link libgcc.a libc.a libm.a
LFLAGS += -lgcc -lc -lm --specs=nosys.specs --specs=nano.specs -std=c99
# generate map file
LFLAGS += -Wl,-Map,$(TARGET).map
 
 
三、參考文檔
stm32 基於ARM GCC Compliler(EmBitz IDE) print重定向到串口打印輸出 com serial https://blog.csdn.net/daxiebao/article/details/52651891
STM32高級開發(12)-在GCC中使用printf打印串口數據 https://blog.csdn.net/zhengyangliu123/article/details/54966402
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章