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

关于裸机的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);
}

电脑发送数据:

开发板接收

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

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

相关文章

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

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

小(微)间距P1.538COB渠道现货销售将加速全面升级替换SMD产品。

COB&#xff08;Chip on Board&#xff09;技术&#xff0c;如一颗璀璨的星辰&#xff0c;在上世纪60年代的科技夜空中悄然升起。它巧妙地将LED芯片镶嵌在PCB电路板的怀抱中&#xff0c;再用特种树脂为其披上一层坚韧的外衣&#xff0c;宛如一位精心雕琢的艺术家在创作一幅完美…

【Python机器学习】处理文本数据——用tf-idf缩放数据

为了按照我们预计的特征信息量大小来缩放特征&#xff0c;而不是舍弃那些认为不重要的特征&#xff0c;最常见的一种做法就是使用词频-逆向文档频率&#xff08;tf-idf&#xff09;。这一方法对某个特定文档中经常出现的术语给与很高的权重&#xff0c;但是堆在语料库的许多文档…

【UE5.1】Chaos物理系统基础——04 事件驱动粒子效果

目录 效果 步骤 一、炸开时的烟雾效果 二、炸开时的碎片效果 效果 步骤 一、炸开时的烟雾效果 1. 选中场景中的几何体集&#xff0c;勾选“通知中断”&#xff0c;这样当几何体集解体时就能产生一个事件&#xff1b;勾选“通知碰撞”&#xff0c;当几何体集检测到碰撞也能…

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

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

华火电燃喷火单灶再荣获中国质量认证中心 CQC 权威证书,引领行业新高度

近日&#xff0c;华火传来了一则令整个行业瞩目的重大喜讯&#xff1a;其电燃喷火单灶“再度”成功荣获中国质量认证中心&#xff08;CQC&#xff09;权威证书。这一里重大程碑式的成就&#xff0c;不仅是对华火产品卓越品质的高度认可&#xff0c;更是华火在品牌发展道路上的一…

网安小贴士(8)IPv4与IPv6

一、前言 IPv4和IPv6都是互联网协议&#xff08;IP&#xff09;的版本&#xff0c;它们用于在互联网上标识和定位设备。 二、定义 IPv4&#xff08;互联网协议第四版&#xff09;&#xff1a; IPv4是互联网协议的第一个广泛使用的版本&#xff0c;最初在1981年被标准化为RFC 7…

单位立方体各个面上的法向量,向量场以及每个面上的通量

单位立方体各个面上的法向量&#xff0c;向量场 F ( x , y , z ) \mathbf{F} (x, y, z) F(x,y,z) 以及每个面上的通量 flyfish 假设我们有一个单位立方体&#xff0c;向量场 F ( x , y , z ) \mathbf{F} (x, y, z) F(x,y,z) 在该立方体上。 法向量 &#xff1a;单位立方…

中霖教育:二建报名成功后怎么审核?

【中霖教育怎么样】【中霖教育靠谱吗】 在成功完成二级建造师资格考试的报名流程后&#xff0c;需要准备后续的审核阶段&#xff0c;审核是否通过关乎考生是否能顺利参加考试&#xff0c;审核的方式包括&#xff1a;现场审核、网络审核以及考试后的审核。 某些地区会要求考生…

空间数据获取与预处理指南:生产与科研应用

1.空间数据简介 2.免费的国外GIS数据下载方法 3.免费的国内GIS数据下载方法 4.遥感云平台数据的获取方法 5.专题数据的获取及预处理示例 (1)行政区划数据 (2)气象数据 (3)土壤数据 (4)遥感产品数据 (5)统计数据 (6)…… 原文链接https://mp.weixin.qq.com/s?__bizMz…

实验三 图像增强—灰度变换

一、实验目的&#xff1a; 1、了解图像增强的目的及意义&#xff0c;加深对图像增强的感性认识&#xff0c;巩固所学理论知识。 2、学会对图像直方图的分析。 3、掌握直接灰度变换的图像增强方法。 二、实验原理及知识点 术语‘空间域’指的是图像平面本身&#xff0c;在空…

【MySQL系列】隐式转换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

构建Android studio版的CarSystemUI工程时因为包名一致导致BuildConfig问题

项目场景&#xff1a; 公司计划开发杰发AC8025-Android 12版本车载平台&#xff0c;前期预研需要构建Android studio版的CarSystemUI工程 问题描述 AAOS车载项目里面的CarSystemUI源码默认无Android studio版本&#xff0c;为了后期快速开发调试需要构建Android studio能直接…

python多线程与多进程开发实践及填坑记(1)

1. 需求分析 1.1. 概述 基于Flask、Pika、Multiprocessing、Thread搭建一个架构&#xff0c;完成多线程、多进程工作。具体需求如下&#xff1a; 并行计算任务&#xff1a;使用multiprocessing模块实现并行计算任务&#xff0c;提高计算效率、计算能力。消息侦听任务&#x…

大厂都在加急招人的大模型LLM,到底怎么学?

大模型如何入坑&#xff1f; 想要完全了解大模型&#xff0c;你首先要了解市面上的LLM大模型现状&#xff0c;学习Python语言、Prompt提示工程&#xff0c;然后深入理解Function Calling、RAG、LangChain 、Agents等 很多人不知道想要自学大模型&#xff0c;要按什么路线学&a…

电脑刚删除的文件怎么恢复?可使用这几种恢复方法!

在日常生活和工作中&#xff0c;我们时常会在电脑上进行各种文件操作&#xff0c;包括删除不需要的文件。然而&#xff0c;有时候我们可能会误删一些重要的文件&#xff0c;或者在删除后立刻意识到这些文件的重要性。 那么&#xff0c;电脑刚删除的东西怎么恢复呢&#xff1f;本…

神领物流项目第一天

文章目录 聚焦快递领域首先第一个是验证码模块流程登录接口权限管家 聚焦快递领域 首先第一个是验证码模块流程 首先生成验证码的流程 可以使用工具类去生成验证码 LineCaptcha lineCaptcha CaptchaUtil.createLineCaptcha(160, 60, 4, 26);// 获取值然后存入redis中 strin…

WEB04MyBatis

Mybatis mybatis查询 准备 准备工作 在目前的数据库中添加一张数据表emp 将资料中提供的day04-01-mybatis导入的目前的工程中 修改配置文件中的数据库的账户和密码 观察实体类中的属性和数据表中的字段的对应关系 查询结果封装 查询所有 SQL语句 select * from emp; …

基于Oauth2.0的OpenFeign远程调用

目录 前言 1.引入openfeign相关依赖 2.开启openFeign远程调用&#xff0c;在启动类头加上注解即可 3. 提供远程调用接口&#xff0c;接口名称必须与controler名称保持一致 4.远程调用关键代码 4.1 注入restTemplate 4.2 配置拦截器 4.3 设置请求头 4.4 获取请求结果 4.5 远…

两次叛国投敌,没有祸及子孙反而家族长盛不衰的传奇

这个人就是韩国国王韩王信&#xff0c;汉朝八大异姓王之一。 第一次叛国投敌&#xff0c;发生在楚汉争霸时期。有一次他的军队被项羽包围&#xff0c;于是选择了投降。不过&#xff0c;这是权宜之计&#xff0c;不久就借机回到刘邦阵营。 第二次叛国投敌&#xff0c;发生在西…