一、LED闪烁

  • 操作STM32的GPIO步骤:
    1. 使用RCC开启GPIO的时钟
    2. 使用GPIO_Init函数初始化GPIO
    3. 使用输入或者输出函数控制GPIO口
  • 在RCC的头文件最下方,我们可以找到关于RCC所有声明的函数,其中最常用的三个RCC AHB外设时钟控制,RCC APB1外设时钟控制,RCC APB2外设时钟控制
    1
    2
    3
    void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
    void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
    void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
  • GPIO的库函数:
  1. GPIO_DeInit
    1
    void GPIO_DeInit(GPIO_TypeDef* GPIOx); //参数可写入GPIOA、GPIOB等等,用于复位指定GPIO
  2. GPIO_AFIODeInit
    1
    void GPIO_AFIODeInit(void); //用于复位AFIO
  3. GPIO_Init
    1
    2
      void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
    //用结构体参数来初始化GPIO口,需要先定义并赋值结构体,通过读取结构体的值来初始化GPIO口
  4. GPIO_StructInit
    1
    2
      void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
    //可以把结构体变量赋一个默认值
  • 源码编写:
    1. 首先是采用APB2外设时钟控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @brief Enables or disables the High Speed APB (APB2) peripheral clock.
* @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
* This parameter can be any combination of the following values:
* @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
* RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
* RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
* RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
* RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
* RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
* RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11
* @param NewState: new state of the specified peripheral clock.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
第一个参数是选择GPIO口,由于本次实验选择的是A0,所以第一个参数为RCC_APB2Periph_GPIOA,第 
 二个参数代表是否开启,直接输入ENABLE
  1. 初始化GPIO
1
2
3
4
5
6
7
8
9
   /**
* @brief Initializes the GPIOx peripheral according to the specified
* parameters in the GPIO_InitStruct.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
* contains the configuration information for the specified GPIO peripheral.
* @retval None
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
  第一个参数代表所需要初始化的GPIO口,同APB2选择GPIOA,第二个参数需要定义并对结构体赋值, 
  所以需要先创建结构体GPIO_InitTypeDef GPIO_InitStructure,同时分别引出结构体的成员,分别
  为GPIO_InitStructure.GPIO_Mode;GPIO_InitStructure.GPIO_Pin;
  GPIO_InitStructure.GPIO_Speed,下面便详细说明三个成员赋值所代表的含义
1
2
3
4
5
6
7
8
9
10
typedef enum
{ GPIO_Mode_AIN = 0x0,//Analog IN 模拟输入
GPIO_Mode_IN_FLOATING = 0x04,//浮空输入
GPIO_Mode_IPD = 0x28,//In Pull Down 下拉输入
GPIO_Mode_IPU = 0x48,//In Pull Down 上拉输入
GPIO_Mode_Out_OD = 0x14,//Out Open Drain 开漏输出
GPIO_Mode_Out_PP = 0x10,//Out Push Pull 推免输出
GPIO_Mode_AF_OD = 0x1C,//Alt Open Drain 复用开漏
GPIO_Mode_AF_PP = 0x18//Alt Push Pull 复用推挽
}GPIOMode_TypeDef;
 首先是GPIO_InitStructure.GPIO_Mode,因为此次点灯我们选择推挽输出所以赋值为
 GPIO_Mode_Out_PP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
 第二项配置GPIO_InitStructure.GPIO_Pin,因为我们选择的是A0口,所以赋值为GPIO_Pin_0
1
2
3
4
5
6
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
 第三项配置GPIO_InitStructure.GPIO_Speed,这一项代表输出速度,50MHz即可

接着将结构体的地址放入初始化函数的第二个参数,源码如下:

1
2
3
4
5
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
  1. GPIO的输出函数
1
2
3
4
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_SetBits函数可以把指定的端口设定高电平(参数为指定对应端口)
 GPIO_ResetBits函数可以把指定端口设定为低电平
 GPIO_WriteBit根据第三个参数的值来指定端口
 GPIO_Write可以同时对对应GPIO的十六个口进行写入操作

首先我们先看GPIO_SetBits函数的使用,函数说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @brief Clears the selected data port bits.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bits to be written.
* This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));

GPIOx->BRR = GPIO_Pin;
}
 第一个参数用来选择对应的GPIO,第二个参数选择GPIO对应的口,将对应的IO口置高电平

GPIO_ResetBits函数的说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @brief Clears the selected data port bits.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bits to be written.
* This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));

GPIOx->BRR = GPIO_Pin;
}
 参数选择同GPIO_SetBits函数一样,只是将对应IO口低电平

GPIO_WriteBit函数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* @brief Sets or clears the selected data port bit.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to be written.
* This parameter can be one of GPIO_Pin_x where x can be (0..15).
* @param BitVal: specifies the value to be written to the selected bit.
* This parameter can be one of the BitAction enum values:
* @arg Bit_RESET: to clear the port pin
* @arg Bit_SET: to set the port pin
* @retval None
*/
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_BIT_ACTION(BitVal));

if (BitVal != Bit_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BRR = GPIO_Pin;
}
}
 前个两参数同上,第三个参数可以进行赋值,如果赋值Bit_RESET默认低电平,赋值Bit_SET默认高电
 平
  • 为了是实现LED的闪烁,需要编写延时(Delay)函数,这里直接将源码给出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "stm32f10x.h"

/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}

/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}

/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}

这样我们就可以实现LED的闪烁,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

while(1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(500);
}
}

二、LED流水灯

  • 在编写流水灯的时候要采用GPIO_Write函数,它可以直接对对应GPIO口进行配置,例如本次首先需要让A0口所连接的LED点亮,则需要使A0口配置低电平,其他口配置高电平所以对应的十六位应该是1111 1111 1111 1110,就相当于0000 0000 0000 0001进行取反操作,想让A1口的LED点亮就需要配置为0000 0000 0000 0010取反,同时在每个LED点亮的中间进行延时配置,就可以写出如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);



while(1)
{
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_ms(500);
}
}

三、蜂鸣器

  • 再有了上述两个程序的基础,蜂鸣器的配置其实就非常简单了,将对应的GND,3.3V高电平正确连接以后,我们本次采用B12口控制蜂鸣器,初始化对应的GPIOB,并且将12号口进行初始化,可以写出如下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 #include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);



while(1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //0000 0000 0000 0001
Delay_ms(100);
GPIO_SetBits(GPIOB, GPIO_Pin_12); //0000 0000 0000 0010
Delay_ms(100);
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //0000 0000 0000 0001
Delay_ms(100);
GPIO_SetBits(GPIOB, GPIO_Pin_12); //0000 0000 0000 0010
Delay_ms(700);

}
}