NUC980 运行 RT-Thread 时使用 GPIO
如何使用 GPIO?
NuMaker-RTU-NUC980 板子引出的 IO 有:

分别有一个 I2C1、GPIO、SPI0、UART4,RT-Thread 中 NuMaker-RTU-NUC980 的默认工程也分别使能了这些外设:

我在想一个问题,板子上就只引出了一个 GPIO,如果我要用多几个GPIO,在这个工程的基础上,需要做些什么,需要几步?
测试工具 & 方法
这里测试硬件是这个:

板子上有 8 个LED,正极都接在一起,既共阳接法,负极接 IO 口,IO口拉低是 LED亮,拉高时 LED 灭,跟 NuMaker-RTU-NUC980 连接如下:

猜想1,一步就行了
直接当作 GPIO 使用,参考给出的代码,我写了个简单的测试程序,把板子上的 PB6、PB4、PC3、PC4、PC5、PC6、PC8、PC9直接设为输出,然后每隔一段时间翻转这些 IO,反复点亮、关闭 LED灯,查看这些 IO 是否能都被控制,这些 IO 正好覆盖了 I2C1、SPI0、UART4、GPIO,代码如下:
#include <rtconfig.h>
#include <rtdevice.h>
#include <rtthread.h>
#include <drv_gpio.h>
#define LED0    NU_GET_PININDEX(NU_PB, 6)
#define LED1   NU_GET_PININDEX(NU_PB, 4)
#define LED2   NU_GET_PININDEX(NU_PC, 3)
#define LED3   NU_GET_PININDEX(NU_PC, 4)
#define LED4   NU_GET_PININDEX(NU_PC, 5)
#define LED5   NU_GET_PININDEX(NU_PC, 6)
#define LED6   NU_GET_PININDEX(NU_PC, 8)
#define LED7   NU_GET_PININDEX(NU_PC, 9)
int test_io(int argc, char **argv)
{
    uint8_t i=0;
    rt_pin_mode(LED0, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1, PIN_MODE_OUTPUT);
    rt_pin_mode(LED2, PIN_MODE_OUTPUT);
    rt_pin_mode(LED3, PIN_MODE_OUTPUT);
    rt_pin_mode(LED4, PIN_MODE_OUTPUT);
    rt_pin_mode(LED5, PIN_MODE_OUTPUT);
    rt_pin_mode(LED6, PIN_MODE_OUTPUT);
    rt_pin_mode(LED7, PIN_MODE_OUTPUT);
    for(i=0;i<100;i++)
    {
        rt_pin_write(LED0, PIN_HIGH);
        rt_pin_write(LED1, PIN_HIGH);
        rt_pin_write(LED2, PIN_HIGH);
        rt_pin_write(LED3, PIN_HIGH);
        rt_pin_write(LED4, PIN_HIGH);
        rt_pin_write(LED5, PIN_HIGH);
        rt_pin_write(LED6, PIN_HIGH);
        rt_pin_write(LED7, PIN_HIGH);
        rt_thread_mdelay(200);
        rt_pin_write(LED0, PIN_LOW);
        rt_pin_write(LED1, PIN_LOW);
        rt_pin_write(LED2, PIN_LOW);
        rt_pin_write(LED3, PIN_LOW);
        rt_pin_write(LED4, PIN_LOW);
        rt_pin_write(LED5, PIN_LOW);
        rt_pin_write(LED6, PIN_LOW);
        rt_pin_write(LED7, PIN_LOW);
        rt_thread_mdelay(200);
    }
    return 0;
}
MSH_CMD_EXPORT(test_io, io test app);
编译运行,结果只有 GPIO PC3 对于的灯才有闪烁:

证明在目前的工程代码中是无法把这些 IO 当作 GPIO 来使用
猜想2,需要2步
因为工程中启用了跟这些 IO 的外设,把这些相关外设去掉试下,首先在配置中不启用 I2C1、SPI0、UART4,相关配置如下:

然后实现相关代码,跟第一个猜想一样,然后编译,运行,跟上一种情况一样,还是无法把其他 IO 用起来。
猜想3,需要3步
后来看了下代码,发现工程 borad目录下有这个文件 nu_pin_init.c,里面有些跟 IO 设置相关的函数,有跟 I2C1、SPI0、UART4相关部分,如下:
static void nu_pin_uart_init(void)
{
    /* UART0: GPF11, GPF12 */
    outpw(REG_SYS_GPF_MFPH, (inpw(REG_SYS_GPF_MFPH) & 0xFFF00FFF) | 0x00011000);
    /* UART4: GPC9, GPC10 */
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xFFFFF00F) | 0x00000770);
    /* UART8: GPC12, GPC13, GPC14 */
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xF000FFFF) | 0x07770000);
}
static void nu_pin_spi_init(void)
{
    /* SPI0: PC[4, 8]  */
    outpw(REG_SYS_GPC_MFPL, (inpw(REG_SYS_GPC_MFPL) & 0xF000FFFF) | 0x05560000);
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xFFFFFFF0) | 0x00000005);
}
static void nu_pin_i2c_init(void)
{
    /* I2C1: PB4, PB6 */
    outpw(REG_SYS_GPB_MFPL, (inpw(REG_SYS_GPB_MFPL) & 0xF0F0FFFF) | 0x02020000);
}
void nu_pin_init(void)
{
    nu_pin_uart_init();
    nu_pin_emac_init();
    nu_pin_qspi_init();
    nu_pin_spi_init();
    nu_pin_i2c_init();
    nu_pin_can_init();
    nu_pin_usbd_init();
    nu_pin_usbh_init();
}
首先把跟 I2C1、SPI0、UART4相关部分 屏蔽了,还有两个步骤跟猜想2一样,编译运行:

其中缘由
其中缘由是,nuc980 IO 复用的问题。比如 uart4 对应得 IO口:

一个 IO 可以复用为很多功能,比如 PC9可以用作 GPIO、USRT_TXD 等,可是同一时刻只能用于一种功能,上述代码中 uart4 相关的:
outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xFFFFF00F) | 0x00000770);
看下宏定义:
/*!< GPIOC Low Byte Multiple Function Control Register */
#define    REG_SYS_GPC_MFPL     (SYS_BA+0x080)
/*!< GPIOC High Byte Multiple Function Control Register */
#define    REG_SYS_GPC_MFPH     (SYS_BA+0x084)
REG_SYS_GPC_MFPH 就是 IO 多功能设置寄存器:

上述代码把 REG_SYS_GPC_MFPH 中 PC9、PC10 对应的部分设置为 7,正好是设置为 uart 功能,从参考手册上得知,NUC980 的 IO 上电默认是作为 GPIO的,如果设置了其他功能就不能用做 GPIO,也就无法直接拉高拉低。如果要把这些 IO 用作 GPIO,只能把这些 IO 复用设置相关的代码去掉。
改进
RT-Thread 工程是使用宏来进行条件编译的,改进下代码,对这些 IO 设置相关的代码也加些宏,如下:
static void nu_pin_uart_init(void)
{
    #if defined(BSP_USING_UART0)
    /* UART0: GPF11, GPF12 */
    outpw(REG_SYS_GPF_MFPH, (inpw(REG_SYS_GPF_MFPH) & 0xFFF00FFF) | 0x00011000);
    #endif
    #if defined(BSP_USING_UART4)
    /* UART4: GPC9, GPC10 */
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xFFFFF00F) | 0x00000770);
    #endif
    #if defined(BSP_USING_UART8)
    /* UART8: GPC12, GPC13, GPC14 */
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xF000FFFF) | 0x07770000);
    #endif
}
static void nu_pin_spi_init(void)
{
#if defined(BSP_USING_SPI0)
    /* SPI0: PC[4, 8]  */
    outpw(REG_SYS_GPC_MFPL, (inpw(REG_SYS_GPC_MFPL) & 0xF000FFFF) | 0x05560000);
    outpw(REG_SYS_GPC_MFPH, (inpw(REG_SYS_GPC_MFPH) & 0xFFFFFFF0) | 0x00000005);
#endif    
}
static void nu_pin_i2c_init(void)
{
#if defined(BSP_USING_I2C1)
    /* I2C1: PB4, PB6 */
    outpw(REG_SYS_GPB_MFPL, (inpw(REG_SYS_GPB_MFPL) & 0xF0F0FFFF) | 0x02020000);
#endif
}
在原来的基础上做了这个改进,就可以实现 2 步使用 GPIO了:
- 实现相关程序
 - 如果所使用 IO 对应的外设有使能,则关闭所使用 IO 对应的外设
 
转载请注明出处:https://www.cnblogs.com/halin/
NUC980 运行 RT-Thread 时使用 GPIO的更多相关文章
- Hadoop运行Jar文件时Output错误
		
当第二次运行Jar程序时,出现Output文件已存在的Exception: Exception in thread "main" org.apache.hadoop.mapred. ...
 - 多个线程运行MR程序时hadoop出现的问题
		
夜间多个任务同时并行,总有几个随机性有任务失败,查看日志: cat -n ads_channel.log |grep "Caused by" Caused by: java.uti ...
 - 在集群上运行caffe程序时如何避免Out of Memory
		
不少同学抱怨,在集群的GPU节点上运行caffe程序时,经常出现"Out of Memory"的情况.实际上,如果我们在提交caffe程序到某个GPU节点的同时,指定该节点某个比较 ...
 - 在linux下运行apt-get update 时,报错/var/lib/apt/lists/lock
		
在运行apt-get update 时,报下面的错误: E: 无法获得锁 /var/lib/apt/lists/lock - open (11: Resource temporarily unavai ...
 - vs2010运行C程序时,运行结果窗口一闪而过
		
摘要:vs2010运行C程序时,运行结果窗口一闪而过; ------------------------------------------------------------ Ctrl F5测试运行 ...
 - 运行 Docker 容器时的安全风险:别丢了你的套接字
		
我们都遇到过这种情况:你只是想尝试一段命令行,但安装进程却如同抵押贷款申请那般繁琐.如果不是强制要求完成这么多步骤,你的开发环境会被永远不会再使用的库弄乱.自然, Docker 来了以后,你惊异地发现 ...
 - 在浏览器运行 java applet时遇到的一些问题及其解决方法
		
运行 java applet时提示:您的安全设置已阻止本地应用程序运行,如何解决?如下图所示 这时候通过设置java的安全级别就可以了. 控制面板->程序->Java->安全 将安全 ...
 - eclipse运行spark程序时日志颜色为黑色的解决办法
		
自从开始学习spark计算框架以来,我们老师教的是local模式下用eclipse运行spark程序,然后我在运行spark程序时,发现控制台的日志颜色总是显示为黑色,哇,作为程序猿总有一种强迫症,发 ...
 - 运行python文件时出错SyntaxError: Non-UTF-8 code starting with '\xb5' in file, but no encoding declared;
		
今天ytkah在运行python文件时出现错误,提示如下,很明显这是没有定义python文件编码引起的问题,那么要怎么解决呢?很简单,在文件头部定义一下就可以了. File "hello.p ...
 - 运行网站项目时,有时出现Bad Request,该怎么解决?
		
有时运行网站项目时,出现Bad Request问题
 
随机推荐
- C++ string的size()和length()函数没有区别
			
C++标准库中的string中两者的源代码如下: size_type __CLR_OR_THIS_CALL length() const { // return ...
 - Docker 部署阿里云RocketMQ 4.5.1
			
搜索镜像 docker search rocketmq 查看镜像版本 如果要查看其它的镜像,只需要将其中的镜像名称foxiswho/rocketmq替换为其它镜像即可 curl https://reg ...
 - 『动善时』JMeter基础 — 15、使用JMeter实现上传文件
			
目录 1.用于演示的项目说明 2.测试计划内包含的元件 3.HTTP请求界面内容 4.查看结果 5.总结 6.补充:MIME类型简介 (1)MIME说明 (2)常见类型 在上一篇文章[使用JMeter ...
 - Linux主机USB RNDIS网卡驱动实现不完整导致的一例问题
			
某通信模块设备,通过USB提供RDNIS和ECM网卡功能.在实际应用中发现,USB RNDIS网卡模式下,当使用AT指令以不同的CID拨号的时候,在Windows主机上能正常拨号成功,但在Linux主 ...
 - [c++] 二级指针的原理
			
示例 将值(实参)传递给值(形参),无法更改val 1 #include <iostream> 2 using namespace std; 3 4 void change(int mem ...
 - Linux命令nohup实现命令后台运行并输出到或记录到日志文件
			
Linux命令nohup实现命令后台运行并输出到或记录到日志文件 导读 我们在调试程序的时候,免不了要去抓一些 log ,然后进行分析.如果 log 量不是很大的话,那很简单,只需简单的复制粘贴就好. ...
 - KVM 添加新硬件
			
1 显卡 spice 2视频 qxl驱动 3 声音 ich6最好 ich9最清楚 4 输入 鼠标 智能图 否则不能VNC找不到焦点 5 磁盘大小 至少80G 否则 无法自动安装 无swap和 ...
 - Docker Swarm(五)Config 配置管理
			
前言 在动态的.大规模的分布式集群上,管理和分发配置文件也是很重要的工作.传统的配置文件分发方式(如配置文件放入镜像中,设置环境变量,volume 动态挂载等)都降低了镜像的通用性. Docker 1 ...
 - Linux创建RAID5_实战
			
Linux创建RAID5实战 Linux创建RAID5 RAID5最少由三个硬盘组成,它将数据分散存储于阵列中的每个硬盘,并且还伴有一个数据校验位,数据位与校验位通过算法能相互验证 RAID5最多能允 ...
 - strcasecmp函数和strncasecmp函数原型
			
函数说明 strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异. 返回值 若参数s1和s2字符串相同则返回0.s1长度大于s2长度则返回大于0 的值,s1 长度若小 ...