从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
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章