1.GPIO输入

三个步骤

1.使用RCC开启GPIO的时钟

2.GPIO_Init函数初始化GPIO

3.使用输出或输入的函数控制GPIO口

一般在.h文件的最下面有所有的库函数声明

RCC的大部分函数并不常用,常用的有以三个

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);

brief:Enables or disables the AHB peripheral clock.

即使能或失能AHB外设时钟

第一个参数选择哪个外设,第二个选择ENABLE或DISABLE

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

这两个函数同理,在arg中可以查找外设列表。

GPIO的库函数:

void GPIO_DeInit(GPIO_TypeDef* GPIOx);

@brief  Deinitializes the GPIOx peripheral registers to their default reset values.

调用这个函数,所指定的GPIO外设就会被复位。

void GPIO_AFIODeInit(void);

@brief  Deinitializes the Alternate Functions (remap, event control and EXTI configuration) registers to their default reset values.

复位AFIO外设

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

@brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.

非常重要的函数,作用是用结构体的参数来初始化GPIO口,先定义结构体变量,再给结构体赋值,最后调用这个函数,这个函数内部就会读取结构体的值,然后自动把外设的各个参数都配置好。

void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);

@brief  Fills each GPIO_InitStruct member with its default value.

这个函数可以把结构体变量赋予一个默认值。

GPIO_InitTypeDef GPIO_InitStructure;

这里结构体的命名有要求,一般按照这种格式来命名。

然后用“ . ”运算符将结构体的成员引出来。

最后是

GPIO_Init(GPIOA, &GPIO_InitStructure);

结构体变量名前加上取地址的符号,这里使用的是地址传递。

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

GPIO的读取函数

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

GPIO的写入函数

这些函数实现读写GPIO口的功能。

使用的流程:

先调用RCC开启时钟,接着初始化GPIO。

这里介绍一下GPIO_Mode的几种输入输出的参数:

  GPIO_Mode_AIN 模拟输入
  GPIO_Mode_IN_FLOATING 浮空输入
  GPIO_Mode_IPD 下拉输入
  GPIO_Mode_IPU 上拉输入
  GPIO_Mode_Out_OD 开漏输出
  GPIO_Mode_Out_PP 推挽输出
  GPIO_Mode_AF_OD 复用开漏
  GPIO_Mode_AF_PP 复用推挽

根据自己的需要选择Pin口。

使用“ | ”,可以初始化多个端口,这里用到了“按位或”。

输出速度一般选择50MHz,

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

将指定端口设置成高电平

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

将指定端口设置成低电平

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

BitAction是一个枚举,Bit_RESET是清除端口值,也就是置低电平

Bit_SET是设置端口值,也就是置高电平

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

推挽模式下,高低电平都有驱动能力,及LED接法无所谓。

开漏模式下,低电平有驱动能力,高电平相当于高阻态。

注意:PA15、PB3、PB4是调试端口,如果用作普通端口,需要额外配置。

最后再讲几种使用库函数的方法:

1.打开.h文件的最后,看一下有哪些函数,右键转到定义,查看函数的参数和用法

2.库函数用户手册

3.参考别人的程序

2.GPIO输出

对于驱动代码,我们一般将其封装起来,单独放在另外的.c和.h文件里,这就是模块化编程的方式

.c文件第一行要有一个头文件

#include "stm32f10x.h"                  // Device header

.h文件要添加一个防止头文件重复包含的代码

#ifndef __LED_H
#define __LED_H

意为如果没有定义LED这个字符串,那么就定义这个字符串

#endif

这个是和ifndef组成的括号,函数和变量声明就放在这个括号里面,最后这个文件要用空行结尾。

在.c文件里面要首先写一个LED初始化函数

void LED_Init(void)

{

}

里面写打开时钟,配置端口这些东西。可以参考上面GPIO输入的东西。

快捷键ctrl+alt+空格可以显示代码提示。

这里以按键控制LED的程序为例。

#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;

//选中1号或2号口
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

//这段代码多打,然后就可以直接上手了
    
    GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}

这个函数需要外部应用,要把第一行放在.h文件里,后面记得加“ ; ”。

void LED_Init(void);

这样就是对模块外部声明,这个函数是可以被外部调用的函数。

在main.c内同样要写上

#include "LED.h"