STM32串口通讯——中断方式

本文详细介绍了如何使用中断方式进行STM32串口通讯,包括中断服务函数和NVIC配置。通过示例代码展示了串口接收中断的处理流程,以及如何根据接收到的数据做出响应。在实验中,当接收到特定字符串时,串口会停止发送数据。此外,还总结了串口通讯的三种方式:查询、中断和DMA,并讨论了它们在不同场景下的适用性。

一、简介

在上一次我们学习了如何使用查询的方式进行串口通讯——发送数据,以及中断的方式,在本次我们使用中断来进行串口通讯。
可以参考以前的博客:
串口通讯:STM32串口通讯实现——USB转串口.
中断:STM32使用中断方式读取按键控制LED灯的亮灭.

二、代码编写

代码部分我是在别人博客进行复制的:链接: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯).
需要输入的内容在bsp_usart.c当中进行修改即可,其它的文件都是库,不需要更改

1.代码分析

bsp_usart.c文件程序:

#include "bsp_usart.h"

// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
  uint8_t ucTemp;
	//串口一接收中断
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{
		//获取接收到的数据
		ucTemp = USART_ReceiveData(DEBUG_USARTx);
		//如果接收标志为 0 ,则执行下面的部分
		if((USART_RX_FLAG & 0x8000) == 0)
		{
			//接收到了0x0d
			if(USART_RX_FLAG & 0x4000)
			{
				//接收错误,重新开始
				if(ucTemp != 0x0a)
					USART_RX_FLAG=0;
				//接收完成
				else
					USART_RX_FLAG |= 0x8000;
			}
			//还未接收到0x0d
			else
			{
				//接收到回车
				if(ucTemp == 0x0d)
				{
					USART_RX_FLAG |= 0x4000;
				}
				else
				{
					USART_RX_BUF[USART_RX_FLAG & 0x3FFF] = ucTemp;
					USART_RX_FLAG++;
					//接收数据错误,重新开始接收
					if(USART_RX_FLAG > 99)
						USART_RX_FLAG = 0;
				}
			}
		}
	}	 
}

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

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 data)
{
	//发送数据函数(串口一,数据)
	USART_SendData(pUSARTx, data);
	//发送数据寄存器为空,则退出
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
	uint8_t i = 0;
	do
	{
		Usart_SendByte(pUSARTx, *(str+i));
		i++;
	}while(*(str+i) != '\0');
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}

//微秒级的延时
void delay_us(uint32_t delay_s)
{    
  volatile unsigned int i;
  volatile unsigned int t;
  for (i = 0; i < delay_s; i++)
  {
    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);
  }
}

//连续发送数据
void Usart_SendString(void)
{
	uint8_t i = 0;
	
	while(1)
	{
		if(USART_RX_FLAG & 0x8000)
		{
			// 获取接收到的数据长度
			len = USART_RX_FLAG & 0x3FFF;
			Usart_SendStr(DEBUG_USARTx, "\n");
			for(i=0; i<len;i++)
			{
				// 向串口发送数据
				USART_SendData(DEBUG_USARTx, USART_RX_BUF[i]);
				//等待发送结束
				while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TC)!=SET);
			}
			Usart_SendStr(DEBUG_USARTx, "\n\n");
			//比较字符串
			if(strcmp((char *)USART_RX_BUF,"stop,stm32!")==0)
			{
				Usart_SendStr(DEBUG_USARTx, "stm32已停止发送!");
				break;//退出循环
			}
			//初始化
			USART_RX_FLAG=0;
			memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));
		}
		else
		{
			//循环发送数据
			Usart_SendStr(DEBUG_USARTx, "梓宝带我走吧\n");
			delay_ms(800);
		}
	}
}

在程序当中定义了一个串口中断服务函数用于控制中断,以及NVIC的嵌套向量中断控制器函数。

2.程序烧录

接线之后,打开mcuisp软件,将生成的.hex文件烧录到芯片当中
在这里插入图片描述

三、实验效果

在这里插入图片描述
在输入框当中输入stop,stm32!然后换行,发送,就可以看到数据发送停止了

四、总结

通过此次实验,使用中断的方式进行串口通讯后,以及学习了三种串口通讯方式了:查询,中断和DMA。在实际的通讯过程当中,我们可以根据需求进行选择,在传输比较大的数据的时候采用DMA方式,可以解放CPU,让CPU进行别的工作。中断方式是通过中断服务函数不断将数据放到串口进行传送。每一种方式都有优缺点,我们学习完这些方法后要学会在不同场景下进行使用。
参考资料: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值