1、硬件准备
我使用的是市面上常见的黑色开发板,烧入器使用的是正点原子的无线烧入器,普通的烧入器也行,这个无所谓。开发板的原理图我放在下面链接里,我们需要知道相应的LED引脚。
2、预期功能
通过函数实现LED灯的闪烁,这里直接采用模块化编程,并且介绍如何完成模块化编程。
3、程序编写
3.1、Cubemx部分
先前的RCC设置与上一篇一致,可以直接将上一个项目直接复制,修改项目名称即可,这里我直接复制上次的项目,把名称修改为GPIO_UP,就不用重新配置RCC与时钟设置了。
但是里面的名称不能修改了,打开复制后的文件夹中的CUBEMX文件。这里不介绍GPIO是什么了,但是简单来说就是板子上面的引脚,可以将其设置不同的模式,例如输出模式,可以向外输出高低电平;输入模式,可以读取外界的电平情况。
首先我们查看,相关的原理图,找到LED灯连接的引脚,从原理图中可知LED连接的引脚为:LED1-PF9;LED2-PF10。
并且从电路图可以,LED灯的一端连接到高电平3V3,因此当引脚输出为高电平时LED灯才发光,接下来我们去CUBEMX中进行初始化配置。
第一步,打开CUBEMX后在红框Pinout View选项中找到相应的引脚PF9和PF10,点击它将其设置为输出模式GPIO_Output。
第二步,将页面调整到左侧的GPIO页面,就能显示刚才设置的两个输出模式的引脚,接下来介绍一下,初始化页面需要的设置。
初始电平:就是引脚没有上电时的引脚电平,通过原理图可知若初始化为高电平则LED不亮,若为低电平则LED亮,这里不想让LED灯上电就亮,因此设为高电平。
输出模式:推挽输出或开漏输出,这里设置为推挽输出。
上拉或者下拉:设置为上拉模式。
输出速度:不需要很高的速度,设置为LOW。
用户标签:这个还是比较好用的,因为设置了用户标签之后,会在生成的Keil文件的main.h中宏定义相关的引脚,这样对于代码的可提更性有着良好的帮助。这里将两个LED分别命名为LED1与LED2。
下面是用户标签设定后生成的宏定义:
接下来点击【Generate Code】生成初始化代码。
3.2、Keil文件编写
我们首先介绍一下HAL库中有关于GPIO的函数,我们可以在Keil软件中找到GPIO的相关函数,本次我们主要介绍黑色方框中的两个函数。
1.HAL_GPIO_WritePin:设置对应的引脚输出的电平。
`void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)`
2.HAL_GPIO_TogglePin:反转相应引脚的电平。
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
接下来我们编写led.c与led.h文件,实现模块化编程。
首先,在项目文件夹中新建一个存放自己编写函数的文件夹,我一般命名为Func。
其次,在Keil中点击新建按钮,新建两个空白文件。
然后,ctrl+s保存,保存在我们刚刚创建的Func文件夹中,保存时分别命名为【led.c】和【led.h】。
接着,我们先对led.h进行编写,大家可以直接复制下面的代码进去,当然这不是最终的头文件,首先我们要先引入main.h。
#ifndef __LED_H__
#define __LED_H__
#include "main.h"
#endif
其次我们编写led.c,我们首先要引入其自身的头文件【led.h】
然后,我们将这两个led的函数文件,与项目连接,连接之后好像才能使用代码联想功能。
完成上述步骤之后需要将,Func文件夹添加到项目路径中。
添加完成之后,在main.c中包含led.h头文件,如果不报错说明操作成功。
这样就完成了模块化编程,我们不用把函数全部塞到main.c中了。
接下来我们编写led.c文件。
这里我写了两个函数,分别控制LED1与LED2的亮,灭与闪烁。
led.c:
#include "led.h"
/* **************LED相关函数****************** */
// LED1
void LED1_Style(uint8_t i)
{
switch(i)
{
case 1:
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
break;
case 3:
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
break;
}
}
// LED2
void LED2_Style(uint8_t i)
{
switch(i)
{
case 1:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
break;
case 3:
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
break;
}
}
led.h:
#ifndef __LED_H__
#define __LED_H__
#include "main.h"
void LED1_Style(uint8_t i);
void LED2_Style(uint8_t i);
#endif
然后我们再在main.c中编写,在使用CUBEMX生成的文件中,我们只能在规定的地方编写,否则当重新生成文件时,位于其他区域的代码会被删除。
例如在main.c函数的开头会有这么一段区域
```c
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
用户开始定义类
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
用户开始宏定义
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
因此我们只能在USER CODE BEGIN和USER CODE END之间编写代码。
这次我们编写的主函数功能为:复位-LED1亮-500ms-LED1灭-500ms-LED2亮-500ms-LED2灭-1000ms-LED1与LED2共同以2000ms的周期闪烁。
main.c:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LED1_Style(1);
HAL_Delay(500);
LED1_Style(2);
HAL_Delay(500);
LED2_Style(1);
HAL_Delay(500);
LED2_Style(2);
HAL_Delay(1000);
while(1)
{
LED1_Style(3);
LED2_Style(3);
HAL_Delay(2000);
}
}
/* USER CODE END 3 */
简单的LED闪烁程序就编写好了,平时写程序时有喜欢用printf调试大法的,我还喜欢用LED调试大法,所以基本每个项目都会有这个文件。简单的程序但是背后的知识有很多,我也没全懂,有错误有问题一定要告诉我,谢谢。
最后附上程序源码,对了这个ZGT6与VET6通用的只要在KEIL里面改一下就能烧进板子里。
链接:https://pan.baidu.com/s/1Y6SWO4kXpsYy_COL0KyjLA
提取码:1234