一、STM32中的GPIO外设
根据ST公司所提供的官方数据手册STM32F103系列的GPIO外设电路原理如下:
从上图中我们可以看到F103系列MCU的GPIO外设主要有两路组成一路是由IO口引入,再由一个施密特触发器(上图有错误)转换读取录入到我们MCU的输入数据寄存器中用于被单片机内核或者其他外设调用。还有一路是根据其他外设或者内核写入到单片机输出数据寄存器的值提供给输出控制单元来实现程序控制单片机的IO口输出我们想要的电信号的值。我们同时也可以通过程序来改变该外设的电阻的开关值以及输出控制单元的两个MOS管的工作方式来实现不同输出输入模式,这一点在一会儿的如何使用标准外设驱动库来配置GPIO的内容中会讲到。
二、在keil软件上使用标准外设驱动库来配置GPIO外设
想要使用我们的MCU的GPIO外设必须先要在keil中提前配置好相关的参数,我们在上次所创建的工程模板上来进行本次的学习。
为了方便我们日后工程的管理和移植,我们采用函数库的思想进行编程。至于该怎么样去建立自己的函数库去进行编程这边就不再专门赘述,有兴趣的话可以去搜索相关的课程进行学习。
首先,复制粘贴我们的工程样板,将新的工程样板改名为GPIO学习(个人习惯,不是必须要这么做)然后再在其中新建一个文件夹名为Hardwave。再在其中新建两个文件分别为:LED.c ,LED.h。打开keil新建Headwave分组。将两个文件添加至Headwave分组中。如何在将Headwave文件夹的地址添加到c的引用中去。(System分组为直接复制江科大的文档中的内容,具体添加方式与添加驱动库文件方式一致)
随后我们需要在LED.h文件中添加一下防止文件重定义的代码代码如下:
#ifndef __LED_H
#define __LED_H
#endif
该代码的意思是如果没有__LED_H库被定义那么就执行下面的定义__LED_H的指令,如果__LED_H已被定义那么便直接跳到#endif一行,这样可以有效的避免重复定义。
然后我们跳到LED.c文件中对配置GPIO的部分进行配置,因为我们是基于标准库对GPIO进行配置的,所以我们要先引用一下标准库输入:
#include "stm32f10x.h"
然后我们要设定一个跟GPIO相关的函数,因为我们这次是想用GPIO来控制LED灯的所以我们将函数名设定为LED_Init( )。即输入如下代码。
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
}
根据STM32F10X系列结构图:
我们发现我们所使用的GPIO外设都是挂载在APB2总线上的所以我们在对GPIO外设的参数进行配置之前要先开启我们的APB2总线的时钟才能让GPIO外设正常工作。所以我们首先需要使用RCC_APB2PeriphClockCmd函数来打开GPIO外设的时钟。
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开GPIOA外设的时钟。
}
然后便是配置GPIO有关的参数,标准库使用了结构体的形式来配置我们的各个外设,配置方法,首先我们要使用GPIO_InitTypeDef结构体声明语句来声明,这里我们把我们新的结构体取名为:GPIO_InitStructure。然后再用 "." 或者 "->"来引出GPIO外设的三个变量,来配置好这三个变量的参数。最后再将结构体赋值给我们的GPIOA外设的寄存器。
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO输出模式使用推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //使用GPIO_1引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO速度配置为50MHz
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
然后在再LED.h中定义一下LED_Init( )函数。这样我们的GPIO外设就配置好了。然后就是如何使用gpio控制引脚输出值了:我们要用到这个函数:GPIO_SetBits( ),这个函数是用于将对应的IO口置高电平,这个函数有两个参数其中第一个是表明你的是那组GPIO即GPIOA,GPIOB等等第二个参数则是标明是这些GPIO组中的那个引脚如GPIO_Pin_1,GPIO_Pin_0等等。还有这个函数:GPIO_ResetBits( ),这个函数是用于将对应的IO口置低电平,用法与GPIO_SetBits( )一样。
这样以后我们就可以在外面的主函数main()中去配置使用IO口输出高低电平了。