STM32調試大法 之 串口通訊


開發過程經常需要查看某些特定參數。通常的方法可以使用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;
  
}
整理后的串口配置代碼 Serial.c
/**
  ********************************************************************
  *
  * @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   
串口調試頭 Serial.h

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM