欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

程序员文章站 2024-02-24 23:38:16
...

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

概念内容,截图给自己留个印象
STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)
STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)
STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)
STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

(内核+外设)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

  1. ICode 总线

    ICode 中的 I 表示 Instruction,即指令。我们写好的程序编译之后都是一条条指令,存
    放在 FLASH 中,内核要读取这些指令来执行程序就必须通过 ICode 总线,它几乎每时每刻
    都需要被使用,它是专门用来取指的。

  2. 驱动单元

    • DCode 总线
      DCode 中的 D 表示 Data,即数据,那说明这条总线是用来取数的。我们在写程序的时
      候,数据有常量和变量两种,常量就是固定不变的,用 C 语言中的 const 关键字修饰,是
      放到内部的 FLASH 当中的,变量是可变的,不管是全局变量还是局部变量都放在内部的
      SRAM
      。因为数据可以被 Dcode 总线和 DMA 总线访问,所以为了避免访问冲突,在取数
      的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
    • System总线
      系统总线主要是访问外设的寄存器,我们通常说的寄存器编程,即读写寄存器都是通
      过这根系统总线来完成的。
    • DMA 总线
      DMA 总线也主要是用来传输数据,这个数据可以是在某个外设的数据寄存器,可以在
      SRAM,可以在内部的 FLASH。因为数据可以被 Dcode 总线和 DMA 总线访问,所以为了
      避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
  3. 被动单元

    • 内部的闪存存储器(Flash)
      内部的闪存存储器即 FLASH,我们编写好的程序就放在这个地方。内核通过 ICode 总
      线来取里面的指令。
    • 内部的 SRAM
      内部的 SRAM,即我们通常说的 RAM,程序的变量,堆栈等的开销都是基于内部的
      SRAM。内核通过 DCode 总线来访问它。
    • FSMC
      FSMC 的英文全称是 Flexible static memory controller,叫灵活的静态的存储器控制器,
      是 STM32F10xx 中一个很有特色的外设,通过 FSMC,我们可以扩展内存,如外部的
      SRAM, NANDFLASH 和 NORFLASH。但有一点我们要注意的是, FSMC 只能扩展静态的
      内存,即名称里面的 S: static,不能是动态的内存,比如 SDRAM 就不能扩展。
    • AHB 到 APB 的桥
      从 AHB 总线延伸出来的两条 APB2 和 APB1 总线,上面挂载着 STM32 各种各样的特
      色外设。我们经常说的 GPIO、串口、 I2C、 SPI 这些外设就挂载在这两条总线上,这个是
      我们学习 STM32 的重点,就是要学会编程这些外设去驱动外部的各种设备。
  4. STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)存储器映射、寄存器映射

    • 什么是寄存器?

      给有特定功能的内存单元取一个别名,这个别名就是我们经常
      说的寄存器,这个给已经分配好地址的有特定功能的内存单元
      取别名的过程就叫寄存器映射。

    • 什么是存储器映射?

      给存储器分配地址的过程叫存储器映射,再分配一个地址叫重
      映射。

    寄存器映射:

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    1.ST官方参考手册

    2.(unsigned int*)(0x40010C0C) == 将0x40010C0C强制转化为地址,通过 *指向该地址的寄存器并写值

    (缺点是太繁琐)

    改进:

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

  5. 总线

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    (APB2与AHB均为高速总线)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

(0100—一个字节对应8位二进制,4字节即为32位)

以GPIOB为例,寄存器地址偏移:

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)
STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

GPIOB_ODR &= ~(1<<x)-----(1左移x位后取反与原来值相与,即为PBx清零,其他位保持不变)

GPIOB_ODR |= (1<<x)-----(1左移x位后与原来值相或,即PBx置1,其他位保持不变)

寄存器工程模板创建

  1. 建立一个文件夹

  2. 通过mdk5定位到该文件夹,新建一个工程

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

  1. 选定设备

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

(不使用keil 在线库文件)

  1. 添加工程文件至文件夹
    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)
    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    魔术棒配置一下output以及keil版本就完事了~

寄存器点亮LED

  1. 原理图判断灯所在外设对应位

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

  2. 对应外设地址与时钟地址

    对应外设地址:

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    时钟地址:
    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

  3. 外设与时钟配置

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

    STM32裸机学习笔记(二)—STM32与寄存器概念(附寄存器版简易LED流水灯)

代码:

# include "stm32f10x.h"

void delay(unsigned int i);

int main(void)
{
	//置1操作:|= ; 清零操作: &=~ ;
	//GPIOB的RCC时钟开启
		*(unsigned int*) 0x40021018 |= (1<<3);
	//GPIOB的配置(推挽输出,10MHZ)
		*(unsigned int*) 0x40010C00 |= (1<<0);
		*(unsigned int*) 0x40010C00 |= (1<<4);
		*(unsigned int*) 0x40010C00 |= (1<<20);
	//while循环闪烁
	while(1)
	{
		//GPIOB的输出
		*(unsigned int*) 0x40010C0C &= ~(1<<0);
		*(unsigned int*) 0x40010C0C |= (1<<1);
		*(unsigned int*) 0x40010C0C |= (1<<5);
		delay(2000);
		*(unsigned int*) 0x40010C0C &= ~(1<<1);
		*(unsigned int*) 0x40010C0C |= (1<<0);
		*(unsigned int*) 0x40010C0C |= (1<<5);
		delay(2000);
		*(unsigned int*) 0x40010C0C &= ~(1<<5);
		*(unsigned int*) 0x40010C0C |= (1<<0);
		*(unsigned int*) 0x40010C0C |= (1<<1);
		delay(2000);
		*(unsigned int*) 0x40010C0C &= ~(1<<0);
		*(unsigned int*) 0x40010C0C &= ~(1<<1);
		*(unsigned int*) 0x40010C0C &= ~(1<<5);
		delay(2000);
	}
}
void SystemInit(void)
{
	//
}

void delay(unsigned int i)
{
		unsigned char j;
		for(i;i>0;i--)
				for(j = 255; j>0; j--);
}