1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html#
第五章 APM32基础知识入门
本章着重介绍APM32的一些基础知识,令读者对APM32有一个初步的了解,为后面的章节学习做铺垫。对于本章的内容,读者可以先只看一个大概,在后面需要使用到这部分知识点的时候,再回过头来仔细看。
本章分为如下几个小节:
5.1 C语言基础知识复习
5.2 寄存器基础知识
5.3 APM32F407系统架构
5.1 C语言基础知识复习
本节介绍C语言的基础知识,对C语言比较熟练的读者,可以跳过本节,对于基础比较薄弱的读者,建议好好学习一下本节的内容。
由于C语言博大精深,不可能由一小节的内容就全讲明白,所以本节知识回顾在进行APM32开发时常用的几个C语言知识点,以便读者的更好的学习本书后续的内容,并编写相关的代码。
5.1.1 位操作
C语言的位操作就是对基本类型变量进行位级别的操作。本节的内容比较简单,这里也就点到为止,不深入探讨。下面先讲解几种位操作运算符,然后介绍其相关的使用技巧。C语言支持如下6种位操作的运算符:
下面介绍这些位操作运算符的使用技巧。
①:在不改变其他位的状况下,对某几个位进行设值
这个场景在单片机开发中经常使用,方法就是先对需要设置的位用&运算符进行清零操作,然后用|运算符设值。例如要设置GPIOA的ODATA寄存器Bit6(第6位)为1,则可以先使用&运算符对该寄存器的Bit6进行清零操作:
GPIOA->ODATA &= 0xFFFFFFBF; /* 将Bit6清0 /
然后再使用|运算符对该寄存器的Bit6进行置1操作:
GPIOA->ODATA |= 0x00000040; / 将Bit6置1 /
②:移位操作提高代码的可读性
例如①中|操作使用到的0x00000040,虽然通过换算,可以知道是将Bit6置1,但是这样的表达可读性比较差,可以通过移位操作对其进行改进:
GPIOA->ODATA |= (1 << 6); / 将Bit6置1 /
这么一来,就可以非常直观地看出是将Bit6置1了。
③:按位取反操作使用技巧
②中使用移位操作改进①中仅使用|运算将Bit6置1的可读性,但要改进①中使用&运算将Bit6清0的可读性还需借助按位取反操作:
GPIOA->ODATA &= ~(1 << 6); / 将Bit6清0 /
这么一来,就可以非常直观地看出是将Bit6清0了。
④:按位异或操作使用技巧
按位异或可以很方便地对Bit位进行翻转,例如不考虑LED当前是何种状态,只要求控制LED翻转状态等情况(假设LED的亮灭状态由PA6输出的高低电平控制):
GPIOA->ODATA ^= (1 << 6); / Bit6的值取反 */
这么一来,就可以很方便地操作PA6引脚输出相反的电平,而不用先读取PA6输出的电平状态然后才输出相反的电平。
5.1.2 define宏定义
define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便,其常见的格式如下:
#define 标识符 字符串
“标识符”为所定义宏的名称;“字符串”可以是常数、表达式、格式串等。例如:
#define HSE_VALUE 8000000U
定义标识符HSE_VALUE的值为8000000U,数字后的U是unsigned(无符号)的意思,随后便可在程序代码中使用HSE_VALUE来代替8000000U。
至于define宏定义的一些其他高级用法,例如宏定义带参数等,本章不过多介绍。
5.1.3 ifdef条件编译
在单片机程序开发过程中,经常会遇到需要在满足某些条件时对一段代码进行编译,而当条件不满足或满足另一条件时编译另一段代码,这就可以使用条件编译,条件编译最常见的形式如下:
#ifdef 标识符
代码段1
#else
代码段2
#endif
如上的条件编译,当标识符被定义过(一般使用define进行定义),则代码段1会被编译,否则会编译代码段2。
5.1.4 extern外部申明
C语言中extern关键字用于修饰变量或函数,以表示变量或函数定义在别的文件中,提示编译器遇到此变量或函数时,需在其他文件中寻找其定义。这里要注意的是,可以使用extern多次在不同文件中修饰同一个变量或函数,但该变量或函数只能被定义一次
5.1.5 typedef类型别名
typedef用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。例如在编写程序时经常使用到的uint8_t、uint16_t和uint32_t等都是由typedef定义的类型别名,其定义如下:
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
这么一来就可以在编写程序代码的时候使用uint8_t等代替unsigned char等,极大地提高的代码的可读性可编写代码的效率。
5.1.6 struct结构体
struct用于定义结构体,结构体就是一堆变量的集合,结构体中的成员变量的作用一般都是相互关联的,定义结构体的形式如下:
struct 结构体名
{
成员变量1的定义;
成员变量2的定义;
......
};
例如:
struct lcd_device_struct
{
uint16_t width;
uint16_t height;
};
如上举例的结构体定义,一堆描述LCD屏幕的变量的集合,其中包含了LCD屏幕的宽度和高度。
结构体变量的定义如下:
struct lcd_device_struct lcd_device;
如上,就定义了一个名为lcd_device的结构体变量,那么怎么访问这个结构体变量中的成员变量呢?如下:
lcd_device.width = 240;
printf(“LCD Height: %d\n”, lcd_device.height);
如上就展示了结构体变量中成员变量的访问操作。
5.1.7 指针
指针是另一个变量的变量,指针变量在内存中保存的是另一个变量在内存中的地址,通过指针可以访问到另一个变量所在内存地址中的数据。
举一个定义指针的例子,如下:
char p_str = “This is a string!”;
如上,就定义一个名为p_str的指针变量,并将p_str指针指向了字符串“This is a string!”保存在内存中首地址,对于APM32来说,此时p_str的值就是一个32位的数,这个数就是一个内存地址,这个内存地址就是上述字符串保存在内存中的首地址。
通过p_str指针就可以访问到字符串“This is a string!”,那具体是如何访问的呢?前面说p_str保存的是一个内存地址,那么就可以通过这个内存地址去内存中读取数据,通过p_str就可以访问地址为p_str的内存数据,(p_str + 1)可以访问下一个内存地址中的数据。
知道了如何访问内存中的数据,但是读取到的数据要如何解析呢?这就有p_str指针的类型决定了。在这个例子中p_str是一个char类型的指针,那么访问p_str就是访问地址为p_str,大小为sizeof(char)(一般为一个字节)的一段内存数据,在这个例子中就可以读取到字符“T”, 读取*(p_str + 1)就是“h”,以此类推。
指针是C语言的精髓,但也是初学者望而生畏的一个知识点,若读者一时半会无法理解指针的用法也没关系,善用搜索引擎,网上有很多参考的学习资料。
5.2 寄存器基础知识
寄存器(Register)是一种特殊的内存,它主要用于实现控制和访问MCU的内核和各个片上外设。
对于APM32来说,寄存器一般都是32位的,但由于MCU上的内存资源十分宝贵,因此在一个32位寄存器中,会使用其中的1位或多位来控制或访问MCU的内核或各个片上外设的一种功能,但即使如此,APM32上也还是有上百个寄存器,这实际上是因为APM32有很多的片上外设导致的,只要将这些寄存器按照功能分好类,学起来就不难了。
从大方向来区分,APM32中的寄存器可分为两大类,分别为内核寄存器和外设寄存器,大类下还可以分出许多小类,如下表所示:
表5.2.1 APM32寄存器分类
对于初学者来说仅需在学习MCU的各个片上外设时,再去学习该片上外设相关的寄存器即可。
5.3 APM32F407系统架构
APM32F407是Geehy公司基于ARM授权Cortex-M4内核设计的一款芯片,而Cortex-M内核采用了ARM v7-M架构,具有低成本、低功耗、实时性好、中断响应快、处理效率高等特点。
5.3.1 Cortex-M4内核&芯片
ARM公司提供内核(例如Cortex-M4内核)授权,完成的MCU芯片还需要很多其他的组件。芯片公司(例如Geehy)在获取Cortex-M4内核授权后,就可以将其用于自己的芯片设计中,并添加存储器、外设、I/O等其他组件。同于型号的芯片也会有不同的规格,实际当大多数就是存储器容量、外设资源等的差异。
5.3.2 APM32F407系统框图
APM32F407的系统框图,如下图所示:
图5.3.2.1 APM32F407系统框图
从上图可以看出,APM32F407就是在ARM提供的Cortex-M4内核上通过各种总线,挂载了各种各样的外设和存储器。
5.3.3 地址映射
APM32是32位的MCU,因此其地址总线的宽度也是32位,因此最大可访问的内存空间为4GB(2^32=4GB),APM32就将这4GB的空间映射给各种寄存器和存储器。
APM32F407地址映射图,如下图所示:
图5.3.3.1 APM32F407地址映射图