code repo: 訪問gitee
上節課成功點亮了LED,這次來把usart 用起來,畢竟有交互才是系統。
技術準備
首先查看手冊,發現mcu有1個usart和1個 lpuart。
usart 的使用需要兩個pin,一個接收一個發送。繼續查看pin and ball definitions, 尋找使用usart可用的pin,發現可選擇PA9+PA10 或者 PB6+PB7。
通過原理圖發現,如果使用PA9+PA10組合,需要單獨接線。而根據圈出的數字順序號,發現PB7,PB6通過轉換連接到了st-link usb接口的DM和DP,因此使用stlink的虛擬串口功能。
查看memory mapping, 得到USART的尋址為:AHB1 --> APB2 --> USART1.
查看時鐘樹,usart 的clock source有4個選擇,分別是PCLKn, SYSCLK, HSI16, LSE.
除此之外,還應當了解有哪些寄存器,以及各個寄存器的作用和意義。但開發優先,可以調用api來開發,多數api都是自注釋的。所以可以等到需要的時候再查詢寄存器。
代碼實現
在main函數中,首先定義一個usart 變量,方便配置usart相關參數,然后新增一個usart初始化函數,并在main中進行調用。初始化函數中定義了串口的配置,波特率,長度等等。
UART_HandleTypeDef huart1;void USART1_UART_Init(void)
{/* USER CODE END USART1_Init 1 */huart1.Instance = USART1;huart1.Init.BaudRate = 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;huart1.Init.OverSampling = UART_OVERSAMPLING_16;huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK){Error_Handler();}if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK){Error_Handler();}if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK){Error_Handler();}
}
還要實現一個HAL_UART_MspInit 接口,該接口是usart初始化的回調接口,用于設置用于usart功能的pin,使能gpio和usart的時鐘
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};if(uartHandle->Instance==USART1){/** Initializes the peripherals clock*/PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){Error_Handler();}/* USART1 clock enable */__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**USART1 GPIO ConfigurationPB6 ------> USART1_TXPB7 ------> USART1_RX*/GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF7_USART1;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}
}
最后實現一個fputc
int fputc(int ch, FILE *f)
{uint8_t data = (uint8_t)ch;if (HAL_UART_Transmit(&huart1, &data, 1, 10) != HAL_OK) // Reduced timeout to 10ms{// Handle transmission errorError_Handler();}return ch;
}
這樣我們就可以使用printf來輸出了。但是別忘記了在工程設置里面使用lib庫,如圖所示。
bugfix:如果在main中調用printf仍舊沒有輸出,可以使用setvbuf設置標準輸出流(stdout)的緩沖模式
setvbuf(stdout, NULL, _IONBF, 0);
效果如下:
code repo: 訪問gitee
commit: 89cba38e2296
搞定收工