嵌入式linux学习之实践操作

前沿

1. 安装交叉编译器

  • 在开发板光盘 A-基础资料->5、开发工具->1、交叉编译器路径下找到 st-example-image-qt
    wayland-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-snapshot.sh。将它拷贝到 Ubuntu 虚拟机上。 拷贝到 Ubuntu 后,赋予 st-example-image-qtwayland-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-snapshot.sh 可执行权限。
    *chmod +x st-example-image-qtwayland-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-snapshot.sh
  • 执行./st*.sh脚本安装
  • 安装完成后,安装的交叉编译工具链都会安装在/opt/目录下。
  • ls /opt/st/
  • 安装完成之后,在使用之前先对交叉编译工具的环境进行设置,使用 source 执行安装目录下的
    environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi 脚本文件即可,如下所示:
    source /opt/st/stm32mp1/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
    在这里插入图片描述

注意:每个终端需要执行上面的source命令之后,才能打印出${CC}.

使用${CC} -o led led.c编译

生成的led可执行文件通过scp命令传输到开发板,./led执行。

1.控制led


15_led.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define LED_TRIGGER "/sys/class/leds/user-led/trigger"
#define LED_BRIGHTNESS "/sys/class/leds/user-led/brightness"
#define USAGE() fprintf(stderr, "usage:\n" \
" %s <on|off>\n" \
" %s <trigger> <type>\n", argv[0], argv[0])
int main(int argc, char *argv[])
{
int fd1, fd2;
/* 校验传参 */
if (2 > argc) {
USAGE();
exit(-1);
/* 打开文件 */
fd1 = open(LED_TRIGGER, O_RDWR);
if (0 > fd1) {
perror("open error");
exit(-1);
}
fd2 = open(LED_BRIGHTNESS, O_RDWR);
if (0 > fd2) {
perror("open error");
exit(-1);
}
/* 根据传参控制 LED */
if (!strcmp(argv[1], "on")) {
write(fd1, "none", 4); //先将触发模式设置为 none
write(fd2, "1", 1);
//点亮 LED
}
else if (!strcmp(argv[1], "off")) {
write(fd1, "none", 4); //先将触发模式设置为 none
write(fd2, "0", 1);
//LED 灭
}
else if (!strcmp(argv[1], "trigger")) {
if (3 != argc) {
USAGE();
exit(-1);
}
if (0 > write(fd1, argv[2], strlen(argv[2])))
perror("write error");
}
else
USAGE();
exit(0);
}

使用${CC} -o 15_led 15_led.c编译

在虚拟机使用ifconfig ens33 192.168.137.4配置ip

开发板ifconfig eth 192.168.137.3配置ip

开发板:scp tao@192.168.137.4:~/linux/c_cpp/15_led ~/将文件传输至开发板。

./15_led on点亮ds1,./15_led off熄灭ds1,./15_led trigger heartbeat使其闪烁。

也可以使用 DS0 进行测试,将 源码中的路径修改一下即可(/sys/class/leds/user-led/修改为/sys/class/leds/sys-led/)

2.操作GPIO

​* 与 LED 设备一样,GPIO 同样也是通过 sysfs 方式进行操控,进入到/sys/class/gpio 目录下,如下所示:
图 16.1.1 /sys/class/gpio 目录
在这里插入图片描述

可以看到该目录下包含两个文件 export、unexport 以及许多个以 gpiochipX(X 等于 0、32、64、96、
128)命名的文件夹。

gpiochipX:当前 SoC 所包含的 GPIO 控制器,我们知道 STM32MP157 一共包含了 12 个 GPIO 控制器,分别为 GPIOA、GPIOB、GPIOC…在这里分别对应 gpiochip0、gpiochip16、gpiochip32…以此类推,每一个 gpiochipX 文件夹用来管理一组 GPIO。随便进入到其中某个目录下,可以看到这些目录下包含了如下文件:

在这里插入图片描述
图 16.1.2 gpiochip0 目录下的文件,在这个目录我们主要关注的是 base、label、ngpio 这三个属性文件,这三个属性文件均是只读、不可写。

  • base:与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号。每一个 GPIO引脚都会有一个对应的编号,Linux 下通过这个编号来操控对应的 GPIO 引脚;label:该组 GPIO 对应的标签,也就是名字;ngpio:该控制器所管理的 GPIO 引脚的数量(所以引脚编号范围是:base ~ base+ngpio-1);可使用cat ngpio查看;
  • 对于给定的一个 GPIO 引脚GPIOB_IO10,那它对应的编号是16 + 10 = 26;同理 GPIOC_IO05对应的编号是 32 + 5 = 37。

export:用于将指定编号的 GPIO 引脚导出。

  • 在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出,譬如:
    echo 0 > export # 导出编号为 0 的 GPIO 引脚(对于 STM32MP157 来说,也就是 GPIOA_IO0)
    导出成功之后会发现在/sys/class/gpio 目录下生成了一个名为 gpio0 的文件夹(gpioX,X 表示对应的编号)在这里插入图片描述
  • 这个文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚,

unexport:将导出的 GPIO 引脚删除,也就是取消导出 GPIO。

  • 当使用完 GPIO 引脚之后,我们需要将导出的引脚删除,同样该文件也是只写文件、不可读,譬如:
    echo 0 > unexport # 删除导出的编号为 0 的 GPIO 引脚,取消导出 GPIO

导出的引脚文件夹

  1. direction:配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式)
  2. value:在 GPIO 配置为输出模式下,向 value 文件写入"0"控制 GPIO 引脚输出低电平,写入"1"则控制 GPIO 引脚输出高电平。在输入模式下,读取 value 文件获取 GPIO 引脚当前的输入电平状态。
1.获取 GPIO 引脚的输入电平状态

echo “in” > direction
cat value

2.控制 GPIO 引脚输出高电平

echo “out” > direction
echo “1” > value

active_low:这个属性文件用于控制极性,可读可写,默认情况下为 0,譬如:

active_low 等于 0 时

echo “0” > active_low
echo “out” > direction
echo “1” > value #输出高
echo “0” > value #输出低

active_low 等于 1 时

echo “1” > active_low
echo “out” > direction
echo “1” > value #输出低
echo “0” > value #输出高
由此看出,active_low 的作用已经非常明显了,就是用于控制极性,对于输入模式来说也同样适用。

edge:控制中断的触发模式,

  • 该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式:
    非中断引脚:echo “none” > edge
    上升沿触发:echo “rising” > edge
    下降沿触发:echo “falling” > edge
    边沿触发:echo “both” > edge
    当引脚被配置为中断后可以使用 poll()函数监听引脚的电平状态变化
    输出示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_path[100];
static int gpio_config(const char *attr, const char *val)
{
 char file_path[100];
 int len;
 int fd;
 sprintf(file_path, "%s/%s", gpio_path, attr);
 if (0 > (fd = open(file_path, O_WRONLY))) {
 perror("open error");
 return fd;
 }
 len = strlen(val);
 if (len != write(fd, val, len)) {
 perror("write error");
 close(fd);
 return -1;
 }
 close(fd); //关闭文件
 return 0;
}
int main(int argc, char *argv[])
{
 /* 校验传参 */
 if (3 != argc) {
 fprintf(stderr, "usage: %s <gpio> <value>\n", argv[0]);
 exit(-1);
 }
 /* 判断指定编号的 GPIO 是否导出 */
 sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
 if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出
 int fd;
 int len;
 if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
 perror("open error");
 exit(-1);
 }
 len = strlen(argv[1]);
 if (len != write(fd, argv[1], len)) {//导出 gpio
 perror("write error");
 close(fd);
 exit(-1);
 }
 close(fd); //关闭文件
 }
 /* 配置为输出模式 */
 if (gpio_config("direction", "out"))
 exit(-1);
 /* 极性设置 */
 if (gpio_config("active_low", "0"))
 exit(-1);
 /* 控制 GPIO 输出高低电平 */
 if (gpio_config("value", argv[2]))
 exit(-1);
 /* 退出程序 */
 exit(0);
}

执行程序时需要传入两个参数,argv[1]指定 GPIO 的编号、argv[2]指定输出电平状态(0 表示低电平、1 表示高电平)。
如./gpio 0 1表示gpio0 输出高电平

gpio输入demo
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_path[100];
static int gpio_config(const char *attr, const char *val)
{
 char file_path[100];
 int len;
 int fd;
 sprintf(file_path, "%s/%s", gpio_path, attr);
 if (0 > (fd = open(file_path, O_WRONLY))) {
 		perror("open error");
 		return fd;
 }
 len = strlen(val);
 if (len != write(fd, val, len)) {
 		perror("write error");
 		close(fd);
 		return -1;
 }
 close(fd); //关闭文件
 return 0;
}
int main(int argc, char *argv[])
{
 char file_path[100];
 char val;
 int fd;
 /* 校验传参 */
 if (2 != argc) {
 		fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
 		exit(-1);
 }
 /* 判断指定编号的 GPIO 是否导出 */
 sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
 if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出
 	int len;
 	if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
 		perror("open error");
 		exit(-1);
 	}
 	len = strlen(argv[1]);
	if (len != write(fd, argv[1], len)) {//导出 gpio
 		perror("write error");
 		close(fd);
 		exit(-1);
 	}
 close(fd); //关闭文件
 }
 /* 配置为输入模式 */
 if (gpio_config("direction", "in"))
 	exit(-1);
 /* 极性设置 */
 if (gpio_config("active_low", "0"))
 	exit(-1);
 /* 配置为非中断方式 */
 if (gpio_config("edge", "none"))
 	exit(-1);
 /* 读取 GPIO 电平状态 */
 sprintf(file_path, "%s/%s", gpio_path, "value");
 if (0 > (fd = open(file_path, O_RDONLY))) {
 	perror("open error");
 	exit(-1);
 	}
 if (0 > read(fd, &val, 1)) {
 	perror("read error");
 	close(fd);
 	exit(-1);
 }
 printf("value: %c\n", val);
 /* 退出程序 */
 close(fd);
 exit(0);
}

执行程序时需要传入一个参数,argv[1]指定要读取电平状态的 GPIO 对应的编号。

gpio 中断demo
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
static char gpio_path[100];
static int gpio_config(const char *attr, const char *val)
{
 	char file_path[100];
 	int len;
 	int fd;
 	sprintf(file_path, "%s/%s", gpio_path, attr);
	 if (0 > (fd = open(file_path, O_WRONLY))) {
 		perror("open error");
 		return fd;
 	}
	len = strlen(val);
 	if (len != write(fd, val, len)) {
 		perror("write error");
 		return -1;
 	}
 	close(fd); //关闭文件
 	return 0;
}
int main(int argc, char *argv[])
{
 	struct pollfd pfd;
 	char file_path[100];
 	int ret;
 	char val;
 	/* 校验传参 */
 	if (2 != argc) {
 		fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
 		exit(-1);
 	}
 	/* 判断指定编号的 GPIO 是否导出 */
 	sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
 	if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出
 		int len;
 		int fd;
 		if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
 			perror("open error");
 			exit(-1);
 		}
 		len = strlen(argv[1]);
 		if (len != write(fd, argv[1], len)) {//导出 gpio
 			perror("write error");
 			exit(-1);
 		}
 		close(fd); //关闭文件
 	}
 	/* 配置为输入模式 */
 	if (gpio_config("direction", "in"))
 		exit(-1);
	 /* 极性设置 */
	 if (gpio_config("active_low", "0"))
	 	exit(-1);
	 /* 配置中断触发方式: 上升沿和下降沿 */
	 if (gpio_config("edge", "both"))
	 	exit(-1);
	 /* 打开 value 属性文件 */
	 sprintf(file_path, "%s/%s", gpio_path, "value");
	 if (0 > (pfd.fd = open(file_path, O_RDONLY))) {
	 	perror("open error");
		exit(-1);
	 }
	 /* 调用 poll */
	 pfd.events = POLLPRI; //只关心高优先级数据可读(中断)
	 read(pfd.fd, &val, 1);//先读取一次清除状态
	 for ( ; ; ) {
	 	ret = poll(&pfd, 1, -1); //调用 poll
	 	if (0 > ret) {
	 		perror("poll error");
	 		exit(-1);
	 	}
	 	else if (0 == ret) {
	 		fprintf(stderr, "poll timeout.\n");
	 		continue;
	 	}
	 /* 校验高优先级数据是否可读 */
	 if(pfd.revents & POLLPRI) {
	 	if (0 > lseek(pfd.fd, 0, SEEK_SET)) {//将读位置移动到头部
	 		perror("lseek error");
	 		exit(-1);
	 	}
	 	if (0 > read(pfd.fd, &val, 1)) {
	 		perror("read error");
			 exit(-1);
	 	}
	 	printf("GPIO 中断触发<value=%c>\n", val);
	 	}
	 }
	 /* 退出程序 */
	 exit(0);
}

执行程序时需要传入一个参数,argv[1]指定要读取电平状态的 GPIO 对应的编号。

3.输入设备应用编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/348827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ死信交换机

目录 1.死信交换机介绍 2.TTL 3.延迟队列 4.消息堆积问题 5.惰性队列 6.代码实战 1.死信交换机介绍 当一个队列中信息满足下列情况之一时&#xff0c;可以成为死信&#xff08;dead letter&#xff09; &#xff08;1&#xff09;消费者使用basic.reject&#xff08;Reject…

Java基础进阶02-xml

目录 一、XML&#xff08;可拓展标记语言&#xff09; 1.学习网站&#xff1a; 2.作用 3.XML标签 4.XML语法 5.解析XML &#xff08;1&#xff09;常见解析思想DOM 6.常见的解析工具 7.DOM4j的使用 8.文档约束 &#xff08;1&#xff09;概述 &#xff08;2&#xf…

全桥变压器计算1

一共有两级&#xff0c;先DC升压&#xff0c;后H桥逆变为AC 因为两级都有损耗&#xff0c;所以一般用输入功率计算 电池升压到400V高压用的效率用表示&#xff0c;后面DC转AC的效率用表示&#xff0c;输入电压用Vin&#xff0c;输出功率Po2000W,输入功率为Pin 一般和96% 所…

Pandas ------ 向 Excel 文件中写入含有 multi-index 和 Multi-column 表头的数据

Pandas ------ 向 Excel 文件中写入含有 multi-index 和 Multi-column 表头的数据 引言正文 引言 之前在 《pandas向已经拥有数据的Excel文件中添加新数据》 一文中我们介绍了如何通过 pandas 向 Excel 文件中写入数据。那么对于含有多表头的数据&#xff0c;我们该如何将它们…

单调性的应用

1单调性 应用场景&#xff1a;常应用于双指针的进一步优化问题中含义&#xff1a;针对指针 i 1 > i i1>i i1>i一定有 j 1 > j j1>j j1>j或者 j 1 < j j1<j j1<j这样我们就可以利用该性质对算法进行进一步优化&#xff0c;避免一些不必要的遍历…

Linux——系统简介

1、从UNIX到LINUX 在目前主流的服务器端操作系统中&#xff0c;UNIX诞生于20世纪60年代末&#xff0c;Windows诞生于20世纪80年代中期&#xff0c;Linux诞生于20世纪90年代初&#xff0c;可以说UNIX是操作系统中的“老大哥”。 1.1、Linux简史 Linux内核最初是由李纳斯托瓦兹…

Caused by: com.mongodb.MongoTimeoutException: Timed out after 30000 ms

报错 Caused by: com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {typeUNKNOWN, servers[{addressmangodb-m.cc.com:3717, typeUNKNOWN, stateCONNECTING, exception{com.mongodb.MongoSocketReadE…

java数据结构与算法刷题-----LeetCode769. 最多能完成排序的块

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 这道题可以理解为&#xff0c;只能保证块内有序的情况下&#xf…

力扣日记1.25-【回溯算法篇】39. 组合总和

力扣日记&#xff1a;【回溯算法篇】39. 组合总和 日期&#xff1a;2023.1.25 参考&#xff1a;代码随想录、力扣 39. 组合总和 题目描述 难度&#xff1a;中等 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和…

【域名解析】如何将域名指向对应服务器IP

目录 &#x1f337;一、域名解析基本概念 &#x1f33c;1. 定义 &#x1f33c;2. 域名解析类型 &#x1f337;二、域名解析服务器IP地址 &#x1f33c;1. 操作步骤 &#x1f33c;2. 验证 &#x1f337;一、域名解析基础知识 &#x1f33c;1. 基本概念 定义&#xff1a; …

微信小程序开发scroll-view在预览或真机调试仅显示第一个元素解决方案

现象如下&#xff1a; 在编译时显示正常&#xff1a; 在预览或真机调试时仅显示第一个元素&#xff1a; 解决方案&#xff1a;将app.json文件中renderer类型由skyline改为webview 更多微信小程序内容欢迎关注我&#xff01; 有帮助的话欢迎打赏&#xff01;

二次开发RuoYi-Vue操作记录

二次开发RuoYi-Vue操作记录 一、本地启动修改1、修改文件路径2、修改redis配置3、数据源配置4、导入sql 二、新增模块1、创建模块2、添加依赖 三、新增页面1、数据准备2、代码生成3、菜单管理&#xff08;1&#xff09;目录创建&#xff08;2&#xff09;菜单创建&#xff08;3…

ESP32开发板可以承受的最大电压

ESP32的最大工作电压为3.3V。但这并不意味着我们不能向 ESP32开发板施加大于 3.3V 的电压。ESP32 具有板载稳压器&#xff0c;使用 VIN 和 GND 引脚可承受最大 15V 的电压。 一旦电压输入到 ESP32 开发板VIN 引脚&#xff0c;该电压就会通过 ESP32 板载稳压器&#xff08;AMS11…

宏景eHR SmsAcceptGSTXServlet XXE漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR SmsAcceptGSTXServlet接口处存在XML实体注入漏洞,未经身份认证的攻击者可以利用此漏洞读取系统内部敏感文件,获取敏…

群辉NAS的远程访问

群辉NAS是私有云存储&#xff0c;局域网访问很容易【详见&#xff1a;网上邻居访问设置、其它设备的访问设置】&#xff0c;远程访问相对复杂&#xff0c;涉及很多关键因素&#xff0c;现将过程记录如下&#xff1a; 目录 1、互联网接入 2、绑定MAC与IP地址 3、路由器开启5…

qml中访问控件内部的子项

如何访问Repeater类型内部的子项、Row等布局类型内部的子项以及ListView内部的子项等。。。 1、测试代码 import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 import QtQuick.Layouts 1.3 import QtQml 2.12Window {id: windowobjectName: "m…

米贸搜|Facebook“精准营销”越来越难?或许是“受众定位”没彻底搞清!

一、为何要确定目标受众 对于每个广告主而言&#xff0c;面向最有可能成为其客户的用户营销非常重要&#xff0c;因此&#xff0c;确定目标受众&#xff0c;是Facebook广告投放中极其重要的一环。 二、什么是目标受众&#xff1f; 目标受众是您希望向其传达营销信息&#xf…

java servlet 高校田径运动会管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 jsp高校田径运动会管理系统是一套完善的java web信息管理系统 采用mvc模式 servletdaobean 模式开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myecl…

“JavaScript 循环中的 ‘await‘

目录 前言 for使用await -- 有效的 forEach使用await -- 无效的 for of 使用await 有效的 for await of 使用await 有效的 总结 前言 在JavaScript的forEach方法中使用await是无效的&#xff0c;因为forEach方法不支持异步操作的等待。 forEach是一个数组的遍历方法&…

如何修改hosts文件-mac

1、什么是hosts文件&#xff1f; Hosts是一个没有扩展名的系统文件&#xff0c;可以用记事本等工具打开&#xff0c;其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”&#xff0c;即域名映射到IP地址&#xff0c;域名是为了方便人类记忆识别&#xff0c…