STM32外部中断及串口概述


前言

中断是 STM32中一个很重要的部分,但是有一些同学对他的理解不到位。如果想要我们编出来的程序效率高,就要摆脱查询式,用中断来提高他的运行效率。本文对STM32的外部中断和串口做一些简要的概述,帮助各位同学理解掌握。

提示:以下是本篇文章正文内容,下面案例可供参考

一、外部中断

1.含义

中断——当需要出现时,CPU暂时停止当前程序的执行,转而执行处理新情况的程序和执行过程。

我们所使用的STM32中断分为外部中断,定时器中断、串口中断。(以下将对外部中断进行解释)

注:外部中断框图:
在这里插入图片描述
EXTI控制器的主要特性:

  • 每个中断都有独立的触发和屏蔽
  • 每个中断都有专用的状态位
  • 支持多达20个软件的中断/事件请求
  • 检测脉冲宽度低于APB2时钟宽度的外部信号。

2.类型

STM32有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。而我们常用的就是这68个可屏蔽中断。在MDK中,与NVIC相关的寄存器,MDK为其定义了如下的结构体:

typedef struct
{
 __IO uint32_t ISER[8]; //中断使能寄存器组
 uint32_t RESERVED0[24];
 __IO uint32_t ICER[8]; //中断除能寄存器组
 uint32_t RSERVED1[24];
 __IO uint32_t ISPR[8]; //中断挂起控制寄存器组
 uint32_t RESERVED2[24];
 __IO uint32_t ICPR[8]; //中断解挂控制寄存器组
 uint32_t RESERVED3[24];
 __IO uint32_t IABR[8]; //中断激活标志位寄存器组
 uint32_t RESERVED4[56];
 __IO uint8_t IP[240]; //中断优先级控制寄存器组
 uint32_t RESERVED5[644];
 __O uint32_t STIR; //软件触发中断寄存器组
} NVIC_Type;

STM32的中断是在这些寄存器的控制下,有序执行的。只有了解这些中断寄存器,才能方便的使用STM32的中断。

下面简略介绍下第一个寄存器:

  • ISER[8] 这是一个中断使能寄存器组。用 8 个 32 位寄存器来控制,每个位控制一个中断。
    ISER[0]的 bit0~31 对应中断0~31;
    ISER[1]的 bit0~32 对应中断 32~63;
    ISER[2]的 bit0~3 对应中断 64~67;
    这样总共 68 个中断就分别对应上了。你要使能某个中断,必须设置相应的 ISER 位为 1,使该中断使能(这里仅仅是使能,还要配合中断分组、屏蔽、IO 口映射等设置才算是一个完整的中断设置)。
    具体每一位对应哪个中断,请参考 stm32f10x.h 里面的第 170 行处。

二、外部中断的配置

外部中断一般步骤为:

1)开启IO口时钟,初始化IO口为输入。调用函数:GPIO_Init()2)开启IO口复用时钟。调用函数:RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE)3)设置IO口与中断线的映射关系。调用函数:GPIO_EXTILineConfig()4)初始化线上中断,设置触发条件等。调用函数:EXTI_Init()5)配置中断分组(NVIC),并使能中断。调用函数:NVIC_Init()6)编写中断服务函数。调用函数:EXTIx_IRQHandler()7)清除中断标志位。调用函数:EXTI_ClearITPendingBit()

以PA11管脚为例:

1.设置时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

2.配置GPIO

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

3.将GPIO管脚与外部中断线连接

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource11);

4.配置EXTI(包括触发方式等)

EXTI_InitStructure.EXTI_Line = EXTI_Line11;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

5.配置NVIC

NVIC_InitTypeDef NVIC_InitStructure;    
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
 
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;  //PPP外部中断线
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

6.写中断服务程序

void  EXTI15_10_IRQHandler( void )
{
     if  (EXTI_GetITStatus(EXTI_Line11) != RESET)
     {
         EXTI_ClearITPendingBit(EXTI_Line11);  //清除标志
         ...
     }
}

三、串口的介绍

1.串口定义

UART : Universal Asynchronous Receiver/Transmitter 通用异步收发器
USART : Universal Synchronous Asynchronous Receiver/Transmitter 通用同步/异步收发器

一种是常用也是最简单的串行数据传输协议。数据线只需要两根就可以实现全双工。

Tx : 发送数据线
Rx : 接收数据线

2.其他必要知识

  • 波特率:在串行通讯中,数据是按位进行传送的,因此传送速率用每秒钟传送格式位的数目来表示,称为波特率。波特率决定了串口传输的速度,1波特=1bps(位/秒)。波特率为9600的话就是1s传输9600位的数据。
  • 串口的传输与网络等其他的传输有着相似之处,比如常用的wifi,区别在与这些网络的单位是k,只有串口是按位来计数的。
  • 单工,半双工,全双工。
  • 单工:只能一个方向传输。
  • 半双工:可以两个方向传输,但需要分时复用。
  • 全双工:两个方向传输。

3.串口的配置

1.串口时钟使能,GPIO时钟使能:

RCC_APB2PeriphClockCmd();

2.串口复位:

USART_ Delnit();

这一步不是必须的

3.GPIO端口模式设置:

GPIO lnit();

模式设置为:

GPIO_Mode_AF_PP

4.串口参数初始化:

USART lnit();

5.开启中断并且初始化NVIC (如果需要开启中断才需要这个步骤)

NVIC_Init();
USART_ITConfig(0);

6.使能串口:

USART_ Cmd();

7.编写中断处理函数:

USARTX_IRQHandler();

8.串口数据收发:

void USART SendData();//发送数据到串口,DR
uint16 tUSART_ ReceiveData(;//接受数据,从DR读取接受到的数据

9.串口传输状态获取:

FlagStatus USART_GetFlagStatus(USART_TypeDef*USARTx,uint16_t USARTL_FLAG);
void USART_ClearlTPendingBit(USART_TypeDef*USARTx,uint16_t USART_IT;

4.示例代码

void USB_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStrue;               		     //声明GPIO结构体
	USART_InitTypeDef USART_InitStrue;						 //声明串口结构体
	NVIC_InitTypeDef  NVIC_InitStrue;                        //声明中断结构体
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);     //GPIO时钟的使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);	 //串口1的时钟使能
	
	
	GPIO_InitStrue.GPIO_Mode = GPIO_Mode_AF_PP;				 //设置为复用推挽
	GPIO_InitStrue.GPIO_Pin = GPIO_Pin_9;				     //9号IO口
	GPIO_InitStrue.GPIO_Speed = GPIO_Speed_10MHz;			 //输出速率
    GPIO_Init(GPIOA,&GPIO_InitStrue);					     //TX9的配置状态
	
	GPIO_InitStrue.GPIO_Mode = GPIO_Mode_IN_FLOATING;         //浮空输入
	GPIO_InitStrue.GPIO_Pin = GPIO_Pin_10;                    //10号IO
	GPIO_InitStrue.GPIO_Speed = GPIO_Speed_10MHz;			  //输出速率
    GPIO_Init(GPIOA,&GPIO_InitStrue);				          //RX10的配置
	
	
	USART_InitStrue.USART_BaudRate = 115200;                 //波特率设置为115200
	USART_InitStrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件数据流控制
	USART_InitStrue.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;        //收发模式都使能
	USART_InitStrue.USART_Parity = USART_Parity_No;                    //无奇偶校验位
	USART_InitStrue.USART_StopBits = USART_StopBits_1;                 //一个停止位
	USART_InitStrue.USART_WordLength = USART_WordLength_8b;	   		   //字长为8
	USART_Init(USART1,&USART_InitStrue);                               //调用其Init函数
	
	USART_Cmd(USART1,ENABLE );        	//中断使能,确定端口,
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	//中断模式。这里是接受中断。
	
	
	NVIC_InitStrue.NVIC_IRQChannel =  USART1_IRQn;         //指出通道,这里是串口一的通道
	NVIC_InitStrue.NVIC_IRQChannelCmd = ENABLE;            //开启中断通道
	NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占优先级,注意选择的模式,即抢占优先级最大位
	NVIC_InitStrue.NVIC_IRQChannelSubPriority = 1;        //子优先级
	NVIC_Init(&NVIC_InitStrue);                         //调用NVIC_INIT函数,将我们定义的结构体地址作为入口参数	
}

void USART1_IRQHandler(void)    //只能使用这个函数名:
{
	u8 data;                                       //定义变量存储读取到的数据
	
	if(USART_GetFlagStatus(USART1,USART_IT_RXNE))  //判断中断是不是之前设置的中断,如果是,值为1
	{
		data  =  USART_ReceiveData(USART1);             //读取串口函数,并将其赋值
		USART_SendData(USART1,data);                    //将读取到的数据发送出去
		
	}

//主函数
 int main(void)
 {
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //在中断函数前就要调用
	 //2号分组,两位抢占优先级,两位响应优先级
    USB_Init();
	 while(1);
	 
 }
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值