STM32端口复用(映射)&中断
文章目录
1 端口复用以及重映射
1.1 什么是端口复用以及重映射
复用就是将某个端口的功能换成另一种功能(这种换是定义好的,我们不能自己定义)
重映射是某个端口可能暂时不能用了,用其他的端口来替换它使用(也是约定好的)
这个极大地合理的利用了STM32端口
1.2 启用端口复用
开启两个时钟使能
实际就是直接一行代码 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
最简单的一个例子就是要使用串口模式
PA9,PA10复用为串口1配置过程
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//①IO时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//②外设时钟使能
//③初始化IO为对应的模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 PA.10 浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
可以看见非常简单
1.3 端口复用
比方说串口USART1就能够从PA9、10映射到PB6、7
映射还分为部分映射和完全映射
简单来说某一种功能可能需要好几个引脚,但是可能开启了部分重映射(对,没错,是可以自己选择是否开启部分重映射的),有一些引脚还保持原来的引脚(比方说USART3)
1.4 总结:
1.使能GPIO时钟(重映射后的IO);
2.使能功能外设时钟(例如串口1);
3.使能AFIO时钟。重映射必须使能AFIO时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
4.开启重映射。
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
根据第一个参数,来确定是部分重映射还是全部重映射根据第一个参数,来确定是部分重映射还是全部重映射
二、中断
简单来说,你在学习,突然有件事你想起来了,然后你会先把那件事做完,然后接着学习,中断也是如此
2.1 中断优先管理概念
STM32中断很多(定时中断,串口中断…),总的有个先后次序吧,不然在打断的时候又被打断我该执行那个?
分组管理:
STM32中断由SCB->AIRCR进行分5组,组0~4(只设计一次,不然会造成紊乱)。每组有抢占优先级和响应优先级值(也叫子优先级)。但是抢占还有响应所占的位置是固定的(只有四个位置,这四个位置可以是抢占也可以是响应),不同组的区别在于这四个位置分配的结果不一样
比较简单的时候就设置0-2组就完全ok。
好的,我们现在已经设置好了分组问题,所有的中断现在在同一个组内,到底谁打断谁呢:
设置优先级
关于抢占优先级还有响应优先级为什么要分成两种优先级,而不是仅仅用一种优先级?
这个问题不做扩充,我用GPT进行分析看的很头疼。
谈一谈优先级:
一个是抢占优先级(主),另一个是响应优先级(从)。主优先级的数值越小,优先级越高;而从优先级的数值越小,优先级越低。因为每个组将四个位置到分到两种优先级的位置数是不一样的,这两种优先级有多少位就能够设置相对应的多少种中断方式,比方说:第0组就能够设置2^4=16个响应优先级的中断,第1组就能够设置2位抢占优先级,每种抢占优先级有8中响应优先级。
这两种优先级的设置方法是由一定道理的,比方说抢占优先级的存在使得在紧急情况下,高优先级的中断可以迅速中断当前正在执行的低优先级中断,从而及时处理紧急事件。这对于实时性要求高的应用非常重要,因为它可以防止低优先级中断占用CPU时间,影响高优先级任务的执行。
程序实现
1、系统运行开始的时候设置中断分组。确定组号,也就是确定抢占优先级和子优先级的 分配位数。调用函数为
NVIC_PriorityGroupConfig();
2. 设置所用到的中断的中断优先级别。对每个中断调用函数为 NVIC_Init();
3.这里说的分组是说在main中定义,之后出现的中断全都放在一个组里面( NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);在main.c中设置)
!纠正一下:一旦分组了就意味着你的抢占和相应(子)都被固定数值了(被限制了,有X位就是可以有2^X个位置,这些位置可以放置不同的中断进行中断的排序),比方说:https://blog.csdn.net/xsk1995/article/details/79997788
这个规则就是抢占优先级越高就会打断抢占优先级低的中断。响应优先级高不能打断,只能等中断结束(同时就会先响应)
0是最大的优先级,4反倒是最小的优先级
2.2 代码部分
2.2.1 设置分组
(在main.c对代码中自己定义的所有中断进行分组)
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup){
...}
2.2.2 设置抢占以及响应优先级
这里有个细节,第一次看感觉没啥,后面看到ppt才反应过来。修改优先级组别首先在USART.c文件内看到中断的定义很简单
比如我们要使能串口 1 的中断,同时设置抢占优先级为是1,子优先级位 是2,初始化的方法是:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化 NVIC 寄存器
也就是说:通过中断结构体进行初始化就行了。我一瞅不也挺简单吗,但是后来看ppt介绍就突然崩溃了,再一仔细看这个初始化函数,好家伙,里面还有一个隐藏的结构体(要注意:NVIC_Type结构体又被重定义位NVIC)
所以实际上还是使用上面这个结构体里面的寄存器组进行修改中断参数的,这也就和ppt里面讲解的就吻合了。
这里就是用了这三个,其他的就不需要细说。
2.3 总结:
1.系统运行后先设置中断优先级分组。调用函数:v
oid NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
整个系统执行过程中,只设置一次中断分组(所以就在main.c中直接定义把)。
2. 针对每个中断,设置对应的抢占优先级和响应优先级:
`void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);`
3.如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可(感觉要到进阶里面说)。
文章评论