每节课都是一个项目 手把手用STM32打造联网气象站-3-STM32基础三件套-掌握GPIO初始化

STM32基础系列包含了三件套,掌握了这三件套,类似于掌握了程咬金三板斧,就可以开始干项目,创造价值了。毕竟,真正的编程是一项实战性很强的技术,掌握编程主要靠实战,而不是靠知识灌输。

STM32的编程三件套就是:

  1. GPIO初始化;
  2. TIM定时器(含中断);
  3. USART串口;
  4. 为何把这三个功能列成编程基础三件套呢?先说GPIO,熟练掌握GPIO之后,就完全可以利用GPIO组成I2C, 1WIRE, SPI等各种复杂总线波形。虽然没有硬件接口效率高,但是胜在不挑端口,不调平台,方便移植。

第二个是TIM定时器,这个很多人不容易理解,毕竟很多教程中,都仅仅用TIM定时器,作为PWM控制LED灯的亮度。但是想象一下,真正项目需求中,哪怕是LED点灯,一般描述也不是"LED闪两下",而是:“LED熄灭0.9S”,然后“LED点亮0.1S”,并且重复3次。也就是:需要非常精准的定时需求。

三件套之三是串口:串口是重要的调试端口,虽然可以采用单步方式查看程序走向,但是用串口方式调试代码,能够更加了解代码运行的整体流程,以及数据交互情况。而且后面有些系统,比如ESP32类的系统,并不支持采用单步查看,这样我们就只能采用串口进行调试了。串口另外一个重要的功能,就是通信功能。我们日常使用的WIFI模块,蓝牙模块,4G模块,NBIOT模块,LORA模块,都是采用串口和MCU进行通信的。因此,弄清楚串口数据首发,也是编程基础三件套之一。

下面先了解一下GPIO初始化步骤

1. GPIO初始化步骤

总体来说,GPIO初始化分为3步。

第一步:定义一个GPIO_InitTypeDef类型的结构体变量;

第二步: 调用RCC_APB2PeriphClockCmd()这个函数,实现时钟初始化;

第三步:选择需要控制的GPIO引脚,将pin, GPIO_Mode, GPIO_Speed这些参数初始化;并将其写入对应的LED_GPIO_PORT中。

理解了上面3个步骤后,我们就需要了解一个问题:

作为一个程序员,编程的时候,需要自己手工输入这些代码吗?还是复制粘贴就行了? 

实际上,网上很多文章都说:要想学会编程,一定要多敲代码。但是像上面的这些代码,其实只是一些简单的配置工作,完全没有必要手动输入。正常情况下,是找到本教程,把其中的GPIO初始化部分,移植到新工程里面即可。

所以,学编程,不要学习敲代码,而要学习移植代码,通过移植,掌握代码块之间的耦合情况。这样就能够快速完成很多功能。

2. 跟着ST学编程

掌握了GPIO初始化三部曲,只是前菜,我们真正需要学习的,是ST官方初始化GPIO的这个方法。学会这个方法,后续反复应用到编程中,才能够不断进步,提升技能。

2.1 定义结构体类型

 首先定义一个结构体类型

typedef struct{

}GPIO_InitTypeDef;

再把对应的3个参数放到结构体类型中。

2.2 使用结构体类型定义参数

接下来,就是用结构体类型,定义一个变量,并且给变量参数赋值,再把变量作为参数写到函数中。

GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.pin=... ; GPIO_InitStructure.GPIO_Speed=...; GPIO_InitStructure.GPIO_Mode=...;通过这种方式,实现变量的赋值和参数的传递。

后面,在需要实际项目中,可以采用类似的方式进行初始化配置:

typedef struct{} my_Struct_Type;

my_Struct_Type my_Struct;

my_Struct.a=...;

my_Struct.b=...;

上面这些伪代码,是我们学习编程时候,真正需要学习的部分,也是我们真正需要手敲代码的地方。

2.3在keil中获取结构体成员变量的快捷方式

在keil中编辑的时候,我们可以用点.来调出成员变量的快捷方式,这样进行初始化更加方便。

2.4在keil中获取函数参数选项的快捷方式

另外,在有些函数的参数我们记不住的时候,可以采用@ref进行调用

比如如果我们记不住USART_WordLength参数具体是多少,我们可以输入@ref USART_Word_Length,全部可选参数就会列出来。

由于keil的这个卓越功能,可以方便我们在调用库函数时,少输入很多内容,因此,建议如果做STM32开发的话,还是采用KEIL这个编译器。

3.降低代码的耦合性

前面反复提到:学编程不是敲代码,而是整理好代码模块,摸清楚代码之间的耦合性。这里就以GPIO初始化为例,讲解一下,究竟什么是代码的耦合性,如何降低代码的耦合性?

3.1 使用宏定义来降低代码耦合性

宏定义的一个重要作用,就是降低代码的耦合性。下面看下具体例子:

在这个LED_GPIO初始化的代码中,用了3处宏定义。后面如果我们如果在其他项目中,用其他的GPIO做LED点灯或者需要初始化其他的GPIO,就可以只修改宏定义中的内容,而无需修改代码本身

我们只要找到这里的宏定义,修改这里的宏定义即可,而不需要死记硬背GPIO初始化的步骤。

 类似的例子还有很多。所以降低代码耦合度的基本步骤之一,就是通过宏定义,实现软编码,减少硬编码。后续可以通过修改宏定义,方便实现功能移植。

 3.2 规范使用头文件

规范,有条理的使用头文件,能够使得代码更加整齐,而且代码的耦合性更低。头文件一般包含下面内容:

1. 最上面一般是宏定义;

2.接下来是结构体类型定义或者枚举类型定义

3.然后是外部使用的全局变量

4.最后是外部使用的函数。

这样,通过宏定义,就可以清楚的确定,哪些代码是.c文件内部使用的,那些代码是暴露给外部使用的。当我们移植代码的时候,根据头文件,按图索骥,即可完成。因此,头文件相当于C文件的地图,便于我们进行查看和梳理 ;

5.避免头文件重复包含

另外值得一提的一个点,就是通过宏定义,避免头文件重复包含。

代码一开始,检查第一句:

#ifndef __LED_H

当第一次包含这个头文件时,发现并没有定义__LED_H,因此会执行第二句

#define __LED_H

当下次其他.c文件再次试图包含此头文件时,会发现__LED_H这个宏已经被定义了,这时就会直接跳转到结尾。

#endif

 这样就不会重复包含头文件中的内容。

led点灯代码。代码简单,主要用来验证开发环境。开发环境采用vscode+keil,详见博文-嵌入式文档类资源-CSDN下载

纸上得来终觉浅,绝知此事要躬行!

接下来会一步一步带你完成家庭气象站的开发工作,敬请收藏关注,以免下次找不到了。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值