STM32学习——USART收发数据

简介

1.串口通讯的双方若采用不同的电平标准,则需要利用电平转换芯片进行转换。
2.调试程序时可以把一些调试信息“打印”在电脑端的串口调试助手上。
3.硬件原理以后有空再研究,应该跟微机里学的挺类似的。。。

配置一个串口的步骤

1.使能USART时钟,以及RX和TX引脚的GPIO时钟
2.初始化GPIO,配置相关的引脚功能
3.配置USART的工作参数
4.配置中断控制器NVIC,使能串口中断
5.使能USART的接收中断
6.使能USART
7.编写中断服务函数

代码设计

通用代码参考的是野火的代码,自己写的太不规范了。。。

(1)串口初始化

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);	    
}

(2)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);
}

(3)发送一个字符以及发送字符串
对于发送字符,这里封装了库函数并增加了等待发送完成的查询(若无该步,字符串无法发送成功)

/*===================发送一个字符=========================*/
void Usart_SendByte(USART_TypeDef* USARTx, uint8_t Data)
{
	USART_SendData(USARTx,Data);
	
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}

/*===================发送一个字符串======================*/
void Usart_SendString(USART_TypeDef* USARTx,char *str)
{
	uint32_t i=0;
	for(;*(str+i)!='\0';i++)
	{
		Usart_SendByte(USARTx,*(str+i));
	}
	
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}

(4)printf的重定向
为了使用c库中的printf,需要对fputc进行重定向

//注意添加头文件
#include <stdio.h>

//……

///重定向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);
}

(5)发送和接受数据
定义一个缓冲区,利用中断方式接受数据,利用FIFO模式发送数据,分别贴出中断服务函数以及主函数

//中断服务函数

extern uint8_t Uart_data[64];
extern uint32_t Rx_Num;

void DEBUG_USART_IRQHandler(void)
{
	uint8_t temp;
	if(USART_GetITStatus(DEBUG_USARTx , USART_IT_RXNE)!=RESET)
	{
		
		temp= USART_ReceiveData(DEBUG_USARTx);
		Uart_data[Rx_Num]=temp;
		Rx_Num++;
		Rx_Num&=0x3f;
	}
}

//主函数
uint8_t Uart_data[64];
uint32_t Rx_Num=0;
uint32_t Tx_Num=0;

int main(void)
{
	DEBUG_USART_Config();
	printf("hello,world\r");
	
	while(1)
	{	
		if(Tx_Num!=Rx_Num)
		{
			USART_SendData(DEBUG_USARTx,Uart_data[Tx_Num]);
			Tx_Num++;
			Tx_Num&=0x3f;
		}
	}
}

上述方法定义了三个外部变量,需要注意用法。

(6)设置指令集(控制LED)
利用上位机发送数据时,只能发送单个字符,发送一串字符时仅能接收到第一个。

/*====================字符串匹配=======================*/
uint8_t Cmp(uint8_t *str,uint8_t num)
{
	uint8_t i=0;
	uint8_t	str1[]="111111111";
	uint8_t str2[]="000000000";
	
	for(i=0;i<(num-1);i++)
	{
		if(*(str1+i)!=*(str+i))
			break;
	}
	if(i==(num-1))
		return 1;
	
	for(i=0;i<(num-1);i++)
	{
		if(*(str2+i)!=*(str+i))
			break;
	}
	if(i==(num-1))
		return 2;
	
	return 0;
}

//中断服务函数
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
  	uint8_t ucTemp;
	u8 i;
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(DEBUG_USARTx);
    	//USART_SendData(DEBUG_USARTx,ucTemp);  
		Uart_Data[Rx_Num]=ucTemp;
		Rx_Num++;
		for(i=0;i<10;i++)
		{
			printf("%c",Uart_Data[i]);
		}
		
		if(Rx_Num==9)
		{
//			for(i=0;i<10;i++)
//			{
//				printf("%c",Uart_Data[i]);
//			}
			Rx_Num=0;
		}
	}	 
}

//主函数
int main(void)
{	
  	USART_Config();
	LED_Config();

 	while(1)
	{	
		switch(Cmp(Uart_Data,10))
		{
			case 1:	LED1_ON;
					LED2_OFF;
					break;
			case 2:	LED1_OFF;
					LED2_ON;
					break;
			case 0:
					LED2_OFF;
					LED1_OFF;
					break;
			}	
	}
}

填坑

在使用正点原子例程进行接受数据时,出现的问题
功能概述:MCU之间通过USART2进行数据传输,然后主控芯片又通过USART1向电脑端的串口助手发送数据。
存在问题:在高速数据传输的过程中第一位丢失
在这里插入图片描述
原因:printf的问题,重定向时存在问题,导致数据高速传输时,使用printf会导致之后的数据丢失(主控向电脑端传输时)
解决方法:原先用printf发送数据的地方改用USART_SendData发送,在用while等待

while(1)
	{
		/*====================MCU之间串口通信的数据显示=========================*/
		//功能说明
		//MCU之间通过USART2进行通信,主控芯片将数据存入缓冲区,并通过串口1发送到电脑端
		//数组有效数据长度为9
		
		if(USART2_RX_STA&0x8000)											//如果发送完成
		{
			len=(USART2_RX_STA&0x3fff);
			
			USART_SendData(USART1,len);//发长度
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			for(i=0;i<len;i++)				//将数据通过串口1发送
			{
				USART_SendData(USART1,USART2_RX_BUF[i]);
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			}
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			USART_SendData(USART1,'\r');//插入换行
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			USART_SendData(USART1,'\n');//插入换行
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			USART2_RX_STA=0;
		}
		
		/*==========================================================================*/	
	}

注意:一定要取一中间变量len,在for循环发送数据时USART2_RX_STA可能会进入中断从而改变数据长度
正点原子串口数据接收的思路:
1.利用缓冲区
2.设置状态变量USART2_RX_STA,低13位表示数据长度,14位表示接收到0x0d,15位表示接收到0x0a(接收完成)(通信协议,发送的数据最后需要加’\r\n’才能接受)

void USART2_IRQHandler(void)                	//串口2中断服务程序
{
	u8 Res;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
		Res =USART_ReceiveData(USART2);//(USART1->DR);	//读取接收到的数据
		
		if((USART2_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART2_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART2_RX_STA=0;//接收错误,重新开始
				else USART2_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)USART2_RX_STA|=0x4000;
				else
				{
					USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
					USART2_RX_STA++;
					if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}
  } 
} 
  • 3
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32F429是一款具有丰富外设功能的微控制器,其中包括了USART和DMA功能。USART(Universal Synchronous/Asynchronous Receiver Transmitter)是一种通用的同步/异步收发器,用于与外部设备进行数据收发。DMA(Direct Memory Access)是一种数据直接内存访问的技术,可以实现数据在外设和内存之间的高速传输。 在STM32F429中,我们可以使用USART和DMA配合使用来实现高效的收发功能。具体步骤如下: 首先,我们需要通过配置USART寄存器将USART配置为所需的通信模式(同步或异步),设置波特率、数据位数、停止位数等参数。 然后,我们需要配置DMA通道以及相关的寄存器,以实现USART数据的传输。配置DMA的相关参数,包括源地址(USART数据寄存器或接收寄存器),目的地址(内存空间)、数据长度,并选择合适的传输方向(接收或发送)。 接下来,我们需要使能USART和DMA,并通过设置相关的中断和标志位来检测接收和发送的完成状态,以及错误状态。可以通过串口中断或查询方式来处理数据收发。 在数据收发过程中,DMA会自动控制数据的传输,减轻了CPU的负担。当数据到达或发送完成时,将触发相应的中断或标志位,我们可以通过相关的中断服务程序或查询标志位来处理数据。 通过使用USART和DMA,可以实现高效的数据收发功能,提高系统的实时性和并发性。但是在使用过程中,需要注意配置USART和DMA的相关参数,确保数据能够正常地收发。此外,在使用DMA进行数据传输时,需要小心处理数据的对齐和长度对齐等问题,以保证数据的正确性。 总而言之,STM32F429的USART和DMA功能可以实现快速、稳定的数据收发。通过合理的配置参数和处理方式,可以满足不同应用场景下的数据传输需求。 ### 回答2: STM32F429是一款基于ARM Cortex-M4内核的微控制器,具有强大的外设功能。USART是它的一种通讯接口,用于实现串行通讯。而DMA(直接内存访问)是一种数据传输方式,可以减轻CPU的负担。 STM32F429的USART模块可以通过DMA来实现数据收发,具体步骤如下: 1. 配置USART模块的参数:首先需要设置USART的波特率、数据位、停止位等参数,并开启USART外设。 2. 配置DMA通道:选择一个可用的DMA通道,并配置其传输方向、数据缓冲区和传输长度等参数。 3. 配置USART的DMA功能:使能USART的DMA传输模式,选择合适的DMA通道。 4. 准备数据缓冲区:在DMA传输之前,需要准备好待发送的数据或者接收数据的存储空间。 5. 使能DMA传输:开始DMA传输,此时数据会通过USART发送或者接收。 6. 等待传输完成:可以使用中断或者轮询等方式来判断DMA传输是否完成。 7. 处理传输结果:根据实际需求,可以对接收到的数据进行处理或者对发送的数据进行确认。 通过使用DMA传输数据,可以大大提高数据传输的效率。因为DMA可以直接在外设和内存之间进行数据传输,而无需CPU的干预,从而减少了CPU的负担,提高了系统的响应速度。 总之,通过配置STM32F429的USART和DMA功能,我们可以方便地实现USART数据收发功能,并提高系统的性能和效率。 ### 回答3: STM32F429是ST公司生产的一款ARM Cortex-M4内核的32位微控制器,具有丰富的外设资源。其中,USART是一种通用异步收发传输接口,而DMA是直接内存访问技术。结合使用USART和DMA可以实现高效的数据收发STM32F429的USART外设提供了寄存器和数据缓冲区,用于设置通信参数和缓存数据。而DMA技术可以将数据直接从内存传输到USART或从USART传输到内存,无需经过CPU的中介。这种方式可以大幅节省CPU的处理时间和系统资源,并且增加数据传输的效率。 使用USART的DMA收发功能有以下几个步骤: 首先,配置USART的工作模式、波特率、数据位数等通信参数,并使能USART和DMA的时钟。 然后,配置DMA的传输方向和传输大小,并设置DMA源地址和目的地址。对于发送操作,源地址为数据缓冲区,目的地址为USART数据寄存器;对于接收操作,源地址为USART数据寄存器,目的地址为数据缓冲区。 接下来,配置DMA的触发源和传输模式。触发源可以选择为USART的发送或接收就绪事件。传输模式可以选择为单次传输或循环传输,根据具体需求进行配置。 最后,使能USART的DMA发送或接收功能,并启动DMA传输。此时,USART会自动将数据发送或接收到配置的地址中。 总结来说,通过配置USART的参数和DMA的传输设置,可以在STM32F429中实现基于USART数据收发功能。使用DMA技术可以提高数据传输的效率,减少CPU的负担,使系统更加稳定和可靠。这种方式在实际的嵌入式应用中经常被使用,适用于串口通信等场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值