2 初识STM32——寄存器

寄存器

 寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。
 补充1:触发器,在数字电路系统中的存储器,需要在同一时刻接收到一个脉冲(CLK)作为控制信号,只有CLK到来时电路才被触发产生动作,并根据输入型号改变输出状态。这种时钟型号触发的存储电路单元称为触发器,以区别没有时钟信号控制的锁存器。根据逻辑功能的不同特点,把触发器分为RS、JK、T、D等几种类型。
 补充2:锁存器,锁存器可以在特定的脉冲电平作用下改变状态,除此以外,电平状态保持不变。常见的用两个CMOS反向器组成的RS锁存器,R清0,S置1.

STM32芯片内部

在这里插入图片描述
 丝印表示产品的生产批号等,芯片丝印的字正对我们时,或者小圆点在左下角时,逆时针数,下面一排左边第一个为引脚1。识别清楚芯片正方向很重要,否则会烧毁芯片。

系统架构

STM32F10XX系统构架图狂徒框图在这里插入图片描述
左半部分为ARM设计得内核,右半边为ST设计的外设。

  • 红色部分为驱动单元——内核
    DCode总线——加载常量和调试访问
    DMA通过DMA总线读取数据,用来翻译数据
    System总线,主要用来读取寄存器(外设)
  • 灰色部分为被动单元——外设部分
    Flash用来存储指令
    SRAM用来存放变量
    FSMC用来驱动外存
    AHB-APB的总线,AHB挂载两个外设,一个是复位和时钟控制(RCC),另一个是SDIO。高速总线AHB通过桥接分成连个时钟总线,一个是低速总线APB1,挂载定时器(TIM2-7)等;另一个是高速APB2,连接了比如GPIO A-F,ADC 1-3 等
  • 黄色部分为ICode总线——内核读取Flash中的指令

存储器映射

  • 什么叫存储器映射?
     存储器本身不具有地址信息,它的地址是由芯片厂商或者用户分配,给存储器飞陪地址的过程就称为存储器映射。
序号 用途 地址范围
Block 0 Code-flash 0x0000 0000 ~ 0x1FFF FFFF(512MB)
Block 1 SRAM 0x2000 0000 ~ 0x3FFF FFFF(512MB)
Block 2 片上外设 0x4000 0000 ~ 0x5FFF FFFF(512MB)
Block 3 FSMC的blank1~blank2 0x6000 0000 ~ 0x7FFF FFFF(512MB)
Block 4 FSMC的blank3~blank4 0x8000 0000 ~ 0x9FFF FFFF(512MB)
Block 5 FSMC寄存器 0xA000 0000 ~ 0xBFFF FFFF(512MB)
Block 6 没有使用 0xC000 0000 ~ 0x3DFF FFFF(512MB)
Block 7 Cortex—M3内部外设 0xE000 0000 ~ 0xFFFF FFFF(512MB)

寄存器映射图:
在这里插入图片描述
  32位ARM芯片可以访问2^32=4GB内存,这4GB内存被分成8个块,每块512MB,不同的外设只能写入相应的部分,但是没有占满512MB,大约在0-128KB不等。
所有的外设在内存块上占用32GB,
block 0——FLASH
block 1——SRAM
block 2——片上外设(重点
  block 2 里对应着许多外设的地址,根据不同的传输速度分成APB1总线、APB2总线、AHB总线。其中AHB和APB2为高速总线,APB1为低速总线。

如何使用寄存器映射?

  在51中有头文件,里边定义了单片机的端口,比如点亮P0^0口上的LED:

#incloude <reg52.h>
sbit LED = P0^0

void main(void)
{
     // P0 =0xFE;
     LED = 0;
}

而P0在51单片机中地址映射为0x80,P1-0x90,P2-0xA0,P3-0xB0。

  那么对于STM32如何让GPIOB端口实现全部输出高电平?
GPIOB地址为0x4001 0C00 - 0x4001 0FFF,但是GPIOB这些地址分配了很多寄存器,分配给16位端口输出数据寄存器(GPIOx_ODR)的地址偏移为 0x0C,
  1、通过绝对地址访问:

//GPIOB 端口全部输出 高电平
*(unsigned int*) (0x40010C0C) = 0xFFFF;

其中寄存器地址=基地址+偏移地址
0x4001 0C00 + 0x0C = 0x40010C0C
(unsigned int*)类型强制转换成int *指针

  2、通过寄存器别名方式访问内存:

//GPIOB 端口全部输出 高电平
#define GPIOB_ODR (unsigned int*)(0x40010C0C)
* GPIOB_ODR = 0xFFFF;

为了方便操作干脆把取地址页定义到寄存器中:

//GPIOB 端口全部输出 高电平
#define GPIOB_ODR *(unsigned int*)(0x40010C0C)
GPIOB_ODR = 0xFFFF;

什么是寄存器

  • 什么是寄存器
      给有特定功能的内存单元去一个别名——寄存器,这个给飞配好地址的有特定功能的内存单元取别名的过程就叫做寄存器映射。
  • 什么叫存储器映射
      给存储器分配地址的过程叫做存储器映射,在分配一个地址叫重映射。
     在官方数据参考手册里边,详细列出了存储器组起始地址。
    STM32F10xxx中内设的起始地址
    在这里插入图片描述
    表里的从下往上看,首先是低速APB1,起始地址为TIM2定时器,然后往上其他外设等,其次是高速APB2、AHB等。

总线

寄存器映射地址

  • 总线是什么?
     所谓总线(Bus),是指计算机设备和设备之间传输信息的公共数据通道。总线是连接计算机硬件系统内多种设备的通信线路,它的一个重要特征是由总线上的所有设备共享,可以将计算机系统内的多种设备连接到总线上。如果是某两个设备或设备之间专用的信号连线,就不能称之为总线。
总线名称 总线基地址 外设相对基地址的偏移
APB1 0x4000 0000 0x0
APB2 0x4001 0000 0x0001 0000
AHB 0x4001 8000 0x0001 8000

GPIO基地址

  • 外设是什么?
     片内copy、外设是两个概念,片内指做成芯片的集成电路内部,简称片内;外设是外部设备的简称,是指集成电路芯片外部的设备。集成电路芯片与外部设备的连接一般需要专门的接口电路和总线的连接(包括控制总线路、地址总线和数据总线等)。 由于大规模集成电路知的技术发展得很快,现在许多芯片在制造时已经能够将部分接口电路和总线集成到芯片内部。对于这部分电路与传统的接口电路和总线是有区别的,为了加于区别可以称之为片内外设,其含义是在集成电路芯片内部集成的用于与外部设备连接的接口电路和总线。 因此道,简单的说,“片内外设”是芯片内部用于与外部设备连接的接口电路和总线

  • 外设GPIO基地址

外设名称 外设及地址 相对 APB2 总线的地址偏移
GPIOA 0x4001 0800 0x0000 0800 (2MB)
GPIOB 0x4001 0C00 0x0000 0C00 (3MB,与GPIOA偏移1MB)
GPIOC 0x4001 1000 0x0000 1000 (4MB)
GPIOD 0x4001 1400 0x0000 1400 (5MB)
GPIOE 0x4001 1800 0x0000 1800 (6MB)
GPIOF 0x4001 1C00 0x0000 1C00 (7MB)
GPIOG 0x4001 2000 0x0000 2000 (8MB)
  • GPIOx端口的寄存器列表
    对于任意端口得7个GPIOx,他们的相对于寄存器基地址的地址偏移都是一样的
寄存器名称 寄存器地址 相对GPIOB极值的偏移
1 GPIOB_CRL  端口配置低寄存器 0x4001 0C00 0x00
2 GPIOB_CRH  端口配置高寄存器 0x4001 0C00 0x04
3 GPIOB_IDR  数据输入寄存器 0x4001 0C00 0x08
4 GPIOB_ODR  数据输出寄存器 0x4001 0C00 0x0C
5 GPIOB_BSRR  端口位设置/清除寄存器 0x4001 0C00 0x10
6 GPIOB_BRR   端口位清除寄存器 0x4001 0C00 0x14
7 GPIOB_LCKR  端口配置锁定寄存器 0x4001 0C00 0x18
  • GPIOx端口32位寄存器说明
    1、 端口配置低寄存器 GPIOx_CRL x=A…E
    在这里插入图片描述
    2、端口配置高寄存器 GPIOx_CRH x=A…E
    在这里插入图片描述
    3、端口数据输入寄存器 GPIOB_IDR x=A…E
    在这里插入图片描述
    4、数据输出寄存器
    在这里插入图片描述
    5、端口位设置/清除寄存器 GPIOx_BSRR x=A…E
    在这里插入图片描述
    6、端口位清除寄存器 GPIOx_BRR x=A…E在这里插入图片描述
    7、 端口配置多订寄存器 GPIOx_LCKR x=A…E
    在这里插入图片描述

C语言对寄存器的封装

1、单独定义

/* 外设基地址 */
#define PERIPH_BASE                (unsigned int)0x40000000

/*  总线基地址  */
#define APB1PERIPH_BASE            PERIPH_BASE
#define APB2PERIPH_BASE            (PERIPH_BASE + 0x00010000)
#define APB3PERIPH_BASE            (PERIPH_BASE + 0x00020000)

/* GPIO 外设基地址 */
#define DPIOA_BASE                 (APB2PERIPH_BASE + 0x0800)
#define DPIOB_BASE                 (APB2PERIPH_BASE + 0x0C00)
#define DPIOC_BASE                 (APB2PERIPH_BASE + 0x1000)
#define DPIOD_BASE                 (APB2PERIPH_BASE + 0x1400)
#define DPIOE_BASE                 (APB2PERIPH_BASE + 0x1800)
#define DPIOF_BASE                 (APB2PERIPH_BASE + 0x1C00)
#define DPIOG_BASE                 (APB2PERIPH_BASE + 0x2000)

/* 寄存器基地址,以GPIOB为例*/
#define GPIOB_CRL                  (GPIOB_BASE +0x00)
#define GPIOB_CRH                  (GPIOB_BASE +0x04)
#define GPIOB_IDR                  (GPIOB_BASE +0x08)
#define GPIOB_ODR                  (GPIOB_BASE +0x0C)
#define GPIOB_BSRR                 (GPIOB_BASE +0x10)
#define GPIOB_BRR                  (GPIOB_BASE +0x14)
#define GPIOB_LCKR                 (GPIOB_BASE +0x18)

例:让PBO输出低/高电平,如何实现

#define PERIPH_BASE                (unsigned int)0x40000000
#define APB2PERIPH_BASE            (PERIPH_BASE + 0x00010000)
#define DPIOB_BASE                 (APB2PERIPH_BASE + 0x0C00)
#define GPIOB_ODR                  *(unsigned int*)(GPIOB_BASE +0x0C)

//PBO输出低电平,保留了GPIOB_ODR其他位
GPIOB_ODR &= ~(1<<4);    //某一位置0

//PBO输出高电平
GPIOB_ODR |= (1<<4);     //某一位置1

/* 其中
GPIOB_ODR 初始值为0x0000 0000

GPIOB_ODR &= ~(1<<0);   分三步
1. 左移 1 << 4 = 0000 1000
2. 取反 ~(1 << 4)= 1111 0111
3. 按位与,若GPIOB_ODR初值为0x1111 1111
   1111 1111
   1111 0111
——————————————
   1111 0111
 从而保留了其他位
 
GPIOB_ODR |= (1<<4);   
1. 左移 1 << 4 = 0000 1000
2. 按位或,若GPIOB_ODR初值为0x0000 0000
   0000 0000
   0000 1000
——————————————
   0000 1000
 从而保留了其他位
*/

2、结构体封装

typedef unsigned         int uint32_t;    /*无符号32位变量*/
typedef unsigned short   int uint16_t;    /*无符号16位变量*/

/* GPIO 寄存器列表 */
typedef struct {
    uint32_t CRL;       /*GPIO端口配置低寄存器     地址偏移:0x00*/
    uin32_t ORH;        /*GPIO端口配置高寄存器     地址偏移:0x04*/
    uin32_t IDR;        /*GPIO数据输入寄存器       地址偏移:0x08*/
    uin32_t ODR;        /*GPIO数据输出寄存器       地址偏移:0x0C*/
    uin32_t BSRR;       /*GPIO位设置/清除寄存器    地址偏移:0x10*/
    uin32_t BRR;        /*GPIO端口位清除寄存器     地址偏移:0x14*/
    uin16_t CLKR;       /*GPIO端口配置锁定寄存器   地址偏移:0x18*/
} GPIO_TypeDef;

使用结构体指针访问寄存器列表:

GPIO_TypeDef * GPIOx;    //定义一个GPIO_TypeDef结构二踢指针GPIOx
GPIOx = GPIOB_BASE;      //把指针地址设置为宏GPIOB_BASE的地址
GPIOx -> IDR =0xFFFF;
GPIOx -> ODR=0xFFFF;

uint32_t temp;
temp = GPIOx->IDR;       //读取GPIOB_IDR 寄存器的值到变量temp中

或者直接使用转化后的GPIO端口基地址指针

/*使用GPIO_TypeDef把地址强制转化成指针*/
#define GPIOA    ((GPIO_TypeDef *)  GPIOA_BASE)
#define GPIOB    ((GPIO_TypeDef *)  GPIOB_BASE)

/*使用定义的宏直接访问*/
/*访问GPIOB端口的寄存器*/
GPIOB->BSRR = 0xFFFF;
GPIOB->CRL = 0xFFFF;
GPIOB->ODR = 0xFFFF;

uint32_t temp;
temp = GPIOB->IDR;

这些内容都包含在库文件中。

发布了16 篇原创文章 · 获赞 1 · 访问量 884

猜你喜欢

转载自blog.csdn.net/qq_33866593/article/details/105522239
今日推荐