開發過程經常需要查看某些特定參數。通常的方法可以使用paintf進行打印輸出,觀察具體的變量值。STM32內部集成有USART的串口功能,可以通過串口直接輸出到電腦(上位機)。使用非常方便,基本不需要不需要寫代碼,只要配置一下就可以使用。
簡單設置就可以看到上面的效果
配置方法:
1、重定向printf的輸出函數 int fputc(int ch, FILE *f)
2、配置STM32F10x的USART串口
重定向方法 stdio.h 的輸出內容
int fputc(int ch, FILE *f) { // 等待USART1 數據發送完成(發送區域空) while (!(USART1->SR & USART_SR_TXE)); // 填充發送寄存器,數據 + 校驗位 最多9位 USART1->DR = (ch & 0x1FF); return (ch); }
啟動STM32的 USART1 串口
1、使能 復用功能
2、使能 A引腳(USART1 在 PA9,PA10)
3、使能 USART1
4、設置 PA9(TX)復用推挽輸出
5、設置 PA10(RX)輸入浮空
6、 設置串口參數:波特率、數據位、校驗、停止位、流控制
7、使能串口、使能輸入、使能輸出
OK
void serial_init(void) { // // 設置串口調試 // // 輸 出: USART1 // 引 腳: PA9(TX), PA10(RX) // 波特率: 9600 // 數據位: 8 bit (default) (CR1) // 校 驗: none (default) (CR1) // 停止位: 1 bit (default) (CR2) // 流控制: none (default) (CR3) // // 清除設置后上面配置為系統默認狀態 int i; /// 使能復用功能,使能GPIOA,使能USART1 RCC->APB2ENR |= RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN; // 關閉映射,確保USART使用 PA9,PA10 AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP; // 清除PA9,PA10狀態 GPIOA->CRH &= ~( GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10 | GPIO_CRH_MODE10 ); // 設置PA9 發送 為復用推挽輸出 2MHz GPIOA->CRH |= GPIO_CR_AFOUT_PP2MHz & ( GPIO_CRH_CNF9 | GPIO_CRH_MODE9 ); // 設置PA10接收 為復用上拉下拉模式 GPIOA->CRH |= GPIO_CR_AFIN_PULLDOWN & ( GPIO_CRH_CNF10 | GPIO_CRH_MODE10 ); // 設置波特率為 9600 // 計算方法 // 系統時鍾 / (16分頻 * 波特率) // Baud = 72,000,000 / (16 * 9600) = 468.75 // 整數部分 << 4 + 取整(小數部分 * 16) // 468 << 4 + 0.75 * 16 USART1->BRR = __USART_BRR(SystemCoreClock, 9600); // 清除寄存器狀態 USART1->CR1 = USART_CR1_REST; USART1->CR2 = USART_CR2_REST; // 停止位 1 USART1->CR3 = USART_CR3_REST; // 沒用控制流 // 防止產生不必要的信息 for (i = 0; i < 0x1000; i++) __NOP(); // USART1 使能, 使能輸出,使能輸入 USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; }
整個過程中關鍵的輸出定向主要用到了2個寄存器:
一個狀態寄存器,檢查發送是否為空(USART_ST_TXE)
一個數據寄存器,用於發送數據
int main(void) { uint8_t ud = 'a'; Delay_init(); // 初始化串口調試 serial_init(); // 使用寄存器直接 輸出 a~z while (ud <= 'z') { while (!(USART1->SR & USART_SR_TXE)); USART1->DR = ud; ud++; } // 使用打印重定向輸出字符串 printf("\ntest!\n"); printf("USART1 使能, 使能輸出,使能輸入\n"); ud = 'a'; while (1) { Delay(20); // 太快降低速度方便看結果(200ms延遲) // 使用寄存器直接輸出 while (!(USART1->SR & USART_SR_TXE)); USART1->DR = ud; ud++; // 使用打印輸出換行 if (ud > 'z') { ud = 'a'; printf("\n"); } }; }
具體的配置寄存器可以查看《參考手冊》
完整代碼

#define GPIO_CR_RESET (uint32_t)0x44444444 #define GPIO_CR_MODE_INPUT (uint32_t)0x00000000 #define GPIO_CR_MODE_2MHz (uint32_t)0x22222222 #define GPIO_CR_MODE_10MHz (uint32_t)0x11111111 #define GPIO_CR_MODE_50MHz (uint32_t)0x33333333 #define GPIO_CR_GP_PUSHPULL (uint32_t)0x00000000 #define GPIO_CR_GP_OPENDRAIN (uint32_t)0x44444444 #define GPIO_CR_OUT_PP2MHz (GPIO_CR_MODE_2MHz | GPIO_CR_GP_PUSHPULL) #define GPIO_CR_OUT_PP50MHz (GPIO_CR_MODE_50MHz | GPIO_CR_GP_PUSHPULL) #define GPIO_CR_AFO_PUSHPULL (uint32_t)0x88888888 #define GPIO_CR_AFO_OPENDRAIN (uint32_t)0xcccccccc #define GPIO_CR_AFOUT_PP2MHz (GPIO_CR_MODE_2MHz | GPIO_CR_AFO_PUSHPULL) // 復用推挽輸出,2MHz #define GPIO_CR_AFIN_FLOAT (uint32_t)0x44444444 // 復用開漏輸入 #define GPIO_CR_AFIN_PULLDOWN (uint32_t)0x88888888 // 復用上拉下拉輸入 #define USART_CR1_REST (uint32_t)0x00000000 #define USART_CR2_REST (uint32_t)0x00000000 #define USART_CR3_REST (uint32_t)0x00000000

/** ******************************************************************** * * @file serial.c * @author fpack * @version v1.0 * @date 2014-9-1 * @brief 小穆妹紙串口調試 * ******************************************************************** **/ #include <stdio.h> #include "armsis.h" /*---------------------------------------------------------------------------- Define Baudrate setting (BRR) for USART *----------------------------------------------------------------------------*/ #define __DIV(__PCLK, __BAUD) ((__PCLK*25)/(4*__BAUD)) #define __DIVMANT(__PCLK, __BAUD) (__DIV(__PCLK, __BAUD)/100) #define __DIVFRAQ(__PCLK, __BAUD) (((__DIV(__PCLK, __BAUD) - (__DIVMANT(__PCLK, __BAUD) * 100)) * 16 + 50) / 100) #define __USART_BRR(__PCLK, __BAUD) ((__DIVMANT(__PCLK, __BAUD) << 4)|(__DIVFRAQ(__PCLK, __BAUD) & 0x0F)) //struct __FILE { int handle; /* Add whatever you need here */ }; //FILE __stdout; //FILE __stdin; int fputc(int ch, FILE *f) { // 等待USART1 數據發送完成(發送區域空) while (!(USART1->SR & USART_SR_TXE)); USART1->DR = (ch & 0x1FF); return (ch); } void serial_init(void) { // // 設置串口調試 // // 輸 出: USART1 // 引 腳: PA9(TX), PA10(RX) // 波特率: 9600 // 數據位: 8 bit (default) (CR1) // 校 驗: none (default) (CR1) // 停止位: 1 bit (default) (CR2) // 流控制: none (default) (CR3) // // 清除設置后上面配置為系統默認狀態 int i; /// 使能復用功能,使能GPIOA,使能USART1 RCC->APB2ENR |= RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN; // 關閉映射,確保USART使用 PA9,PA10 AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP; // 清除PA9,PA10狀態 GPIOA->CRH &= ~( GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10 | GPIO_CRH_MODE10 ); // 設置PA9 發送 為復用推挽輸出 2MHz GPIOA->CRH |= GPIO_CR_AFOUT_PP2MHz & ( GPIO_CRH_CNF9 | GPIO_CRH_MODE9 ); // 設置PA10接收 為復用上拉下拉模式 GPIOA->CRH |= GPIO_CR_AFIN_PULLDOWN & ( GPIO_CRH_CNF10 | GPIO_CRH_MODE10 ); // 設置波特率為 9600 // 計算方法 // 系統時鍾 / (16分頻 * 波特率) // Baud = 72,000,000 / (16 * 9600) = 468.75 // 整數部分 << 4 + 取整(小數部分 * 16) // 468 << 4 + 0.75 * 16 USART1->BRR = __USART_BRR(SystemCoreClock, 9600); // 清除寄存器狀態 USART1->CR1 = USART_CR1_REST; USART1->CR2 = USART_CR2_REST; // 停止位 1 USART1->CR3 = USART_CR3_REST; // 沒用控制流 // 防止產生不必要的信息 for (i = 0; i < 0x1000; i++) __NOP(); // USART1 使能, 使能輸出,使能輸入 USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; }

/** ******************************************************************** * * @file serial.h * @author fpack * @version v1.0 * @date 2014-9-1 * @brief 小穆妹紙串口調試 * ******************************************************************** **/ #ifndef __SERIAL_H__ #define __SERIAL_H__ #ifdef __cplusplus extern "C" { #endif void serial_init(void); #ifdef __cplusplus } #endif #endif