imx6ull/linux应用编程学习(11)CAN应用编程基础

news2024/11/26 8:59:03

关于裸机的can通信,会在其他文章发,这里主要讲讲linux上的can通信。

        与I2C,SPI等同步通讯方式不同,CAN通讯是异步通讯也就是没有时钟信号线来保持信号接收同步,也就是所说的半双工,无法同时发送与接收,在同一时刻,只能有一个节点发送数据,其余节点都只能接收数据。它有CAN_HIGH与CAN_LOW两条信号线组成。

CAN通信的关键特征

  1. 异步通信

    • CAN通信是异步的,这意味着它不使用独立的时钟信号线来同步发送和接收信号。每个节点自带时钟,通过位定时(bit timing)机制来确保数据同步。
  2. 半双工通信

    • CAN是半双工通信,这意味着在任一时刻,网络上只有一个节点可以发送数据,其余所有节点只能接收数据。发送和接收不能同时进行。
  3. 差分信号线

    • CAN使用两条信号线:CAN_H(CAN High)CAN_L(CAN Low),这两条信号线用于传输差分信号。差分信号有助于增强抗干扰能力,适合长距离传输。
  4. 仲裁机制

    • CAN采用非破坏性仲裁机制(Non-Destructive Arbitration),在总线上多个节点尝试发送数据时,优先级高的节点会优先发送,低优先级的节点会自动退出并等待下一个发送机会。

与I2C和SPI的区别

  1. 时钟信号

    • I2C:同步通信协议,使用SCL(时钟线)和SDA(数据线)进行通信,同步数据传输。
    • SPI:同步通信协议,使用主时钟(SCK)、主出从入(MOSI)、主入从出(MISO)和片选(CS)进行通信。
    • CAN:异步通信,没有时钟信号线,使用位定时机制同步数据传输。
  2. 通信模式

    • I2C:支持多主多从模式,但通常只有一个主设备主动发起通信。
    • SPI:主从模式,通常一个主设备控制多个从设备。
    • CAN:多主模式,任一节点都可以主动发送数据。
  3. 双工方式

    • I2C:半双工通信,数据线在一次通信中只能单向传输。
    • SPI:全双工通信,可以同时发送和接收数据。
    • CAN:半双工通信,一次只能有一个节点发送数据,其余节点接收。

如果是发送数据:控制器发送一个信号(0或1),收发器将这个信号变成差分信号传送到总线中。
若果是接收数据:收发器将差分信号转化为0或1的二进制编码;

差分信号其实使用CAN_HIGH减去CAN_LOW的到的,在逻辑信号中,5V代表1, 0V代表0,而在差分信号中
0V---------逻辑1------隐形电平
2.0V-------逻辑0-----显性电平

        以汽车电子为例,汽车上有空调、车门、发动机、大量传感器等,这些部件、模块都是通过 CAN 总线连在一起形成一个网络,车载网络构想图如下所示

CAN的特点:

(1)、多主控制

        在总线空闲时,所有的单元都可开始发送消息(多主控制)。最先访问总线的单元可获得发送权(CSMA/CA 方式*1)。

        多个单元同时开始发送时,发送高优先级 ID 消息的单元可获得发送权

(2)、消息的发送

        在 CAN 协议中,所有的消息都以固定的格式发送。总线空闲时,所有与总线相连的单元都可以开始发送新消息。两个以上的单元同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。 ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。

(3)、系统的柔软性

与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。

(4)、通信速度

        根据整个网络的规模,可设定适合的通信速度。

        在同一网络中,所有单元必须设定成统一的通信速度。即使有一个单元的通信速度与其它的不一样,此单元也会输出错误信号,妨碍整个网络的通信。不同网络间则可以有不同的通信速度。

(5)、远程数据请求

        可通过发送“遥控帧” 请求其他单元发送数据。

(6)、具有错误检测功能·错误通知功能·错误恢复功能

        所有的单元都可以检测错误(错误检测功能)。

        检测出错误的单元会立即同时通知其他所有单元(错误通知功能)。

        正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。

(7)、故障封闭

        CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。

(8)、连接

        CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。

CAN 的电气属性
 

        CAN 总线使用两根线来连接各个单元: CAN_H 和 CAN_L, CAN 控制器通过判断这两根线上的电位差来得到总线电平, CAN 总线电平分为显性电平和隐性电平两种。显性电平表示逻辑“0”,此时 CAN_H 电平比 CAN_L 高,分别为 3.5V 和 1.5V,电位差为 2V。隐形电平表示逻辑“1”,此时 CAN_H 和 CAN_L 电压都为 2.5V 左右,电位差为 0V。 CAN 总线就通过显性和隐形电平的变化来将具体的数据发送出去,如下图所示:

        

CAN 网络拓扑

        CAN 是一种分布式的控制总线, CAN 总线作为一种控制器局域网,和普通的以太网一样,它的网络由很多的 CAN 节点构成, 其网络拓扑结构如下图所示:

CAN 网络的每个节点非常简单,均由一个 MCU(微控制器)、一个 CAN 控制器和一个 CAN 收发器构成, 然后通过 CAN_H 和 CAN_L 这两根线连接在一起形成一个 CAN 局域网络。 CAN 能够使用多种物理介质,例如双绞线、光纤等。最常用的就是双绞线。信号使用差分电压传送,两条信号线被称为“CAN_H”和“CAN_L” ,在我们的开发板上, CAN 接口使用了这两条信号线, CAN 接口也只有这两条信号线。

can总线通信模型

        CAN 总线传输协议参考了 OSI 开放系统互连模型,但是实际上 CAN 协议只定义了“传输层” 、 “数据链路层”以及“物理层”这三层

        数据链路层分为 MAC 子层和 LLC 子层, MAC 子层是 CAN 协议的核心部分。数据链路层的功能是将物理层收到的信号组织成有意义的消息,并提供传送错误控制等传输控制的流程。具体地说,就是消息的帧化、仲裁、应答、错误的检测或报告。数据链路层的功能通常在 CAN 控制器的硬件中执行。

CAN帧的种类

        CAN 通信协议定义了 5 种类型的报文帧,分别是:数据帧、遥控帧、错误帧、过载帧、间隔帧。 通信是通过这 5 种类型的帧进行的。 其中数据帧和遥控帧有标准格式和扩展格式两种,标准格式有 11 位标识符(ID),扩展格式有 29 个标识符(ID)。这 5 种类型的帧如下表所示:

其中数据帧是使用最多的帧类型

        图中 D 表示显性电平 0、 R 表示隐性电平 1, D/R 表示显性或隐性,也就是 0 或 1,我们来简单分析一下数据帧的这 7 个段

数据帧由 7 个段构成:

(1)、帧起始

        表示数据帧开始的段。

(2)、 仲裁段

        表示该帧优先级的段。

(3)、控制段

        表示数据的字节数及保留位的段。

(4)、数据段

        数据的内容,可发送 0~8 个字节的数据

(5)、 CRC 段

        检查帧的传输错误的段。

(6)、 ACK 段

         表示确认正常接收的段。

(7)、帧结束

        表示数据帧结束的段

SocketCan 应用编程
 

        CAN 总线套接字的创建采用标准的网络套接字操作来完成, 网络套接字在头文件<sys/socket.h>中定义。创建 CAN 套接字的方法如下:

int sockfd = -1;
/* 创建套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}

        第一个参数用于指定通信域,在 SocketCan 中,通常将其设置为PF_CAN,指定为CAN通信协议;第二个参数用于指定套接字的类型,通常将其设置为SOCK_RAW;第三个参数通常设置为 CAN_RAW。

将套接字与 CAN 设备进行绑定


        譬如,将创建的套接字与 can0 进行绑定,示例代码如下所示

.....
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
int ret;
......
strcpy(ifr.ifr_name, "can0"); //指定名字
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN; //填充数据
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将套接字与 can0 进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
设置过滤规则
 

        在我们的应用程序中,如果没有设置过滤规则,应用程序默认会接收所有 ID 的报文;如果我们的应用程序只需要接收某些特定 ID 的报文(亦或者不接受所有报文,只发送报文),则可以通过 setsockopt 函数设置过滤规则, 譬如某应用程序只接收 ID 为 0x60A 和 0x60B 的报文帧,则可将其它不符合规则的帧全部给过滤掉, 示例代码如下所示:

struct can_filter rfilter[2]; //定义一个 can_filter 结构体对象
// 填充过滤规则,只接收 ID 为(can_id & can_mask)的报文
rfilter[0].can_id = 0x60A;
rfilter[0].can_mask = 0x7FF;
rfilter[1].can_id = 0x60B;
rfilter[1].can_mask = 0x7FF;
// 调用 setsockopt 设置过滤规则
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

        struct can_filter 结构体中只有两个成员, can_id 和 can_mask。

        如果应用程序不接收所有报文, 在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少CPU 资源的消耗。 此时可将 setsockopt()函数的第 4 个参数设置为 NULL,将第 5 个参数设置为 0,如下所示

setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
数据发送/接收


        在数据收发的内容方面, CAN 总线与标准套接字通信稍有不同,每一次通信都采用 struct can_frame 结构体将数据封装成帧。结构体定义如下

struct can_frame {
canid_t can_id; /* CAN 标识符 */
__u8 can_dlc; /* 数据长度(最长为 8 个字节) */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[8]; /* 数据 */
};

        can_id 为帧的标识符,如果是标准帧,就使用 can_id 的低 11 位;如果为扩展帧,就使用 0~28 位。can_id 的第 29、 30、 31 位是帧的标志位,用来定义帧的类型,定义如下:

/* special address description flags for the CAN_ID */
#define CAN_EFF_FLAG 0x80000000U /* 扩展帧的标识 */
#define CAN_RTR_FLAG 0x40000000U /* 远程帧的标识 */
#define CAN_ERR_FLAG 0x20000000U /* 错误帧的标识,用于错误检查 */
/* mask */
#define CAN_SFF_MASK 0x000007FFU /* <can_id & CAN_SFF_MASK>获取标准帧 ID */
#define CAN_EFF_MASK 0x1FFFFFFFU /* <can_id & CAN_EFF_MASK>获取标准帧 ID */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
(1)、数据发送

        对于数据发送,使用 write()函数来实现,譬如要发送的数据帧包含了三个字节数据 0xA0、 0xB0 以及0xC0,帧 ID 为 123,可采用如下方法进行发送:

struct can_frame frame; //定义一个 can_frame 变量
int ret;
frame.can_id = 123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 123;
frame.can_dlc = 3; //数据长度为 3
frame.data[0] = 0xA0; //数据内容为 0xA0
frame.data[1] = 0xB0; //数据内容为 0xB0
frame.data[2] = 0xC0; //数据内容为 0xC0
ret = write(sockfd, &frame, sizeof(frame)); //发送数据
if(sizeof(frame) != ret) //如果 ret 不等于帧长度,就说明发送失败
perror("write error");

如果要发送远程帧(帧 ID 为 123),可采用如下方法进行发送:
 

struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | 123;
write(sockfd, &frame, sizeof(frame));
(2)、数据接收
 

        数据接收使用 read()函数来实现,如下所示:

struct can_frame frame;
int ret = read(sockfd, &frame, sizeof(frame));
(3)、错误处理
 

        当应用程序接收到一帧数据之后,可以通过判断 can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。错误帧的符号位在头文件<linux/can/error.h>中定义

/* error class (mask) in can_id */
#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */
#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */
#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */
#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */
#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */
#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */
#define CAN_ERR_BUSOFF 0x00000040U /* bus off */
#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
......
......

回环功能设置
 

        在默认情况下, CAN 的本地回环功能是开启的,可以使用下面的方法关闭或开启本地回环功能

int loopback = 0; //0 表示关闭, 1 表示开启(默认)
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

在本地回环功能开启的情况下,所有的发送帧都会被回环到与 CAN 总线接口对应的套接字上。
 

编程实战(正点源码)

        在进行测试之前需要对开发板上的 can 设备进行配置,执行以下命令:

ifconfig can0 down #先关闭 can0 设备
ip link set can0 up type can bitrate 1000000 triple-sampling on #设置波特率为 1000000

        注意, CAN 分析仪设置的波特率要和开发板 CAN 设备的波特率一致!配置完成之后,接着可以使用 cansend 命令发送数据,可以用can收发器,波特率和上面设置的一样,设为1000k

cansend can0 123#01.02.03.04.05.06.07.08

“#”号前面的 123 表示帧 ID,后面的数字表示要发送的数据,此时上位机便会接收到开发板发送过来的数据,如下所示

接着测试开发板接收 CAN 数据,首先在开发板上执行 candump 命令:
 

candump -ta can0

CAN 数据发送实例
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
int main(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
struct can_frame frame = {0};
int sockfd = -1;
int ret;
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}
/* 指定 can0 设备 */
strcpy(ifr.ifr_name, "can0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将 can0 与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
/* 设置过滤规则:不接受任何报文、仅发送数据 */
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* 发送数据 */
frame.data[0] = 0xA0;
frame.data[1] = 0xB0;
frame.data[2] = 0xC0;
frame.data[3] = 0xD0;
frame.data[4] = 0xE0;
frame.data[5] = 0xF0;
frame.can_dlc = 6; //一次发送 6 个字节数据
frame.can_id = 0x123;//帧 ID 为 0x123,标准帧
for ( ; ; ) {
ret = write(sockfd, &frame, sizeof(frame)); //发送数据
if(sizeof(frame) != ret) { //如果 ret 不等于帧长度,就说明发送失败
perror("write error");
goto out;
}
sleep(1); //一秒钟发送一次
}
out:
/* 关闭套接字 */
close(sockfd);
exit(EXIT_SUCCESS);
}

CAN 数据接收
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
int main(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
struct can_frame frame = {0};
int sockfd = -1;
int i;
int ret;
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}
/* 指定 can0 设备 */
strcpy(ifr.ifr_name, "can0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将 can0 与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
/* 设置过滤规则 */
//setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* 接收数据 */
for ( ; ; ) {
if (0 > read(sockfd, &frame, sizeof(struct can_frame))) {
perror("read error");
break;
}
/* 校验是否接收到错误帧 */
if (frame.can_id & CAN_ERR_FLAG) {
printf("Error frame!\n");
break;
}
/* 校验帧格式 */
if (frame.can_id & CAN_EFF_FLAG) //扩展帧
printf("扩展帧 <0x%08x> ", frame.can_id & CAN_EFF_MASK);
else //标准帧
printf("标准帧 <0x%03x> ", frame.can_id & CAN_SFF_MASK);
/* 校验帧类型:数据帧还是远程帧 */
if (frame.can_id & CAN_RTR_FLAG) {
printf("remote request\n");
continue;
}
/* 打印数据长度 */
printf("[%d] ", frame.can_dlc);
/* 打印数据 */
for (i = 0; i < frame.can_dlc; i++)
printf("%02x ", frame.data[i]);
printf("\n");
}
/* 关闭套接字 */
close(sockfd);
exit(EXIT_SUCCESS);
}

电脑发送数据:

开发板接收

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YARN运行流程源码分析

一、yarn任务执行流程图 在分析任务之前先走一下yarn内部的流程细节。 二、RM 内部处理提交阶段运行流程 如上图流程所示&#xff1a; 1.client 提交任务给yarn&#xff0c;yarn 这边会获取任务的AM相关资源&#xff0c;client在提交阶段会上传job.split &#xff08;数据切分…

Mysql-01-主从搭建

一、安装Mysql 下载 https://downloads.mysql.com/archives/community/ 安装 注意顺序 tar -xvf mysql-8.0.38-1.el9.x86_64.rpm-bundle.tar rpm -ivh mysql-community-common-8.0.38-1.el9.x86_64.rpm rpm -ivh mysql-community-client-plugins-8.0.38-1.el9.x86_64.r…

Vue3重构案例(使用vue3的语法重构element的button组件)

这篇文章紧接的上一篇文章&#xff0c;上篇文章是对给element的button组件写了一个单元测试&#xff0c;这篇文章是使用vue3的语法进行重构&#xff0c;这里说一下单元测试和重构的联系&#xff0c;当你给组件写了单元测试之后&#xff0c;重构会减少你很多的debug时间&#xf…

jdk22+maven环境配置教程+idea的maven环境配置(Windows系统)

前言 jdk是Java开发必要的编程环境&#xff0c;idea是常用的Java开发工具&#xff0c;这里着重解释一下maven。 maven就是我们经常看见的pom.xml文件&#xff0c;maven有以下三点功能&#xff1a; 1.项目构建&#xff08;可以帮助我们更快速的打包、构建项目&#xff09; 2.依…

数据操作10-15题(30 天 Pandas 挑战)

数据操作 1. 相关知识点1.12 分组与连表1.13 排名 2. 题目2.10 第N高的薪水2.11 第二高的薪水2.12 部门工资最高的员工2.13 分数排名2.14 删除重复的电子邮箱2.15 每个产品在不同商店的价格 1. 相关知识点 1.12 分组与连表 分组max_salaryemployee.groupby(departmentId)[sal…

【leetcode】双指针算法题

文章目录 1.算法思想2.移动零3.复写零方法一方法二 4.快乐数5.盛水最多的容器方法一&#xff08;暴力求解&#xff09;方法二&#xff08;左右指针&#xff09; 6.有效三角形的个数方法一&#xff08;暴力求解&#xff09;方法二&#xff08;左右指针&#xff09; 7.两数之和8.…

k8s学习--基于k8s的ELK日志收集的详细过程

文章目录 FilebeatFilebeat主要特点Filebeat使用场景 ELK简介Elasticsearch简介Elasticsearch主要特点Elasticsearch使用场景 Logstash简介Logstash主要特点Logstash使用场景 Kibana简介Kibana主要特点Kibana使用场景 简单理解 环境一、ELK集群部署1.软件安装2.软件配置及启动(…

【python】PyQt5控件尺寸大小位置,内容边距等API调用方法实战解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Java毕业设计 基于SSM vue新生报到系统小程序 微信小程序

Java毕业设计 基于SSM vue新生报到系统小程序 微信小程序 SSM 新生报到系统小程序 功能介绍 学生 登录 注册 忘记密码 首页 学校公告 录取信息 录取详情 师资力量 教师详情 收藏 评论 用户信息修改 宿舍安排 签到信息 在线缴费 教室分配 我的收藏管理 我要发贴 我的发贴 管理…

STM32外扩SRAM及用法

一.概述 一般单片机有片内的RAM&#xff0c;但都不多&#xff0c;比如&#xff1a;STM32F407ZGT6 自带了 192K 字节的 RAM&#xff0c;对一般应用来说&#xff0c;已经足够了&#xff0c;不过在一些对内存要求高的场合&#xff0c;比如做华丽效果的 GUI&#xff0c;处理大量数据…

ionic7 使用Capacitor打包 apk 之后,设置网络权限

报错处理 在打包的时候遇到过几个问题&#xff0c;这里记录下来两个 Visual Studio Code运行ionic build出错显示ionic : 无法加载文件 ionic 项目通过 android studio 打开报错 capacitor.settings.gradle 文件不存在 ionic7 项目初始化以及打包 apk 这篇文章讲到了如果安装…

Java+前后端分离架构+ MySQL8.0.36产科信息管理系统 产科电子病历系统源码

Java前后端分离架构 MySQL8.0.36产科信息管理系统 产科电子病历系统源码 产科信息管理系统—住院管理 数字化产科住院管理是现代医院管理中的重要组成部分&#xff0c;它利用数字化技术优化住院流程&#xff0c;提升医疗服务质量和效率。以下是对数字化产科住院管理的详细阐述…

您的私人办公室!-----ONLYOFFICE8.1版本的桌面编辑器测评

随时随地创建并编辑文档&#xff0c;还可就其进行协作 ONLYOFFICE 文档是一款强大的在线编辑器&#xff0c;为您使用的平台提供文本文档、电子表格、演示文稿、表单和 PDF 编辑工具。 网页地址链接&#xff1a; https://www.onlyoffice.com/zh/office-suite.aspxhttps://www…

2个方法教你轻松移除pdf文件编辑限制

PDF是一种常见的办公文档格式&#xff0c;常用于文件共享和保护。然而&#xff0c;有时候我们需要编辑PDF文件中的内容&#xff0c;但受到了编辑限制。本文将介绍一些有效的方法&#xff0c;帮助您解除PDF的编辑限制&#xff0c;轻松进行编辑和修改。 一、通过密码取消PDF“限制…

运维锅总详解计算机缓存溢出

本文尝试从缓存溢出、如何平衡防止缓存溢出和OOM、conntrack缓存满载影响及优化措施、TCP/IP协议栈缓存满载影响及优化措施等方面对计算机缓存溢出进行详细分析&#xff0c;最后给出一些缓存满载的Prometheus告警规则。希望对您有所帮助&#xff01; 一、计算机缓存溢出简介 …

卫星轨道平面简单认识

目录 一、轨道平面 1.1 轨道根数 1.2 应用考虑 二、分类 2.1 根据运行高度 2.2 根据运行轨迹偏心率 2.3 根据倾角大小 三、卫星星座中的轨道平面 四、设计轨道平面的考虑因素 一、轨道平面 1.1 轨道根数 轨道平面是定义卫星或其他天体绕行另一天体运动的平面。这个平…

通过端口和进程pid查找启动文件/脚本

今天审计一个程序又让GPT给我上了一课&#xff0c;记一下笔记&#xff1a; 1、首先该程序开启了8080端口&#xff0c;使用如下命令得到pid为1817 netstat -tunlp|grep 80802、使用pid得到父进程 pstree -ps 1817输出结果如下&#xff1a; 3、看出程序是由systemd启动的&…

nginx安装演示(离线安装,直接安装在Linux中)

文章目录 1、创建文件夹 tool / nginx2、把安装文件放到 /opt/tool/nginx 目录下面3、yum install gcc4、yum install gcc-c5、tar -zxvf pcre-8.37.tar.gz6、./configure7、make8、make install9、tar -zxvf openssl-1.0.1t.tar.gz10、./config11、/config 1、创建文件夹 tool…

python绘制领域矩形

问题描述&#xff1a; 使用python书写代码实现以下功能&#xff1a;给定四个点的坐标&#xff0c;调用一个函数&#xff0c;可以使原来的四个点分别向四周上下左右移动15距离&#xff0c;分别记录下移动后的坐标&#xff0c;然后画出内侧矩形和外侧矩形 代码&#xff1a; im…

电脑为什么会提示丢失msvcp140.dll?怎么修复msvcp140.dll文件会靠谱点

电脑为什么会提示丢失msvcp140.dll&#xff1f;其实只要你的msvcp140.dll文件一损坏&#xff0c;然而你的电脑程序需要运用到这个msvcp140.dll文件的时候&#xff0c;就回提示你丢失了msvcp140.dll文件&#xff01;因为没有这个文件&#xff0c;你的很多程序都用不了的。今天我…