嵌入式系统实验-GPIO实验
Published in:2023-12-03 | category: 嵌入式系统

硬件图如下

硬件图

实际上他们在端口命名的时候进行了分组

如上所示,P和点号之间的我认为他就是代表一个组,用某个寄存器控制,所以有0,1,2组

1 GPIO编程用到的寄存器介绍

1.1 PxSEL寄存器

基本介绍

端口功能选择,用来设置端口为通用I/O还是外设I/O功能

关于这两个功能区别如下

通用I/O功能,可以输出高低电平,在本实验中我们只需要给LED灯高低电平即可,因而设置为通用的

外设I/O功能 一般的外部设备,例如摄像头或者打印机他们具体实现某些功能(拍照或打印文档),单片机要控制这些外部设备,一般的来说单片机的I/O口与这些外设的引脚相连,通过I/O引脚实现对外部设备的控制,让它们完成我们要求的功能

使用方法

PxSEL中的x代表几号端口组

比如上面的按键1KEY1对应的是P0.1 所以就应该控制P0SEL寄存器

那么每一位上面含义呢,对于位位0代表是通用I/O,1代表外设I/O

例如:将P1_0、P1_1、P1_3和P1_4设置成通用I/O,即相应的bit置0

1
P1SEL &=~0x1B; //0001 1011

注意这里有取反操作,

设0用取反与,设1用或

1.2 PxDIR寄存器

基本介绍

端口方向选择,是输入还是输出

注意这里的输入还是输出都是站在单片机角度的

比如:对于LED灯是单片机输出信号到灯,所以对应端口设置为输出,按键是外部给单片机输入,所以设置为输入

使用方法

PxDIR中的x代表几号端口组

将P1_0、P1_1、P1_3和P1_4设置成输出口,即相应的bit置1

1
P1DIR |=0x1B; //0001 1101

设置了传输方向为输出后,比如输出给LED灯,然后我们通过在端口设置高电平直接就可以控制灯的亮暗了

例如:

1
P1_0=1; P1_1=0;

1.3 PxINP寄存器

基本介绍

当端口设置为输入模式的时候,即上面的PxDIR对应位设置为0的时候,可以进一步设置输入

具体有三种,上拉和下拉和三态

上拉是指单片机的引脚通过一个电阻连接到电源(高电平),当外界没有信号输入到引脚时,引脚被上拉电阻固定在高电平(逻辑值1)。相当于初始给引脚一个高电平

下拉是指单片机的引脚通过一个电阻连接到地(低电平),当外界没有信号输入到引脚时,引脚被下拉电阻固定在低电平(逻辑值0)。相当于初始给引脚一个低电平

三态也称高阻,即I/O引脚既没有上拉到电源,也没有下拉到地,呈现高阻值状态。三态模式一般用于引脚的输出功能,特别当单片机的引脚接在多个设备公用的通信总线上时。当单片机不发送信号时,采用三态工作模式可以保证不干扰其他设备之间的通信。三态模式用于输入引脚时,引脚必须外接其他器件,此时不存在上拉或下拉电阻,还能降低单片机的功耗。

使用方法

P0INP,P1INP寄存器每一位含义如下

image-20240104114100233

P2INP寄存器每一位含义如下

image-20240104114159092

可以在输入端口读取电平值

比如

1
if(P1_2 == 0) //判断按键被按下

2 按键消抖

2.1 软件消抖

最简单的消抖原理,就是当检测到按键状态变化后,先等待一个10ms左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了。

1
2
3
4
5
6
7
8
9
if(SW1 == 0) //判断按键被按下
{
DelayMS (10); //为消抖进行延时
if(SW1 == 0 ) //经过延时后按键仍处在按下状态
{
...
while(!SW1); //等待按键松开
}
}

3 经典任务代码解析

三个LED灯跑马灯效果,采用软件消抖

注意InitKey的初始化函数

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/****************************************************************************
* 文 件 名: main.c
* 描 述: 按下按键KEY1控制LED1.LED2.LED3实现跑马灯效果
****************************************************************************/
#include <ioCC2530.h>

typedef unsigned char uchar;
typedef unsigned int uint;


#define LED1 P1_0 //定义P1.0口为LED1控制端
#define LED2 P1_1 //定义P1.1口为LED2控制端
#define LED3 P1_4 //定义P1.4口为LED3控制端

#define KEY1 P0_1 // P0.1口控制按键KEY1
#define KEY2 P2_0 // P2.0口控制按键KEY2
#define KEY3 P0_7 // P0.7口控制按键KEY3

#define ON 1
#define OFF 0


/****************************************************************************
* 名 称: DelayMS()
* 功 能: 以毫秒为单位延时,系统时钟不配置时默认为16M(用示波器测量相当精确)
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint msec)
{
uint i,j;
static int DelayCallCount=0;

for (i=0; i<msec; i++)
for (j=0; j<535; j++);
DelayCallCount++;
}

/****************************************************************************
* 名 称: LedOnOrOff()
* 功 能: 点亮或熄灭所有LED灯
* 入口参数: mode为0时LED灯亮 mode为1时LED灯灭
* 出口参数: 无
****************************************************************************/
void LedOnOrOff(uchar mode)
{
LED1 = mode;
LED2 = mode;
LED3 = mode;
}

/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{

P1DIR |= 0x01; //P1.0定义为输出口
P1DIR |= 0x02; //P1.1定义为输出口
P1DIR |= 0x10; //P1.4定义为输出口
asm("NOP");

LedOnOrOff(0); // 使所有LED灯默认为熄灭状态
}

/****************************************************************************
* 名 称: InitKey()
* 功 能: 设置按键相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitKey(void)
{

P0SEL &= ~0x02; //设置P0.1为普通IO口
P0DIR &= ~0x02; //按键接在P0.1口上,设P0.1为输入模式
P0INP &= ~0x02; //打开P0.1上拉电阻

P2SEL &= ~0x01; //设置P2.0为普通IO口
P2DIR &= ~0x01; //按键接在P2.0口上,设P2.0为输入模式
P2INP &= ~0x01; //打开P2.0上拉电阻

P0SEL &= ~0x80; //设置P0.7为普通IO口
P0DIR &= ~0x80; //按键接在P0.7口上,设P0.7为输入模式
P0INP &= ~0x80; //打开P0.7上拉电阻

}

/****************************************************************************
* 名 称: KeyScan()
* 功 能: 读取按键状态
* 入口参数: 无
* 出口参数: 0为抬起 1为按键按下
****************************************************************************/
uchar KeyScan_1(void) //检测按键key1
{
if (KEY1 == 0)
{
DelayMS(10); //延时10MS去抖
if (KEY1 == 0)
{
while(!KEY1); //松手检测
return 1; //有按键按下
}
}

return 0; //无按键按下
}

uchar KeyScan_2(void) //检测按键key2
{
if (KEY2 == 0)
{
DelayMS(10); //延时10MS去抖
if (KEY2 == 0)
{
while(!KEY2); //松手检测
return 1; //有按键按下
}
}

return 0; //无按键按下
}


uchar KeyScan_3(void) //检测按键key3
{
if (KEY3 == 0)
{
DelayMS(10); //延时10MS去抖
if (KEY3 == 0)
{
while(!KEY3); //松手检测
return 1; //有按键按下
}
}

return 0; //无按键按下
}

/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{
InitLed(); //设置LED灯相应的IO口
InitKey(); //设置按键KEY1相应的IO口
int flow_1=1; //初始设置
int flow_2=0;
int flow_3=0;
while(1)
{
DelayMS(2);
if(KeyScan_1())
{
flow_1=!flow_1;
if(flow_1==1) //判断如果此时flow1按下,则把其余按键置零,防止干扰
flow_2=0;
flow_3=0;
}
if(KeyScan_2())
{
flow_2=!flow_2;
if(flow_2==1) //判断如果此时flow2按下,则把其余按键置零,防止干扰
flow_1=0;
flow_3=0;
}
if(KeyScan_3())
{
flow_3=!flow_3; //判断如果此时flow2按下,则把其余按键置零,防止干扰
if(flow_3==1)
flow_1=0;
flow_2=0;
}
//扫描按键当前状态,按下抬起一次改变LED显示效果,在跑马灯效果从左到右,从右到左,与LED2灯闪烁效果间切换
if (flow_1) //依次点亮 LED1 LED2 LED3 实现跑马灯效果
{ LED1 = ON; //点亮LED1
DelayMS(500);
LED1 = OFF; //熄灭LED1
LED2 = ON;
DelayMS(500);
LED2 = OFF;
LED3 = ON;
DelayMS(500);
LED3 = OFF;
}
if (flow_2) //依次点亮 LED3 LED2 LED1 实现跑马灯效果
{ LED3 = ON; //点亮LED1
DelayMS(500);
LED3 = OFF; //熄灭LED1
LED2 = ON;
DelayMS(500);
LED2 = OFF;
LED1 = ON;
DelayMS(500);
LED1 = OFF;
}
if (flow_3) //依次点亮 LED2 实现亮灯是灭灯时长的2倍效果
{ LED2 = ON; //点亮LED1
DelayMS(1000);
LED2 = OFF; //熄灭LED1
DelayMS(500);
}

}
}
Prev:
数据库系统(三)SQL语句全解析
Next:
数据库系统(二)关系代数