ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

STM32F103寄存器方式点亮LED流水灯

2021-10-23 22:02:34  阅读:245  来源: 互联网

标签:STM32F103 LED r1 r2 ldr BASE GPIOA 寄存器 GPIO


目录

一、STM32F103系列芯片的地址映射和寄存器映射原理

1.地址映射

2.寄存器映射

二、了解GPIO端口的初始化设置三步骤

三、点亮LED流水灯

1.代码

2. 执行波形

3.结果

四、参考文献


一、STM32F103系列芯片的地址映射和寄存器映射原理

1.地址映射

 STM32固件库中,有个头文件叫stm32f10x.h,其中就定义了寄存器的映射,部分代码如下:

  外设基地址PERIPH_BASE:

#define PERIPH_BASE           ((uint32_t)0x40000000)

总线基地址,在外设基地址上加上偏移:

#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

GPIO外设基地址,在APB2总线基地址上加上偏移:

#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)

定义GPIO外设结构体,因为结构体成员在内存中是连续的,这种形式与寄存器组非常类似,所以用结构体能够很好的管理寄存器:

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;

定义GPIOA结构体指针,因为单单定义GPIO外设结构体,并不能确定其内存地址,因此用指针将其绑定到GPIOA外设基地址:

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

 访问寄存器方式的对比,映射访问明显更为直观:

//直接的地址访问
*(unsigned int *)(0x4001_0800)|= 0x0001;
//映射访问
GPIOA->CRL |= 0x0001;

2.寄存器映射

        寄存器映射主要针对于Block2。这种映射不同于存储器映射的分配地址操作,而是在程序中对具有特定功能的内存单元进行命名的过程,每个内存单元都是四个字节,称作寄存器。例如GPIOA外设有个寄存器地址范围为0x4001_0800~0x4001_0803,该寄存器是用来配置GPIOA部分端口工作模式的,因此被映射为GPIOA_CRL。由此可知,这种映射方便了对寄存器的访问操作,因为如果每次访问寄存器都要查地址范围的话是很痛苦的。

        如何实现这种映射的呢?以GPIOA_CRL为例,其映射地址 = 外设总基地址(块基地址)+ 总线相对于外设总基地址的偏移 + 具体外设基地址相对于总线基地址的偏移 + 寄存器相对于具体外设基地址的偏移。

  外设总基地址恰好就是Block2的起始地址0x4000_0000;

  GPIO属于APB2总线外设,因此查阅芯片手册如下图所示,我们其实直接可以得到APB2起始地址和GPIOA的起始地址,但是程序中一般不这么做,而是以偏移量来表示层次关系。从图中可计算到总线相对于外设总基地址的偏移为0x1_0000,GPIOA相对于APB2基地址的偏移为0x800。

再查阅GPIO的寄存器组,如下图所示。可以得到CRL寄存器相对于GPIO基地址偏移为0x00。综上GPIOA_CRL的基地址为:0x4000_0000+0x1_0000+0x800+0x00。

二、了解GPIO端口的初始化设置三步骤

STM32F103ZE的开发板里总共有7组IO口,每组IO口有16个IO,即这块板子总共有112个IO口分别是GPIOA~GPIOG。每个I/O端口位可以自由编程,但I/O端口寄存器必须按32位字节访问,不允许半字或单字节访问。
GPIO的工作模式主要有八种:4种输入方式,4种输出方式,分别为输入浮空,输入上拉,输入下拉,模拟输入;输出方式为开漏输出,开漏复用输出,推挽输出,推挽复用输出。
(1)GPIO_Mode_AIN 模拟输入 (应用ADC模拟输入,或者低功耗下省电)
(2)GPIO_Mode_IN_FLOATING 浮空输入 (浮空就是浮在半空,可以被其他物体拉上或者拉下,可以用于按键输入)
(3)GPIO_Mode_IPD 下拉输入 (IO内部下拉电阻输入)
(4)GPIO_Mode_IPU 上拉输入 (IO内部上拉电阻输入)
(5)GPIO_Mode_Out_OD 开漏输出(开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行)
(6)GPIO_Mode_Out_PP 推挽输出 (推挽就是有推有拉电平都是确定的,不需要上拉和下拉,IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的 )
(7)GPIO_Mode_AF_OD 复用开漏输出(片内外设功能(I2C的SCL,SDA))
(8)GPIO_Mode_AF_PP 复用推挽输出 (片内外设功能(TX1,MOSI,MISO.SCK.SS))

GPIO初始化步骤
第一步:使能GPIOx口的时钟
第二步:指明GPIOx口的哪一位,这一位的速度大小以及模式。
第三步:调用GPIOx口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。

实例如下
☞对于单个GPIO口的初始化如下

GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步:设置GPIOA参数:输出OR输入,工作模式,端口翻转速率
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_8; //设定要操作的管脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz

第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

第四步:调用GPIO-SetBits函数,进行相应为的置位。
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出高

☞对于多个GPIO口的初始化如下

GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA,GPIOE的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

第二步:设置GPIOA,GPIOE参数:输出OR输入,工作模式,端口翻转速率
第三步:调用GPIOA口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。

▶把第二、三、四步合并分别设置GPIOA和GPIOE
先设置GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 第四个口,PA4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOA,&GPIO-InitST); //根据设定参数初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_4); //输出高

再设置GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 第三个口,PE3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOE,&GPIO-InitST); //根据设定参数初始化GPIOE
GPIO_SetBits(GPIOE,GPIO_Pin_3); //输出高

三、点亮LED流水灯

1.代码

1.c

#include "stm32f10x.h"
//----------------APB2??????? ---------------------
#define RCC_APB2ENR		*((unsigned volatile int*)0x40021018)
//----------------GPIOA????? -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
#define	GPIOA_ODR		*((unsigned volatile int*)0x4001080C)
//----------------GPIOB????? -----------------------
#define GPIOB_CRL		*((unsigned volatile int*)0x40010C00)
#define	GPIOB_ODR		*((unsigned volatile int*)0x40010C0C)
//----------------GPIOC????? -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
#define	GPIOC_ODR		*((unsigned volatile int*)0x4001100C)
	
extern void led(void);

//????
 void Delay()
 {
   u32 i=0;
   for(;i<5000000;i++);
 }
 
//?1
 void led1()
 {
    GPIOA_ODR|=1<<4;		//PA4???
	 	Delay();
		GPIOA_ODR&=~(1<<4);//PA4???,???????
		Delay();		
 }
 
//?2
 void led2()
 {
	  GPIOB_ODR|=1<<5;		//PB4???
	 	Delay();
		GPIOB_ODR&=~(1<<5);//PB4???,???????
		Delay();		
 }
 
//?3
 void led3()
 {
	 
		GPIOC_ODR|=1<<14;	//PC14???
	 	Delay();
		GPIOC_ODR&=~(1<<14);//PC14???,???????
		Delay();		
 } 
 
 int main(void)
 {	
	 led();
	RCC_APB2ENR|=1<<2|1<<3|1<<4;	//APB2-GPIOA?GPIOB?GPIOC??????		
	
	GPIOA_CRL&=0xFFF0FFFF;	//??? ??		
	GPIOA_CRL|=0x00020000;	//PA4????	
	GPIOA_ODR&=~(1<<4);		//???????	
	
	GPIOB_CRL&=0xFF0FFFFF;	//??? ??		
	GPIOB_CRL|=0x00200000;	//PB5????		
	GPIOB_ODR&=~(1<<5);		//???????	
	 
	GPIOC_CRH&=0xF0FFFFFF;	//??? ??		
	GPIOC_CRH|=0x02000000;	//PC14????		
	GPIOC_ODR&=~(1<<14);	//???????			

	while(1){		
		led1();
		
        led2();
		
        led3();
		}
}

 2.s

 AREA MYDATA, DATA
	
 AREA MYCODE, CODE
	ENTRY
	EXPORT led

led
	;??A,B,C
    ldr r0, =0x40021018
    ldr r1, =0x0000001c
    str r1, [r0]                


	;????A4
	ldr r0, =0x40010800
    ldr r1, [r0]
    bic r1, r1, #0x000f0000
    orr r1, r1, #0x00010000
    str r1, [r0]

	;????B5
    ldr r0, =0x40010c00
    ldr r1, [r0]
    bic r1, r1, #0x00f00000
    orr r1, r1, #0x00100000
    str r1, [r0]
	
	;????C14
	ldr r0, =0x40011004
    ldr r1, [r0]
    bic r1, r1, #0x0f000000
    orr r1, r1, #0x01000000
    str r1, [r0]

	;??A4??
	ldr r0, =0x4001080c
    ldr r1, =0x00000010
    str r1, [r0]

	ldr r0, =5000000;??
    ldr r1, =0
	
;????
blink
    add r1, r1, #1
    cmp r1, r0
    blt blink
	
	;??A4?
	ldr r1, =0x4001080c
    ldr r2, [r1]
    eor r2, r2, #0x00000010
    str r2, [r1]
	
	;??B5?
	ldr r1, =0x40010c0c
    ldr r2, [r1]
    eor r2, r2, #0x00000020
    str r2, [r1]
	
	ldr r1, =0

blink1	
	add r1, r1, #1
    cmp r1, r0
    blt blink1
	
	;??B5?
	ldr r1, =0x40010c0c
    ldr r2, [r1]
    eor r2, r2, #0x00000020
    str r2, [r1]
	
	;??C14?
	ldr r1, =0x4001100c
    ldr r2, [r1]
    eor r2, r2, #0x00004000
    str r2, [r1]
	

	ldr r1, =0

blink2
	add r1, r1, #1
    cmp r1, r0
    blt blink2
	
    ;??C14?
	ldr r1, =0x4001100c
    ldr r2, [r1]
    eor r2, r2, #0x00004000
    str r2, [r1]
	
	;??A4?
	ldr r1, =0x4001080c
    ldr r2, [r1]
    eor r2, r2, #0x00000010
    str r2, [r1]
	

	ldr r1, =0
    b blink

	
	END

2. 执行波形

3.结果

 12346876453_哔哩哔哩_bilibili

 

四、参考文献

STM32存储器映射和寄存器映射 - KenSporger - 博客园 (cnblogs.com)

 STM32入门-GPIO初始化步骤_爱学习的大喵喵的博客-CSDN博客

 STM32F103寄存器方式点亮LED流水灯_平行叶子的博客-CSDN博客

标签:STM32F103,LED,r1,r2,ldr,BASE,GPIOA,寄存器,GPIO
来源: https://blog.csdn.net/m0_61816657/article/details/120923945

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有