STM32
直播中

李林

7年用户 1240经验值
私信 关注
[问答]

如何利用串口调试程序?

如何利用串口调试程序?

回帖(1)

张婧怡

2021-12-8 13:57:44
  一、串口通讯

  为实现最迫切的需求,利用串口来帮助我们调试程序;
  最常用的方法:全双工、异步通讯方式
  
   通讯协议:
   对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流。
  
  以下是串口异步通讯协议示意图
  
  

  

  对于串口的更多参数及相关介绍在这篇文章中有更多较详细的解释
  USART——串口通信
  二、USART串口通信实例

  
   实验环境
   1️⃣野火mini(STM32F103RC)
   2️⃣IDE:KEIL5 MDK
   3️⃣实验串口:USART1
  
  STM32开发板串口硬件原理图
  
  

  

  
新创建三个子文件,bsp_usart.c,bsp_usart.h,main.c,并将三个文件添加到以引入STM32固件库的工程中


三个子文件代码如下


bsp_usart.h


#ifndef __BSP_USART_H__
#define __BSP_USART_H__


#include "stm32f10x.h"
#include
#include


/******************************************************
                串口的宏定义:总线时钟宏和GPIO的宏
*******************************************************/


// 串口USART1
#define  DEBUG_USARTx                   USART1
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200




// USART GPIO 引脚宏定义
#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
   
#define  DEBUG_USART_TX_GPIO_PORT       GPIOA   
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_9
#define  DEBUG_USART_RX_GPIO_PORT       GPIOA
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_10


#define  DEBUG_USART_IRQ                USART1_IRQn
#define  DEBUG_USART_IRQHandler         USART1_IRQHandler




// 函数
void USART_Config(void);
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString(USART_TypeDef * pUSARTx, char *str);
void delay_ms(uint16_t delay_ms);
       
#endif /*__BSP_USART_H__*/


bsp_usart.c


#include "bsp_usart.h"




/**************************************************
                配置嵌套向量中断控制器NVIC
**************************************************/
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  // 嵌套向量中断控制器组选择
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  // 配置USART为中断源
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  // 抢断优先级
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  // 子优先级
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  // 使能中断
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  // 初始化配置NVIC
  NVIC_Init(&NVIC_InitStructure);
}




/**************************************************
                        USART初始化配置
**************************************************/
void USART_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;


        // 打开串口GPIO的时钟
        DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
       
        // 打开串口外设的时钟
        DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);


        // 将USART Tx的GPIO配置为推挽复用模式
        GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);


    // 将USART Rx的GPIO配置为浮空输入模式
        GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
       
        // 配置串口的工作参数
        // 配置波特率
        USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
        // 配置 针数据字长
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        // 配置停止位
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        // 配置校验位
        USART_InitStructure.USART_Parity = USART_Parity_No ;
        // 配置硬件流控制
        USART_InitStructure.USART_HardwareFlowControl =
        USART_HardwareFlowControl_None;
        // 配置工作模式,收发一起
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        // 完成串口的初始化配置
        USART_Init(DEBUG_USARTx, &USART_InitStructure);
       
        // 串口中断优先级配置
        NVIC_Configuration();
       
        // 使能串口接收中断
        USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);       
       
        // 使能串口
        USART_Cmd(DEBUG_USARTx, ENABLE);
}




/**************************************************
                        发送一个字节
**************************************************/
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
        // 发送一个字节数据到USART
        USART_SendData(pUSARTx, ch);
        // 等待发送数据寄存器为空
        while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}




/**************************************************
                                发送字符串
**************************************************/
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
{
        do
        {
                Usart_SendByte(pUSARTx, *str++);
        }while(*str != '');
        // 等待发送完成
        while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET);
}




/**************************************************
                                微秒级的延时
**************************************************/
void delay_us(uint32_t delay_us)
{   
  volatile unsigned int num;
  volatile unsigned int t;

  
  for (num = 0; num < delay_us; num++)
  {
    t = 11;
    while (t != 0)
    {
      t--;
    }
  }
}




/**************************************************
                                毫秒级的延时
**************************************************/
void delay_ms(uint16_t delay_ms)
{   
  volatile unsigned int num;
  for (num = 0; num < delay_ms; num++)
  {
    delay_us(1000);
  }
}




/***************************************************
    重定向c库函数printf到串口,重定向后可使用printf函数
****************************************************/
int fputc(int ch, FILE *f)
{
        // 发送一个字节数据到串口
        USART_SendData(DEBUG_USARTx, (uint8_t) ch);
        // 等待发送完毕
        while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
        return (ch);
}




/*********************************************************
    重定向c库函数scanf到串口,重定向后可使用scanf、getchar函数
**********************************************************/
int fgetc(FILE *f)
{
        // 等待串口输入数据
        while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
        return (int)USART_ReceiveData(DEBUG_USARTx);
}


main.c


#include "stm32f10x.h"
#include "bsp_usart.h"




// 接收缓冲,最大100个字节
uint8_t USART_RX_BUF[100];
// 接收状态标记位
uint16_t USART_RX_FLAG=0;




/*********************************************************
                                            串口中断函数
**********************************************************/
void DEBUG_USART_IRQHandler(void)
{
        uint8_t temp;
        //接收中断
        if(USART_GetFlagStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
        {
                // 读取接收的数据
                temp = USART_ReceiveData(DEBUG_USARTx);
                //接收未完成
                if((USART_RX_FLAG & 0x8000)==0)
                {
                        //接收到了0x0d
                        if(USART_RX_FLAG & 0x4000)
                        {
                                // 接收错误,重新开始
                                if(temp != 0x0a) USART_RX_FLAG=0;
                                // 接收完成
                                else USART_RX_FLAG |= 0x8000;
                        }
                        // 还未接收到0x0d
                        else
                        {
                                if(temp == 0x0d) USART_RX_FLAG |= 0x4000;
                                else
                                {
                                        USART_RX_BUF[USART_RX_FLAG & 0x3FFF]=temp;
                                        USART_RX_FLAG++;
                                        //接收数据错误,重新开始接收
                                        if(USART_RX_FLAG > 99) USART_RX_FLAG=0;
                                }
                        }
                }
        }
}




int main(void)
{
        uint8_t len=0;
        uint8_t i=0;
        // USART初始化
        USART_Config();
        while(1)
        {
                if(USART_RX_FLAG & 0x8000)
                {
                        // 获取接收到的数据长度
                        len = USART_RX_FLAG & 0x3FFF;
                        printf("你发送的消息为:");
                        for(i=0; i                         {
                                // 向串口发送数据
                                USART_SendData(DEBUG_USARTx, USART_RX_BUF);
                                //等待发送结束
                                while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TC)!=SET);
                        }
                        printf("nn");
                        if(strcmp((char *)USART_RX_BUF,"Stop,stm32!")==0)
                        {
                                printf("stm32已停止发送!");
                                break;
                        }
                        USART_RX_FLAG=0;
                        memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));
                }
                else
                {
                        printf("hello windows!n");
                        delay_ms(800);
                }
        }
}


编译后烧录程序,在野火多功能调试程序下运行程序


三、效果演示


  三、效果演示

    

  

  这里需要安装CH340驱动,傻瓜式安装法(http://www.wch.cn/search?t=all&q=CH341A)
  四、参考资料

  《零死角玩转STM32——mini版本》
  USART——串口通讯
举报

更多回帖

×
20
完善资料,
赚取积分