• 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);
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    #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);
    	
    	}
    	
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    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;
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    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();  //初始化用来接收指令的字符数组
    					
            }
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    2.运行结果

    在这里插入图片描述

    三、总结

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

  • 相关阅读:
    【AIGC核心技术剖析】用于高效 3D 内容创建生成(从单视图图像生成高质量的纹理网格)
    【全网热点】打造全网最全爱心代码仓库【火速领取爱心】
    重学Android基础系列篇(五):Android虚拟机指令
    【知识点随笔分析】我看看谁还不会用CURL命令
    案例---用户信息列表展示模块
    网页采集工具-免费的网页采集工具
    mysql增加分区
    第84步 时间序列建模实战:Xgboost回归建模
    酒店客房管理系统设计与实现(论文+源码)_kaic
    我试图给你分享一种自适应的负载均衡。
  • 原文地址:https://blog.csdn.net/wodeshijiexialey/article/details/138815695