#STM32 1.从C51驱动一颗LED到认识ARM_GPIO(最浅显入门)

系列文章目录-认识ARM开发

/ARM开发初学目录:/

第3章:#STM32 3.根据官方库新建ARM工程

第2章:#STM32 2.寄存器位操作方法及GPIO点亮一颗LED

第1章:#STM32 1.从C51驱动一颗LED到认识ARM_GPIO(最浅显入门)

Lip:从中颖8位迁移到Cortex M3东软IC了,也逐步从51转到STM32的学习


一.场景

上手一个ARM工程,结合“寄存器思想”,初步了解GPIO设定,“51”与“ARM”牵线搭桥

二.理论与实际结合

1. 代码比较(驱动LED输出为例)

//. 8位单片机

P1_7 = 1;	//main()函数用户设置输出高电平
sbit P1_7 = P1^7;	//SH79F6481.h文件
sfr P1    = 0x90;		//SH79F6481.h文件

以上,sfr寄存器赋值操作,取P1内存地址操作,等效于赋值于变量,便于操作。

//. 32位ARM

GPIO_InitTypeDef  GPIO_Init;
RCC->APB2ENR  |=  ( (1) << 3 );
GPIO_GPIO_Init.GPIO_Pin = GPIO_Pin_0;
GPIO_GPIO_Init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_GPIO_Init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_GPIO_Init);	
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_ResetBits( GPIOB,GPIO_Pin_0 );

咋一看相当懵逼,从51到ARM脱节的地方就在于找不到对应的I/O引脚,寄存器的地址也不好找。在不破坏程序既有定义的前提下,不能直接写1/0操作

2.引导篇

Tip:常用的几种工程开发模式:汇编语言寄存器操作、c语言寄存器操作、标准库开发、HAL库开发。从51转到ARM最凸出的变化就是库开发,及寄存器思想

2.1 指针地址访问内存地址

对地址强制类型转换为指针变量(unsigned int*),在对指针*解引用操作,赋值

// GPIOB_ODR 端口全部设为逻辑1,ODR:1高 0低
*(unsigned int*) (0x40010c0c) = 0xFFFF;

为什么是GPIOB输出高?
以下为官方STM32F1xxx datasheet

在这里插入图片描述
ODR寄存器1高0低

2.1+1 定义寄存器别名访问内存地址

提高代码可读性,重写如下:

// GPIOB_ODR 端口全部设为逻辑1,ODR:1高 0低
#define	GPIOB_ODR		(unsigned int *)(GPIOB_BASE + 0x0c)
*GPIOB_ODR = 0xFF;

再进一步,指针操作*标准化,修改为:

// GPIOB_ODR 端口全部设为逻辑1,ODR:1高 0低
#define	GPIOB_ODR		*(unsigned int *)(GPIOB_BASE + 0x0c)
GPIOB_ODR = 0xFF;
2.1+2 封装总线及外设地址
a.寄存器映射概念

片上外设合计3条总线:APB1/APB2/AHB
在这里插入图片描述
//

总线名称相对外设的地址偏移总线基地址
APB100x4000 0000
APB20x0001 00000x4001 0000
AHB0x0001 80000x4001 8000

//

外设名称相对APB2地址偏移外设基地址
GPIOB0x0000 0C000x4001 0C00

所以,现在明白了上面实例操作的是:APB2总线上的GPIOB外设的ODR寄存器

b.宏定义总线及外设地址
// 外设基地址
#define	PERIPHERAL_BASE		(unsigned int)(0x4000 0000)
//总线基地址
#define APB1PERIPHERAL_BASE		PERIPHERAL_BASE
#define	APB2PERIPHERAL_BASE		(PERIPHERAL_BASE + 0x0001 0000)
#define AHBPERIPHERAL_BASE		(PERIPHERAL_BASE + 0x0002 0000)

//GPIO外设地址
#define	GPIOB_BASE				(APB2PERIPHERAL_BASE + 0x0C00)

//寄存器地址GPIOB_
#define	GPIOB_ODR				(GPIOB_BASE + 0x000C)
#define	GPIOB_BSRR				(GPIOB_BASE + 0x0010)

以上,已经用指针将立即数强制转换为了外设地址,对具体寄存器可以直接读写操作,如:

// GPIOB_BSRR的BR0置1(PB0引脚输出0)
*(unsigned int *)GPIOB_BSSR = 1 << (16 + 0);

// GPIOB_BSRR的BS0置1(PB0引脚输出1)
*(unsigned int *)GPIOB_BSSR  = 1 << 0;

在这里插入图片描述

2.1+3 指针访问寄存器

运用C语言结构体定义寄存器。因结构体内变量是连续的内存地址,外设的寄存器也是连续地址,一个寄存器占4个字节地址,与每个寄存器地址相符。此时仅需申明结构体的首地址则每个寄存器地址也会被定义。

typedef unsigned 		int uint32_t;
typedef unsigned short	int uint16_t;

//结构体定义寄存器列表
typedef struct{
	uint32_t CRL;	//GPIO端口配置低寄存器 地址偏移:0x00
	uint32_t CRH;	//GPIO端口配置高寄存器 地址偏移:0x04
	uint32_t IDR;	//GPIO数据输入寄存器 地址偏移:0x08
	uint32_t ODR;	//GPIO数据输出寄存器 地址偏移:0x0C
	uint32_t BSRR;	//GPIO位设置/清楚寄存器 地址偏移0x10
	uint32_t BRR;	//GPIO端口位清楚寄存器 地址偏移:0x14
	uint32_t LCKR;	//GPIO端口配置锁定寄存器 地址偏移:0x18
}GPIO_InitTypeDef  

//定义一个结构体指针变量GPIOx,并将GPIOB基地址给予首地址

GPIO_InitTypeDef  *GPIOx;
GPIOx = GPIOB_BASE;
GPIOx -> ODR = 0xFFFF;
2.1+4 指针访问寄存器plus版

宏定义文件下将基地址强制转化为指针变量
仅需修改基地址GPIOx即可

//使用结构体GPIO_InitTypeDef将地址强制转化为指针
#define GPIOB		(GPIO_InitTypeDef *) GPIOB_BASE

直接访问寄存器:

GPIO -> BSRR = 0xFFFF;
GPIO -> ODR = 0xFFFF;

总结

  1. Cortex M3内核与51最明显的区别是对寄存器的操作方式,转化为代码形式则是结构体与指针的结合使用。通过对指针地址*操作,进行内存单元的赋值等处理。
  2. 附简易的指针表达:
int i = 10;		// 声明并定义变量i
int *p = &i;	// int型指针指向i对应的内存地址,*操作符无运算意义,仅指针表达,&取地址
				//规范使用int *p而不是int* p,否则以下会有误解:int* p1,p2;//int型指针变量p1,int型变量p2
*p = 20;		// *表明解引用,改变对应内存地址内的数值
printf("%d\n",i);	// 此时i的数值已经是20
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值