STM32中断编程入门

一、 理论部分

1.中断系统

在这里插入图片描述

2.中断执行流程

在这里插入图片描述

3.NVIC的基本结构

在这里插入图片描述

在这里插入图片描述

4.EXTI介绍

在这里插入图片描述在这里插入图片描述

5.AFIO复用IO口

在这里插入图片描述

二、实验目的:学习stm32中断原理和开发编程方法。使用标准完成以下任务:

用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
可参考教材课件上的6.4.3示例
采用串口中断方式重做上周的串口通信作业,分别实现:1)当stm32接收到字符“s”时,停止持续发送“hello windows!”; 当接收到字符“t”时,持续发送“hello windows!”(提示:采用一个全局标量做信号灯);2)当stm32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”(提示:要将接收到的连续字符保存到一个字符数组里,进行判别匹配。写一个接收字符串的函数。

(一)实验一 开关控制LED的亮灭

1.代码部分

//exti_key.c文件
#include "exti_key.h"
#include "misc.h"



void EXTI_Key_Init()
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);  //打开GPIOA和复用输入输出口的时钟
	
	//配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Pin_3;     
	GPIO_InitStructure.GPIO_Pin = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置NVIC(Nested Vectored Interrupt Controller:嵌套向量中断控制器)
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	//配置EXTI(External Interrupt/Event Controller:外部中断/事件控制器)
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_ClearITPendingBit(EXTI_Line3);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3);
	EXTI_InitStructure.EXTI_Line = EXTI_Line3;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
}
#include "stm32f10x.h"  
#include "exti_key.h"
#include "LED.h"

uint8_t led = 1;
int main()
{
	
	GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET); //默认为熄灭
	EXTI_Key_Init();
	while(1)
	{}
}

void EXTI3_IRQHandler()
{
	
	if(EXTI_GetITStatus(EXTI_Line3) != RESET )
	{
	led = ~led;
	if(led == 1)
	{
		GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);
	}
		
	
	else
	{
		GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);
	}		
	EXTI_ClearITPendingBit(EXTI_Line3);
	
	}
	
}


2.运行结果

20240519_002

(二)实验二 接收单个字符控制发送数据

采用串口中断方式,当stm32接收到1个字符“s”时,停止持续发送“hello windows!”; 当接收到1个字符“t”时,持续发送“hello windows!”(提示:采用一个全局标量做信号灯);

1.代码部分

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int status = 0;//设置是否发送数据的标志位
int main()
{	
	//开启GPIOA和USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
	
	
	
	//实例化控制器的对象
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	//先配置GPIO控制器
	//1.设置PA9为复用推挽输出模式
	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_Init()一次就可以了,结果忘了这些参数会覆盖的。
	
	//2.设置PA10为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置为浮空输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
	//再配置USART控制器
	USART_InitStructure.USART_BaudRate = 9600;
	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_ClearFlag(USART1, USART_FLAG_TC);
	
	USART_Init(USART1,&USART_InitStructure);  //初始化串口1
	
	
	//配置中断源
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//当USART串口接收到数据的时候,就触发USART中断
	
	// 4.给这个中断源配置相应的抢占优先级和执行优先级
		NVIC_InitTypeDef  NVIC_InitStructure;
		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;      
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //设置抢占(主)优先级    
		NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;      // 设置子优先级   
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             
		NVIC_Init(&NVIC_InitStructure);    
	
	
	USART_Cmd(USART1,ENABLE);			//使能串口1
	
	char transmitArray[18]={"hello windows! \r\n "};   //windows系统串口发送时,用回车换行组合 (\r\n) 来实现换行
	
	while(1)
	{	
		if(status == 1) //标志位status = 1 发送
		{for(int i=0;i<=17;i++)
		{
		USART_SendData(USART1,transmitArray[i]);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)== RESET);  //RESET就是0,表示不符合,TXE的E是empty,表示发送寄存器不符合为空,即里面有东西,还在发送。	
		}
		Delay_s(1);
		}
	}
	
}

void USART1_IRQHandler(void)
{
	while(USART_GetITStatus(USART1,USART_IT_RXNE) == RESET ) //这里不再是USART_GetFlagStatus、USART_FLAG_RXNE,而是USART_GetITStatus、SART_IT_RXNE,要换成中断
	{};  
	uint8_t RData=USART_ReceiveData(USART1);
	if(RData == 's')
	{
		status = 0;
	}
	
	else if (RData == 't')
	{
		status = 1;
	}

}

2.运行结果

在这里插入图片描述

(三)实验三 接收字符串控制发送数据

1.代码部分

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void InitRDataArray();

int status = 0;//设置是否发送数据的标志位

char RDataArray[20];//接收指令的字符数组


int main()
{	
	//开启GPIOA和USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
	
	
	
	//实例化控制器的对象
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	//先配置GPIO控制器
	//1.设置PA9为复用推挽输出模式
	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_Init()一次就可以了,结果忘了这些参数会覆盖的。
	
	//2.设置PA10为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置为浮空输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
	//再配置USART控制器
	USART_InitStructure.USART_BaudRate = 9600;
	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_ClearFlag(USART1, USART_FLAG_TC);
	
	USART_Init(USART1,&USART_InitStructure);  //初始化串口1
	
	
	//配置中断源
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//当USART串口接收到数据的时候,就触发USART中断
	
	// 4.给这个中断源配置相应的抢占优先级和执行优先级
		NVIC_InitTypeDef  NVIC_InitStructure;
		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;      
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //设置抢占(主)优先级    
		NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;      // 设置子优先级   
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             
		NVIC_Init(&NVIC_InitStructure);    
	
	
	USART_Cmd(USART1,ENABLE);			//使能串口1
	
	char transmitArray[18]={"hello windows! \r\n "};   //windows系统串口发送时,用回车换行组合 (\r\n) 来实现换行
	
	
	InitRDataArray();  //初始化用来接收指令的字符数组
	
	while(1)
	{	
		
		
		
		
		if(status == 1) //标志位status = 1 发送
		{for(int i=0;i<=17;i++)
		{
		USART_SendData(USART1,transmitArray[i]);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)== RESET);  //RESET就是0,表示不符合,TXE的E是empty,表示发送寄存器不符合为空,即里面有东西,还在发送。	
		}
		Delay_s(1);
		}
		
		
	}
	
}


//初始化字符数组
void InitRDataArray()
{
 for(int i=0;i<20;i++)
	{
	RDataArray[i]=0;
	}
}

void USART1_IRQHandler(void)
{
	int i=0;
	 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//判断中断是接收数据中断
    {
       RDataArray[i]= USART_ReceiveData(USART1); //接收字符
				i++;
    } 

if (strcmp(RDataArray,"stop stm32!")==0)
				{
            			status = 0;//结束发送
					InitRDataArray();  //初始化用来接收指令的字符数组
					
        }
else if (strcmp(RDataArray,"go stm32!")==0)
        {
           				 status = 1;//发送数据
		  InitRDataArray();  //初始化用来接收指令的字符数组
					
        }
}



2.运行结果

在这里插入图片描述

三、总结

我刚把串口通信学得差不多,现在又来了这个中断,中断我感觉比之前学的东西都要难。我也说不出为什么,就是觉得它很抽象。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值