STM32 HAL I2C(IIC)通信的序列传输(restart condition)

news2024/9/29 21:24:34

STM32 HAL I2C(IIC)通信的序列(Seq)传输函数(restart condition)

neozng1@hnu.edu.cn

文章目录

  • STM32 HAL I2C(IIC)通信的序列(Seq)传输函数(restart condition)
    • XferOption的含义
    • HAL源码解析
    • 实验验证

阅读本文需要你对I2C协议有基本的理解,包括收发过程,协议包的定义等。
参考资料和数据手册:

  1. I2C specification
  2. STM32 F4XX Reference Manual
  3. I2C Bus

我们知道,在I2C通信中,如果主机不想释放总线的归属权,希望在此次通信完成后继续给当前从机发送数据,或向另一个新的地址(另一个从机)发送数据,那么可以不发送STOP信号,而是继续占有总线,直接发送一个新的START信号,即I2C协议中所谓的Restart Condition。HAL自然提供了相应的函数支持,他们是一系列以HAL_I2C_Master/Slave_Seq_Transmit/Receive_IT/DMA()命名的函数。

但是HAL库的文档中对这些函数的使用并没有详细的介绍,国内外的网站上也没有相关函数的使用教程和信息,因此笔者在通过资料查阅和实验,以及花费了大量的时间阅读HAL的源码之后,总结出了这一篇参考教程。

本文重点介绍HAL的I2C序列传输主机(master)接口,即HAL库中下列函数的使用,和他们的参数XferOptoin的含义:

在这里插入图片描述
在这里插入图片描述

HAL库提供的8个用于I2C序列通信的接口

在这里插入图片描述

XferOption中的几种可选定义

XferOption的含义

我们按照定义的顺序进行讲解。

I2C_FIRST_AND_LAST_FRAME
I2C_FIRST_FRAME    
I2C_NEXT_FRAME 
I2C_FIRST_AND_NEXT_FRAME
I2C_LAST_FRAME
I2C_LAST_FRAME_NO_STOP             
I2C_OTHER_FRAME        
I2C_OTHER_AND_LAST_FRAME      
  1. I2C_FIRST_AND_LAST_FRAME

    如果在调用以上函数时传入了该参数,则和普通的I2C传输函数没有什么区别,字如其名,本次传输的是第一次也是最后一次,传输将会在发送或接收了函数参数指定的字节数后结束(主机会发送STOP结束通信)。

  2. I2C_FIRST_FRAME

    该参数在开始第一次传输的时候使用。即如果你需要在一次传输结束之后不释放总线马上开始另一次方向相同且目标从机都相同的传输(此次是transmit下次必须还是transmit,不可以转为receive,且传输的从机必须是同一个),那么就选择这个参数。使用此参数,会在传输结束之后让I2C硬件继续占用总线,直到下一次传输开始。

    传入这个参数后,I2C不会发出RESTART信号,只是传输数据之后保持对总线的占用,因此此次连接的从机会继续对总线保持监测。因此在下一次传输时,通信不能改变方向且必须和同一个从机进行;除非使用I2C_LAST_FRAME_NO_STOPI2C_OTHER_FRAMEI2C_OTHER_AND_LAST_FRAME参数。

  3. I2C_NEXT_FRAME

    字如其名。在之前已经调用过一次传输函数并且传入的参数为I2C_FIRST_FRAME之后,第二次调用同一个传输接口,并希望之后继续占用总线,不要释放(比如有第三次传输或更多次的传输),则使用此参数。注意,传输的方向必须和第一次相同。如第一次使用HAL_I2C_Master_Seq_Receive_IT()并传入了**I2C_FIRST_FRAME,那么本次也应该调用HAL_I2C_Master_Seq_Receive_IT(),同时传入I2C_NEXT_FRAME**参数。

    在完成本次传输之后,下一次的通信不能改变方向且必须和同一个从机进行;除非使用I2C_LAST_FRAME_NO_STOPI2C_OTHER_FRAMEI2C_OTHER_AND_LAST_FRAME参数。

  4. I2C_FIRST_AND_NEXT_FRAME

    该参数是2和3的结合。仅仅是为了代码的复用性和编程更加方便而添加的。在第一次和第二次调用传输接口的时候,都可以传入这个参数。即I2C占有总线之后,连续进行两次方向相同的传输,就可以使用这个参数,同时保持总线不释放,继续占用。

  5. I2C_LAST_FRAME

    在之前已经调用过传输接口函数,即我们已经占有了总线的情况下,希望在本次传输结束后终止,即释放总线发出STOP信号,则传入此参数。注意,传输方向需要和之前相同,地址也需要相同。在本次传输结束之后,主机将会发出STOP信号,释放总线。

  6. I2C_LAST_FRAME_NO_STOP

    注意,这是最关键的一个参数。此参数在已经完成一次传输并且希望在下一次传输中调换方向时使用。很多时候我们需要先向从机传送消息,写入“命令码”,从机会根据命令码准备反馈消息;完成写入后,主机需要立刻启动读取,将数据读回。为了防止其他主机占用总线,我们就需要这个接口。

    在之前一次传输中若调用了参数为I2C_FIRST_FRAMEI2C_NEXT_FRAMEI2C_FIRST_AND_NEXT_FRAME的传输函数,且在此次希望改变传输的方向,则在调用传输函数时传入此参数。

    I2C_LAST_FRAME_NO_STOP为参数的传输函数中,首先会发出restart,然后重新发送从机地址(当然包括读写位),再进行数据写入/读取。并且在此次传输结束之后,总线不会被释放如果希望在下一次传输中再次变换传输方向,可以继续传入此参数,或使用I2C_OTHER_FRAMEI2C_OTHER_AND_LAST_FRAME参数

接下来两个参数都是为切换从机准备的,即使用这两个参数允许此次通信的目标从机(地址)和之前不同。

  1. I2C_OTHER_FRAME

    只需要在之前启用了传输且没有发出STOP(只要没有释放总线),便可以使用此参数开启一次新的传输。并且在这次传输中可以选中其他从机,**即参数中的DevAddress可以不同。**在此次传输结束之后,不会发出STOP信号,之后可以继续传输。

    例如,首先调用HAL_I2C_Master_Seq_Receive_IT(),传入了从机1的地址,XferOptionI2C_FIRST_FRAME,从从机1处接收了10byte的数据;随后,调用HAL_I2C_Master_Seq_Transmit_IT(),传入了从机2的地址,XferOptionI2C_OTHER_FRAME,向从机2发送了5byte的数据,最后再次调用HAL_I2C_Master_Seq_Transmit_IT()XferOptionI2C_LAST_FRAME,向从机2发送了1byte数据之后发出STOP,释放总线。

    整个过程中,I2C总线的情况是这样的:

    1. 主机拉低SDA发送START信号,随后发送从机1的地址,从机1 ack之后主机连续发送10byte的数据(每个byte间从机都会ack应答)
    2. 主机拉低SDA发送RESTART信号,随后发送从机2的地址,从机2 ack后主机连续发送5byte数据
    3. 主机不会发送RESTART,继续向总线上发出1byte数据,从机2 ack后主机发出STOP,释放总线完成整个序列传输。
  2. I2C_OTHER_AND_LAST_FRAME

    此参数和第七个参数类似,只不过在传输结束后会发出STOP信号,结束通信让出总线的归属权。

P.S. : I2C的读写都必须由主机发起,也就是说,如果要在传输的途中改变传输方向,那么主机必须重新发出一包地址信息,因为地址的LSB(最低为)是读写位,只有从机收到地址才知道接下来一个字节是read or write。同时,要发送地址信息,之前必须要由RESTART信号,从机收到START or RESART,才会开始监听接下来一个byte的数据并将其当作地址处理,如果和自己的地址匹配,就接收接下来的信息。
10位地址模式也类似。

P.P.S. : STM32 F7系列就简化了序列通信的复杂度,将所有的参数归结为三种:AUTO_END,SOFT_END以及RELOAD_MODE,分别代表当前传输结束后发送STOP,当前传输结束后啥也不干继续占用总线以及传输前会发送RESTART信号。通过“或”运算( | )来组合三种标志,让用户灵活度大大提高。

HAL源码解析

I2C通信的函数实现其实大同小异,我们以STM32F4 HAL中的HAL_I2C_Master_Seq_Transmit_IT()为例,介绍I2C的Seq transfer序列传输过程。为了有最好的体验,建议将代码复制到VSCode中,提供高亮支持以便观看,或自行打开HAL中的对应文件(stm32f4xx_hal_i2c.c,在CubeMX生成的Driver/STM32F4xx_HAL_Driver/Src文件夹下)。

注意,ST不同的产品线HAL代码的实现不同,这是由于不同系列的硬件支持的特性不同,以及他们之间的兼容性不同。

直接上源码,笔者已经添加了注释并将无用的部分省略(通过//注释以及//…),很详细:

HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions)
{
	// 临时变量申明和赋值,参数检查等
    // ...

  if (hi2c->State == HAL_I2C_STATE_READY) // 判断I2C外设是否READY,有没有其他线程占用
  {
    /* 如果不是第一次调用接口(不是首次开启传输),要通过I2C的状态寄存器检查I2C硬件是否BUSY */
    if ((READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP) || (XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME))
    {
      /* Wait until BUSY flag is reset */
      count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U);
      do  
      {
          //这部分都是超时检查,如果超时会返回HAL_ERROR错误...
      }
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); // 轮询,直到I2C_FLAG_BUSY被硬件RESET
    }

    // 传输的初始化配置,包括给I2C硬件加锁,配置传输字节数和传输方向等
	// ... 

    /* 如果传输的方向没有改变,并且XferOption并不是I2C_OTHER_FRAME或I2C_OTHER_AND_LAST_FRAME,那么就不会产生RESTART */
    if ((Prev_State != I2C_STATE_MASTER_BUSY_TX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) // Prev_State当中保存了上一次传输的状态(Tx or Rx)
    {
      /* Generate Start */
      SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
    }
      
	// 解锁I2C硬件,开启中断等
	// ...
      
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

HAL_I2C_Master_Seq_Transmit_IT()实际上是中断和任务前端分离的设计,调用此函数只是设定了一些标志位,随后更多处理会在中断中进行,即HAL_I2C_EV_IRQHandler()函数,这里同样略去不重要的部分:

void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c)
{
	// 临时变量和参数的初始化与赋值
	// ...
    
  /* Master or Memory mode selected */
  if ((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM))
  {
    sr2itflags   = READ_REG(hi2c->Instance->SR2);
    sr1itflags   = READ_REG(hi2c->Instance->SR1);

    /* Exit IRQ event until Start Bit detected in case of Other frame requested */
    if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_SB) == RESET) && (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(CurrentXferOptions) == 1U))
    {
      return; // 如果start位还没有产生,直接退出,等到其被置位
    }

    /* SB Set ,起始位已经产生----------------------------------------------------------------*/
    if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_SB) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET))
    { // 会通过这个判断说明之前已经产生了RESTART位,在之前的分析中我们知道,只有第一次传输或传入了I2C_OTHER_FRAME的情况下,会发出RESTART信号
      // 也就是说,如果我们在第一次调用传输接口时传入I2C_FIRST_FRAME,第二次使用I2C_NEXT_FRAME的话,是不会进到这里的,也不会重新发送地址,而是会直接进入下方的/* I2C in mode Transmitter */部分.
      /* Convert OTHER_xxx XferOptions if any */
      I2C_ConvertOtherXferOptions(hi2c); // 这个宏会把OTHER_FRAME转化成其他参数,方便后续处理,我们不用管

      I2C_Master_SB(hi2c); // 此函数会根据调用HAL_I2C_Master_Seq_Transmit_IT()时设定的配置,并发送从机地址
    }
    /* ADDR Set,从机已经接收到地址发回ACK --------------------------------------------------------------*/
    else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADDR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET))
    { // 会通过这个判断进入到这里,说明从机已经接收到主机发送的地址,在之前的分析中我们知道,只有FIRST_FRAME或另外两个OTHER_FRAME会发出RESTART并发送从机地址,传入其他参数则不会重新发送地址.
      I2C_Master_ADDR(hi2c); // 此函数会处理ADDR等相关标志位,并启动数据位的发送
    }
    /* I2C in mode Transmitter,说明已经处在数据发送状态下-----------------------------------------------*/
    else if (I2C_CHECK_FLAG(sr2itflags, I2C_FLAG_TRA) != RESET)
    {  // !!!在使用I2C_NEXT_FRAME,I2C_FIRST_AND_NEXT_FRAME,I2C_LAST_FRAME的时候,进入数据传输阶段都会直接跑到这里,不会进入SB判断和ADDR的判断!!! 也就是说,使用这些参数不会发出RESTART信号,而是继续数据的传输.
      /* 如果启用了DMA传输,那么不能干扰DMA,会跳过这个判断语句.这里我们以IT传输为例,不用关心这句判断,会直接满足条件进入 */
      if (READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) != I2C_CR2_DMAEN)
      {
        // 补充:BTF=Byte Transfer Finished, TXE=Transmit data register Empty
        /* TXE set and BTF reset ,TXE=1,BTF=0说明发送数据寄存器为空(上一次发送已经完成),新的一次发送尚未开始-----------------------------------------------*/
        if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_TXE) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_BUF) != RESET) && (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) == RESET))
        {
          I2C_MasterTransmit_TXE(hi2c); // 这个函数会判断当前是否已经发送完所有字节,如果发送完,则根据传入的XferOption是否包含LAST决定要不要发送STOP位
        }
        /* BTF set -------------------------------------------------------------*/
        else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET))
        {
          if (CurrentState == HAL_I2C_STATE_BUSY_TX)
          {
            I2C_MasterTransmit_BTF(hi2c); // 这个函数会判断是否已经发送完所有字节,如果没发送完,则将数据写入DR进行发送;如果发送完,则处理同上.
          }
        }
      }
    }
    else
    {
      /* I2C in mode Receiver --------------------------------------------------*/
      // 我们以发送为例,接收就不讲解了,有兴趣的同学可以自行查看源码.当然,需要配合寄存器和功能说明手册
    }
  }
}

// 补充: I2C的CurrenState(工作状态)有以下几种,含义如注释所示:
typedef enum
{
  HAL_I2C_STATE_RESET             = 0x00U,   /*!< Peripheral is not yet Initialized         */
  HAL_I2C_STATE_READY             = 0x20U,   /*!< Peripheral Initialized and ready for use  */
  HAL_I2C_STATE_BUSY              = 0x24U,   /*!< An internal process is ongoing            */
  HAL_I2C_STATE_BUSY_TX           = 0x21U,   /*!< Data Transmission process is ongoing      */
  HAL_I2C_STATE_BUSY_RX           = 0x22U,   /*!< Data Reception process is ongoing         */
  HAL_I2C_STATE_LISTEN            = 0x28U,   /*!< Address Listen Mode is ongoing            */
  HAL_I2C_STATE_BUSY_TX_LISTEN    = 0x29U,   /*!< Address Listen Mode and Data Transmission
                                                 process is ongoing                         */
  HAL_I2C_STATE_BUSY_RX_LISTEN    = 0x2AU,   /*!< Address Listen Mode and Data Reception
                                                 process is ongoing                         */
  HAL_I2C_STATE_ABORT             = 0x60U,   /*!< Abort user request ongoing                */
  HAL_I2C_STATE_TIMEOUT           = 0xA0U,   /*!< Timeout state                             */
  HAL_I2C_STATE_ERROR             = 0xE0U    /*!< Error                                     */
} HAL_I2C_StateTypeDef;

实验验证

回学校后补充示波器图像。

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

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

相关文章

ceph-ansible安装指南-添加BlueStore

前言&#xff1a;ceph的资料真是很少&#xff0c;摸索一断时间&#xff0c;将整理的一资料和操作经验分享。本篇为干货&#xff0c;实操。生产环境可以借鉴使用。 知识点&#xff1a; 1、建议使用LVM卷管理作为Ceph底层的存储块设备&#xff0c;因为LVM卷可以随时扩展&#xf…

石子合并(分治+贪心+DP+前缀和)

石子合并一、题目内容二、思路分析1、状态转移方程&#xff08;1&#xff09;状态表示&#xff08;2&#xff09;状态转移2、循环设计及初始化&#xff08;1&#xff09;循环&#xff08;2&#xff09;初始化3、代码实现一、题目内容 二、思路分析 这道题也是一个很经典的DP问…

灵感来源于宇宙光束 长安汽车发布全新设计理念

12月28日&#xff0c;“重构想象 创领未来”2022首届长安汽车设计日正式启幕&#xff0c;长安汽车副总裁王孝飞发表“以创新之手、触万象之境”的主题演讲&#xff0c;分享了最新设计理念&#xff0c;正式发布长安汽车全新设计理念“纵横万象”。同时&#xff0c;基于这一理念打…

【Docker社区大会】WebAssembly:无需容器的 Docker——VMware技术总监 Daniel Lopez

本文授权翻译自 Wasm Labs VMware OCTO 的 blog&#xff1a; WebAssembly: Docker without container。这是 Wasm Labs 在 2022 年 12 月 15 日在冬季Docker Community All Hands 7 的关于 DockerWebAssembly 的演讲的文字版。 作者&#xff1a;Asen Alexandrov&#xff0c;Wa…

C#,图像二值化(08)——全局阈值优化算法及其源代码

1、全局阈值算法 基于灰度直方图的优化迭代算法之一。 Iterative Scheduler and Modified Iterative Water-Filling In the downlink, the inter-cell interference is only function of the power levels and is independent of the user scheduling decisions. This suggest…

【全网最细PAT题解】【PAT乙】1005 继续(3n+1)猜想(map和vector的运用)

题目链接 1005 继续(3n1)猜想 题目描述 1005 继续(3n1)猜想 分数 25 作者 CHEN, Yue 单位 浙江大学 卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递…

Linux网络收包过程

一、Linux 网络收包总览 在 TCP / IP 网络分层模型里&#xff0c;整个协议栈被分成了物理层、链路层、网络层&#xff0c;传输层和应用层。物理层对应的是网卡和网线&#xff0c;应用层对应的是我们常见的 Nginx&#xff0c;FTP 等等各种应用。Linux 实现的是链路层、网络层和…

scaner从外网到内网域渗透笔记

scaner 从外网到内网域渗透 1.环境配置 1.1靶场信息 用到的虚拟机共有三个 分别是 12server-db 、12-dc 、web1 12server-db、web1 这两个可以使用桥接或者nat模式根据需求可以设置 网卡1 12-dc用的是VMnet 19 这台机子已经绑定ip 主机名ip账号和密码web1192.168.0.160we…

工具(三):Jmeter压测数据在Grafana展示

Docker 安装 InfluxDBJMeter 配置 InfluxDB数据源Grafana 配置influxdb数据源 Docker 安装 InfluxDB docker pull influxdb:1.8.6 # 拉取influxdb镜像docker run -d -p 8086:8086 --namejmeterdb influxdb:1.8.6 # 启动influxdb&#xff0c;并命名为jmeterdbdocker exec -it …

使用Canvas实现封装路径,添加颜色,实现渐变,3d特效

目录 1.封装路径 2.添加颜色 3.渐变特效 3.1线性渐变 3.2径向渐变 3.3径向渐变模拟3d球 图形我们已经会绘制了&#xff0c;但是单一的图形肯定不好看&#xff0c;就像html没了css一样&#xff0c;所以今天我们要把图形上色。 1.封装路径 new Path2D()进行封装&#x…

NAPI简介

NAPI简介 它的核心概念就是不采用中断的方式读取数据&#xff0c;而代之以首先采用中断唤醒数据接收的服务程序&#xff0c;然后 POLL 的方法来轮询数据。NAPI是综合中断方式与轮询方式的技术。 中断的好处是响应及时&#xff0c;如果数据量较小&#xff0c;则不会占用太多的…

百度发布Apollo 8.0,架构、能力双双升级

12月28日&#xff0c;百度举行了Apollo开放平台8.0线上发布会。会上&#xff0c;百度正式推出Apollo开放平台8.0&#xff0c;进一步夯实了平台的易用性&#xff0c;让开发者操作更简单易上手。同时&#xff0c;百度Apollo也面向外界分享了在自动驾驶教育、生态合作伙伴等方面的…

SuperMap GIS基础软件中数据库使用指南

作者&#xff1a;Carlo 一、支持的主流数据库类型 1、主流数据库介绍 数据库名称版本不支持的数据集类型需要配置 客户端支持工作空间支持集群模式SQLPlus2008/2012/2016/2018&#xff08;仅 Windows 平台支持&#xff09;视频、复合点、复合线、复合面、复合文本数据集是是是…

球王贝利去世终年 82 岁,其是世界上唯一三次夺取世界杯冠军的足球运动员,如何评价他的传奇一生?

当地时间12月29日&#xff0c;巴西圣保罗市阿尔伯特爱因斯坦医院发布公告称&#xff0c;巴西知名运动员、“球王”贝利因结肠癌引发多器官衰竭&#xff0c;于当天15时27分去世&#xff0c;终年82岁。贝利女儿凯丽纳西门托在社交媒体发文&#xff1a;“我们的一切都归功于你&…

VR餐厅全新思路,可以为餐饮行业带来哪些好处?

餐饮行业的寒冬即将过去&#xff0c;逐渐迎来了发展的好机会&#xff0c;趁此机遇你会怎么做呢&#xff1f;餐饮行业的竞争依旧激烈&#xff0c;也许你的餐厅占据了很好的地理位置&#xff0c;或者是拥有时尚有品位的装修风格&#xff0c;亦或者拥有美味可口的菜品&#xff0c;…

报表开发工具FastReport.NET的五大常见问题及解决方法

Fastreport是目前世界上主流的图表控件&#xff0c;具有超高性价比&#xff0c;以更具成本优势的价格&#xff0c;便能提供功能齐全的报表解决方案&#xff0c;连续三年蝉联全球文档创建组件和库的“ Top 50 Publishers”奖。 FastReport.NET官方版下载&#xff08;qun&#x…

黑马Hive+Spark离线数仓工业项目--数仓主题应用层ST层构建(1)

数仓主题应用层ST层构建 1. 构建ST层&#xff1a;数据应用层 掌握每个主题的聚合指标和聚合的维度 - 工单主题 - 油站主题 - 回访主题 - 安装主题 - 费用主题2. DM层的设计 - 运营部门需要的数据抽取 数仓分层回顾 目标&#xff1a;回顾一站制造项目分层设…

使用命令设置Windows音量和音频输出设备

前言 Windows似乎并没有音量设置的命令&#xff0c;也没有输出设备的设置命令。如果你知道&#xff0c;请告诉我一下~ 因此&#xff0c;这里使用了一个神级小工具&#xff1a;nircmd 官网下载地址&#xff1a; 32位&#xff1a;http://www.nirsoft.net/utils/nircmd.zip 64…

2023年网络安全工程师面试题合集【首发】

以下为信息安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作~ 【一一帮助安全学习【点我】一一】①网络安全学习路线②20 份渗透测试电子书③安全攻防 357 页笔记④50 份安全攻防面试指南⑤安全红队渗透工具包⑥网络安…

Mathorcup数学建模竞赛第五届-【妈妈杯】D题:图像去噪中几类稀疏变换的矩阵表示(附一等奖获奖论文和matlab代码实现)

赛题描述 假设一幅二维灰度图像 X 受到加性噪声的干扰:Y=X+N ,Y 为观察到的噪声图像, N 为噪声。通过对于图像 Y 进行稀疏表示可以达到去除噪声的目的。任务: 2. 利用 Cameraman 图像中的一个小图像块(见图 1)进行验证。 3. 分析稀疏系数矩阵,比较四种方法的硬阈值稀…