Duanxx的STM32学习:GPIO的位带操作

支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在 CM3中,有两个区中实现了位带。其中一个是
SRAM 区的最低
1MB 范围,第二个则是片内外设区的最低
1MB 范围。这两个区中的地址除了可以像普通的
RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

关于位带操作的博客说明有很多,这里主要将代码贴出来,并做详细的注释

/**
    ******************************************************************************
    * @file GPIO.h
    * @author Duanxx
    * @version V1.1
    * @data 2015-06-07
    * @brief 这个头文件是对"stm32f10x_gpio.h"的一个补充
    *        主要是对《Cortex-M3权威指南(中文版)》chp05存储器系统->位带操作的一个实现
    *        这个功能实现之后,可以使得STM32像51一样对IO口按位操作
    *
    ******************************************************************************
*/

#ifndef _GPIO_H_
#define _GPIO_H_

#include "stm32f10x_gpio.h"

/**
    * 这里的实现是从《Cortex-M3权威指南(中文版)》chp05存储器系统->位带操作第92页直接抄过来的
    * 其目的是为了简化位带操作,而定义了一些专用的宏
*/
///< 把“位带地址+位序号”转换成别名地址的宏
#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输入输出数据寄存器的地址
    * 这里的地址是根据《STM32F10x Refernce manual(RM0008 英文版)》中
    * chp3 memory and bus architecture -> 3.2 Memory organization 以及
    * chp9 General-purpose and alternate-function I/Os (GPIOs and AFIOs) -> 9.5 GPIO and AFIO register maps
    * 中关于GPIO的地址分配表得到的
*/
///< 在GPIO的基址上偏移0x8,就是GPIOx_IDR的地址,即GPIO Input Data Register(输入数据寄存器)
#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 

///< 在GPIO的基址上偏移0x8,就是GPIOx_ODR的地址,即GPIO Output Data Register(输出数据寄存器)
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

/**
    * 下面是基于GPIO对位带操作的使用做了进一步的宏定义
    * 其使用方法如下
    * 如果GPIO是输出模式:
    * Step1: 将GPIO初始化为输出,比如:
        GPIO_InitTypeDef Duanxx_GPIO_InitStructure;   

        //< Enable GPIOA, RCC_APB2Periph_GPIOA
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);    

        //< Configure and PA.1 as output push-pull
        Duanxx_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        Duanxx_GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        Duanxx_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_Init(GPIOA, &Duanxx_GPIO_InitStructure);

    *Step2: 控制PA1的输出
        PAout(1) = 0; //<PA1输出低电平
        PAout(1) = 1; //<PA1输出为高电平

    * 当然,我们也可以使用宏定义,对下面的宏定义做进一步的封装
    * 这样,就更有利于我们使用有意义的GPIO控制
    * 比如PA1链接的是LED,那么就可以有如下的操作
        #define LED PAout(1) ///<LED 为PA1
        #define LED_ON  1   ///<定义LED亮的值
        #define LED_OFF 0   ///<定义LED灭的值

        LED = LED_OFF; ///< LED 灭
        LED = LED_OFF; ///< LED 亮、

    **********************************************************************
    * 对于GPIO输入而言,也可有有相似的操作
    * 第一步也是初始化,将GPIo初始化位输入
    * 第二步则是对GPIO进行读取,比如
    * 判断PA1是否是高电平如下:
        if(PAin(1) == 1)
        {
            ....
        }
    *
*/
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n) 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n) 

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n) 

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n) 

void GPIO_Disale_JTAG(void);

#endif
时间: 2024-10-14 05:14:05

Duanxx的STM32学习:GPIO的位带操作的相关文章

STM32之GPIO端口位带操作

#ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //位带操作 //把“位带地址+位序号”转换别名地址宏 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) //把该地址转换成一个指针 #define MEM_ADDR(addr) *((volatil

STM32位带操作总结---浅显易懂

正在准备做毕业设计,配置LED_Config()的时候,又看到了位带操作的宏定义,我又嘀咕了,什么是位带操作,一年前在使用位带操作的时候,就查阅过好多资料,Core-M3也看过,但是对于博主这种"低能儿"来说,你不把它说的白一点,就是感觉理解的不够透彻,于是今天又一次,查阅了各种手册,也算是基本弄懂了,鉴于博主的个人特点,所以本人的介绍也会十分浅显易懂,希望能帮到各位! 首先,抛砖引玉,来两个问题: 1)为什么STM32里面会有位带操作? 2)STM32里面的位带操作是什么意思? 我也

第13章 GPIO—位带操作

第13章     GPIO-位带操作 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege 本章参考资料:<STM32F4xx 中文参考手册>存储器和总线构架章节.GPIO章节,<Cortex?-M4内核编程手册>2.2.5 Bit-banding.学习本章时,配套这些参考资料学习效果会更佳. 13.1 位带简介 位操作就是可以单独的对一个比特位读和写,这个在51单片机

玩转X-CTR100 | 位带操作-GPIO

更多塔克创新资讯欢迎登陆[塔克社区www.xtark.cn ][塔克博客www.cnblogs.com/xtark/ ] STM32F4位带概念,及位带的GPIO操作实践应用. 原理介绍 51单片机相信各位都用过,假设P1.1的IO口上挂了一个LED,那么你单独对LED的操作就是P1.1 = 0或P1.1 = 1,注意,是你可以单独的对P1端的第一个IO口进行操作,然而STM32是不允许这样做的,那么为了像51单片机一样能够单独的对某个端的某一个IO单独操作,就引入了位带操作这样的概念,简单说就

08_stm32位带操作

一:位带操作介绍 1.   位带操作 在学习 51 单片机的时候就使用过位操作, 通过关键字 sbit 对单片机 IO 口进行位定义. 但是 STM32 没有这样的关键字, 而是通过访问位带别名区来实现.即将每个比特位膨胀成一个 32 位字, 当访问这些字的时候就达到了访问比特的目的. 比方说 BSRR 寄存器有 32 个位, 那么可以映射到 32 个地址上, 当我们去访问这 32 个地址就达到访问 32 个比特的目的. STM32F1 中有两个区域支持位带操作, 一个是 SRAM 区的最低 1

STM32F030系列实现仿位带操作

1.闲言 最近开发的时候,用到了STM32F030F4P6型号的单片机,它只有20个引脚,价格非常便宜,但是功能齐全:定时器.外部中断.串口.IIC.SPI.DMA和WWDG等等,应用尽有,非常适合用来做小设备.可是有个问题是,它是Cortex-M0内核的,不像M3,M4内核一样,可以支持位带操作(就是一位一位地操作,像80C51单片机一样),这就给程序移植或者开发带来了一点点小麻烦,因此我就利用C语言结构的位段操作,实现了个访位带操作,只是在效率可能会稍逊于真正的位带操作,但是代码上可以兼容,

位带操作

1.位带区: 支持位带操作的地址区 2.位带别名:对别名地址的访问最终作用在位带区的访问(中途有地址映射) 3. 4. 5. 对于片上外设,映射关系参照上图关系修改即可. 6.举例: 建立一个把“位带地址+位序号”换成别名地址的宏,再建立一个把别名地址转换成指针类型的宏. 使用位带功能时,要访问的变量必须用volatile 来定义.(指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.)

Duanxx的STM32学习:GPIO操作

Duanxx的STM32学习:STM32下载方式选择

前几天熟悉了STM32的启动方式,主要由Boot0和Boot1设置 现在需要解决的就是STM32的下载的问题. 一开始的时候,我选择的是SWD下载,这种下载方式需要Boot0=0,Boot1=0,占用两个线,同时需要两个电阻和一个电容: 但是我的设计上需要使用串口,利用串口下载程序也是下载到Main Flash中,既然这样的话,直接使用串口下载程序就可以了. 但是使用串口下载程序需要反复的将Boot0抬高,然后复位,然后将下载程序,然后将Boot0拉低,这个操作比较的复杂. 在正点原子的开发板上