G
N
I
D
A
O
L

STM32学习笔记(1)——LED和蜂鸣器

阅读前提示: 我们使用的板子是正点原子的ALIENTEK精英STM32F103。本文使用固件库进行编程,因为使用固件库编程较为方便,且阅读程序也较易理解。

零、GPIO简介及其库函数

1. GPIO简介

7组IO口(具体地址可见头文件stm32f10x.h): GPIOA ~ GPIOG。每组IO口可控制7个寄存器,这7个寄存器可控制一组GPIO的16个IO口:

  • GPIOx_CRL:端口配置低寄存器
  • GPIOx_CRH:端口配置高寄存器
  • GPIOx_IDR:端口输入寄存器
  • GPIOx_ODR:端口输出寄存器
  • GPIOx_BSRR:端口位设置/清除寄存器
  • GPIOx_BRR:端口位清除寄存器
  • GPIOx_LCKR:端口配置锁存寄存器

16个管脚(GPIO_Pin)(位于头文件stm32f10x_gpio.h): GPIO_Pin_0 ~ GPIO_Pin_15,若想全部选中则GPIO_Pin_All。

4种输入模式(GPIO_Mode)(位于头文件stm32f10x_gpio.h):

  • 浮空输入(GPIO_Mode_IN_FLOATING)
  • 上拉输入(GPIO_Mode_IPU)
  • 下拉输入(GPIO_Mode_IPD)
  • 模拟输入(GPIO_Mode_AIN)

4种输出模式(GPIO_Mode)(位于头文件stm32f10x_gpio.h):

  • 开漏输出( GPIO_Mode_Out_OD)
  • 复用开漏输出(GPIO_Mode_AF_OD)
  • 推挽输出(GPIO_Mode_Out_PP)
  • 复用推挽输出(GPIO_Mode_AF_PP)

3种最大输出速度(GPIO_Speed)(位于头文件stm32f10x_gpio.h):

  • GPIO_Speed_2MHz
  • GPIO_Speed_10MHz
  • GPIO_Speed_50MHz

简要介绍常用的输出模式:

推挽输出:
可以输出强高低电平,连接数字器件。

开漏输出:
只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)

GPIO结构体定义(位于头文件stm32f10x_gpio.h):

typedef struct
{
  uint16_t GPIO_Pin;             /* 设置初始化管脚 */

  GPIOSpeed_TypeDef GPIO_Speed;  /* 设置输入或输出速度 */

  GPIOMode_TypeDef GPIO_Mode;    /* 设置输入或输出模式 */
}GPIO_InitTypeDef;

2. 与GPIO有关的几个常用库函数

(1)初始化函数:

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

作用:初始化一个或者多个IO口(同一组)的工作方式和速度。该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的时候有设置BSRR或者BRR寄存器。

(2)读取输入电平函数

读取某个GPIO的输入电平(实际操作的是GPIOx_IDR寄存器):

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

读取某组GPIO的输入电平(实际操作的是GPIOx_IDR寄存器):

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

(3)读取输出电平函数

读取某个GPIO的输出电平(实际操作的是GPIOx_ODR寄存器):

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

读取某组GPIO的输出电平(实际操作的是GPIOx_ODR寄存器):

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

(4)设置输出电平函数

设置某个IO口输出为高电平(实际操作BSRR寄存器):

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

设置某个IO口输出为低电平(实际操作的BRR寄存器):

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);
/* 这两个函数不常用,也是用来设置IO口输出电平 */

(5)初始化GPIO口的一般步骤

我们以一段程序为例来说明初始化GPIO口的几个步骤。

/* 1.定义初始化GPIO结构体 */
GPIO_InitTypeDef GPIO_InitStructure;

/* 2.开启GPIO外设的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* 3.设置为推挽输出模式 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

/* 4.设置输出速度为50MHz*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* 5.选择管脚为5 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

/* 6.进行初始化操作 */
GPIO_Init(GPIOB, &GPIO_InitStructure);

一、LED跑马灯的实现

本程序实现了两个LED轮流点亮及熄灭的效果。

有关LED的电路图如下所示:

从电路图中可知,当输出IO口电平为低电平时,LED灯亮;当输出IO口电平为高电平时,LED灯灭。

从LED电路图可知,LED0接在PB5,LED1接在PE5。选择的输出模式:推挽输出。

程序如下(本程序包含3个源文件,其中delay.h为正点原子资料盘内自带的头文件,亦可使用51单片机常用的简易延时函数,即循环延时法):

/* =====main.c===== */
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"

int main(void)
{
	delay_init();
	LED_Init();
	
	while(1)
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_5);
		GPIO_SetBits(GPIOE, GPIO_Pin_5);
		delay_ms(500);
		
		GPIO_SetBits(GPIOB, GPIO_Pin_5);
		GPIO_ResetBits(GPIOE, GPIO_Pin_5);
		delay_ms(500);
	}
}


/* =====led.h===== */
//这样的宏定义是为了防止led.c内的函数被重复声明
#ifndef __LED_H
#define __LED_H

void LED_Init(void);

#endif


/* =====led.c===== */
#include "led.h"
#include "stm32f10x.h"

//当函数参数为空时,写上void是很不错的习惯
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/* 开启使能IO口时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
	//也可以写成:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOB, ENABLE);
	// “|”为或运算符
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB, GPIO_Pin_5);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	GPIO_SetBits(GPIOE, GPIO_Pin_5);
	
}

二、蜂鸣器循环响灭

有关蜂鸣器的电路图如下所示:

从电路图中可知,当输出IO口电平为低电平时,三极管处于截止状态,蜂鸣器不响;当输出IO口电平为高电平时,三极管处于放大状态,蜂鸣器响。BEEP接在PB8。

程序如下:

/* =====main.c===== */
#include "stm32f10x.h"
#include "delay.h"
#include "beep.h"

int main(void)
{	
	Beep_Init();
	delay_init();
	while(1)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_8);
		delay_ms(500);
		GPIO_ResetBits(GPIOB, GPIO_Pin_8);
		delay_ms(500);
	}
}


/* =====beep.h===== */
#ifndef __BEEP_H
#define __BEEP_H

void Beep_Init(void);

#endif


/* =====beep.c===== */
#include "stm32f10x.h"
#include "beep.h"

void Beep_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOB, GPIO_Pin_8);
}

三、蜂鸣器和LED灯循环

本程序实现了蜂鸣器与两个LED轮流工作的效果。前500ms,LED1和BEEP工作,后500ms,仅LED0工作。

为方便程序阅读,我们将设置高低电平的函数封装成宏。程序如下:

/* =====main.c===== */
#include "stm32f10x.h"
#include "delay.h"
#include "beep.h"
#include "led.h"

int main(void)
{	
	LED_Init();
	Beep_Init();
	delay_init();
	while(1)
	{
		BEEP_ON;
		LED0_OFF;
		LED1_ON;
		delay_ms(500);
		
		BEEP_OFF;
		LED0_ON;
		LED1_OFF;
		delay_ms(500);
	}
}


/* =====led.h===== */
#ifndef __LED_H
#define __LED_H

#define LED0_OFF GPIO_SetBits(GPIOB, GPIO_Pin_5)
#define LED0_ON GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define LED1_OFF GPIO_SetBits(GPIOE, GPIO_Pin_5)
#define LED1_ON GPIO_ResetBits(GPIOE, GPIO_Pin_5)

void LED_Init(void);

#endif


/* =====led.c===== */
#include "stm32f10x.h"
#include "led.h"

void LED_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	LED0_OFF;
	LED1_OFF;
}


/* =====beep.h===== */
#ifndef __BEEP_H
#define __BEEP_H

#define BEEP_ON GPIO_SetBits(GPIOB, GPIO_Pin_8)
#define BEEP_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_8)

void Beep_Init(void);

#endif



/* =====beep.c===== */
#include "stm32f10x.h"
#include "beep.h"

void Beep_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	BEEP_OFF;
}

posted @ 2021-04-10 09:57  漫舞八月(Mount256)  阅读(1308)  评论(0编辑  收藏  举报