当前位置:网站首页>新唐NUC980使用记录:在用户应用中使用GPIO
新唐NUC980使用记录:在用户应用中使用GPIO
2022-08-05 00:46:00 【Naisu Xu】
目的
GPIO是最基础的外设,使用频率也非常高,这篇文章将简单体验在NUC980 Liunx用户应用中使用GPIO功能。
这篇文章中内容均在下面的开发板上进行测试:
《新唐NUC980使用记录:自制开发板(基于NUC980DK61YC)》
开发板中提供了两组共四个直连到GPIO口上的轻触按钮和发光二极管,可以方便地进行GPIO功能测试:
这篇文章主要是在下面文章基础上进行的:
《新唐NUC980使用记录:访问以太网(LAN8720A) & 启用SSH》
基础说明
默认情况下NUC980官方的内核是配置启用了sysfs文件系统GPIO支持的:
所以可以通过读写 /sys/class/gpio/
目录下指定GPIO口编号的文件来操作GPIO口。GPIO口编号换算如下:PB13 = 32 x 1(PA) + 13 = 45
PF10 = 32 x 5(PA/PB/PC/PD/PE) + 10 = 170
PE10 = 32 x 4(PA/PB/PC/PD) + 10 = 138
PE12 = 32 x 4(PA/PB/PC/PD) + 12 = 140
需要注意的是默认情况下PE10和PE12是被设置成USB相关功能的,需要修改内核进行调整:
在终端中操作
基于上面内容我们就可以直接在终端中操作GPIO口了:
# 导出以使用GPIO45
echo 45 > /sys/class/gpio/export
# 导出后将在 /sys/class/gpio/ 目录下出现 gpio45 目录,读写其中的文件即可操作该GPIO口
# 将GPIO45设置为输出模式
echo out > /sys/class/gpio/gpio45/direction
# 将GPIO45设置为输出高电平
echo 1 > /sys/class/gpio/gpio45/value
# 将GPIO45设置为输出低电平
echo 0 > /sys/class/gpio/gpio45/value
# ====================
# 导出以使用GPIO140
echo 140 > /sys/class/gpio/export
# 将GPIO140设置为输入模式
echo in > /sys/class/gpio/gpio140/direction
# 打印GPIO140端口电平
cat /sys/class/gpio/gpio140/value
# ====================
# 取消使用GPIO45
echo 45 > /sys/class/gpio/unexport
# 取消使用GPIO45
echo 140 > /sys/class/gpio/unexport
上面演示中按钮按下和松开时可以读取到不同的电平值。
使用程序操作
除了在终端中使用,也可以通过程序进行操作:
cd ~/nuc980-sdk/
mkdir -p apps/gpio
cd apps/gpio/
gedit main.c
在 main.c 文件中写入下面代码:
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int i;
system("echo 45 > /sys/class/gpio/export");
system("echo out > /sys/class/gpio/gpio45/direction");
for (i = 0; i < 8; i++)
{
system("echo 0 > /sys/class/gpio/gpio45/value");
sleep(1);
system("echo 1 > /sys/class/gpio/gpio45/value");
sleep(1);
}
system("echo 45 > /sys/class/gpio/unexport");
return 0;
}
编译生成程序并拷贝到开发板中:
export PATH=$PATH:/home/nx/nuc980-sdk/buildroot-2022.02.3/output/host/bin
arm-linux-gcc main.c
# 开发板启用了SSH的话可以使用SCP命令将程序通过网络拷贝到开发板中
scp a.out [email protected]:/root/
在开发板上运行程序:
/root/a.out
上面代码也可以使用下面这种传统的文件操作方式:
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define OPEN_FILE(fd, file, flag) \ (fd) = open((file), (flag)); \ if ((fd) < 0) {
printf("open %s failed!\n", (file)); return -1; }
#define WRITE_FILE(fd, str) \ if(write((fd), (str), strlen(str)) != strlen(str)) \ {
printf("write %s failed!\n", (str)); return -1; }
int main(void)
{
int i, fd;
if(access("/sys/class/gpio/gpio45/", F_OK))
{
OPEN_FILE(fd, "/sys/class/gpio/export", O_WRONLY);
WRITE_FILE(fd, "45");
close(fd);
}
OPEN_FILE(fd, "/sys/class/gpio/gpio45/direction", O_WRONLY);
WRITE_FILE(fd, "out");
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/gpio45/value", O_RDWR);
for (i = 0; i < 8; i++)
{
lseek(fd, 0, SEEK_SET); // 移动文件操作指针到文件开头
WRITE_FILE(fd, "0");
sleep(1);
lseek(fd, 0, SEEK_SET); // 移动文件操作指针到文件开头
WRITE_FILE(fd, "1");
sleep(1);
}
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/unexport", O_WRONLY);
WRITE_FILE(fd, "45");
close(fd);
return 0;
}
上面的C语言程序都是输出控制LED的,也可以用程序来读取按键输入电平:
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define OPEN_FILE(fd, file, flag) \ (fd) = open((file), (flag)); \ if ((fd) < 0) {
printf("open %s failed!\n", (file)); return -1; }
#define WRITE_FILE(fd, str) \ if(write((fd), (str), strlen(str)) != strlen(str)) \ {
printf("write %s failed!\n", (str)); return -1; }
#define READ_FILE(fd, bufptr, size) \ if (read((fd), bufptr, size) != size) \ {
printf("read failed!\n"); return -1; }
int main(void)
{
int i, fd;
char value[2] = {
0};
if(access("/sys/class/gpio/gpio140/", F_OK))
{
OPEN_FILE(fd, "/sys/class/gpio/export", O_WRONLY);
WRITE_FILE(fd, "140");
close(fd);
}
OPEN_FILE(fd, "/sys/class/gpio/gpio140/direction", O_WRONLY);
WRITE_FILE(fd, "in");
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/gpio140/value", O_RDWR);
for (i = 0; i < 8; i++)
{
lseek(fd, 0, SEEK_SET); // 移动文件操作指针到文件开头
READ_FILE(fd, value, 1);
printf("value is %s\n", value);
sleep(2);
}
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/unexport", O_WRONLY);
WRITE_FILE(fd, "140");
close(fd);
return 0;
}
在程序运行过程中按下按钮可以看到输出的值改变。
上面对于输入值获取操作属于轮询方式,也可以使用中断方式来获取(开发板上两个按键的引脚都是有外部中断功能的):
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#define OPEN_FILE(fd, file, flag) \ (fd) = open((file), (flag)); \ if ((fd) < 0) {
printf("open %s failed!\n", (file)); return -1; }
#define WRITE_FILE(fd, str) \ if(write((fd), (str), strlen(str)) != strlen(str)) \ {
printf("write %s failed!\n", (str)); return -1; }
#define READ_FILE(fd, bufptr, size) \ if (read((fd), bufptr, size) != size) \ {
printf("read failed!\n"); return -1; }
int main(void)
{
int i, fd, ret;
char value[2] = {
0};
struct pollfd fds[1];
nfds_t nfds = 1;
if(access("/sys/class/gpio/gpio140/", F_OK))
{
OPEN_FILE(fd, "/sys/class/gpio/export", O_WRONLY);
WRITE_FILE(fd, "140");
close(fd);
}
OPEN_FILE(fd, "/sys/class/gpio/gpio140/direction", O_WRONLY);
WRITE_FILE(fd, "in");
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/gpio140/edge", O_WRONLY); // edge文件用于设置外部中断触发方式
// none 无; rising 上升沿触发; falling 下降沿触发(实际测试有点问题); both 双边触发
WRITE_FILE(fd, "rising"); // 使能下降沿中断
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/gpio140/value", O_RDWR | O_NONBLOCK);
READ_FILE(fd, value, 1); // 先读取一次,以免触发第一次不期望的中断
fds[0].fd = fd;
fds[0].events = POLLPRI;
for (i = 0; i < 8; i++)
{
ret = poll(fds, nfds, 5000);
// ret = poll(fds, nfds, -1); // timeout=-1 无限等待
if (ret > 0)
{
// 这里返回的fds[0].revents其实是 POLLERR | POLLPRI
if (fds[0].revents & POLLPRI)
{
lseek(fd, 0, SEEK_SET); // 移动文件操作指针到文件开头
READ_FILE(fd, value, 1);
printf("value is %s\n", value);
}
}
else if (ret == 0)
{
printf("timeout!\n");
}
else
{
printf("poll error!\n");
}
}
close(fd);
OPEN_FILE(fd, "/sys/class/gpio/unexport", O_WRONLY);
WRITE_FILE(fd, "140");
close(fd);
return 0;
}
总结
GPIO是最基础的外设,使用频率非常高,同时在用户应用中使用GPIO也是比较简单的,基础的使用参考上面这些内容就差不多了。
边栏推荐
- Software Testing Interview Questions: What aspects should be considered when designing test cases, i.e. what aspects should different test cases test against?
- Pytorch usage and tricks
- 创意代码表白
- QSunSync Qiniu cloud file synchronization tool, batch upload
- gorm joint table query - actual combat
- 2021年11月网络规划设计师上午题知识点(上)
- 软件测试面试题:关于自动化测试工具?
- GCC: paths to header and library files
- 软件测试面试题:您以往所从事的软件测试工作中,是否使用了一些工具来进行软件缺陷(Bug)的管理?如果有,请结合该工具描述软件缺陷(Bug)跟踪管理的流程?
- Bit rate vs. resolution, which one is more important?
猜你喜欢
2022杭电多校第三场 K题 Taxi
PCIe 核配置
"WEB Security Penetration Testing" (28) Burp Collaborator-dnslog out-band technology
[idea] idea configures sql formatting
could not build server_names_hash, you should increase server_names_hash_bucket_size: 32
MongoDB搭建及基础操作
LiveVideoStackCon 2022 上海站明日开幕!
Introduction to JVM class loading
ORA-01105 ORA-03175
JWT简单介绍
随机推荐
ora-01105 ora-03175
Getting Started with Kubernetes Networking
E - Distance Sequence (prefix and optimized dp
Software testing interview questions: What stages should a complete set of tests consist of?
### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionExcep
自定义线程池
Software testing interview questions: the difference and connection between black box testing, white box testing, and unit testing, integration testing, system testing, and acceptance testing?
ORA-01105 ORA-03175
E - Many Operations (bitwise consideration + dp thought to record the result after the operation
Pytorch使用和技巧
tiup status
GCC:编译时库路径和运行时库路径
软件测试面试题:软件验收测试的合格通过准则?
2022杭电多校 第三场 B题 Boss Rush
leetcode: 269. The Martian Dictionary
Matlab uses plotting method for data simulation and simulation
leetcode: 267. Palindromic permutations II
2022杭电多校训练第三场 1009 Package Delivery
2021年11月网络规划设计师上午题知识点(上)
Helm Chart