STM32笔记10--C语言复习,寄存器地址名称映射

STM32笔记10--C语言复习,寄存器地址名称映射,第1张

STM32笔记10--C语言复习,寄存器地址名称映射

10.1、C语言复习

  

10.2、STM32中寄存器地址名称映射的分析

参考资料 :库函数开发指南中 4.1 和 4.6 小节

10.1、C语言基础知识复习

10.1.1、位 *** 作:6种位 *** 作运算符

PS:需要注意的是,写入寄存器的步骤一般分为三步,分别是:把寄存器的值读出来,接着修改寄存器的值,最后将修改好的数值放回寄存器。位与运算、位或运算、异或运算、取反运算、不再赘述。重点说一下移位运算;

1010 左移一位就会变成 0100(最右边补零)

1010 右移一位就会变成 0101(最左边补零)

位运算在STM32的编程中,有着广泛地运用。

10.1.2、define宏定义关键词

define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。

常见格式为:#define 标识符 字符串 

“标识符”是所定义的宏名,“字符串”可以是常数、表达式、格式串等等

#define sysclk_freq_72MHz 72000000

上述宏定义的意思为:定义标识符 sysclk_freq_72MHz 的值为72000000

10.1.3、ifdef条件编译

单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,当条件不满足时则编译另一组语句。条件编译最常见的形式为:

#ifdef 标识符

程序段1

#else

程序段2

#endif

上述程序中的#ifdef用于判断标识符在前面是否被  #define宏定义过,如果已经被宏定义过,则执行程序段1,如果没有被宏定义,则编译程序段2。

10.1.4、extern变量申明

C语言中,extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找定义。

extern申明变量可以多次,但定义只有一次。

        

 上述中 u8 id 被定义在main.c文件中,在test.c文件中被引用,使用extern提示编译器在main.c中寻找 u8 id 的定义。

10.1.5、typedef类型别名

定义一种类型的别名,而不只是简单的宏替换。可以用作同时申明指针型的多个对象。

typedef unsigned char unit8_t;//将unsigned char定义为别名unit8_t 

typedef unsigned short int unit16_t; 

typedef unsigned int unit32_t;

typedef unsigned _int64 unit64_t;

10.1.6、结构体:构造类型

Sttruct 结构体名{

成员列表1;

成员变量2;

...

}变量名列表;

结构体就是将一堆变量组织到一起,在结构体申明的时候可以定义变量,也可以申明之后定义。方法是:Struct 结构体名字   结构体变量列表;

在C语言中,结构体的优势在于:可以将一堆无序的变量放在一起

PS:结构体作用

同一个类型可以用数组,不同的类型可以用结构体组织到一起,另外结构体的扩展性强。在编写程序时,如果临时要添加参数,不用结构体的情况下,需要修改申明和函数的定义,非常麻烦。

10.1.7、C语言关键字:static

Static申明的局部变量,存储在静态存储区。

它在函数被调用结束之后,不会被释放。它的值会一直被保留下来。

所以说Static申明的局部变量,具有记忆功能。

除了申明变量,static也可以定义函数,static定义的函数是在文件内部引用,不会引用到文件外部。

 

10.2、MDK中寄存器地址名称映射分析

对于MCU,一切底层配置,最终都是配置寄存器,换句话说,在STM32中,一切 *** 作最终都是在 *** 作寄存器,无论是调用库函数还是位 *** 作,最终都是对单片机中各种寄存器的配置。

10.2.1、STM32中的 *** 作:

GPIOA->ODR=0x00000000    //在前面关于寄存器版本点亮LED灯的实验中,用到了这个 *** 作

那么,值0x00000000是怎么赋值给GPIOA的ODR寄存器地址的呢?

也就是说GPIOA->ODR这种写法,是怎么与GPIOA的ODR寄存器地址映射起来的呢?

如何理解寄存器映射的地址?

以GPIOA为例,首先,GPIOA对应有一个基地址,基地址再加上偏移量,就构成了GPIOA的映射地址,于是GPIOA所对应的ODR寄存器就是以GPIOA的基地址为开头,加上偏移。

那么基地址是怎么来的呢?由于GPIOA挂载在APB2总线上,APB2有自己的基地址,GPIOA对于APB2基地址有一个自身的偏移,那么基地址加上偏移就是GPIOA的映射地址。定义如下:

#define PERIPH_base //这是STM32的外设基地址
#define APB2PERIPH_base //这是APB2总线的基地址,其对于外设基地址有一个偏移
#define GPIOA_base //这是GPIOA在APB2总线上的基地址
#define GPIOA //这是加上了GPIOA自身的偏移,一层层从上往下,找到了GPIOA的映射地址

至于每个IO口具体的偏移,可以在参考手册中查到,如下所示:(8.5小节)

如下图,在顶层头文件中,

 

 通过特殊标识符指向GPIOA的地址,而 TypeDef 是一个结构体。而GPIOA基地址之后的偏移,就放在这个结构体里,如下:

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;

 

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/zaji/5698568.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-17
下一篇2022-12-17

发表评论

登录后才能评论

评论列表(0条)

    保存