一、STM32芯片简介(手册下载)、内部结构、存储器映射、寄存器映射

一、STM32简介

1. STM32含义

  • STM,即意法半导体(STMicroelectronics);
    • 1987 年由意大利的 SGS 微电子公司和法国 Thomson 半导体公司合并而成。
    • 1998 年 5 月,SGS-THOMSON Microelectronics 将公司名称改为意法半导体有限公司。
    • 公司总部设在瑞士日内瓦,美国总部设在德克萨斯州达拉斯市的卡罗顿,亚太区总部设在新加坡,日本业务以东京为总部,大中国区总部设在上海
  • 32,即32位的微控制器;
  • 即STM32表示意法半导体32位系列的微控制器;

2.STM32芯片

  • 下图印刷电路板中的标注的芯片是144pin的STM32F103ZET6;
  • 芯片正面是丝印,标记这芯片的型号(arm表示该芯片使用的是arm内核);
  • 芯片四周是引脚,左下角的小圆点表示1脚,其余引脚从1脚按照逆时针顺序排列;
    【把芯片引脚引出来,连接到各种传感器上,然后在芯片上编程来控制各种传感器,这就是STM32开发】
    在这里插入图片描述
    在这里插入图片描述

3.STM32分类

  • STM32命名方法
    在这里插入图片描述

    • 从内核上分有Cortex-M0、M3、M4和M7这几种
      • 每个内核又大概分为主流、高性能、低功耗;
    • 单纯从学习的角度出发,可以选择F1和F4;
      • F1代表基础型,Cortex-M3内核,主频72MHZ;
      • F4代表高性能,Cortex-M4内核,主频180MHZ;
      • F4(429系列以上) 除了内核不同和主频的提升外,升级的明显特色就是带了LCD控制和摄像头接口;

4.开发时MCU的选择方法

  • 根据项目需求先大概选择MCU的内核;
    • 普通应用,不需要接大屏幕的一般选择Cortex-M3内核的F1系列;
    • 追求高性能、需要大量的数据运算、且需要外接大屏幕的选择Cortex-M4内核的F429系列;
  • 确定引脚数量
    • 引脚多的功能就多,价格也越贵。根据具体项目中需要使用到的功能,够用就好;
  • 选择Flash大小
    • 相同引脚数的MCU会有不同的Flash大小可供选择;程序大的就选择大点的Flash。
  • 根据数据手册来查询每个IO的具体功能。开发时,常用到参考手册(reference manual)和数据手册(Data Sheet)这两个官方文档,具体区别如下。
  • 分配原理图IO(画原理图前,一般先把引脚分类好,具体方法如下)
    在这里插入图片描述

5. 数据手册和参考手册下载方法

二、STM32内部结构

1.STM32的系统结构(了解即可);

  • 内核 ,即CPU,由ARM公司设计。(ARM公司不生产芯片,而是出售其芯片技术授权)Cortex-M表示该内核属于M系列;
    • ARM内核分为以下系列
      • A系列:Application缩写,高性能应用,用于手机、电脑、路由器等;
      • R系列,Real-Time缩写,实时性强,用于汽车电子、军工、无线基带等;
      • M系列:Microcontroller缩写,微控制器,用于消费电子、家电、医疗器械、工控等;
      • 性能由高到低,时钟频率由高到底;
  • 内核之外的部件为片上外设,如GPIO、USART、I2C、SPI等都叫做片上外设。(芯片生产厂商,负责在内核之外设计部件并生产整个芯片,例如ST、TI等)
  • 内核和外设之间通过各种总线连接,其中驱动单元、被动单元各有4个;
    在这里插入图片描述
    • ICode(指令代码)总线:该总线将内核与闪存指令接口相连接,用来指令预取;
    • 总线矩阵:协调内核系统总线和DMA主控总线之间的访问仲裁;
    • 4个驱动单元:DCode(数据代码)总线、System(系统)总线、通用DMA1和通用DMA2;
      • DCode总线: 该总线将内核与闪存数据接口相连接,用来加载常量和调试访问;
      • System总线:用于内核访问外设;
      • DMA总线:该总线将DMA的AHB主控接口与总线矩阵相连接;
    • 4个被动单元:内部SRAM、内部Flash、FSMC、AHB到APB的桥;
      • 内部SRAM,用于存放程序中的变量以及堆栈的开销,内核通过Dcode总线来进行访问;
      • 内部Flash:用于存放编写好的程序,内核通过ICode宗信来取里面的指令;
      • FSMC,Flexible Static Memory Controller,灵活的静态存储器控制器,用来扩展静态内存;
      • AHB到APB的桥:AHB总线延伸出来2条总线(APB1、APB2),用来挂载各种外设,如GPIO、USART、I2C等;

三、STM32的存储器映射

  • STM32的Flash、SRAM、FSMC、AHB到APB的桥,这些功能部件共同排列在一个4GB的地址空间内。我们在编程时,可以通过地址找到它们,然后进行操作(通过C语言进行数据的读写)。

    • STM32为32位控制器,所以最多只能访问224 字节(即4GB)存储空间;
  • 存储器本身不具有信息,它的地址由厂商或用户分配,给存储器分配地址的过程就称为存储器映射;如果给存储器再分配一个地址就叫存储器重映射

    • 存储器映射的硬件实现原理是通过地址译码电路。当CPU发一个一个内存访问请求时,会输出一个地址信号,地址译码电路会根据这个地址信号判断要访问哪个模块(如Flash、SRAM、外设等),然后将访问请求引导到相应的模块上;
      在这里插入图片描述
  • ARM将这4G的地址空间平均分成了8块(512MB/块),每块规定了相应的用途,如下表所示;

  • 这8个Block中,由三个块非常重要,即Block0、1、2;

    • Block0用来设计成内部Flash;
    • Block1用来设计成内部RAM;
    • Block2用来设计成片上外设;
    序号用途地址范围
    Block 0Code(内部Flash)0x0000 0000 ~ 0x1FFF FFFF(512MB)
    Block 1SRAM0x2000 0000 ~ 0x3FFF FFFF(512MB)
    Block 2片上外设0x4000 0000 ~ 0x5FFF FFFF(512MB)
    Block 3FSMC的bank1~bank20x6000 0000 ~ 0x7FFF FFFF(512MB)
    Block 4FSMC的bank3~bank40x8000 0000 ~ 0x9FFF FFFF(512MB)
    Block 5FSMC寄存器0xA000 0000 ~ 0xBFFF FFFF(512MB)
    Block 6未使用0xC000 0000 ~ 0xDFFF FFFF(512MB)
    Block 7Cortex-M3内部外设0xE000 0000 ~ 0xFFFF FFFF(512MB)
  • STM32F103ZET6的Flash大小为512KB,存储器Block0内部区域功能划分如下:
    在这里插入图片描述

    • ISP(In-System Programing),在系统中编程(指不需要把IC从电路板上取下就可以烧录程序的方法),串口下载时需要用到这部分程序;
    • 可以配置BOOT引脚来选择程序从FLASH、RAM还是系统存储器启动;
  • STM32F103ZET6的SRAM大小为64KB,存储器Block1内部区域功能划分如下
    在这里插入图片描述

  • Block2用于设计篇上外设,根据外设总线速度不同,Block2被分成了APB、AHB1、AHB2,内部区域功能划分如下:
    在这里插入图片描述

四、STM32的寄存器映射

  • 在存储器Block2这块区域,设计的是片上外设,它们以4个字节(32bit)为一个单元,每个单元对应不同的功能------>我们通过C语言向这些单元进行读写时就可以驱动外设工作;
    • 如果我们直接通过地址来进行访问,不仅不好记忆还容易出错,如下面所示:
      • GPIOB的ODR(输出数据寄存器)地址为0x4001 0C0C,共32bit,低16bit有效,对应着16个IO,写0/1对应的IO则输出低/高电平,下面是通过C语言指针的操作方式,让GPIOB的16个IO都输出高电平;(0x4001 0C0C是GPIOB ODR的地址,如果要让STM32也将其看成一个地址,需要把它强制转换成指针)
        *(unsigned int *)(0x4001 0C0C) = 0xFF;
        
    • 所以可以根据每个单元的功能,为其取一个别名,这个别名就是我们所说的寄存器,即为外设的每个功能单元取的别名就是寄存器;而给已经分配好地址的,有特定功能的,内存单元取别名的过程就是寄存器映射; 如下图所示
      #define GPIOB_ODR			(unsigned int*)(0x4001 0C0C)
      * GPIOB_ODR = 0xFF;
      
      • 为了更方便操作,可以直接把解指针操作"*"定义到寄存器别名中,如下图所示
        #define GPIOB_ODR		*(unsigned int*)(0x4001 0C0C)
        GPIOB_ODR = 0xFF;
        

1. 总线基地址

  • 片上外设区分为三条总线,分别挂载着不同的速度的外设;
    • APB1挂载低俗外设;
    • APB2、AHB挂载告诉外设;
  • 总线的最低地址,称为总线基地址;(总线基地址也是挂载在该总线上首个外设的起始地址);
  • 三条总线中,APB1总线地址最低,片上外设的地址从这里开始,也就做外设基地址
    在这里插入图片描述

2. xx外设基地址

  • 每条总线上挂载着各种外设,这些外设有着自己的地址范围,xx外设的起始地址称为"xx外设基地址"具体有关 STM32F10xx 外设的基地址请参考《STM32F10xx参考手册》的 2.3 小节的存储器映射的表 1:STM32F10xx 寄存器边界地址。,下表所示为挂载在APB2总线上的GPIOA~G的基地址
    在这里插入图片描述

3. 外设寄存器

  • 在xx外设的地址范围内,分布着的就是该外设的寄存器。以GPIOB为例,每个寄存器为32bit(占4个字节),在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。
    在这里插入图片描述

  • 外设的寄存器说明可参考《STM32F10xx 参考手册》中具体章节的寄存器描述部分,在编程
    的时候我们需要反复的查阅外设的寄存器说明。以端口位设置/清除寄存器为例,来对参考手册中寄存器的描述进行说明。
    在这里插入图片描述

    • 名称:GPIOx_BSRR(x=A…E),其中"x"可以为A ~ E,即这个寄存器说明适用于GPIOA ~ GPIOE,这些GPIO端口都有这样的一个寄存器;
    • 偏移地址:该寄存器相对于外设的基地址的偏移;
    • 寄存器位表:列出了0 ~ 31位的名称及权限;表的上方数字为位编号、中间为位名称、最下方为读写权限(w表示只写,r表示只读,rw表示可读写);
    • 位功能说明:详细介绍了寄存器每一个位的功能;

五、C语言对寄存器的封装

1.封装总线和外设基地址

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

/* 总线基地址 */
#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

/* GPIO 外设基地址 */
#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_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)

2.封装寄存器列表

  • GPIOA~GPIOE都有一组功能相同的寄存器,这些寄存器在该外设的基地址上按照顺序,C语言中的结构体变量的存储空间也是连续的。那么我们就可以通过结构体对寄存器进行封装。
    typedef unsigned int uint32_t; /* 无符号 32 位变量 */
    typedef unsigned short int uint16_t; /* 无符号 16 位变量 */
    
    /* GPIO 寄存器列表 */
    typedef struct
    {
    	uint32_t CRL;
    	uint32_t CRH;
    	uint32_t IDR;
    	uint32_t ODR;
    	uint32_t BSRR;
    	uint32_t BRR;
    	uint32_t LCKR;
    } GPIO_TypeDef;
    
  • 接着我们我们使用宏定义好GPIO_TypeDef类型的指针,而指针指向各个GPIO端口的首地址,使用时直接用该宏访问寄存器即可。
    /* 使用 GPIO_TypeDef 把地址强制转换成指针 */
    #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
    #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
    #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
    #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
    #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
    #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
    #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
    #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
    
    /* 访问 GPIOA 端口的寄存器 */
    GPIOA->BSRR = 0xFFFF;
    GPIOA->CRL = 0xFFFF;
    GPIOA->ODR =0xFFFF;
    
    uint32_t temp;
    temp = GPIOA->IDR; //读取 GPIOA_IDR 寄存器的值到变量 temp 中
    

六、修改寄存器的位操作方法

  • 使用C语言操作寄存器时,常常要求只修改寄存器某几位的值,而寄存器其他位的值保持不变。这时就需要用到C语言的位操作了;

1. 把某位清0 &= ~

//定义一个变量 a = 1001 1111 b (二进制数)
unsigned char a = 0x9f;

//对 bit2 清零
a &= ~(1<<2);
//括号中的 1 左移两位,(1<<2) 得二进制数:0000 0100 b
//按位取反,~(1<<2) 得 1111 1011 b
//假如 a 中原来的值为二进制数: a = 1001 1111 b
//所得的数与 a 作”位与&”运算,a = (1001 1111 b)&(1111 1011 b),
//经过运算后,a 的值 a=1001 1011 b
// a 的 bit2 位被清零,而其它位不变。

2.把某位置1 |=

//定义一个变量 a = 1001 1111 b (二进制数)
unsigned char a = 0x9f;

//对 bit5 置1
a |= (1<<5);
//括号中的 1 左移5位,(1<<5) 得二进制数:0010 0000 b
//假如 a 中原来的值为二进制数: a = 1001 1111 b
//所得的数与 a 作”位或|”运算,a = (1001 1111 b)|(0010 0000 b),
//经过运算后,a 的值 a=1011 1011 b
// a 的 bit5 位被置1,而其它位不变。

3.把某位取反 ^=

//定义一个变量 a = 1001 1111 b (二进制数)
unsigned char a = 0x9f;

//对 bit3 取反
a ^= (1<<3);
//括号中的 1 左移3位,(1<<3) 得二进制数:0000 1000 b
//假如 a 中原来的值为二进制数: a = 1001 1111 b
//所得的数与 a 作”异或^”运算,a = (1001 1111 b)^(0000 1000 b),
//经过运算后,a 的值 a=1001 0111 b 
// a 的 bit3 位取反,而其它位不变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值