AXI CANFD MicroBlaze 测试笔记

文章目录

    • 前言
    • 测试用的硬件连接
    • Vivado 配置
    • Vitis MicroBlaze CANFD 代码
    • 测试代码
    • 测试截图
    • Github Link

前言

官网: CAN with Flexible Data Rate (CAN FD) (xilinx.com)

特征:

  • 支持8Mb/s的CANFD
  • 多达 3 个数据位发送器延迟补偿(TDC, transmitter delay compensation)
  • 32-deep TX FIFO, 2 * 64-deep RX FIFO, 32 ID Filter
  • 接收支持 顺序(Sequential)模式 和 邮箱(Mailbox)模式
  • Bus-Off 恢复模式: 自动恢复 或 用户干预的自动恢复

参考:

  • How to configure CAN/CANFD clocks and identify the CAN nodes (xilinx.com)
  • canfd 默认文档和示例路径: C:\Xilinx\Vitis\2023.2\data\embeddedsw\XilinxProcessorIPLib\drivers\canfd_v2_8

本文仅作学习交流使用.

测试用的硬件连接

硬件:

  • FPGA: xc7a35tfgg484-2
  • 时钟: 50MHz, 有源, 单端, 3V3, 引脚Y18
  • 复位: 低电平复位, 3V3, 引脚F20
  • UART: TX G16, RX G15
  • CANFD: TX F16, RX E17

Vivado 配置

如图:

请添加图片描述

时钟:

  • clk_out1, 160MHz, can_clk_x2, 也是其它组件的时钟
  • clk_out2, 80MHz, can_clk, 是CAN和CANFD配置的主时钟
  • 低电平复位

调试串口:

  • 9600 or 115200 bps

时钟的配置截图

在这里插入图片描述

CANFD的配置, 收发FIFO Depth都是32, 接收使用顺序模式, 不用FIFO1

在这里插入图片描述

可适当减少RX FIFO-0 Depth以减少RAM消耗. 含MicroBlaze 64K, 一路CANFD, 没有使用任何外部RAM的消耗如下(xc7a35tfgg484-2):

在这里插入图片描述

Vitis MicroBlaze CANFD 代码

初始化:

  • 查找并初始化已有CANFD配置
  • 进入配置模式, 配置位速率, 采样点, TDC, 滤波器, 关闭BRS
  • 设置收发错误事件回调, 使能中断
  • 进入正常模式
  • 注意在C文件中编译, 不然Cpp中 XSetupInterruptSystem 会报错 error: invalid conversion from 'void (*)(void*)' to 'void*' [-fpermissive]

参考代码如下:

int bsp_canfd_init(XCanFd *InstancePtr, uint32_t BaseAddress, uint32_t BaudRate,
                   float SamplePoint, uint32_t FastBaudRate,
                   float FastSamplePoint) {
  XCanFd_Config *ConfigPtr = XCanFd_LookupConfig(BaseAddress);
  if (ConfigPtr == NULL) {
    bsp_canfd_debug_printf("Error: XCanFd_LookupConfig returned NULL\n");
    return -1;
  } else {
    bsp_canfd_debug_printf("XCanFd_Config:\n");
    bsp_canfd_debug_printf("  BaseAddress: 0x%08X\n", ConfigPtr->BaseAddress);
    bsp_canfd_debug_printf("  Rx_Mode: %s\n",
                           ConfigPtr->Rx_Mode ? "Mailbox" : "Sequential");
    bsp_canfd_debug_printf("  NumofRxMbBuf: %d\n", ConfigPtr->NumofRxMbBuf);
    bsp_canfd_debug_printf("  NumofTxBuf: %d\n", ConfigPtr->NumofTxBuf);
    bsp_canfd_debug_printf("  IntrId: %d\n", ConfigPtr->IntrId);
    bsp_canfd_debug_printf("  IntrParent: 0x%08X\n", ConfigPtr->IntrParent);
  }
  int Status =
      XCanFd_CfgInitialize(InstancePtr, ConfigPtr, ConfigPtr->BaseAddress);
  if (Status != XST_SUCCESS) {
    bsp_canfd_debug_printf("Error: XCanFd_CfgInitialize returned %d\n", Status);
    return -2;
  } else {
    bsp_canfd_debug_printf("XCanFd_CfgInitialize: Success\n");
  }

  // config mode
  XCanFd_EnterMode(InstancePtr, XCANFD_MODE_CONFIG);
  while (XCanFd_GetMode(InstancePtr) != XCANFD_MODE_CONFIG)
    ;
  bsp_canfd_debug_printf("XCanFd_EnterMode: XCANFD_MODE_CONFIG\n");

  // 80MHz / (3 + 1) = 20MHz, 20MHz / (1 + (30 + 1) + (7 + 1)) = 500KHz
  // XCanFd_SetBitTiming(InstancePtr, 8, 7, 30);
  XCanFd_SetBaudRatePrescaler(InstancePtr, 0x3);
  u16 total_tq = 20000000 / BaudRate;
  u16 tseg1 = (u16)(SamplePoint * total_tq) - 2;
  u8 tseg2 = (u8)(total_tq - tseg1 - 3);
  u8 sjw = tseg2 + 1;
  XCanFd_SetBitTiming(InstancePtr, sjw, tseg2, tseg1);

  // 80MHz, 80 / (1 + (30 + 1) + (7 + 1)) = 2MHz
  // XCanFd_SetFBitTiming(InstancePtr, 8, 7, 30);
  XCanFd_SetFBaudRatePrescaler(InstancePtr, 0x0);
  u16 ftotal_tq = 80000000 / FastBaudRate;
  u8 ftseg1 = (u8)(FastSamplePoint * ftotal_tq) - 2;
  u8 ftseg2 = (u8)(ftotal_tq - ftseg1 - 3);
  u8 fsjw = ftseg2 + 1;
  XCanFd_SetFBitTiming(InstancePtr, fsjw, ftseg2, ftseg1);

  // TDC, 0~31
  // XCanFd_Set_Tranceiver_Delay_Compensation(InstancePtr, 0x3);

  XCanFd_SetBitRateSwitch_DisableNominal(InstancePtr);
  bsp_canfd_debug_printf("XCanFd: %d@0.%d, %d@0.%d\n", BaudRate,
                         (int)(SamplePoint * 1000), FastBaudRate,
                         (int)(FastSamplePoint * 1000));

  if (XCANFD_GET_RX_MODE(InstancePtr) == 0) {
    bsp_canfd_debug_printf(
        "RX_MODE Sequential Filter: XCANFD_AFR_UAF_ALL_MASK\n");
    XCanFd_AcceptFilterDisable(InstancePtr, XCANFD_AFR_UAF_ALL_MASK);
    XCanFd_AcceptFilterEnable(InstancePtr, XCANFD_AFR_UAF_ALL_MASK);
  } else {
    bsp_canfd_debug_printf("RX_MODE Mailbox Filter: Need to be implemented\n");
  }

  XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_SEND, (void *)SendHandler,
                    (void *)InstancePtr);
  XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_RECV, (void *)RecvHandler,
                    (void *)InstancePtr);
  XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_ERROR, (void *)ErrorHandler,
                    (void *)InstancePtr);
  XCanFd_SetHandler(InstancePtr, XCANFD_HANDLER_EVENT, (void *)EventHandler,
                    (void *)InstancePtr);
  Status =
      XSetupInterruptSystem(InstancePtr, &XCanFd_IntrHandler, ConfigPtr->IntrId,
                            ConfigPtr->IntrParent, XINTERRUPT_DEFAULT_PRIORITY);
  if (Status != XST_SUCCESS) {
    bsp_canfd_debug_printf("Error: XSetupInterruptSystem returned %d\n",
                           Status);
    return 1;
  } else {
    bsp_canfd_debug_printf("XSetupInterruptSystem: Success\n");
  }
  XCanFd_InterruptEnable(InstancePtr, XCANFD_IXR_ALL);
  XCanFd_EnterMode(InstancePtr, XCANFD_MODE_NORMAL);
  while (XCanFd_GetMode(InstancePtr) != XCANFD_MODE_NORMAL)
    ;
  bsp_canfd_debug_printf("XCanFd_EnterMode: XCANFD_MODE_NORMAL\n");

  return 0;
}

发送套用Linux SocketCAN接口, 毕竟这个用的人多, 易于理解. 因为发送FIFO深度为32, 所以, 正常情况下连发32帧无需插入延时, 也无需自己处理发送队列, 这已经够大部分情况使用了.

int bsp_canfd_send(XCanFd *InstancePtr, struct canfd_frame *frame) {
  bool is_extended = frame->can_id & CAN_EFF_FLAG ? true : false;
  bool is_remote = frame->can_id & CAN_RTR_FLAG ? true : false;
  bool is_fd = frame->flags & CANFD_FDF ? true : false;
  bool is_brs = frame->flags & CANFD_BRS ? true : false;
  bool is_esi = frame->flags & CANFD_ESI ? true : false;
  u32 TxFrame[CANFD_MTU];
  TxFrame[0] = XCanFd_CreateIdValue(
      CAN_SFF_MASK & (is_extended ? ((frame->can_id & CAN_EFF_MASK) >> 18)
                                  : frame->can_id),
      is_extended ? 1 : (u32)is_remote, (u32)is_extended,
      (u32)is_extended ? (frame->can_id & 0x3FFFF) : 0,
      is_extended ? (u32)is_remote : 0);
  if ((!is_fd) && (!is_brs)) {
    TxFrame[1] = XCanFd_CreateDlcValue(frame->len);
  } else {
    if (is_brs) {
      TxFrame[1] =
          XCanFd_Create_CanFD_Dlc_BrsValue(XCanFd_GetLen2Dlc(frame->len));
    } else {
      TxFrame[1] = XCanFd_Create_CanFD_DlcValue(XCanFd_GetLen2Dlc(frame->len));
    }
  }
  u8 *FramePtr = (u8 *)(&TxFrame[2]);
  for (int i = 0; i < frame->len; i++) {
    FramePtr[i] = frame->data[i];
  }
  u32 TxBufferNumber;
  int status = XCanFd_Send(InstancePtr, TxFrame, &TxBufferNumber);
  if (status == XST_FIFO_NO_ROOM) {
    bsp_canfd_debug_printf("Error: XCanFd_Send returned XST_FIFO_NO_ROOM\n");
    return -1;
  }
  if (status != XST_SUCCESS) {
    bsp_canfd_debug_printf("Error: XCanFd_Send returned %d\n", status);
    return -2;
  }
  return 0;
}

接收的示例, 类似 candump:

  • 标准帧是%03X打印, 扩展帧是%08X打印.
  • 远程帧打R, 数据帧打D
  • CANFD打F且长度为[%02d], Classic CAN打-且数据长度为[%d]
  • 开启了BRS打B, 否则打-
  • ESI 暂不关心
  • 当然这里打印接收只是用于测试, 实际不要在中断中阻塞打印
static void RecvHandler(void *CallBackRef) {
  XCanFd *CanPtr = (XCanFd *)CallBackRef;
  int Status;
  u32 RxFrame[CANFD_MTU];

  /* Check for the design 1 - MailBox 0 - Sequential */
  if (XCANFD_GET_RX_MODE(CanPtr) == 1) {
    Status = XCanFd_Recv_Mailbox(CanPtr, RxFrame);
  } else {
    Status = XCanFd_Recv_Sequential(CanPtr, RxFrame);
  }

  u32 id1 = (RxFrame[0] >> (u32)XCANFD_IDR_ID1_SHIFT) & (u32)0x7FF;
  u32 is_extended = (RxFrame[0] >> (u32)XCANFD_IDR_IDE_SHIFT) & (u32)0x1;
  u32 id2 = (RxFrame[0] >> (u32)XCANFD_IDR_ID2_SHIFT) & (u32)0x3FFFF;
  u32 is_remote = is_extended
                      ? (RxFrame[0] & 0x01)
                      : ((RxFrame[0] >> (u32)XCANFD_IDR_SRR_SHIFT) & (u32)0x1);

  /* Get the Dlc inthe form of bytes */
  u32 len = XCanFd_GetDlc2len(RxFrame[1] & XCANFD_DLCR_DLC_MASK, EDL_CANFD);
  if (Status != XST_SUCCESS) {
    bsp_canfd_debug_printf("Error: XCanFd_Recv returned %d\n", Status);
    return;
  }
  u32 is_brs = RxFrame[1] & XCANFD_DLCR_BRS_MASK ? 1 : 0;
  u32 is_fdf = RxFrame[1] & XCANFD_DLCR_EDL_MASK ? 1 : 0;
  // bsp_canfd_debug_printf("%08X ", RxFrame[0]);
  u8 *FramePtr = (u8 *)(&RxFrame[2]);
  if (is_extended) {
    bsp_canfd_debug_printf("%08X ", id1 << 18 | id2);
  } else {
    bsp_canfd_debug_printf("%03X ", id1);
  }
  if (is_remote) {
    bsp_canfd_debug_printf("R [%d]", len);
  } else {
    bsp_canfd_debug_printf("D ");
    if (is_fdf) {
      bsp_canfd_debug_printf("F ");
    } else {
      bsp_canfd_debug_printf("- ");
    }
    if (is_brs) {
      bsp_canfd_debug_printf("B ");
    } else {
      bsp_canfd_debug_printf("- ");
    }
    if ((!is_fdf) && (!is_brs)) {
      bsp_canfd_debug_printf("[%d] ", len);
    } else {
      bsp_canfd_debug_printf("[%02d] ", len);
    }
    for (int i = 0; i < len; i++) {
      bsp_canfd_debug_printf("%02X ", FramePtr[i]);
    }
  }
  bsp_canfd_debug_printf("\n");
}

测试代码

如下:

  • 位速率 500K@80%, 4M@80%, 如果出现收发不正常, 可能需要微调初始化中的TDC, 检查CAN收发器以及终端电阻
  • 对数据帧远程帧, CAN或CANFD或CANFD BRS都做了测试
  • 连续发送32帧
int main() {
  xil_printf("============================================\n");

  XCanFd CanFd0;
  int Status =
      bsp_canfd_init(&CanFd0, XPAR_CANFD_0_BASEADDR, 500000, 0.8, 4000000, 0.8);
  if (Status != 0) {
    xil_printf("Error: bsp_canfd_init returned %d\n", Status);
    return -1;
  }

  for (int i = 0; i < 4; i++) {
    struct canfd_frame frame = {
        .can_id = 0x123,
        .len = 8,
        .flags = 0,
        .__res0 = 0,
        .__res1 = 0,
        .data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
                 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
                 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,
                 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
                 0x3C, 0x3D, 0x3E, 0x3F},
    };
    // std can
    frame.can_id = 0x123;
    frame.len = 8;
    frame.flags = 0;
    int Status = bsp_canfd_send(&CanFd0, &frame);
    // std can remote
    frame.can_id = 0x124 | CAN_RTR_FLAG;
    frame.len = 8;
    frame.flags = 0;
    Status |= bsp_canfd_send(&CanFd0, &frame);
    // std can fd
    frame.can_id = 0x125;
    frame.len = 64;
    frame.flags = CANFD_FDF;
    Status |= bsp_canfd_send(&CanFd0, &frame);
    // std can fd brs
    frame.can_id = 0x126;
    frame.len = 64;
    frame.flags = CANFD_FDF | CANFD_BRS;
    Status |= bsp_canfd_send(&CanFd0, &frame);

    // ext can
    frame.can_id = 0x12345678 | CAN_EFF_FLAG;
    frame.len = 8;
    frame.flags = 0;
    Status |= bsp_canfd_send(&CanFd0, &frame);
    // ext can remote
    frame.can_id = 0x12345679 | CAN_EFF_FLAG | CAN_RTR_FLAG;
    frame.len = 8;
    frame.flags = 0;
    Status |= bsp_canfd_send(&CanFd0, &frame);
    // ext can fd
    frame.can_id = 0x1234567A | CAN_EFF_FLAG;
    frame.len = 64;
    frame.flags = CANFD_FDF;
    Status |= bsp_canfd_send(&CanFd0, &frame);
    // ext can fd brs
    frame.can_id = 0x1234567B | CAN_EFF_FLAG;
    frame.len = 64;
    frame.flags = CANFD_FDF | CANFD_BRS;
    Status |= bsp_canfd_send(&CanFd0, &frame);

    if (Status != 0) {
      xil_printf("Error: bsp_canfd_send %d returned %d\n", i, Status);
      return -1;
    }
  }

  while (1) {
  }

  return 0;
}

测试截图

设置:

在这里插入图片描述

MCU连续发出的32帧报文:

在这里插入图片描述

逻辑分析仪上可以看出来两帧之间卡着标准的3 ITM来的

在这里插入图片描述

出现BRS时的情况, 左边500K, 右边4M

在这里插入图片描述

CAN分析仪向FPGA发送测试:

在这里插入图片描述

Github Link

domain_controller_orin_x2_tc397/axi_canfd_microblaze at main · weifengdq/domain_controller_orin_x2_tc397 (github.com)

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

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

相关文章

Jenkins 面试题及答案整理,最新面试题

Jenkins中如何实现持续集成与持续部署&#xff1f; Jenkins通过自动化构建、测试和部署应用程序来实现持续集成与持续部署&#xff08;CI/CD&#xff09;。这个过程包括以下步骤&#xff1a; 1、源代码管理&#xff1a; Jenkins支持与多种版本控制系统集成&#xff0c;如Git、…

数据结构 之 优先级队列(堆) (PriorityQueue)

&#x1f389;欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨ &#x1f389;感谢各位读者在百忙之中抽出时间来垂阅我的文章&#xff0c;我会尽我所能向的大家分享我的知识和经验&#x1f4d6; &#x1f389;希望我们在一篇篇的文章中能够共同进步&#xff01;&#xff01;&…

oops-framework框架 之 启动流程(三)

引擎&#xff1a; CocosCreator 3.8.0 环境&#xff1a; Mac Gitee: oops-game-kit 回顾 上篇博客中我们通过 oops-game-kit 模版构建了基础的项目&#xff0c;另外讲解了下assets目录结构和游戏配置文件的基本使用相关&#xff0c;详情内容可参考&#xff1a; oops-framewo…

mysql5.7离线安装 windows

windows上离线安装mysql5.7 下载安装包 去官网下载对应版本的mysql官网 点击archives,接着选择自己要下载的版本&#xff0c;选择windows系统&#xff0c;并根据自己电脑的位数选择相应的版本【找到“此电脑”&#xff0c;鼠标右击&#xff0c;出来下拉框&#xff0c;选择“属性…

频率响应概述与波特图

频率响应的定义 在放大电路中&#xff0c;存在电抗元件&#xff08;如电容、电感&#xff09;、半导体管&#xff08;存在极间电容&#xff09;。由于电抗元件和极间电容的存在&#xff0c;当输入信号频率过高或过低时&#xff0c;不但放大倍数的数值会减小&#xff0c;而且将…

Python 3.x 快速安装 pip 包管理工具

目录 ℹ️ 1. 查看是否安装 pip1.1 方法一1.2 方法二 &#x1f6e0;️ 2. 安装方法2.1 通过 ensurepip 进行安装2.2 通过 get-pip.py 进行安装 参考文档&#xff1a; pip 官方安装文档&#xff1a;https://pip.pypa.io/en/stable/installation/ ℹ️ 1. 查看是否安装 pip 【…

最详细数据仓库项目实现:从0到1的电商数仓建设(数仓部分)

1、数仓 数据仓库是一个为数据分析而设计的企业级数据管理系统&#xff0c;它是一个系统&#xff0c;不是一个框架。可以独立运行的&#xff0c;不需要你参与&#xff0c;只要运行起来就可以自己运行。 数据仓库不是为了存储&#xff08;但是能存&#xff09;&#xff0c;而是…

hcia复习总结7

1&#xff0c;AR2发送2.0网段的信息给AR1&#xff0c;如果&#xff0c;AR1本身并不存在该网段的路由 信息&#xff0c;则将直接 刷新 到本地的路由表中。 Destination/Mask Proto Pre Cost Flags NextHop Interface 2.2.2.0/24 RIP 100…

Codeql复现CVE-2018-11776学习笔记

基本使用 1、首先下载struts2漏洞版本源码&#xff1a; https://codeload.github.com/apache/struts/zip/refs/tags/STRUTS_2_3_20 2、构建codeql数据库&#xff08;构建失败文末有解决办法&#xff09;&#xff1a; codeql database create ~/CodeQL/databases/struts2-2.3.…

unraid docker.img扩容

unraid 弹Docker image disk utilization of 99%&#xff0c;容器下载/更新失败 我的版本是6.11.5&#xff0c;docker.img满了导致容器不能更新&#xff0c;遇到同样问题的可以先用docker命令清除一下仓库(当然不一定能清理出来&#xff0c;我已经清理过只清理出来1G多点&…

存储卡乱码:原因、恢复与预防全攻略

一、存储卡乱码现象初现 在数字时代&#xff0c;存储卡已成为我们生活中不可或缺的一部分&#xff0c;无论是手机、相机还是其他电子设备&#xff0c;都离不开它的陪伴。然而&#xff0c;当我们在某一天突然发现存储卡上的文件出现了乱码&#xff0c;那种焦虑和困惑感简直无法…

Linux环境(Ubuntu)上的防火墙工具使用方法

目录 概述 1 防火墙工具&#xff08;ufw&#xff09; 1.1 安装防火墙工具&#xff1a; 1.2 操作防火墙相关命令 2 ufw操作命令的范例 2.1 打开/关闭防火墙 2.1.1 打开防火墙 2.1.2 关闭防火墙 2.1.3 查询当前防火墙状态 2.1.4 允许选择的端口访问 2.1.5 允许选择固定…

【海贼王的数据航海】排序——直接选择排序|堆排序

目录 1 -> 选择排序 1.1 -> 基本思想 1.2 -> 直接选择排序 1.2.1 -> 代码实现 1.3 -> 堆排序 1.3.1 -> 代码实现 1 -> 选择排序 1.1 -> 基本思想 每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&…

c++入门你需要知道的知识点(下)

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今日主菜&#xff1a;c入门 主厨&#xff1a;邪王真眼 所属专栏&#xff1a;c专栏 主厨的主页&#xff1a;Chef‘s blog 前言&#xff1a; 上次我们通过c入…

C#构建类库

类库程序集能将类型组合成易于部署的单元&#xff08;DLL文件&#xff09;&#xff0c;为了使编写的代码能够跨多个项目重用&#xff0c;应该将他们放在类库程序集中。 一、创建类库 在C#中&#xff0c;构建类库是指创建一个包含多个类的项目&#xff0c;这些类可以被其他应用…

JavaScript进阶:js的一些学习笔记-4

文章目录 1. 拷贝1. 浅拷贝2. 深拷贝 2. 异常处理 1. 拷贝 这里指的拷贝是指拷贝引用类型的数据(对象) 1. 浅拷贝 拷贝对象&#xff1a;Object.assign() 或者 {…obj} 展开运算符 const obj {name:liuze,age:23 } const o {...obj}; o.age 22; console.log(o); console.…

华为WLAN配置攻击检测功能示例

华为WLAN配置攻击检测功能示例 组网图形 图1 配置攻击检测功能组网图 配置流程组网需求配置思路配置注意事项操作步骤配置文件 配置流程 WLAN不同的特性和功能需要在不同类型的模板下进行配置和维护&#xff0c;这些模板统称为WLAN模板&#xff0c;如域管理模板、射频模板、…

瑞熙贝通打造智慧校园实验室安全综合管理平台

一、建设思路 瑞熙贝通实验室安全综合管理平台是基于以实验室安全&#xff0c;用现代化管理思想与人工智能、大数据、互联网技术、物联网技术、云计算技术、人体感应技术、语音技术、生物识别技术、手机APP、自动化仪器分析技术有机结合&#xff0c;通过建立以实验室为中心的管…

LTE中的多址接入技术

OFDM&#xff08;Orthogonal Frequency Division Multiplexing&#xff09;正交频分复用技术&#xff0c;多载波调制的一种。将一个宽频信道分成若干正交子信道&#xff0c;将高速数据信号转换成并行的低速子数据流&#xff0c;调制到每个子信道上进行传输。 传统FDM:为避免载波…

Redisson 分布式锁原理分析

Redisson 分布式锁原理分析 示例程序 示例程序&#xff1a; public class RedissonTest {public static void main(String[] args) {Config config new Config();config.useSingleServer().setPassword("123456").setAddress("redis://127.0.0.1:6379"…