Stm32

2024-03-01 1745阅读

温馨提示:这篇文章已超过440天没有更新,请注意相关的内容是否还可用!

目录标题

  • 前言
  • 1、串口中断接收固定帧头帧尾数据
    • 1.1、任务需求
    • 1.2、实现思路
    • 1.3、程序源码:
    • 2、串口中断接收+用定时器来判断帧结束
    • 3、串口中断接收数据+空闲中断
      • 3.1、串口的空闲中断
      • 3.2、实现思路
      • 3.3、程序源码
      • 4、串口的空闲中断+DMA转运
        • 4.1、DMA简介
        • 4.2、DMA模式
        • 4.3、DMA资源
        • 4.4、DMA主要特征
        • 4.5、实现思路
        • 4.6程序源码:
        • 报错及解决:

          前言

          使用串口传输数据时,因为串口是异步通信协议,所以我们需要去判断哪是一帧完整的数据,并进行数据的处理。


          接收不定长的数据以下几个主要有以下方法:

          • 加固定的帧头和帧尾
          • 串口中断接收+用定时器来判断帧结束
          • 串口中断接收+利用串口空闲中断来判断帧结束

            1、串口中断接收固定帧头帧尾数据

            1.1、任务需求

            1、PC端通过串口1发送给单片机一个有固定帧头帧尾的数据包。

            2、单片机利用串口中断接收数据并判断帧头帧尾。

            3、当识别到对应的帧头帧尾时,将接收到的数据再发送给PC端。

            4、清除接收缓存。

            1.2、实现思路

            • 1、使能相关时钟

              使能相关GPIO所在APB2总线的时钟

              使能串口所在APB2总线的时钟

            • 2、初始化串口

              配置数据位个数、停止位个数、校验位、波特率等

            • 3、初始化GPIO

              配置RX、TX对应GPIO口。

            • 4、初始化串口中断

              配置中断通道,中断优先级等

            • 4、使能串口中断

            • 5、使能串口

            • 6、编写中断服务程序:

              • ①判断接收到的数据是否是帧头
              • ②若是帧头则将数据写入到缓冲区;若不是则无视,等待下一个数据。
              • ③当有帧头后,不断在后面接收到的数据中找帧尾。找到了则说明这一帧数据接收完成了。
              • ④将这一帧数据再通过printf发送回PC端。
              • ⑤清楚缓冲区数据,将索引清零。

                1.3、程序源码:

                usart.h

                #ifndef __SERIAL_H__
                #define __SERIAL_H__
                #include "stm32f10x.h"                  // Device header
                #include 
                #include "stdio.h"
                #include "string.h"
                #define USART1_ENABLE  1          //使能串口1      
                #define USART1_BAUDRATE 9600      //串口1波特率
                #define USART1_INTERRUPT_ENABLE 1  //使能串口1中断
                #define RECEIVE_BUF_MAX_SIZE 100  //单次最大接收字节数
                typedef struct{
                	uint8_t Buffer[RECEIVE_BUF_MAX_SIZE];
                	uint16_t Lenth;
                }usart_data;
                void Serial_Init(void);//串口初始化
                #endif
                

                usart.c

                void Serial_Init(void)
                {
                	GPIO_InitTypeDef GPIO_InitStructure;
                	USART_InitTypeDef USART_InitStructure;
                	NVIC_InitTypeDef NVIC_Structure;
                	
                #if USART1_ENABLE  
                	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
                	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
                	
                	
                	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
                	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
                	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                	GPIO_Init(GPIOA,&GPIO_InitStructure);
                	
                	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
                	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
                	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                	GPIO_Init(GPIOA,&GPIO_InitStructure);
                	
                	
                	USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
                	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
                	USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
                	USART_InitStructure.USART_Parity= USART_Parity_No;
                	USART_InitStructure.USART_StopBits= USART_StopBits_1;
                	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
                	USART_Init(USART1,&USART_InitStructure);
                #if USART1_INTERRUPT_ENABLE	
                	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
                	
                	NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
                	NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
                	NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
                	NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
                	NVIC_Init(&NVIC_Structure);
                #endif
                	USART_Cmd(USART1,ENABLE);
                #endif
                }
                int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
                {
                	USART_SendData(USART1,ch);	
                	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
                	return ch;
                }
                //串口一中断处理函数
                usart_data usart1_rxdata;
                uint16_t data;
                void USART1_IRQHandler(void)
                {
                	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET) //若发生串口中断
                	{
                		usart1_rxdata.Buffer[usart1_rxdata.Lenth++] = USART_ReceiveData(USART1);
                		if(usart1_rxdata.Buffer[0]!='h') //判断帧头
                			usart1_rxdata.Lenth =0;
                		if((usart1_rxdata.Buffer[0]=='h')&&(usart1_rxdata.Buffer[usart1_rxdata.Lenth-1]=='e'))
                		//判断帧头帧尾
                		{
                			printf("rx_data:%s\r\n",usart1_rxdata.Buffer);//将接收到的一帧数据再发送回去,做验证
                			memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
                			usart1_rxdata.Lenth = 0;
                		}	
                		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清中断标志位
                	}
                }
                

                2、串口中断接收+用定时器来判断帧结束

                暂时不写

                3、串口中断接收数据+空闲中断

                3.1、串口的空闲中断

                空闲中断USART_IT_IDLE,俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(就是没数据接收的状态),检测到此空闲状态后即执行中断程序。进入中断程序即意味着已经接收到一组完整帧数据,仅需及时对数据处理或将数据转移出缓冲区即可。

                相较于上面的利用固定帧头和帧尾来判断完整数据帧,这种方法更为使用,通过利用空闲中断,对于没有固定帧头和帧尾的数据我们也能准确接收了。

                3.2、实现思路

                • 1、使能相关时钟

                  使能相关GPIO所在APB2总线的时钟

                  使能串口所在APB2总线的时钟

                • 2、初始化串口

                  配置数据位个数、停止位个数、校验位、波特率等

                • 3、初始化GPIO

                  配置RX、TX对应GPIO口。

                • 4、初始化串口中断

                  配置中断通道,中断优先级等

                • 4、使能串口中断
                • 5、使能串口的空闲中断
                • 5、使能串口
                • 6、编写中断服务程序:
                  • ①判断中断类型:串口中断、串口的空闲中断
                  • ②若是串口中断,就将接收的数据存入缓冲区。然后清除中断标志
                  • ③若是串口的空闲中断,则说明这一帧数据接收完了后面就是数据处理了。
                  • ④数据处理完后,就将数据缓冲区清除,将索引号清零。
                  • ⑤清除串口空闲中断标志位(通过读串口的SR和DR寄存器)

                    3.3、程序源码

                    usart.h

                    #ifndef __SERIAL_H__
                    #define __SERIAL_H__
                    #include "stm32f10x.h"                  // Device header
                    #include 
                    #include "stdio.h"
                    #include "string.h"
                    #define USART1_ENABLE  1                
                    #define USART1_BAUDRATE 9600
                    #define USART1_INTERRUPT_ENABLE 1
                    #define USART1_IDLE_INTERRUPT_ENABLE 1
                    #define RECEIVE_BUF_MAX_SIZE 100  //单次最大接收字节数
                    typedef struct{
                       uint8_t Buffer[RECEIVE_BUF_MAX_SIZE];
                       uint16_t Lenth;
                    }usart_data;
                    void Serial_Init(void);//串口初始化
                    #endif
                    

                    usart.c

                    #include "Serial.h"
                    void Serial_Init(void)
                    {
                       GPIO_InitTypeDef GPIO_InitStructure;
                       USART_InitTypeDef USART_InitStructure;
                       NVIC_InitTypeDef NVIC_Structure;
                       
                    #if USART1_ENABLE  
                       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
                       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
                       
                       
                       GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
                       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
                       GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                       GPIO_Init(GPIOA,&GPIO_InitStructure);
                       
                       GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
                       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
                       GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                       GPIO_Init(GPIOA,&GPIO_InitStructure);
                       
                       
                       USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
                       USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
                       USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
                       USART_InitStructure.USART_Parity= USART_Parity_No;
                       USART_InitStructure.USART_StopBits= USART_StopBits_1;
                       USART_InitStructure.USART_WordLength= USART_WordLength_8b;
                       USART_Init(USART1,&USART_InitStructure);
                       
                    #if USART1_INTERRUPT_ENABLE	
                      
                       USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
                       
                       NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
                       NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
                       NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
                       NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
                       NVIC_Init(&NVIC_Structure);
                    #if USART1_IDLE_INTERRUPT_ENABLE  
                       USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能串口1的空闲中断
                    #endif
                    #endif
                       USART_Cmd(USART1,ENABLE);
                    #endif
                    }
                    //=================================================================
                    int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
                    {
                       Serial_Sendbyte(USART1,ch);
                       return ch;
                    }
                    //串口一中断
                    usart_data usart1_rxdata;
                    uint16_t data;
                    void USART1_IRQHandler(void)
                    {
                       uint16_t clear;
                       if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
                       {
                       	usart1_rxdata.Buffer[usart1_rxdata.Lenth++] = USART_ReceiveData(USART1);
                       	if(usart1_rxdata.Lenth>RECEIVE_BUF_MAX_SIZE)
                       		usart1_rxdata.Lenth =0;
                       	USART_ClearITPendingBit(USART1,USART_IT_RXNE);
                       }
                       else if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)//串口空闲中断
                       {
                       	printf("rx_data:%s\r\n",usart1_rxdata.Buffer);
                       	memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
                       	usart1_rxdata.Lenth = 0;
                       	clear = USART1->SR;
                       	clear = USART1->DR;
                       }
                       
                    }
                    

                    4、串口的空闲中断+DMA转运

                    4.1、DMA简介

                    直接存储器访问(Direct Memory Access),简称DMA。DMA是CPU一个用于数据从一个地址空间到另一地址空间“搬运”(拷贝)的组件,数据拷贝过程不需CPU干预,数据拷贝结束则通知CPU处理。因此,大量数据拷贝时,使用DMA可以释放CPU资源。

                    4.2、DMA模式

                    DMA数据拷贝过程,典型的有:

                    (1)内存—>内存,内存间拷贝;

                    (2)外设—>内存,如uart、spi、i2c等总线接收数据过程;

                    (3)内存—>外设,如uart、spi、i2c等总线发送数据过程。

                    4.3、DMA资源

                    STM32F1系列的MCU有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道,DMA2有5个通道,每个通道专门用来管理来自于一个或者多个外设对存储器的访问请求。还有一个仲裁器来协调各个DMA请求的优先权。

                    Stm32

                    Stm32

                    4.4、DMA主要特征

                    • 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
                    • 在同一个 DMA 模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求 0 优先于请求 1 ,依此类推,可以参考STM32数据手册)。
                    • 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
                    • 支持循环的缓冲器管理(会把原来的数据覆盖)。
                    • 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。
                    • 存储器和存储器间的传输(仅 DMA2 可以)。
                    • 外设和存储器、存储器和外设之间的传输。
                    • 闪存、SRAM 、外设的 SRAM 、APB1 、APB2 和 AHB 外设均可作为访问的源和目标。
                    • 可编程的数据传输数目:最大为65535。

                      高波特率传输场景下,串口非常有必要使用DMA。

                      4.5、实现思路

                      • 1、使能相关时钟

                        使能相关GPIO所在APB2总线的时钟

                        使能串口所在APB2总线的时钟

                        使能DMA1时钟

                      • 2、初始化串口

                        配置数据位个数、停止位个数、校验位、波特率等

                      • 3、初始化GPIO

                        配置RX、TX对应GPIO口。

                      • 4、初始化串口空闲中断

                        配置中断通道,中断优先级等

                      • 5、使能串口的空闲中断
                      • 6、配置初始化DMA1。
                      • 7、使能串口1的DMA接收;使能DMA1的TX通道(DMA1_Channel4)
                      • 8、使能串口
                      • 9、编写中断服务程序:
                        • ①判断中断类型:串口的空闲中断
                        • ②清除串口空闲中断标志位(通过读串口的SR和DR寄存器)
                        • ③关闭DMA通道
                        • ④进行数据处理(置标志位等)
                        • ⑤重新设置 DMA 传输数据长度
                        • ⑥使能DMA通道

                          4.6程序源码:

                          usart.h

                          #ifndef __SERIAL_H__
                          #define __SERIAL_H__
                          #include "stm32f10x.h"                  // Device header
                          #include 
                          #include "stdio.h"
                          #include "string.h"
                          #define USART1_ENABLE  1                
                          #define USART1_BAUDRATE 9600
                          #define USART1_INTERRUPT_ENABLE 1
                          #define USART1_IDLE_INTERRUPT_ENABLE 1
                          #define USART1_DMA_TX_ENABLE 0
                          #define USART1_DMA_RX_ENABLE 1
                          #define USART_BUF_MAX_SIZE 100  //单次最大接收字节数
                          typedef struct{
                          	uint8_t Buffer[USART_BUF_MAX_SIZE];
                          	uint16_t Lenth;
                          }usart_data;
                          void Serial_Init(void);//串口初始化
                          #endif
                          

                          usart.c

                          #include "Serial.h"
                          usart_data usart1_rxdata;
                          usart_data usart_txdata;
                          void Serial_Init(void)
                          {
                          	GPIO_InitTypeDef GPIO_InitStructure;
                          	USART_InitTypeDef USART_InitStructure;
                          	NVIC_InitTypeDef NVIC_Structure;
                          	DMA_InitTypeDef DMA_InitStructure;
                          #if USART1_ENABLE  
                          	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
                          	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
                          	
                          	
                          	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
                          	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
                          	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                          	GPIO_Init(GPIOA,&GPIO_InitStructure);
                          	
                          	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
                          	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
                          	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                          	GPIO_Init(GPIOA,&GPIO_InitStructure);
                          	
                          	
                          	USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
                          	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
                          	USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
                          	USART_InitStructure.USART_Parity= USART_Parity_No;
                          	USART_InitStructure.USART_StopBits= USART_StopBits_1;
                          	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
                          	USART_Init(USART1,&USART_InitStructure);
                          	
                          #if USART1_INTERRUPT_ENABLE	|USART1_IDLE_INTERRUPT_ENABLE
                             
                          	NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
                          	NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
                          	NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
                          	NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
                          	NVIC_Init(&NVIC_Structure);
                          #if USART1_INTERRUPT_ENABLE
                          	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
                          #endif 
                          #if USART1_IDLE_INTERRUPT_ENABLE  
                          	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能串口1的空闲中断
                          #endif
                          #endif
                          #if USART1_DMA_TX_ENABLE
                          	/*Usart1_TX_DMA_config,从存储区到USART1->DR*/
                          	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
                          	DMA_DeInit(DMA1_Channel4);
                          	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);   //外设站点起始地址
                          	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
                          	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址不自增
                          	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart_txdata.Buffer;//存储器站点起始地址
                          	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
                          	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器站点自增
                          	
                          	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;    //存储器站点到外设站点   //传输方向
                          	DMA_InitStructure.DMA_BufferSize = USART_BUF_MAX_SIZE;//缓冲区大小,传输计数器
                          	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //普通模式,不循环
                          	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //失能(不是存储器到存储器)
                          	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级
                          	DMA_Init(DMA1_Channel4, &DMA_InitStructure);
                          	
                          	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送
                          	
                          	DMA_Cmd(DMA1_Channel4,ENABLE); //使能DMA1的TX通道(DMA1_Channel4)
                          	
                          #endif
                          #if USART1_DMA_RX_ENABLE
                          	/*Usart1_RX_DMA_config,从USART1->DR到存储区*/
                          	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
                          	DMA_DeInit(DMA1_Channel5);
                          	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);   //外设站点起始地址
                          	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
                          	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址不自增
                          	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart1_rxdata.Buffer;//存储器站点起始地址
                          	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
                          	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器站点自增
                          	
                          	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;    //外设站点到存储器站点   //传输方向
                          	DMA_InitStructure.DMA_BufferSize = USART_BUF_MAX_SIZE;//缓冲区大小,传输计数器
                          	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //普通模式,不循环
                          	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //失能(不是存储器到存储器)
                          	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级
                          	DMA_Init(DMA1_Channel5, &DMA_InitStructure);
                          	
                          	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收
                          	DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的TX通道(DMA1_Channel4)
                          	
                          #endif
                          	USART_Cmd(USART1,ENABLE);
                          #endif
                          }
                          //串口一中断
                          void USART1_IRQHandler(void)
                          {
                          	uint16_t clear;
                          	if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
                          	{
                          		clear = USART1->SR;
                          		clear = USART1->DR;
                          		DMA_Cmd(DMA1_Channel5, DISABLE);  // 关闭 DMA 通道
                          		usart1_rxdata.Lenth = sizeof(usart1_rxdata.Buffer) - DMA_GetCurrDataCounter(DMA1_Channel5);  // 计算接收到的数据长度
                          		printf("rx_data:%s\r\n",usart1_rxdata.Buffer);
                          		memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
                          		DMA_SetCurrDataCounter(DMA1_Channel5, sizeof(usart1_rxdata.Buffer));  // 重新设置 DMA 传输数据长度
                          		DMA_Cmd(DMA1_Channel5, ENABLE);  // 使能 DMA 通道
                          	}
                          	
                          }
                          

                          报错及解决:

                          int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
                          {
                          	USART_SendData(USART1,ch);	
                          	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
                          	return ch;
                          }
                          

                          我们在使用上面的程序进行printf重构定向时,需要注意以下两点:

                          1、在“魔法棒”—>"Target"中,将”USB Micro LIB“勾选上,否则会出现不能正常打印甚至单片机直接进入硬件错误中断宕机的情况。

                          Stm32

                          2、需要添加头文件 #include “stdio.h”,否则会出现报错“error: unknown type name “FILE” ”。

                          Stm32

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]