写本文的缘由
似乎有一句诗提到类似的情景,忽然有所收获了,就很想与大家一起分享这种收获,让这种豁然开朗的幸福感传递给更多的人。我也是这样的缘由,放假两天,学习了STM32的开发,自我感觉有所得了,希望能够将这种“知之”的快乐感分享给其他想要入门这个方面的朋友。
标题为何专门提及菜鸟与两天?
有些人觉得无所谓,反正就是一个标题,但也有些朋友会认为这是我的一种自我炫耀,说两天就能学会,多牛,为了避免此类误解(虽不重要,但心里总是觉得这个一个BUG),所以专门澄清说明修复下此BUG:通过两天这个标题直接给阅读的朋友两个信息:
1. 内容涉及的深度不深;
2. 时间可控;
学习STM32的目的
我对嵌入式开发不熟悉、不了解,但内心渴望制作小东西,所以可能会涉及模型构建(3D打印),电路制作,单片机嵌入式开发。前一段时间用Arduino板子较多一些,主要原因是便宜与易上手,但最近写了一个通过WiFi控制职能小车的程序,发现板子在一段时间后,总是有一些异常,我怀疑是内存出了问题,所以就想着学习下STM32的板子,毕竟这个感觉更强大,这个就是我的初衷。也就是说,我学习STM32不是为了找工作,仅仅就是为了自己制作一些小玩具做储备。
材料准备
这里我分为了两个部分材料,一个是我实际使用的材料,另一个是本文档有效的最小材料列表。
材料列表:
1. STM32F103VE核心板(最小必须)
2. STM32F103VE核心板调试器,野火调试器[随便一个调试器就可](最小必须)
3. Nucleo-L4R5ZI板卡
4. Nucleo-F302R8板卡
5. USB线缆若干,几个板子接口不完全一样
板卡图片:
使用软件列表:
1. Keil5,官方网站下载(必须)
2. ST-Link驱动,在ST官网下载(必须)
3. Keil5相关于这几个处理器的Pack,Keil官网下载(必须)
开发方式选择
在目前关于STM32开发有了几种不同的选择(其他IDE不算不同选择):
1. 传统的Keil ARM开发模式
2. 通过STM的HAL以及CubeMx配置的模式
3. 通过MbedOS网站提供的方式
这三种方式,我都进行了简单的尝试,最方便简单的其实应该是第3种方式,因为网站提供了在线的IDE,我们编写代码后直接编译生成一个bin文件,将此文件拷贝到板卡磁盘(安装驱动后,自动产生一个盘符,类似U盘),板卡自动加载该bin文件执行。这种方式最大的缺点在于只是支持部分板卡(虽然已经很多板卡),比如我手上的Nucleo-L4R5ZI这个板卡就不支持。鉴于此,未来可能拿到的一个板卡也是不支持的,怎么办?所以放弃了这种方式。
CubeMx这个词也是这两天里边知道的,大致的一个概念就是通过一个图形化的界面,对板卡初始代码模块进行配置,相当于生成了一个应用模板,这个在简单试用了以后,没有发现特别的地方。这种方式也还不错,但配置中模块有些少,例如GPIO模块我便没有找到,所以为了使用更多的模块,放弃了这一种方式。
在这三种方式中,最复杂的是第一种方式,也是我选择静下心来好好弄清楚的方式。选择这种方式,除了前两种方式的不足,还有另外一个原因,那就是Keil for ARM用的人较多,产品更加成熟,书写代码更接地气。
在后续章节中,我主要描述了我是如何来思考学习这个开发工具的。
要学习什么方面?
STM32是一个比较复杂的处理器芯片(这么说不准确),而且嵌入式开发也是一个很大范畴的概念,为了能够将时间利用更加充分,所以首先应该去搞清楚一个问题,自己希望了解这些领域的那些知识技能?
对于我来说,未来希望使用STM32板卡做一些东西,而这些东西相对来说应该要稍微复杂一些(相对于Arudino板卡上的程序),可能会使用操作系统的概念,所以我对自己的要求有两点:
1. 通过最简单的GPIO来学习此工具链环境的使用规则、流程;
2. 学习如何使用操作系统来完成一件事情,例如LED灯开关;
GPIO点灯
因为不知道该如何描述可以让大家更清晰的了解细节,所以我打算忠实的按操作步骤进行描述、记录,中间会穿插我对此过程的理解。
新建项目
选项目录
选择芯片
选择包
添加源码文件
添加文件及Main函数
在Source Group1下新建一个.c源码文件,main.c,在此文件中添加一个空的main主函数,编译项目,确保项目编译正确。
编译按钮图:
添加GPIO控制
在main.c文件中添加GPIO控制。先看下最终的代码结果:
#include "stm32f10x.h"
#include "GPIO_STM32F10x.h"
int main() {
GPIO_PortClock(GPIOE, true);
GPIO_PinConfigure(GPIOE, 5, GPIO_OUT_PUSH_PULL, GPIO_MODE_OUT2MHZ); GPIO_PinWrite(GPIOE, 5, 0);
while(1) {}
return 0;
}
其中关于GPIO控制的几条语句已经加粗显示。三条语句分别为时钟激活、引脚配置、引脚输出。在本文中,重点不是讲解这几个函数每个函数的具体含义或者函数参数的具体含义,本文重点在于说清楚,对于一个菜鸟的我来说,应该如何去找需要调用的函数?也许有一天接口名称变了,也许有一天函数参数变了,但本文重点说明的内容应该很久都会有用的。
我在生成的项目代码中,代码结构如下图:
很明显,在Device模块下,有几个源码文件,应该对应与我选择的包。其中一个GPIO_STM32F10x.c源码文件一看就知道是与GPIO相关的。在此文件包含的头文件中,找到了一个与此相对紧密地头文件,GPIO_STM32F10x.h。
在找到的GPIO_STM32F10x.h文件中,罗列了与GPIO相关的API接口,以及相关结构定义,例如:
被选中的函数,有函数说明,有参数定义,大多数情况下,根据函数名称就能大致判别出此函数的用途。
所以,GPIO操作相关的几个函数便是我在阅读了此头文件以后,确定下来的相关操作函数。
在此过程中,最终重要的是学会了在一个包模块中如何去寻找模块包的操作API接口函数。
修改配置
在使用野火的调试器时,需要在项目选项中进行设置。
1. 设置选项选择;
2. 调试器选择;
3. 调试器参数设置
下载程序
在点击下载按钮后,如果提示下载成功,那么对应开发板的引脚就可以进行对应的输出。
操作系统GPIO点灯
新建项目
选项目录
此处参见“GPIO点灯”章节下对应的子章节内容。
选择芯片
此处参见“GPIO点灯”章节下对应的子章节内容。
选择包
此处参见“GPIO点灯”章节下对应的子章节内容。
添加源码文件
添加文件及Main函数
此处参见“GPIO点灯”章节下对应的子章节内容。
添加GPIO控制
在main.c文件中添加GPIO控制。先看下最终的代码结果:
#include "stm32f10x.h"
#include "cmsis_os2.h"
#include "GPIO_STM32F10x.h"
int val = 0;
void TaggleTimer(void *argument) {
val = !val;
GPIO_PinWrite(GPIOE, 5, val);
}
int main() {
GPIO_PortClock(GPIOE, true);
GPIO_PinConfigure(GPIOE, 5, GPIO_OUT_PUSH_PULL, GPIO_MODE_OUT10MHZ);
osTimerId_t timer_id = osTimerNew(TaggleTimer, osTimerPeriodic, (void*)0, NULL); osTimerStart(timer_id, 500);
osKernelStart();
while (1) { }
return 0;
}
相比前一个实例来说,这个实例代码更加复杂了一些,在GPIO控制之外添加了定时器设置的函数调用。
相对来说,本实例是前一个实例总结方法的另一个验证过程,通过这个验证过程,可以确认包提供的API都是可以通过头文件被找到,虽然有一些稍微复杂了一些,另一个基本可以确认的是,操作系统并不直接提供外设驱动操作API,更多关注在任务、定时器等等相关方面,所以,未来应该很可能是通过操作系统来管理各种任务,然后在各种任务中调用外设的相关API接口来进行设备交互操作。
修改配置
此处参见“GPIO点灯”章节下对应的子章节内容。
下载程序
此处参见“GPIO点灯”章节下对应的子章节内容。
总结
芯片的变化速度很快,即使以后不变化,目前芯片种类已经太多了,即使ARM芯片自身就有太多不同型号了,为了避免这些不同型号之间代码移植的难度,ARM提供了CMSIS库,封装了芯片的不同,尽量通过一致的接口来完成预期的功能。
始于此,Keil支持了不同的Pack,用来提供不同的操作接口,在代码层面来看,不同的模块对应了不同的源码,可以通过查询代码直接看到一个模块提供的具体操作接口。
在此次学习过程中,我有一个感悟,只要了解了如何去使用(了解、理解、使用)一个包提供的接口,那么就学会了如何来进行STM32开发了,其余剩下的无非就是查询下板卡资料,看看芯片的具体引脚连接而已。
当然,本文也只是一个入门的过程,后边我的计划是继续了解学习两个方面内容:1,针对其他库操作进行具体的实践,了解接口、部件的具体内容;2,了解如何在应用中添加一个库,最好添加到Pack中,这样每次建立项目都可以直接选择使用。
写完之后的遗憾,在动笔之初,想要把所有的心得都分享出来,但动笔之后(动键盘之后),才发现很难将自己的心得思路完整呈现给其他人,抱歉,下次我再好好积累经验。