STM32入门之旅(第四天)-------位带操作、中断

发布者:信息巫师最新更新时间:2019-07-10 来源: eefocus关键字:STM32  位带操作  中断 手机看文章 扫描二维码
随时随地手机看文章

一、位带操作

1.意义

回想以前写51代码

P0 = 0x10; //将P0端口设置为0x10

P1_0=1; //将P1端口1号引脚设置为高电平

a = P2_2;         //获取P2端口2号引脚的电平


根据上述的方法,我们可以发现快速定位修改某个引脚的电平还有获取引脚的状态

GPIO_SetBits、GPIO_ResetBits操作IO口的性能没有达到极致,因为这些函数都需要进行现场保护和现场恢复的动作,比较耗时间,没有进行一步到位,使用位带操作则没有上述的烦恼,简单快速!


//位带操作,实现51类似的GPIO控制功能


//IO口操作宏定义

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 

#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 

#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 


GPIO_SetBits(GPIOF,GPIO_Pin_9);


修改为


PFout(9)=1;


公式如下:


寄存器的位带别名 = 0x42000000 + (寄存器的地址- 0x40000000)*8*4 + 引脚编号*4


M4中,有两个地方实现了位带,一个是SRAM最低的1MB,一个是外设区最低1MB


1、外设区位带


ADDR = 0x42000000 + (A - 0x40000000) * 8 * 4 + n*4


2、SRAM区


ADDR = 0x22000000 + (A - 20000000) * 8 * 4 + n*4


统一公式#define BITBAND(addr, bitnum) ((addr & 0xF000 0000)+0x200 0000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 


volatile关键字分析,往往应用在三种场合

1)多线程编程共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要优化该变量。

2)裸机编程的时候,某函数与中断服务函数共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要优化该变量

3)ARM定义寄存器的时候,寄存器是指向一个地址,要加上volatile进行修饰,让编译器不要优化该变量。

编译器不要优化该变量也就是不对该资源进行保护,让任何程序随时都可以对它修改。

加上volatile关键字生成的汇编代码会发生明显的变化,同样调用delay函数,灯的速度发生变化!

#include "stm32f4xx.h"

 

//使用结构体的初始化,可以增强代码的阅读性

static GPIO_InitTypeDef  GPIO_InitStructure;

int main(void)

{

//获取GPIOF的ODR寄存器的地址

uint32_t PF_ODR_ADDR = GPIOF_BASE + 0x14;

//转换为别名地址

uint32_t *PF9_BitBand = (uint32_t *)(0x42000000+(PF_ODR_ADDR-0x40000000)*32+9*4);

/* GPIOF Peripheral clock enable,使能GPIOF端口工作,让GPIOF设备时钟使能(上电) */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

/* 让PF9引脚设置为输出模式 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIO哪一根引脚,当前是使用第9号引脚

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置PF9引脚为输出模式,具有输出高电平或低电平的功能

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,让PF9引脚输出的电流更大[可选]

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //PF9引脚工作的速度为100MHz,当前的频率可以是2MHz/25MHz/50MHz/100MHz,频率越高,对应的功耗就越高

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上下拉电阻,如果发现PF9引脚需要更大的输出电流,可以使用上拉电阻,设置为GPIO_PuPd_UP,对应的功耗就越高

GPIO_Init(GPIOF, &GPIO_InitStructure);

while(1)

{

//点灯,PF9引脚为低电平

//GPIO_ResetBits(GPIOF,GPIO_Pin_9);

*PF9_BitBand=0;

//延时,灯亮一会儿

delay();

//灭灯,PF9引脚为高电平

//GPIO_SetBits(GPIOF,GPIO_Pin_9);

*PF9_BitBand=1;

//延时,灯灭一会儿

delay();

}

return 0;

}

二、M4的中断体系


嵌套向量中断控制寄存器


1、NVIC特性


无论是ARM Cortex M0/M3/M4 还是 ARM Cortex-A8/A53/A72/A73等等内核,都有NVIC。


STM32F405xx/07xx 和 STM32F415xx/17xx 具有 82 个可屏蔽(能够通过代码进行开和关中断)中断通道,10个不可屏蔽(无法通过代码关闭该中断)的中断,16 个可编程优先级。


向量vector意味就是中断源。


向量表,也就是中断源表。


2、外部中断/事件控制器 (EXTI)


多达 140 个 GPIO(STM32F405xx/07xx 和 STM32F415xx/17xx)通过以下方式连接到 16 个外部中断/事件线:


另外七根 EXTI 线连接方式如下:


● EXTI 线 16 连接到 PVD 输出


● EXTI 线 17 连接到 RTC 闹钟事件


● EXTI 线 18 连接到 USB OTG FS 唤醒事件


● EXTI 线 19 连接到以太网唤醒事件


● EXTI 线 20 连接到 USB OTG HS(在 FS 中配置)唤醒事件


● EXTI 线 21 连接到 RTC 入侵和时间戳事件


● EXTI 线 22 连接到 RTC 唤醒事件



3.库函数


a.选择对应的GPIO引脚连接到相应的中断控制线


   void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)


b.根据EXTI_InitTypeDef结构体进行外部中断控制线0初始化


    void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)


c.根据NVIC_InitTypeDef结构体对中断向量进行配置


   void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)


4、中断优先级


中断优先级的一个意义:出现多个中断同时触发,但是不能同时处理,所以先后顺序之分,要根据实际上的运行环境优先处理重要的中断。


a.概述


STM32对中断进行分组,共5组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级级。


函数原型如下:


/**


  * @brief  Configures the priority grouping: pre-emption priority and subpriority.


  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length.


  *   This parameter can be one of the following values:


  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority //没有抢占优先级


  *                                4 bits for subpriority //4位设置响应优先级


  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority //1位抢占优先级,能设置2个中断抢占优先级


  *                                3 bits for subpriority //3位设置响应优先级


  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority //2位抢占优先级,能设置4个中断抢占优先级


  *                                2 bits for subpriority //2位设置响应优先级


  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority //3位抢占优先级,能设置8个中断抢占优先级


  *                                1 bits for subpriority //1位设置响应优先级


  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority //4位抢占优先级,能设置16个中断抢占优先级


  *                                0 bits for subpriority //没有响应优先级


  * @note   When the NVIC_PriorityGroup_0 is selected, IRQ pre-emption is no more possible.


  *         The pending IRQ priority will be managed only by the subpriority.


  * @retval None


  */


void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

只要开机初始化一次就可以了。


b.抢占优先级与响应优先级区别


1)高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。


2)抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。


3)抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。


4)抢占优先级相同且响应优先级相同的中断,假如同时发生,会按照硬件内部固定的优先级执行,如下图。


5)无论是抢占优先级还是响应优先级,优先级数值越小,就代表优先级越高。



//GPIO初始化的结构体

static GPIO_InitTypeDef   GPIO_InitStructure;


static EXTI_InitTypeDef   EXTI_InitStructure;


static NVIC_InitTypeDef   NVIC_InitStructure;


void Exit_Init(void)

{

     /* Enable SYSCFG clock */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    /* Enable GPIOA clock */

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

    

    /* Configure PA0 pin as input floating */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOA, &GPIO_InitStructure);


    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3| GPIO_Pin_4 ;

    GPIO_Init(GPIOE, &GPIO_InitStructure);

    

    /* Connect EXTI Line0 to PA0 PE2 PE3 PE4pin */

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);

   

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    

    /* Configure EXTI Line0 2 3 4 */

    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  

    EXTI_InitStructure.EXTI_LineCmd = ENABLE;

    EXTI_Init(&EXTI_InitStructure);

    

    /* Enable and set EXTI Line0 Interrupt to the lowest priority */

    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    

    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    

    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    

    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}



关键字:STM32  位带操作  中断 引用地址:STM32入门之旅(第四天)-------位带操作、中断

上一篇:STM32小白入门(第五天)-------启动文件、系统时钟
下一篇:STM32入门之旅(第三天)-------按键电路、时钟体系

推荐阅读最新更新时间:2024-11-04 14:07

基于STM32的新型角度测量系统设计
在现代控制系统中,角度测量装置是非常关键的需要高精度的部件,其测量精度直接影响着整个系统的性能和精度。例如施工 升降机上有角度测控机构来控制起降;火箭炮瞄准系统中都有大量的角度传感器,实时检测炮塔偏转角度,以便对火箭炮瞄准进行调整。目前已有的利用的加速度传 感器实现高精度角度测量的研究,主要侧重于单轴的角度测量。本文将重点讨论利用双轴加速传感器ADXL202实现高精度角度测量的软硬件方法。 1 角度测量仪系统硬件方案设计 本角度测量仪采用STM32F107作为数据处理的核心芯片。这是一款低功耗、高速度的32位处理器,拥有Cortex-M3内核。角度测量模块使用的是高精度、低功耗的双轴加速度传感器ADXL202,能将加速度信号转换成
[单片机]
基于<font color='red'>STM32</font>的新型角度测量系统设计
STM32外设DMA使用总结
STM32外设DMA使用总结: 1、根据需要选择DAM模式: (1)循环模式—DMA_Mode = DMA_Mode_Circular (2)正常模式—DMA_Mode = DMA_Mode_Normal 2、对于DMA1的Chanel3,对应外设为USART3的RX 试想:如果串口接收中断和DAM中断同时打开,CPU如何相应? (1)中断优先级不同:这好说,支持嵌套中断(NVIC)的Cortex-M3自然优先服务中断优先级高的 (2)中断优先级相同:处理原则,先来先处理;若同时到来,中断号低的优先处理 查询手册可知,DMA(IRQn number 13)会先于USART3(39)被CPU处理 3、设置DMA模式为循环模式,则:
[单片机]
STM32Cube MX学习二--定时器、外部中断
对于一些基本操作可以参照第一篇的内容学习,几乎都是步骤图片,步骤内容都是在图里了。这个软件的学习主要分为基础的两三篇,然后转为RTOS的学习,毕竟是工具的使用,原理的东西虽然会涉及描述,但应该不会在这个系列里面太多。遇到困难的知识,我还会再次分类学习。 本章学习一下配置定时器,或者外部中断,内容比较相近,就不分开讲述了,进入学习内容,重点请看图: 1、开启定时器功能 选择自己想要配置的定时器,如TIM1/TIM2/TIM3....,当然定时器有很多的模式,那个是定时计数模式? 第一步:图中,mode板块里,第三个选项:Clock Source :选Internal Clock。这个就是定时计数模式了。 2、定时计算
[单片机]
STM32Cube MX学习二--定时器、外部<font color='red'>中断</font>
ATmega8 复位与中断处理
AVR有不同的中断源。每个中断和复位在程序空间都有独立的中断向量。所有的中断事件 都有自己的使能位。当使能位置位,且状态寄存器的全局中断使能位I 也置位时,中断可 以发生。根据程序计数器PC 的不同,在引导锁定位BLB02 或BLB12 被编程的情况下, 中断可能被自动禁止。这个特性提高了软件的安全性。详见 P 209“ 存储器编程” 的描述。 程序存储区的最低地址缺省为复位向量和中断向量。完整的向量列表请参见P 43“ 中断” 列表也决定了不同中断的优先级。向量所在的地址越低,优先级越高。RESET 具有最高 的优先级,第二个为INT0 – 外部中断请求0。通过置位通用中断控制寄存器 (GICR) 的 IVSEL,中断向量可以移
[单片机]
嵌入式编程(以STM32为例)中的volatile,const意义及应用场景
__I、 __O 、__IO是什么意思? 这是ST库里面的 宏定义 ,定义如下: #define __I volatile const /*! defines 'read only' permissions */ #define __O volatile /*! defines 'write only' permissions */ #define __IO volatile /*! defines 'read / write' permissions */ 显然,这三个宏定义都是用来替换成 volati
[单片机]
中断的概念及中断处理流程
什么是中断,我们从一个生活中的例子引入。你正在家中看书,突然电话铃响了,你放下书本,去接电话,和来电话的人交谈,然后放下电话,回来继续看你的书。这就是生活中的“中断”的现象,就是正常的工作过程被外部的事件打断了。 仔细研究一下生活中的中断,对于我们学习单片机的中断也很有好处。 第一、什么可以引起中断,生活中很多事件可以引起中断:有人按了门铃了,电话铃响了,你的闹钟闹响了,你烧的水开了….等等诸如此类的事件,我们把可以引起中断的称之为中断源,单片机中也有一些可以引起中断的事件,8031中一共有5个:两个外部中断,两个计数/定时器中断,一个串行口中断。 第二、中断的嵌套与优先级处理:设想一下,我们正在看书,电话铃响了,同时又有人按了门
[单片机]
【菜鸟入门】stm32 之 iic
纠结了两天,终于重新开始写了,这两天一直卡在硬件iic上,由于硬件iic是比较难啃的一块骨头,问题一大堆,明明感觉配置好,测试时,一会出这个问题,一会出那个问题,哎,说多了都是泪。。。。 最后木有办法了,总不能吊死在一棵树上吧,然后就写了个模拟的iic的,由于对iic研究和应用的比较多(我们实验室的设备都是iic通信的,所有设备的驱动都是我来写的),所以在搞这个的时候得心应手,一个小时就把所有的搞定了,有花了1个小时把eeprom(at24c02)调通; 我大致测了下,我的板子上的eeprom电路类似这个: 所以我要做的是就是把PB6配置称时钟线SCL,PB7配置成数据线SDA 这里我们再配置输出的时候,要把管脚配
[单片机]
【菜鸟入门】<font color='red'>stm32</font> 之 iic
正点原子STM32 USB读卡器代码分析
USB读卡器的基本原理就是向主机提供SD读写功能,并不需要加入文件系统功能。 USB设备的实现步骤: 1、 初始化系统时钟,设置USB时钟 2、 配置USB中断,选择通道,设置优先级,使能中断 3、 配置GPIO 4、 USB的初始化,对描述符、设备的端点接口等的初始化 5、 FLASH的初始化 sd_size=(long long)SD_GetSectorCount()*512; //得到SD卡容量,字节. Mass_Memory_Size =sd_size%4294967296; //当SD卡容量超过4G的时候,需要用到两个u32来表示 Mass_Memory_Size
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved