GPIO实验

GPIO实验


一 灯光闪烁实验

小灯正极插在电路 负极接引脚PA0处(处于低电平是小灯点亮 处于高电平时小灯熄灭)

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
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//小灯正极插在电路 负极接引脚0处(处于低电平是小灯点亮 处于高电平时小灯熄灭)
int main(void) {
//开启时钟
//初始化GPIO引脚(采用推挽输出模式 初始化0引脚 输出速度为50MHz)
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);

//ResetBits为低电平 SetBits为高电平
GPIO_SetBits(GPIOA, GPIO_Pin_0); //高电平小灯熄灭 初始化小灯为熄灭状态
//GPIO_ResetBits(GPIOA, GPIO_Pin_0); //低电平小灯点亮
//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); 低电平小灯点亮
//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 高电平小灯熄灭


//实现小灯闪烁 需放在死循环里 因为插电后嵌入式需要一直工作
while (1) {
GPIO_ResetBits(GPIOA, GPIO_Pin_0); //小灯点亮500ms
Delay_Ms(500);
GPIO_SetBits(GPIOA, GPIO_Pin_0); //小灯熄灭500ms
Delay_Ms(500);
}
}

步骤:

1.首先需要开启时钟

1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启APB2的GPIOA的时钟

2.初始化GPIO引脚

1
2
3
4
5
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽模式 高低电平强驱动
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //定义PA0引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);

3.设置引脚的高低电平,一共有三个函数 :

GPIO_SetBits(引脚分组,引脚)为高电平

GPIO_ ResetBits(引脚分组,引脚)为低电平

1
2
3
4
5
//ResetBits为低电平 SetBits为高电平
GPIO_SetBits(GPIOA, GPIO_Pin_0); //高电平小灯熄灭 初始化小灯为熄灭状态
//GPIO_ResetBits(GPIOA, GPIO_Pin_0); //低电平小灯点亮
//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); 低电平小灯点亮
//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 高电平小灯熄灭

GPIO_WriteBit(引脚分组,引脚,高低电平)其中Bit_RESET为低电平,Bit_SET为高电平

4.要想让小灯一直工作需要放在死循环里 while (1)中

1
2
3
4
5
6
while (1) {
GPIO_ResetBits(GPIOA, GPIO_Pin_0); //小灯点亮500ms
Delay_Ms(500); //延时作用
GPIO_SetBits(GPIOA, GPIO_Pin_0); //小灯熄灭500ms
Delay_Ms(500); //延时作用
}

二 流水灯实验

流水灯GPIOA(0~7引脚) 负极插在引脚

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
42
43
44
45
46
47
48
49
50
51
52
53
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//流水灯GPIOA(0~7引脚)
int main(void) {
//开启时钟GPIOA
//初始化GPIO引脚(采用推挽输出模式 初始化所有引脚 输出速度为50MHz)
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);

//采用三种方法遍历0~7引脚

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

// 方法二:使用for循环遍历8个引脚
for (uint16_t i = 0; i < 8; i++) {
GPIO_Write(GPIOA, ~(0x0001 << i)); // 左移i位,然后取反
Delay_Ms(500);
}

// 方法三:定义引脚值数组
uint16_t pins[] = {0x0001, 0x0002, 0x0004, 0x0008,
0x0010, 0x0020, 0x0040, 0x0080
};

// 遍历数组
for (int i = 0; i < 8; i++) {
GPIO_Write(GPIOA, ~pins[i]);
Delay_Ms(500);
}
}
}

1.首先需要开启时钟

1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启APB2的GPIOA的时钟

2.初始化GPIO引脚

1
2
3
4
5
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; //输出速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);

3.采用三种方法遍历0~7引脚

第一种常规方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        //调用GPIO_Write, 向GPIO_Pin_1输出数据寄存器写1, 其余引脚全部写0
// GPIO_Write(GPIOA,~0x0001); //0000 0000 0000 0001 从右到左分别是PA0 PA1 PA2.........
// 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);

GPIO_Write(引脚,16进制数)函数 ,前面代表写哪个引脚后面表示指定了要写入端口输出数据寄存器的值。

第二种采用for循环方法

1
2
3
4
for (uint16_t i = 0; i < 8; i++) {
GPIO_Write(GPIOA, (0x0001 << i)); // 左移i位,然后取反
Delay_Ms(500);
}

第三种采用数组for循环方法

1
2
3
4
5
6
7
8
9
uint16_t pins[] = {0x0001, 0x0002, 0x0004, 0x0008,
0x0010, 0x0020, 0x0040, 0x0080
};

// 遍历数组
for (int i = 0; i < 8; i++) {
GPIO_Write(GPIOA, pins[i]);
Delay_Ms(500);
}

三 蜂鸣器鸣响实验

实现蜂鸣器急促滴滴响,使用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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//实现蜂鸣器急促滴滴响
int main(void) {
//开启时钟
//初始化GPIO引脚(采用推挽输出模式 初始化GPIOB 12引脚 输出速度为50MHz)
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);


// 延时时间初始设定为500ms,后面会慢慢减少
uint16_t DelayTime = 500;
// 每次缩短的时间间隔,设定为10ms
uint16_t Step = 10;
// 最小的延时时间,设定为10ms
uint16_t MinDelay = 10;

//实现蜂鸣器响
while (1) {
// GPIO_ResetBits(GPIOB, GPIO_Pin_12);
// Delay_Ms(500);
// GPIO_SetBits(GPIOB, GPIO_Pin_12);
// Delay_Ms(500);

// 如果已经达到最小延时时长,那么让蜂鸣器持续发声
if (DelayTime == MinDelay) {
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
continue;
}

// 在蜂鸣器工作与关闭之间插入延时,即可实现"滴..滴..滴"的效果
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay_Ms(DelayTime);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay_Ms(DelayTime);

// 减少延时时间,让滴滴声更急促
DelayTime -= Step;
}
}

1.首先需要开启时钟

1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启APB2的GPIOB的时钟

2.初始化GPIO引脚

1
2
3
4
5
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; //输出速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);

3.变量定义部分

1
2
3
uint16_t DelayTime = 500;  // 初始延时500ms,控制蜂鸣器响和停的间隔
uint16_t Step = 10; // 每次循环减少10ms,让声音越来越快
uint16_t MinDelay = 10; // 最小延时10ms,达到后蜂鸣器长鸣

4.判断是否达到最小时延

1
2
3
4
if (DelayTime == MinDelay) {
GPIO_ResetBits(GPIOB, GPIO_Pin_12); // 让蜂鸣器一直响
continue; // 跳过下面的代码,直接进入下一次循环
}
  • 当延时时间减少到10ms时,蜂鸣器持续发声(长鸣)
  • GPIO_ResetBits是让蜂鸣器开始工作

5.产生滴滴声音

1
2
3
4
GPIO_ResetBits(GPIOB, GPIO_Pin_12);  // 蜂鸣器响
Delay_Ms(DelayTime); // 持续 DelayTime 毫秒
GPIO_SetBits(GPIOB, GPIO_Pin_12); // 蜂鸣器停
Delay_Ms(DelayTime); // 停 DelayTime 毫秒
  • 先响一段时间,再停一段时间,形成"滴"的一声
  • 刚开始时 DelayTime=500,所以是响0.5秒,停0.5秒

6.加快节奏

1
DelayTime -= Step;  // 每次循环减少10ms
  • 每循环一次,延时减少10ms
  • 声音会越来越快:500ms → 490ms → 480ms ...
  • 直到达到10ms的最小值

四 按键控制小灯实验

本实验采用模块化编程,可清晰知道每个模块是什么功能

实现按钮与小灯的交互的小实验,材料为两个小灯、两个按钮 。

简述

  • 使用两个小灯,分别使用GPIOA的PA1与PA2的两个引脚
  • 使用两个按键,分别使用GPIOB的PB1与PB11的两个按钮
  • 按键PB1控制小灯PA1,按键PB11控制小灯PA2

1.首先我们来编写小灯的程序分别创建两个文件 ‘’ LED.h’‘ 与 ‘’LED.c ‘’文件

LED.h文件

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
#ifndef  __LED_H
#define __LED_H

//初始化LED
void LED_Init(void);

//点亮LED1

void LED1_ON(void);


//熄灭LED1

void LED1_OFF(void);



//点亮LED2

void LED2_ON(void);


//熄灭LED2

void LED2_OFF(void);
//反转灯的电平
void LED1_Turn(void);
void LED2_Turn(void);



#endif

LED.c 文件

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "stm32f10x.h"                  // Device header
//初始化小灯
void LED_Init(void) {
//开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//初始化两个小灯PA1与PA2
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
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);


}

//点亮LED1

void LED1_ON(void) {

GPIO_ResetBits(GPIOA, GPIO_Pin_1);

}

//熄灭LED1

void LED1_OFF(void) {

GPIO_SetBits(GPIOA, GPIO_Pin_1);

}


//点亮LED2

void LED2_ON(void) {

GPIO_ResetBits(GPIOA, GPIO_Pin_2);

}

//熄灭LED2

void LED2_OFF(void) {

GPIO_SetBits(GPIOA, GPIO_Pin_2);

}


void LED1_Turn(void) {
//读取当前端口输出的状态 如果为0那就置为1,否则就为0
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0) {

GPIO_SetBits(GPIOA, GPIO_Pin_1); //高电平
} else {

GPIO_ResetBits(GPIOA, GPIO_Pin_1); //低电平

}

}

void LED2_Turn(void) {
//读取当前端口输出的状态 如果为0那就置为1,否则就为0
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0) {

GPIO_SetBits(GPIOA, GPIO_Pin_2); //高电平
} else {

GPIO_ResetBits(GPIOA, GPIO_Pin_2); //低电平

}

}

2.再我们来编写按钮的程序分别创建两个文件 ‘’ Key.h’‘ 与 ‘’Key.c ‘’文件

Key.h 文件

1
2
3
4
5
6
7
8
9
#ifndef  __KEY_H
#define __KEY_H
#include <stdint.h>

void Key_Init(void);
uint8_t Key_GetNum(void);


#endif

Key.c 文件

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
42
43
44
45
46
47
48
49
50
51
52
53
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
void Key_Init(void) {

//为GPIOB开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//初始化两个按钮PB1与PB11
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //为GPIOB1与11设为上拉输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输入模式没用
GPIO_Init(GPIOB, &GPIO_InitStructure);

}


//获取按键的键码
uint8_t Key_GetNum(void) {

uint8_t KeyNum = 0;

//判断如果读取的值为0 表示按下 灯亮
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) {
//消除抖动需要加延时20ms
Delay_Ms(20);

//如果按键一直按下就会卡在while循环直到松手
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);

//消除松手的抖动需要加延时20ms
Delay_Ms(20);
KeyNum = 1;

}

return KeyNum;

if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) {
//消除抖动需要加延时20ms
Delay_Ms(20);

//如果按键一直按下就会卡在while循环直到松手
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);

//消除松手的抖动需要加延时20ms
Delay_Ms(20);
KeyNum = 2;

}

return KeyNum;

}

3.最后我们编写主程序main函数

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
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

uint8_t KeyNum;

int main(void) {
//初始化
LED_Init();
Key_Init();

while (1) {
//获取Key传来的值
KeyNum = Key_GetNum();

if (KeyNum == 1) {

LED1_Turn();

}

if (KeyNum == 2) {

LED2_Turn();

}

}
}

五 光敏电阻传感器控制蜂鸣器实验

本实验采用模块化编程,可清晰知道每个模块是什么功能

实现光敏电阻传感器与蜂鸣器的交互的小实验,材料为光敏电阻传感器、蜂鸣器

简述

  • 使用光敏电阻传感器接在GPIOB上的PB13引脚
  • 使用蜂鸣器接在GPIOB上的PB12引脚
  • 光线暗的时候蜂鸣器响 光线强的时候蜂鸣器不响

1.首先我们来编写光敏电阻传感器的程序分别创建两个文件 ‘’ LightSensor.h’‘ 与 ‘’ LightSensor.c ‘’文件

LightSensor.h 文件

1
2
3
4
5
6
7
8
9
10
11
#ifndef  __LIGHTSENSOR_H
#define __LIGHTSENSOR_H
#include <stdint.h>

void LightSensor_Init(void);

uint8_t LightSensor_Get(void);


#endif

LightSensor.c 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "stm32f10x.h"                  // Device header


void LightSensor_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t LightSensor_Get(void) {
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}

2.接下来我们来编写蜂鸣器的程序分别创建两个文件 ‘’ Buzzer.h’‘ 与 ‘’Buzzer.c ‘’文件

Buzzer.h 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef  __BUZZER_H
#define __BUZZER_H

//蜂鸣器初始化
void Buzzer_Init(void);
//蜂鸣器开
void Buzzer_ON(void);
//蜂鸣器关
void Buzzer_OFF(void);
//反转蜂鸣器电平
void Buzzer_Turn(void);

#endif

Buzzer.c 文件

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
42
43
#include "stm32f10x.h"                  // Device header


void Buzzer_Init(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(GPIOA, &GPIO_InitStructure);
//初始化蜂鸣器为关闭状态
GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

void Buzzer_ON(void) {

GPIO_ResetBits(GPIOB, GPIO_Pin_12);

}



void Buzzer_OFF(void) {

GPIO_SetBits(GPIOB, GPIO_Pin_12);

}


void Buzzer_Turn(void) {
//读取当前端口输出的状态 如果为0那就置为1,否则就为0
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0) {

GPIO_SetBits(GPIOB, GPIO_Pin_12); //高电平
} else {

GPIO_ResetBits(GPIOB, GPIO_Pin_12); //低电平

}

}

3.最后我们编写主程序main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"


int main(void) {
Buzzer_Init();
LightSensor_Init();


while (1) {
//光线比较暗的时候
if(LightSensor_Get() == 1){
//蜂鸣器响
Buzzer_ON();
}else{
//蜂鸣器关闭
Buzzer_OFF();

}
}
}