假如只有板子和芯片的数据手册,没有开发指南,没有别人写好的代码,那如何开始点亮一盏LED灯?(为之后使用别的芯片做准备)
那就意味着要从头开始写代码。回顾一下之前的代码:

1.C语言规则(语法)的理解
第一部分:头文件
#include <stdint.h>
这是C语言标准库的头文件,也就是说不依赖于芯片平台,只要这个芯片能用C语言去写,这个头文件都能用。那将来移植芯片这行语句也能用。
第二部分:宏定义
这个地方就比较复杂一点。以第一句为例解读。
#define RCC_APB2ENR (*(volatile uint32_t *)0x40021018)
首先这个语句,从空格来分就有3部分,
#define,宏定义
RCC_APB2ENR,一个变量
(*(volatile uint32_t *)0x40021018) ,比较复杂,一大串东西
前面两部分都是比较好理解,见到#define,知道这是一个宏定义,意思是RCC_APB2ENR这个东西是被(*(volatile uint32_t *)0x40021018)一串替代,
那就细读(*(volatile uint32_t *)0x40021018)。按照我们以前学数学的运算习惯思路,先读里面那一层括号,再读外面那一层括号。
里面那一层,volatile uint32_t *,也是3个部分,逐个拆解,
volatile,搜了很多资料,只记得是直接读内存,也就是直接从地址取值,其他忘记了,
uint32_t,u for unsigned,无符号,int,整型,32,32位,_t,t for type,下划线是一种起名方式,所以,无符号32位整型类型的变量,到这里都还好,
*,然后就是这个*符号了,这个就涉及到C语言中常常说的指针,
稍微展开一点。指针,就是一种特殊的变量,储存的是地址,然后地址再储存值。一般的变量,a=10,输出a,就是输出10,但是如果a是指针,那就是a的值是一个地址,这个地址存储10这个值,如果我们想输出10,不能输出a,要“解引用”,要写*a。
打个比喻就是,别人送你礼物,有人直接给,有人放箱子里,比较有仪式感,安全,但是放箱子里就要一把小刀开箱,这个*就是这个小刀。
但这里涉及到定义和用法。仔细看(*(volatile uint32_t *)0x40021018)这个语句,出现了2个*,2把小刀,按照刚刚的阅读习惯,我们是先读到中间的、跟在uint32_t后面的*,第一次出现的,是定义。还是用刚刚的比喻,这个也是小刀,但这个小刀不是拿来用的,是拿来告诉你,送你的礼物放箱子里,这个小刀是假的,是图标。
所以,(volatile uint32_t *)0x40021018(仔细看,这里只有一把小刀,是假的那把),表示一个指向0x40021018的指针。反向来想,如果只有0x40021018,这就是一个普通的十六进制的数值,只有加了前面这个定义(有个*在),说是一把小刀,有了小刀,就需要有个箱子,这个0x40021018才会成为一个箱子(地址)。
然后再读外面一层,(*刚刚一大串)(刚刚一大串=(volatile uint32_t *)0x40021018),*是小刀,刚刚一大串是箱子,所以我们就得到了箱子里面的礼物了。意思就是对应地址下的值。
所以,#define RCC_APB2ENR (*(volatile uint32_t *)0x40021018)
RCC_APB2ENR直接就是0x40021018对应下的数值了。
2.语句内容、逻辑上的理解
刚刚是从C语言的语法规则上去理解这个宏定义语句,接下来是逻辑上理解,为什么要定义这三个变量,为什么要开这3个箱子,里面的礼物要怎么用。
接下来用回第一篇博客里面的“储物柜”比喻。这个箱子本身很特殊,是一个大箱子,是由32个小箱子组成的。这个礼物有点像乐高,是由基本零件组装在一起,不同的组法就会有不同的形状,就看自己想要什么。在嵌入式的乐高世界里面,基本零件只有两个,0和1。现在看看这两个零件在这32个小箱子里是怎么排列组合出我们想要的形状的。
回看这个三个变量叫什么名字,
RCC_APB2ENR
GPIOB_CRL
GPIOB_ODR
基本都很陌生,那就读一下开发指南、问一下AI,究竟这些变量是什么意思。
先看RCC,Reset and Clock Control,字面翻译,复位与时钟控制。从这里开始知道,时钟对于板子来说很重要,就像时间是人的唯一、真正的货币一样?没有时间,万物就不存在了(装一下)。没有时间,就没有信号了吧,至少信号传输很麻烦吧?我们的目的是什么,设置PB5输出低电平。那意思是要开启GPIOB外设。复习:所有外设要开启对应的时钟才能使用。这里的时钟跟电源的感觉好像。
终于要成长了,要去丛林冒险了,要去读数据手册了。手册在指南里推了两本,《STM32F10xxx参考手册_V10(中文版)》和《Cortex-M3权威指南(中文)》,看东西囫囵吞枣,也不知道到底在哪里,都看看。
语句里面有RCC,有0x40021018,结合之前的碎片知识和看过的别人写的代码,猜想其实就是手册里找到我们要设置的地址,和这个地址下值的设置规则。这个查找过程就是多翻翻,对着上下文理解,不会就问AI,起码STM32的学习资料比较丰富,AI也比较能答出来。
3.查找手册获取信息
以RCC为关键词,查看两本手册里对应的内容。但其实数据手册叫这个名字《STM32F103xCDE_DS_CH_V5》(因为是用STM32F103ZET6,所以看这个CDE,人家是正宗数据手册,在指南里也有提及)
《STM32F103xCDE_DS_CH_V5》的28页,有个图,整理了我们要用的外设,外设,peripherals,最大块的阴影面积,就是我们要用的那块了。
说实话这里思绪比较乱,实际上对这些不理解不熟悉的时候,反复在这些手册中横跳来看。先看图2,先找到RCC对应的内容,STM32F10xxx参考手册_V10(中文版)的目录:
好多寄存器,是哪一个?懂的人很快就看出来,不懂的时候真的觉得摸不着头脑,就作一下弊,会看这个变量名,RCC_APB2ENR,那应该是6.3.7,为啥是APB2呢,这时候再去看图3,还有下面的图5,
GPIOB在APB2上。谜底解开了,所以叫做RCC_APB2ENR,EN for enable,R for register。
OK,梳理我们目前获取到的关于RCC的信息。
根据图2,RCC的起始地址是0x4002 1000(中间有空格是方便阅读,写代码时去掉),
我们要找到RCC里APB2的使能寄存器,根据图6,偏移量是0x18,这里我们已经得到了这个能够使能GPIOB时钟的寄存器的地址是,0x4002 1000+0x18=0x4002 1018,
结合图7,这个寄存器位3是控制GPIOB的,1就是开启,所以我们要将该位置1.
接下来就是涉及到C语言的位运算语法与实际嵌入式开发的写操作了。
对于时钟而言,只操作1位(位3),而且是置1,所以直接位或(|=)运算,因为位或是只要有一个1,该位的值就是1.这里用位移运算更直观。
1<<3,这个语句意思是十进制的1,机器会解读为32位二进制的值,即0B0000 0000 0000 0000 0000 0000 0000 0001,然后左移3位,0B0000 0000 0000 0000 0000 0000 0000 1000,跟原先的寄存器的值做位或运算,那么只有位3会对上1,会被置1,其他位遇0,保持原值,这样就是开启了GPIOB的时钟了。

2284

被折叠的 条评论
为什么被折叠?



