3、RDA8910CSDK二次开发:GPIO输入详解

目录

点击这里查看所有博文

  本系列博客所诉资料均来自合宙官方,并不是本人原创(只有博客是自己写的),csdk只是得到了口头的允许公开授权。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

  本系列博客基于紫光展锐的RDA8910 LTE Cat 1 bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。

  先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(也有可能变砖,慎重!!!)。

  我使用的是Air724UG开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考!

一、前言

  本系列开发教程最近才开始准备,sdk中也有了很多内置的demo,但是这个配套的博客教程却更不上节奏。大家也不要急,我会尽量加快速度,最近事情也是挺多的。别指望我一天更新一篇,写这玩意太费时间了。大家也可以先攒一攒,先攒它一个月在讲,养肥了再看。在这里不得不佩服那些网络小说的作者能做到一天一章,一章好几千字在下实在佩服。
在这里插入图片描述
  人们为了能够从外面的世界获取有用的信息,不得不需要借助于像眼睛鼻子等感觉器官,而在探索自然的现象和研究自然的规律以及总结人们在生产时的活动时,仅仅依靠人们自身的感觉器官这些,它们的功能就根本不够使用了,为了能够适应这种特殊的情况,那么就必须要使用外部的传感器。
在这里插入图片描述在这里插入图片描述
  有很大一部分传感器输出的信号仅仅是一个开关量,对于开关量的信号的采集,我们这里需要用到一个功能,那就是GPIO的输入功能。紧接着上篇博客我门用到了GPIO0和GPIO1模拟了一下LED的以一定的周期闪烁。那么这篇博客我们就把GPIO0和GPIO1初始化为输入功能,模拟一下开关量的采集。
在这里插入图片描述

二、编写测试程序

  利用GPIO的输入功能获取开关信号有两种方法,一种是查询法,另外一种是中断法,我们依次讲解

2.1、中断法

  中断我对它的理解是,他的优先级高于普通函数,可以打断正在执行的低优先级中断,和普通任务。
  有打断的意思,只要正在执行的任务优先级比它低,当中断来临时就可以被打断,转而去执行中断函数。
  中断的原则是快进快出,不能在里面执行复杂的事情,否则会影响其他任务执行。相对普通任务实时性较高,适用于对事件敏感的情况
  具体使用方法如下,

2.1.1、初始化GPIO0为中断输入模式

1
2
3
4
5
6
7
8
9
10
11
T_AMOPENAT_GPIO_CFG input_cfg = {0};
BOOL err = 0;
input_cfg.mode = OPENAT_GPIO_INPUT_INT; //配置输入中断
input_cfg.param.defaultState = 0; //默认为低电平
input_cfg.param.intCfg.debounce = 50; //防抖50ms
input_cfg.param.intCfg.intType = OPENAT_GPIO_INT_BOTH_EDGE; //中断触发方式双边沿
input_cfg.param.intCfg.intCb = gpio_handle; //中断处理函数
err = iot_gpio_config(0, &input_cfg); //初始化gpio为中断输入模式
if (!err)
return;
iot_debug_print("[gpio] set gpio0 INT input");

2.1.2、编写中断服务程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void gpio_handle(E_OPENAT_DRV_EVT evt, E_AMOPENAT_GPIO_PORT gpioPort, unsigned char state)
{
uint8 status = 0;
//iot_debug_print("[gpio] gpio_handle %d,%d,%d", evt, gpioPort, state);
// 判断是gpio中断
if (evt == OPENAT_DRV_EVT_GPIO_INT_IND)
{
// 判断触发中断的管脚
if (gpioPort == 0)
{
// 触发电平的状态
iot_debug_print("[gpio] input handle gpio %d, state %d", gpioPort, state);
// 读当前gpio状态, 1:高电平 0:低电平
iot_gpio_read(gpioPort, &status);
iot_debug_print("[gpio] input handle gpio %d, status %d", gpioPort, state);
}
}
}

  中断的使用方法相比查询到要显得麻烦一下,需要多写一个函数,代码量比较多,但是好处就是实时性高。

2.2、查询法

  顾名思义,查询法就是不停的查询GPIO的状态,不管开关有没有按下,我都去查询,查询到什么就是什么,我没有查询的时候,你按了也没有用,这种方法的实时性比较低。
  具体使用方法如下,

2.2.1、初始化GPIO1为普通输入模式

  虽然gpio模式已经设置为了普通输入模式,这里需要注意的是,中断的类型必须要设置为,不使用中断,不然初始化会报错(ps:这里我觉得应该可以库内部实现默认,既然设置了普通输入模式那不久和中断没关系了吗,没有必要再去设置一下不使用中断)。

1
2
3
4
5
6
7
8
9
10
T_AMOPENAT_GPIO_CFG input_cfg = {0};
BOOL err = 0;
input_cfg.mode = OPENAT_GPIO_INPUT; //配置输入模式
input_cfg.param.defaultState = 0; //默认为低电平
input_cfg.param.intCfg.debounce = 50; //防抖50ms
input_cfg.param.intCfg.intType = OPENAT_GPIO_NO_INT; //不使用中断
err = iot_gpio_config(1, &input_cfg); //初始化gpio为普通输入模式
if (!err)
return;
iot_debug_print("[gpio] set gpio1 input");

2.2.2、死循环查询程序

  由于是1000ms查询一次,防止每次查询都会打印查询信息,导致查询日志刷屏。这里做了一个小处理,保存一下上次的查询结果,每次查询都会与上次查询的结果进行比较,若不等于就说明状态发生了变化,这时候就可以打印输出了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	uint8 value = 0;
uint8 oldstate = 0;
while (1)
{
//iot_debug_print("[gpio] Tesk Run");
if (iot_gpio_read(1, &value) == TRUE)
{
/* iot_debug_print("[gpio] input gpio1 ok");
iot_debug_print("[gpio] value:%d,oldstate:%d", value, oldstate); */
if (value != oldstate)
{
iot_debug_print("[gpio] input gpio1, state %d", value);
oldstate = value;
}
}
else
{
iot_debug_print("[gpio] input gpio1 error");
}
//线程休眠500ms
osiThreadSleep(1000);
}

  查询法用起来比较简单需要不停的去查询
  假如延时过短,就会出现任务切换频繁,执行效率低,cpu一直在忙着查询。
  延时时间过长就会出现实时性低,比如我上面的代码GPIO1接通后运气不好的时候需要等一秒钟才会有反应,不建议在对事件敏感的时候使用

  使用GPIO的驱动需要包含#include "iot_gpio.h"头文件,我们这里只用到了两个函数,分别是:

/*初始化gpio
*@param port: GPIO编号
*@param cfg: 配置信息
*@return TRUE: 成功
    FALSE: 失败
*
/

三、编译并下载程序

  完整代码在这,自取。

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
/*
* @Author: your name
* @Date: 2020-05-19 14:05:32
* @LastEditTime: 2020-05-20 10:45:57
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \RDA8910_CSDK\USER\user_main.c
*/

#include "string.h"
#include "cs_types.h"

#include "osi_log.h"
#include "osi_api.h"

#include "iot_debug.h"
#include "iot_uart.h"
#include "iot_os.h"
#include "iot_gpio.h"
#include "iot_pmd.h"
//GPIO_Input

void gpio_handle(E_OPENAT_DRV_EVT evt, E_AMOPENAT_GPIO_PORT gpioPort, unsigned char state)
{
uint8 status = 0;
//iot_debug_print("[gpio] gpio_handle %d,%d,%d", evt, gpioPort, state);
// 判断是gpio中断
if (evt == OPENAT_DRV_EVT_GPIO_INT_IND)
{
// 判断触发中断的管脚
if (gpioPort == 0)
{
// 触发电平的状态
iot_debug_print("[gpio] input handle gpio %d, state %d", gpioPort, state);
// 读当前gpio状态, 1:高电平 0:低电平
iot_gpio_read(gpioPort, &status);
iot_debug_print("[gpio] input handle gpio %d, status %d", gpioPort, state);
}
}
}

static void TestTask(void *param)
{
T_AMOPENAT_GPIO_CFG input_cfg = {0};
BOOL err = 0;
input_cfg.mode = OPENAT_GPIO_INPUT; //配置输入模式
input_cfg.param.defaultState = 0; //默认为低电平
input_cfg.param.intCfg.debounce = 50; //防抖50ms
input_cfg.param.intCfg.intType = OPENAT_GPIO_NO_INT; //不使用中断
err = iot_gpio_config(1, &input_cfg); //初始化gpio为普通输入模式
if (!err)
return;
iot_debug_print("[gpio] set gpio1 input");

uint8 value = 0;
uint8 oldstate = 0;
while (1)
{
//iot_debug_print("[gpio] Tesk Run");
if (iot_gpio_read(1, &value) == TRUE)
{
/* iot_debug_print("[gpio] input gpio1 ok");
iot_debug_print("[gpio] value:%d,oldstate:%d", value, oldstate); */
if (value != oldstate)
{
iot_debug_print("[gpio] input gpio1, state %d", value);
oldstate = value;
}
}
else
{
iot_debug_print("[gpio] input gpio1 error");
}
//线程休眠500ms
osiThreadSleep(1000);
}
osiThreadExit();
}

//main函数
int appimg_enter(void *param)
{
T_AMOPENAT_GPIO_CFG input_cfg = {0};
BOOL err = 0;
input_cfg.mode = OPENAT_GPIO_INPUT_INT; //配置输入中断
input_cfg.param.defaultState = 0; //默认为低电平
input_cfg.param.intCfg.debounce = 50; //防抖50ms
input_cfg.param.intCfg.intType = OPENAT_GPIO_INT_BOTH_EDGE; //中断触发方式双边沿
input_cfg.param.intCfg.intCb = gpio_handle; //中断处理函数
err = iot_gpio_config(0, &input_cfg); //初始化gpio为中断输入模式
if (!err)
return;
iot_debug_print("[gpio] set gpio0 INT input");

//创建一个任务,用作查询法
osiThreadCreate("TestTask", TestTask, NULL, OSI_PRIORITY_NORMAL, 2048, 0);
return 0;
}

//退出提示
void appimg_exit(void)
{
OSI_LOGI(0, "application image exit");
}

  编译成功
在这里插入图片描述

  查看输出,将GPIO0和GPIO1分别接高电平,高电平只能接入1.8v,一定不要接入比1.8v高的电压!!!GPIO0双边沿都成功触发中断打印,查询法也只是打印出来了状态交替的现象,验证了程序运行是正确的。
在这里插入图片描述
在这里插入图片描述

不会下载的点击这里,进去查看我的RDA8910 CSDK二次开发入门教程专题第一篇博文1、RDA8910CSDK二次开发:环境搭建里面讲了怎么下载
这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束

上次更新 2021-01-28