本文章使用STM32F103ZET6单片机做实验
原理
系统架构
以STM32F103ZET6单片机为例,介绍一下系统架构如图所示:
如图,红色部分是ARM内核(Cortex™-M3内核),蓝色部分则是外设。这里先介绍一下STM32F103ZET6芯片的背景,以便大家理解。
首先,ARM公司提供ARM内核(红色部分),这类提供内核的公司称为IP厂商。然后,再由ST意法半导体公司设计外设(蓝色部分),这类拿到内核并设计外设的公司称为SOC厂商。经过上述步骤,STM32F103的芯片便诞生了。下面补充一下MCU和MPU的区别:
好了,下面我们步入正题,STM32中32是32bit的意思。所以单片机内部有2^32=4GB的内存空间,而这些空间的分配是由ARM公司定义的。如图:
由图可知,4GB的空间分为8个部分,每个部分512MB。从下往上看,第一部分,是Flash(存放串口下载的程序,常量)。第二部分,是SRAM(存放变量)。第三部分,是外设地址(如:GPIO,SPI,IIC等),第四,五,六部分,是FSMC(OLED)。第七部分,未被使用。第八部分,ARM内核使用。
寄存器
寄存器本质是具有特殊功能的内存单元,寄存器映射本质是给这些特殊功能的内存单元进行命名。
就是对第三部分的外设地址进行命名。因为是通过地址对地址上的内容赋值,所以,我们使用指针操作。例如:*(unsigned int *)0x40021018 |= (1<<3),就可以实现对0x40021018这个地址的第三位置1。
寄存器编程
仿51单片机编程
#include "stm32f10x.h"
int main(void)
{
//配置GPIOB的时钟
*(unsigned int *)0x40021018 |= (1<<3);
//配置GPIOB的I/O输出
*(unsigned int *)0x40010C00 |= (1<<(4*0));
//使能PB0 = 0
*(unsigned int *)0x40010C0C &= ~(1<<0);
}
void SystemInit()
{
}
#include "stm32f10x.h" 这个头文件里面是空内容,这里写上是为了保证编译通过(为了骗过编译器)
startup_stm32f10x_hds是启动文件,
启动文件里面写着,先运行SystemInit,然后,在执行main函数,所以,这里我们加上了void SystemInit()里面不写函数,同样也是为了骗过编译器。
配置寄存器
GPIO口点亮LED,如图:
PB0输出低电平,G点亮
步骤:
1.启动GPIOB的时钟-_________(APB2外设时钟使能寄存器(RCC_APB2ENR))
2.设置PB0的输出模式和输出速度_________(端口配置低寄存器(GPIOx_CRL))
3.设置PB0输出0__________(端口输出数据寄存器(GPIOx_ODR))
通过查阅STM32F10x参考手册,可以知道GPIOB的基地址,偏移地址,时钟地址。所以,
//配置GPIOB的时钟
*(unsigned int *)0x40021018 |= (1<<3);
//配置GPIOB的I/O输出
*(unsigned int *)0x40010C00 |= (1<<(4*0));
//使能PB0 = 0
*(unsigned int *)0x40010C0C &= ~(1<<0);
比如:*(unsigned int *)0x40021018 |= (1<<3);
因为直接对0x40021018赋值是不允许的,所以,先强转为指针(unsigned int *)0x40021018,然后,在指针赋值操作*(unsigned int *)0x40021018。这个时候,就可以对0x40021018进行赋值操作了
因本人水平有限,不足之处在所难免,敬请各位网友指正