[AUTOSAR][诊断管理][ECU][$19] 读取ECU的DTC故障信息

news2024/12/23 13:05:13

一、简介

  1. 在车载诊断中常用的诊断协议有ISO 14229等,在协议中主要定义了诊断请求、诊断响应的报文格式及ECU该如何处理诊断请求的应用。
  2. 其中ISO 14229系列标准协议定义了用于行业内诊断通信的需求规范,也就是UDS。UDS主要应用于OSI七层模型的第七层——应用层,它支持的汽车总线包括:CAN、LIN、FlexRay、Ethernet及K-LINE。
  3. UDS中的服务根据其功能分为6大类,共26种。其中包含的0x19服务(ReadDTCInformation)则是UDS中的重中之重。那么我们今天就一起进入到19服务中,感受其中的奥秘。

二、 服务介绍

19服务(ReadDTCInformation)用于读取ECU的DTC故障信息,此服务允许客户端从服务器读取诊断故障代码(DTC)的相关信息。此服务包含28个子服务(Subfunction),常用的5种子服务如下:

  • 0x01 reportNumberOfDTCByStatusMask(读取客户端定义状态掩码匹配的DTC数量)
  • 0x02 reportDTCByStatusMask(读取客户端定义状态掩码匹配的DTC)
  • 0x04 reportDTCSnapshotRecordByDTCNumber(检索客户端定义DTC掩码的快照数据)
  • 0x06 reportDTCExtDataRecordByDTCNumber(读取某个DTC及其相关的扩展数据,扩展数据包括DTC状态,优先级,发生次数,时间戳,里程等。)
  • 0x0A reportSupportedDTC(读取ECU支持的所有DTC的状态,包含支持的各个DTC编号以及相关状态)

今天主要解析19服务中的04子服务,也就是检索客户端定义DTC的快照号对应的快照记录数据,在AUTOSAR中也叫冻结帧。

(1)子服务介绍

  1. 快照数据概念介绍
    前面讲19服务常用子服务的时候,提到了Subfunction为04的子服务,使用04子服务对服务端进行请求,可以获取DTC发生时记录的快照数据。那04子服务是如何获取快照数据的呢?首先我们需要理解什么是快照数据。从ISO 14229-1协议可知,快照数据为发生某一故障时记录的DTC的电压、发动机转速、时间戳等,从而使工程师在ECU出现故障时能及时了解车辆的历史和实时故障信息。

  2. 报文格式介绍
    接下来通过介绍19 04子服务请求和响应的报文格式,分析报文中各个字节的相关定义。

请求格式

在这里插入图片描述
从图1中可知,19 04的请求报文包括四个部分,其中服务ID和Subfunction就不用过多解释了。DTCMaskRecord表示某个故障的DTC,当系统检测到一个故障发生时,则会存储其对应的故障数值,这个故障数值就是DTC。通过读取DTC可知一个故障发生时的具体位置以及原因和类型。通常UDS中DTC占3个字节,OBD Ⅱ占2个字节,在ISO 15031-6中定义的DTC由两个字节根基和一个字节的故障类型组成。我们通常用到的DTC格式都是由ISO 15031-6中定义的。图2是ISO 15031-6中定义的DTC的两个字节根基,图中很详细地解释了每一个Bit的含义。

在这里插入图片描述
SnapshotRecordNumber需要提前定义,可以有多个。如SnapshotRecordNumber设置为FF,则表示读取所有的快照数据组。

响应格式

图3
图3为响应报文格式,当使用19 04对ECU进行请求时,ECU给出的肯定响应的报文格式由七部分组成。此时的DTCAndStatusRecord由三个字节的DTC和一个字节的StatusOfDTC组成,StatusOfDTC表示DTC的状态。假设现在的DTC状态为0x09,则Bit0和Bit3置1。如某个DTC一直存在并且确认,则在ECU响应的报文中的StatusOfDTC为0x09。如图4
图4
SnapshotRecordNumber这个字节表示DTC快照记录的组号;DTCSnapshotRecordNumberOfldentifiers表示快照DID的个数,占一个字节;Dataldentifier这部分由两个字节组成,表示快照数据对应的DID,DTCSnapshotRecord表示快照DID对应的具体数据。

三、示例代码

(1)19_read_dtc_info.c

/********************************************************************************
* @file    19_read_dtc_info.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2023-05-30
* @brief   读取DTC信息
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "modules.h"
#include "os_api.h"
#include "edebug.h"
#include "kv_sys.h"
#include "ecu_ble_uart.h"
/* Private includes ----------------------------------------------------------*/
#include "std_math.h"
#include "app_can.h"
#include "can_nm.h"
#include "app_nm.h"
#include "diag_main.h"
#if AUTOSAR_DIAG_DTC_SWITCH
#include "dtc_main.h"
#endif
/* Private define ------------------------------------------------------------*/
#define UDS_ID         0x19
#define MAX_BUFF_SIZE  150
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/***************软定时器创建***************/
/* Private func --------------------------------------------------------------*/

/**
 * @brief  通过状态掩码报告DTC数目
 * @param  *data: 数据指针
 * @param  len: 数据长度
 * @retval 0--成功  >0--错误
 */
static int8_t uds19_01(uint8_t *data, uint16_t len, uint8_t *out) {
    if (len != 3) {
        LOGE("len err != 3, sub%02x", data[1]);
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        return 1;
    }
    if (data[1] & 0x80) { // 无需应答
        LOGI("No answer required, sub%02x", data[1]);
    } else {
        // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID,
        out[0] = 6;  // 数据总长度= 服务号 + sub_id + mask + data + num(2byte)
        out[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
        out[2] = data[1];
        out[3] = AUTOSAR_DIAG_DTC_STATE_BIT; // 获取DTC掩码
        out[4] = 0; // SAE_J2012-DA_DTCFormat_00

        uint16_t dtc_count = get_dtc_num_by_mask(data[2]);
        out[5] = (uint8_t)(dtc_count >> 8);
        out[6] = (uint8_t)(dtc_count & 0xFF);
        out[7] = 0xAA;
        app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
    }
    return 0;
}

/**
 * @brief  通过状态掩码报告DTC
 * @param  *data: 数据指针
 * @param  len: 数据长度
 * @retval 0--成功  >0--错误
 */
static int8_t uds19_02(uint8_t *data, uint16_t len, uint8_t *out) {
    if (len != 3) {
        LOGE("len err != 3, sub%02x", data[1]);
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        return 1;
    }
    if (data[1] & 0x80) { // 无需应答
        LOGI("No answer required, sub%02x", data[1]);
    } else {
        // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID,
        out[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
        out[2] = data[1];
        out[3] = AUTOSAR_DIAG_DTC_STATE_BIT; // 获取DTC掩码

        uint8_t d_len = 0;
        d_len = get_dtc_status_by_mask(data[2], &out[4], MAX_BUFF_SIZE - 4 - 1); // 4--数据头 1--连续帧头预留

        out[0] = 3 + d_len; // 数据总长度 = 服务号 + sub_id + mask + ndata

        // 判断数据长度,单帧还是连续帧发送
        if (out[0] > 7) {
            memmove(out + 1, out, out[0] + 1); // 单帧改连续帧格式,数据总长度 + 长度位,数据总长度 + 长度位
            out[0] = NWL_FIRST_FRAME << 4; // 数据帧格式(nwl_frame_st_t)
            if (g_tx_msg.data != 0) {
                free(g_tx_msg.data);
                g_tx_msg.data = NULL;
            }
            // 发送首帧(只含6byte data)后,剩余长度:去除 (服务号|sub_id|mask + D0D1D2)
            d_len = out[1] - 3 - 3;
            g_tx_msg.data = malloc(d_len);
            if (g_tx_msg.data == NULL) {
                send_nrc_data(UDS_ID, NRC_ACCESS_DENIED);
                return 2;
            }
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
            memcpy(g_tx_msg.data, out + 8, d_len);
            g_tx_msg.len = d_len;
        } else {
            memset(&out[out[0] + 1], 0xAA, 8 - out[0] - 1);  // 空白区填充指定值
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
        }
    }
    return 0;
}

/**
 * @brief  通过DTC码报告DTC 快照记录
 * @param  *data: 数据指针
 * @param  len: 数据长度
 * @retval 0--成功  >0--错误
 */
static int8_t uds19_04(uint8_t *data, uint16_t len, uint8_t *out) {
    uint32_t dtc_id;
    if (len != 6) {
        LOGE("len err != 6, sub%02x", data[1]);
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        return 1;
    } else { // == 6
        uint8_t record_numb = data[5]; // 记录号
        if ((record_numb > SS_NB_MAX) && record_numb != 0xFF && record_numb != 0x00) {
            LOGE("record numb nonsupport:%02x, sub%02x", record_numb, data[1]);
            send_nrc_data(UDS_ID, NRC_REQUEST_OUT_OF_RANGE);
            return 2;
        }
        dtc_id = data[2];
        dtc_id <<= 8;
        dtc_id += data[3];
        dtc_id <<= 8;
        dtc_id += data[4];
        uint8_t SN = is_dtc_id(dtc_id); // 得到dtc id,对应的数组索引
        if (SN == 0xFF) {
            LOGE("dtc id id err:%02x, sub%02x", dtc_id, data[1]);
            send_nrc_data(UDS_ID, NRC_SUBFUNCTION_NOT_SUPPORTED);
            return 2;
        }

        if (data[1] & 0x80) { // 无需应答
            LOGI("No answer required, sub%02x", data[1]);
        } else {
            // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID,
            out[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
            out[2] = data[1]; // SUB_ID 子功能ID
            out[3] = data[2]; // DTC_ID 低16bit
            out[4] = data[3]; // DTC_ID 高8bit
            out[5] = data[4]; // DTC_ID 低8bit
            out[6] = get_dtc_snap_shot_status(SN, record_numb); // DTC Status 最近一次错误状态
            out[7] = record_numb;
            out[8] = SS_TYPE_MAX_NUMBER;

            uint16_t d_len = 0;
            d_len = get_dtc_snap_shot_by_id(SN, record_numb, &out[9], MAX_BUFF_SIZE - 8 - 1); // 7--数据头 1--连续帧头预留
            // 数据总长度 = 服务号 + 子功能ID + DTC_ID(3byte) + DTC Status + record_numb + MAX_NUMBER + DATA_LEN
            out[0] = 8 + d_len;

            memmove(out + 1, out, out[0] + 1); // 单帧改连续帧格式,数据总长度 + 长度位
            out[0] = NWL_FIRST_FRAME << 4; // 数据帧格式(nwl_frame_st_t)

            if (g_tx_msg.data != 0) {
                free(g_tx_msg.data);
                g_tx_msg.data = NULL;
            }
            // 发送首帧(只含6byte data)后,剩余长度:去除 (服务号 + 子功能ID + DTC_ID(3byte) + DTC Status)
            d_len = out[1] - 2 - 3 - 1;
            g_tx_msg.data = malloc(d_len);
            if (g_tx_msg.data == NULL) {
                send_nrc_data(UDS_ID, NRC_ACCESS_DENIED);
                return 3;
            }
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
            memcpy(g_tx_msg.data, out + 8, d_len);
            g_tx_msg.len = d_len;
        }
    }
    return 0;
}

/**
 * @brief  通过DTC码报告DTC扩展数据记录
 * @param  *data: 数据指针
 * @param  len: 数据长度
 * @retval 0--成功  >0--错误
 */
static int8_t uds19_06(uint8_t *data, uint16_t len, uint8_t *out) {
    uint32_t dtc_id;
    if (len != 6) {
        LOGE("len err != 6, sub%02x", data[1]);
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        return 1;
    }
    uint8_t record_numb = data[5];  // 记录号
    if ((record_numb > SS_NB_MAX) && record_numb != 0xFF && record_numb != 0x00) {
        LOGE("record numb nonsupport:%02x, sub%02x", record_numb, data[1]);
        send_nrc_data(UDS_ID, NRC_REQUEST_OUT_OF_RANGE);
        return 2;
    }
    dtc_id = data[2];
    dtc_id <<= 8;
    dtc_id += data[3];
    dtc_id <<= 8;
    dtc_id += data[4];
    uint8_t SN = is_dtc_id(dtc_id); // 得到dtc id,对应的数组索引
    if (SN == 0xFF) {
        LOGE("dtc id id err:%02x, sub%02x", dtc_id, data[1]);
        send_nrc_data(UDS_ID, NRC_SUBFUNCTION_NOT_SUPPORTED);
        return 2;
    }

    if (data[1] & 0x80) { // 无需应答
        LOGI("No answer required, sub%02x", data[1]);
    } else {
        // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID,
        out[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
        out[2] = data[1]; // SUB_ID 子功能ID
        out[3] = data[2]; // DTC_ID 低16bit
        out[4] = data[3]; // DTC_ID 高8bit
        out[5] = data[4]; // DTC_ID 低8bit
        out[6] = get_dtc_snap_shot_status(SN, record_numb); // DTC Status 最近一次错误状态
        out[7] = record_numb;
        //os_delay(1);
        uint16_t d_len = 0;
        d_len = get_dtc_snap_shot_ex_data(SN, record_numb, &out[8], MAX_BUFF_SIZE - 8 - 1); // 7--数据头 1--连续帧头预留
        // 数据总长度 = 服务号 + 子功能ID + DTC_ID(3byte) + DTC Status + record_numb  + DATA_LEN
        out[0] = 7 + d_len;
        if (out[0] > 7) {
            memmove(out + 1, out, out[0] + 1); // 单帧改连续帧格式,数据总长度 + 长度位
            out[0] = NWL_FIRST_FRAME << 4; // 数据帧格式(nwl_frame_st_t)
            if (g_tx_msg.data != 0) {
                free(g_tx_msg.data);
                g_tx_msg.data = NULL;
            }
            // 发送首帧(只含6byte data)后, 去除 (服务号 + 子功能ID + DTC_ID(3byte) + DTC Status)
            d_len = out[1] - 2 - 3 - 1;
            g_tx_msg.data = malloc(d_len);
            if (g_tx_msg.data == NULL) {
                send_nrc_data(UDS_ID, NRC_ACCESS_DENIED);
                return 3;
            }
            memcpy(g_tx_msg.data, out + 8, d_len);
            g_tx_msg.len = d_len;
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
        } else {
            memset(&out[out[0] + 1], 0xAA, 8 - out[0] - 1);  // 空白区填充指定值
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
        }
    }
    return 0;
}

/**
 * @brief  报告支持的全部DTC
 * @param  *data: 数据指针
 * @param  len: 数据长度
 * @retval 0--成功  >0--错误
 */
static uint8_t uds19_0A(uint8_t *data, uint16_t len, uint8_t *out) {
    if (len != 2) {
        LOGE("len err != 2, sub%02x", data[1]);
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        return 1;
    }
    if (data[1] & 0x80) { // 无需应答
        LOGI("No answer required, sub%02x", data[1]);
    } else {
        // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID, mask
        out[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
        out[2] = data[1]; // SUB_ID 子功能ID
        out[3] = AUTOSAR_DIAG_DTC_STATE_BIT; // 掩码

        uint16_t d_len = 0;
        d_len = get_all_dtc_status(&out[4], MAX_BUFF_SIZE - 4 - 1); // 4--数据头 1--连续帧头预留
        // 数据总长度 = 服务号 + 子功能ID + 掩码  + DATA_LEN
        out[0] = 3 + d_len;
        // LOGD("%u,%u\r\n", out[0], d_len);
        if (out[0] > 7) {
            memmove(out + 1, out, out[0] + 1); // 单帧改连续帧格式,数据总长度 + 长度位
            out[0] = NWL_FIRST_FRAME << 4; // 数据帧格式(nwl_frame_st_t)

            if (g_tx_msg.data != 0) {
                free(g_tx_msg.data);
                g_tx_msg.data = NULL;
            }
            // 发送首帧(只含6byte data)后, 去除 (服务号 + 子功能ID + DTC_ID(3byte) + DTC Status)
            d_len = out[1] - 2 - 3 - 1;
            g_tx_msg.data = malloc(d_len);
            if (g_tx_msg.data == NULL) {
                send_nrc_data(UDS_ID, NRC_ACCESS_DENIED);
                return 3;
            }
            memcpy(g_tx_msg.data, out + 8, d_len);
            LOGD("%x,%u,%x,%u\r\n", g_tx_msg.data[d_len-1], d_len, out[out[1]+1], out[1]+1);
            g_tx_msg.len = d_len;
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
        } else {
            memset(&out[out[0] + 1], 0xAA, 8 - out[0] - 1);  // 空白区填充指定值
            app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, out, 8);
        }
    }
    return 0;
}

void uds19_main(nwl_msg_t* p) {
    uint8_t data[MAX_BUFF_SIZE];
    uint8_t d_len = 0;
    if (p->len < 2) {
        LOGE("len err < 2");
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        goto end;
    }
    switch (p->data[1] & 0x7F) { // 子功能,bit7为应答位。  =1则不允许应答
        // 通过状态掩码报告DTC数目
        case 0x01: {
            if (uds19_01(p->data, p->len, data) != 0) {
            }
            break;
        }
        // 通过状态掩码报告DTC
        case 0x02:
            if (uds19_02(p->data, p->len, data) != 0) {
            }
            break;
        // 通过DTC码报告DTC 快照记录
        case 0x04: {
            if (uds19_04(p->data, p->len, data) != 0) {
            }
            break;
        }
        // 通过DTC码报告DTC扩展数据记录
        case 0x06: {
            if (uds19_06(p->data, p->len, data) != 0) {
            }
            break;
        }
        // 报告支持的全部DTC
        case 0x0A: {
            if (uds19_0A(p->data, p->len, data) != 0) {
            }
            break;
        }
        default:
            send_nrc_data(UDS_ID, NRC_SUBFUNCTION_NOT_SUPPORTED);
            break;
    }
end:
    return;
}

#if AUTOSAR_DIAG_SWITCH && USE_UDS_19 && AUTOSAR_DIAG_DTC_SWITCH
DIAG_SERVICE_REG(UDS_ID, DIAG_NO_SECURITY_LEVEL, (DEFAULT_SESSION|EXTENDED_SESSION),
                 (DIAG_PHYS_REQ|DIAG_FUNC_REQ), NULL, NULL, uds19_main);
#endif

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

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

相关文章

LInux系统编程(3)

取得拓展属性 #include <sys/types.h> #include <attr/xattr.h>ssize_t getxattr(const char* path, const char* key, void* value, size_t size); ssize_t lgetxattr(const char* path, const char* key, void* value, size_t size); ssize_t fgetxattr(int fd,…

FreeRTOS 任务的创建与删除

目录 1. 什么是任务&#xff1f; 2. 任务创建与删除相关函数 任务创建与删除相关函数有如下三个&#xff1a; 任务动态创建与静态创建的区别&#xff1a; xTaskCreate 函数原型​编辑 vTaskDelete 函数原型 3. 创建两个任务进行点灯实操 使用CubeMX快速移植 1.增加两个…

【谢希尔 计算机网络】第4章 网络层

目录 网络层 网络层的几个重要概念 网络层提供的两种服务 网络层的两个层面 网际协议 IP 虚拟互连网络 IP 地址 IP 地址与 MAC 地址 地址解析协议 ARP IP 数据报的格式 IP 层转发分组的过程 基于终点的转发 最长前缀匹配 使用二叉线索查找转发 网际控制报文协议…

2023CSPS 种树 —— 二分+前缀和

This way 题意&#xff1a; 一开始以为是水题&#xff0c;敲了一个二分贪心检查的代码&#xff0c;20分。发现从根往某个节点x走的时候&#xff0c;一路走来的子树上的节点到已栽树的节点的距离会变短&#xff0c;那么并不能按照初始情况贪心。 于是就想着检查时候用线段树…

2023-1024‍节日(内含表白代码)

文章目录 一、前言二、代码实现三、动态展示四、总结 一、前言 1024可以是计算机操作系统的进制单位&#xff0c;也可以是&#x1f9d1;‍&#x1f4bb;程序员们的特殊纪念日。 每年10月24日被行业认定为“程序员节”。 今天&#xff0c;正是一年一度的“1024程序员节”在此纪…

LeetCode讲解篇之面试题 01.08. 零矩阵

文章目录 题目描述题解思路题解代码 题目描述 题解思路 遍历矩阵&#xff0c;若当前元素为零&#xff0c;则将该行和该列的第一个元素置零 遍历第一行&#xff0c;若当前元素为零&#xff0c;则将当前列置零 遍历第一列&#xff0c;若当前元素为零&#xff0c;则将当前行置零 …

Kong:高性能、插件化的云原生 API 网关 | 开源日报 No.62

Kong/kong Stars: 35.2k License: Apache-2.0 Kong 是一款云原生、平台无关且可扩展的 API 网关。它以高性能和插件化的方式脱颖而出&#xff0c;提供了代理、路由、负载均衡、健康检查和认证等功能&#xff0c;并成为编排微服务或传统 API 流量的中心层。 以下是 Kong 的核心…

浏览器面试题及答案【集合目录】

前言&#xff1a; 欢迎浏览和关注本专栏《 前端就业宝典 》&#xff0c; 不管是扭螺丝还是造火箭&#xff0c; 多学点知识总没错。 这个专栏是扭螺丝之上要造火箭级别的知识&#xff0c;会给前端工作学习的小伙伴带来意想不到的帮助。 本专栏将前端知识拆整为零&#xff0c;主要…

kr第三阶段(二)32 位汇编

编译与链接 环境配置 masm32 masm32 是微软的 masm32 的民间工具集合。该工具集合除了 asm32 本身的汇编器 ml 外还提供了&#xff1a; SDK 对应的函数声明头文件和 lib 库。32 位版本的 link&#xff08;原版本是 16 位&#xff0c;这里的 32 位版本的 link 来自 VC 6.0&a…

IDEA工具第二篇:自定义Java方法注释模板 | 京东云技术团队

网上搜索类似的文章有很多&#xff0c;但是一味的复制粘贴总会出现各种奇葩问题&#xff0c;最后然并卵&#xff01;今天特意自己研究琢磨一下&#xff0c;将最终结果分享给大家&#xff0c;100%亲测可用。 一、说明 想必大家都用过Eclipse的方法注释生成&#xff0c;方法上输…

Django结合Celery进行异步调用

目录 Celery介绍 相关环境 相关配置 1、在proj/proj/目录下创建一个新的celery.py模块 定义 Celery 实例&#xff1a; 2、在proj/proj/__init__.py 模块中导入这个应用程序。 3、在各自模块中定义任务文件tasks.py 4、settings.py配置 服务启动 异步调用 Celery介绍 C…

ChatGPT AIGC 办公自动化拆分Excel工作表

在职场办公中对数据的操作,经常需要将一份表格数据拆分成多个表。 但是在Excel中进行表格拆分的步骤比较多。 在Excel中拆分工作表的步骤: 1.打开您的Excel工作簿,选择您要拆分的工作表。 2.右键单击工作表标签(通常在底部),选择“移动或复制”。 3.在“移动或复制”…

SpringCloud和Kubernetes的区别

又见小道仙&#xff1a; https://blog.csdn.net/Tomwildboar/article/details/129531315 对于SpringCloud在实际项目中并未使用过&#xff0c;只是自学过SpringCloud和SpringCloud Alibaba&#xff0c;也基于学习搭建过demo。 对于Kubernetes&#xff0c;目前这家公司就是使用…

SpringBoot引入包报红,无法使用Maven依赖

今天又是一年一度的程序员节&#xff0c;希望各位编码的小伙伴们能够健健康康&#xff0c;开开心心。 最近弄了一个SpringBoot项目&#xff0c;今天拉取代码的时候发现文件都变成了这样子 平时常用的依赖包都用不了了&#xff0c;重新加载&#xff0c;重新install都无效&#…

浏览器标签上添加icon图标;html引用ico文件

实例 <link rel"shortcut icon" href"./XXX.ico" type"image/x-icon">页面和图标在同一目录内 则 <link rel"shortcut icon" type"text/css" href"study.ico"/>可以阿里矢量图库关键字搜索下载自己…

【tg】9 : InstanceImpl 、 虚拟的音频渲染设备FakeAudioDeviceModuleImpl

代码分布 WebRTC-Manager 线程:manager线程 G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\InstanceImpl.h Manager 使用的是 WebRTC-Manager 线程 InstanceImpl 对Manager 的封装和调用 #

【ESP-BOX-LITE】:照片查看器

目录 项目场景&#xff1a; 项目需求描述&#xff1a; 项目技术&#xff1a; 项目成果&#xff1a; 项目总结&#xff1a; 项目视频&#xff1a; 芳香 项目场景&#xff1a; 使用ESP-BOX-LITE实现照片查看器功能&#xff0c;显示多级目录下的图片或文件夹&#xff0c;自…

Mac风扇控制电脑降温软件Macs Fan Control Pro 简体中文

Macs Fan Control Pro是一款功能强大的Mac风扇控制软件&#xff0c;旨在帮助用户更好地管理和控制Mac电脑的风扇速度和温度传感器。以下是该软件的主要特色介绍&#xff1a; 监测和调整Mac电脑的风扇速度和温度传感器&#xff0c;帮助用户控制设备温度&#xff0c;提高电脑性能…

浅谈RabbitMQ的延迟队列

Part 01、 延迟队列是什么 延迟队列代表了一种强大的消息传递机制&#xff0c;允许我们在将消息发送至RabbitMQ时&#xff0c;规定它们只能在未来某个预定的时间点被消费。这种特殊类型的消息被简称为"延迟消息"。 以RabbitMQ为例&#xff0c;它允许我们通过延迟…

【LeetCode:637. 二叉树的层平均值 | bfs】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…