STM32的CAN总线调试经验分享

相关文章

CAN总线简易入门教程
CAN总线显性电平和隐性电平详解
STM32的CAN总线调试经验分享

文章目录

  • 相关文章
  • 背景
  • CAN总线
    • CAN控制器
    • CAN收发器
  • 调试过程
    • 硬件排查
    • CAN分析仪
    • 芯片CAN控制器调试
  • 总结

背景

最近负责的一个项目用的主控芯片是STM32F407IGT6,需要和几个电机控制器进行通讯,有很多参数需要进行监控。负责固件开发的同事一直搞不定一个问题。就是开启CAN的接收中断,接收不到数据,问题卡了很久,一直无法闭环。

CAN总线

CAN总线是一种串行通信协议,用于在微控制器和其他设备之间传输数据。CAN总线通常用于汽车、工业自动化和机器人等领域。

CAN总线的硬件通常由以下几个部分组成:

  • 控制器区域:包括CAN控制器和CAN收发器;
  • 总线电缆:用于连接CAN总线上的所有设备;
  • 终端电阻:用于终止总线,以减少反射和信号干扰;
  • 外部电源:用于为CAN总线提供电源;

CAN总线的控制器区域通常包括CAN控制器CAN收发器

  • CAN控制器负责处理CAN总线上的数据传输,包括数据发送和接收、错误检测和纠正等;
  • CAN收发器则负责将CAN控制器的信号转换为总线上的电信号,并将总线上的电信号转换为CAN控制器可以理解的信号。

CAN控制器

主板上的芯片STM32F407IGT6中带有两路的CAN控制器,分别为CAN1CAN2,具体如下图所示;
STM32F407中的CAN控制器

CAN收发器

主板上使用的是芯片SN65HVD230,这是TI公司的一款性能强大且具体低功耗功能的CAN收发器,具体的典型应用电路如下所示;
CAN硬件

调试过程

硬件排查

设备的调试过程中,首先要确保硬件链路上是否正常。最常见的方法就是直接用示波器进行检查。
具体如下所示;

  1. 检查CAN控制器和CAN收发器之间是否正常;
  2. 检查CAN收发器的差分信号是否正常,这里可能要了解一下CAN总线电平的显性电平和隐性电平的特点,以及CAN底层协议的细节,会比较复杂;

个人比较推荐使用上述步骤检查硬件链路是否存在问题,那如何对数据进行分析呢?当然可以对着示波器的波形一点一点进行分析,但是这样是很低效的,这里我建议使用CAN分析仪进行数据抓包,下面我们继续进行介绍。

CAN分析仪

至于数据传输是否正确,可以使用CAN盒进行数据监听,下面是我使用的一款CAN分析仪,如图;

CAN分析仪
将CAN分析仪的CAN_HCAN_L分别并联到CAN收发器的CAN_HCAN_L上,然后打开CAN分析仪厂家提供的PC软件,就可以对CAN总线的数据进行监听;
实际连接情况

  1. 将CAN分析仪接入到CAN总线;
  2. 将CAN分析仪连接到电脑(这里是USB接口),需要配置相同的波特率;
  3. 打开CAN分析仪配套的PC软件,进行数据的收发;

    进行到这里,我在项目中遇到的问题是,发送正常,但是STM32F407无法接收到连续的数据,可以接收到一次数据,后面便无法再进入中断。
    这时候,只能再芯片端进行Debug了。

芯片CAN控制器调试

这里的代码用的HAL库,库版本相对来说比较老,是V1.7.10版本的,如下图所示;

当时我把项目升级到最新的HAL库,发现CAN部分的驱动改动比较大,另外,下文都是基于V1.7.10版本的HAL库。

CAN控制器的初始化代码如下所示;

void MX_CAN_Init(void)
{
	CAN_FilterConfTypeDef  sFilterConfig;

	/*CAN单元初始化*/
	hCAN.Instance = CANx;             /* CAN外设 */
	hCAN.pTxMsg = &TxMessage;
	hCAN.pRxMsg = &RxMessage;

	hCAN.Init.Prescaler = 6;          /* BTR-BRP 波特率分频器  定义了时间单元的时间长度 42/(1+6+7)/6 = 500Kbps */
	hCAN.Init.Mode = CAN_MODE_NORMAL; /* 正常工作模式 */
	hCAN.Init.SJW = CAN_SJW_1TQ;      /* BTR-SJW 重新同步跳跃宽度 1个时间单元 */
	hCAN.Init.BS1 = CAN_BS1_6TQ;      /* BTR-TS1 时间段1 占用了6个时间单元 */
	hCAN.Init.BS2 = CAN_BS2_7TQ;      /* BTR-TS1 时间段2 占用了7个时间单元 */
	hCAN.Init.TTCM = DISABLE;         /* MCR-TTCM  关闭时间触发通信模式使能 */
	hCAN.Init.ABOM = ENABLE;          /* MCR-ABOM  自动离线管理 */
	hCAN.Init.AWUM = ENABLE;          /* MCR-AWUM  使用自动唤醒模式 */
	hCAN.Init.NART = DISABLE;         /* MCR-NART  禁止报文自动重传	  DISABLE-自动重传 */
	hCAN.Init.RFLM = DISABLE;         /* MCR-RFLM  接收FIFO 锁定模式  DISABLE-溢出时新报文会覆盖原有报文 */
	hCAN.Init.TXFP = DISABLE;         /* MCR-TXFP  发送FIFO优先级 DISABLE-优先级取决于报文标示符 */
	HAL_CAN_Init(&hCAN);

	/*CAN过滤器初始化*/
	sFilterConfig.FilterNumber = 0;                    /* 过滤器组0 */
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  /* 工作在标识符屏蔽位模式 */
	sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; /* 过滤器位宽为单个32位。*/
	/* 使能报文标示符过滤器按照标示符的内容进行比对过滤,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */
	sFilterConfig.FilterIdHigh         = 0x0000;	//(((uint32_t)0x1314<<3)&0xFFFF0000)>>16;				/* 要过滤的ID高位 */
	sFilterConfig.FilterIdLow          = 0x0000;	//(((uint32_t)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; /* 要过滤的ID低位 */
	sFilterConfig.FilterMaskIdHigh     = 0x0000;			/* 过滤器高16位每位必须匹配 */
	sFilterConfig.FilterMaskIdLow      = 0x0000;			/* 过滤器低16位每位必须匹配 */
	sFilterConfig.FilterFIFOAssignment = 0;           /* 过滤器被关联到FIFO 0 */
	sFilterConfig.FilterActivation = ENABLE;          /* 使能过滤器 */ 
	sFilterConfig.BankNumber = 14;
	HAL_CAN_ConfigFilter(&hCAN, &sFilterConfig);
  
}

根据注释,可以大概看懂,另外再简单分析一下关键的几点;

  • 波特率设置为 500Kbps;
  • 对报文不进行过滤,可以接收任何扩展ID的数据;

虽然不进行任何过滤,但是还是无法接收到CAN回传的数据,无法进入的接收中断;

从STM32F407的编程手册里了解到,
CAN1的FIFO0的接收中断
不难发现,CAN1FIFO0产生接收中断需要满足三个条件中的任意一个;

  • FMPIE01FMP01FIFO不为空会产生中断
  • FFIE01FULL1FIFO满,会产生中断
  • FOVIE01FOVR01FIFO溢出,会产生中断

手册里是这样描述的,如下图所示;
接收中断
使用仿真器对芯片进行调试,设置断点,发现FMPIE0被清空了,具体如下图所示;

FMPIE0这一位是FIFO0中有挂起的消息会产生中断的中断使能标志位;


所以到这里,问题有点明朗了,为什么无法进入中断?是中断使能位被清空了。

那么下面就是检查代码,看看是哪里把中断给disable了。

继续调试,发现在ESR寄存器中,TEC的值一直增加,然后EWGF被值1了;具体如下所示;
在这里插入图片描述
TECREC分别是发送错误计数器和接收错误计数器;

如 CAN 协议所述,错误管理完全由硬件通过发送错误计数器( CAN_ESR 寄存器中的 TEC
值)和接收错误计数器( CAN_ESR 寄存器中的 REC 值)来处理,这两个计数器根据错误
状况进行递增或递减。有关 TEC 和 REC 管理的详细信息,请参见 CAN 标准。
两者均可由软件读取,用以确定网络的稳定性。此外, CAN 硬件还将在 CAN_ESR 寄存器中
提供当前错误状态的详细信息。通过 CAN_IER 寄存器( ERRIE 位等),软件可以非常灵活
地配置在检测到错误时生成的中断。

TEC大于96的时候,硬件会将EWGF1(错误警告标志位);在代码中找到了相应的宏定义;这下问题越来越清晰了。

在这里插入图片描述
全文搜索这个宏定义,在HAL_CAN_IRQHandler中找到了__HAL_CAN_DISABLE_IT(CAN_IT_FMP0),关闭了FIFO0的消息挂起中断,
整体代码如下;

/**
  * @brief  Handles CAN interrupt request  
  * @param  hcan: pointer to a CAN_HandleTypeDef structure that contains
  *         the configuration information for the specified CAN.
  * @retval None
  */
void HAL_CAN_IRQHandler(CAN_HandleTypeDef* hcan)
{
  uint32_t tmp1 = 0U, tmp2 = 0U, tmp3 = 0U;
  uint32_t errorcode = HAL_CAN_ERROR_NONE;

  /* Check Overrun flag for FIFO0 */
  tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FOV0);
  if(tmp1 && tmp2)
  {
    /* Set CAN error code to FOV0 error */
    errorcode |= HAL_CAN_ERROR_FOV0;

    /* Clear FIFO0 Overrun Flag */
    __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV0);
  }
  /* Check Overrun flag for FIFO1 */
  tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FOV1);

  if(tmp1 && tmp2)
  {
    /* Set CAN error code to FOV1 error */
    errorcode |= HAL_CAN_ERROR_FOV1;

    /* Clear FIFO1 Overrun Flag */
    __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV1);
  }

  /* Check End of transmission flag */
  if(__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_TME))
  {
    tmp1 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_0);
    tmp2 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_1);
    tmp3 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_2);
    if(tmp1 || tmp2 || tmp3)  
    {
      tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0);
      tmp2 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1);
      tmp3 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2);
      /* Check Transmit success */
      if(tmp1 || tmp2 || tmp3)
      {
        /* Call transmit function */
        CAN_Transmit_IT(hcan);
      }
      else /* Transmit failure */
      {
        /* Set CAN error code to TXFAIL error */
        errorcode |= HAL_CAN_ERROR_TXFAIL;
      }

      /* Clear transmission status flags (RQCPx and TXOKx) */
      SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0  | CAN_TSR_RQCP1  | CAN_TSR_RQCP2 | \
                                   CAN_FLAG_TXOK0 | CAN_FLAG_TXOK1 | CAN_FLAG_TXOK2);
    }
  }

  tmp1 = __HAL_CAN_MSG_PENDING(hcan, CAN_FIFO0);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FMP0);
  /* Check End of reception flag for FIFO0 */
  if((tmp1 != 0U) && tmp2)
  {
    /* Call receive function */
    CAN_Receive_IT(hcan, CAN_FIFO0);
  }

  tmp1 = __HAL_CAN_MSG_PENDING(hcan, CAN_FIFO1);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FMP1);
  /* Check End of reception flag for FIFO1 */
  if((tmp1 != 0U) && tmp2)
  {
    /* Call receive function */
    CAN_Receive_IT(hcan, CAN_FIFO1);
  }

  /* Set error code in handle */
  hcan->ErrorCode |= errorcode;

  tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_EWG);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_EWG);
  tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR);
  /* Check Error Warning Flag */
  if(tmp1 && tmp2 && tmp3)
  {
    /* Set CAN error code to EWG error */
    hcan->ErrorCode |= HAL_CAN_ERROR_EWG;
  }
  
  tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_EPV);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_EPV);
  tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR); 
  /* Check Error Passive Flag */
  if(tmp1 && tmp2 && tmp3)
  {
    /* Set CAN error code to EPV error */
    hcan->ErrorCode |= HAL_CAN_ERROR_EPV;
  }
  
  tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_BOF);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_BOF);
  tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR);  
  /* Check Bus-Off Flag */
  if(tmp1 && tmp2 && tmp3)
  {
    /* Set CAN error code to BOF error */
    hcan->ErrorCode |= HAL_CAN_ERROR_BOF;
  }
  
  tmp1 = HAL_IS_BIT_CLR(hcan->Instance->ESR, CAN_ESR_LEC);
  tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_LEC);
  tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR);
  /* Check Last error code Flag */
  if((!tmp1) && tmp2 && tmp3)
  {
    tmp1 = (hcan->Instance->ESR) & CAN_ESR_LEC;
    switch(tmp1)
    {
      case(CAN_ESR_LEC_0):
          /* Set CAN error code to STF error */
          hcan->ErrorCode |= HAL_CAN_ERROR_STF;
          break;
      case(CAN_ESR_LEC_1):
          /* Set CAN error code to FOR error */
          hcan->ErrorCode |= HAL_CAN_ERROR_FOR;
          break;
      case(CAN_ESR_LEC_1 | CAN_ESR_LEC_0):
          /* Set CAN error code to ACK error */
          hcan->ErrorCode |= HAL_CAN_ERROR_ACK;
          break;
      case(CAN_ESR_LEC_2):
          /* Set CAN error code to BR error */
          hcan->ErrorCode |= HAL_CAN_ERROR_BR;
          break;
      case(CAN_ESR_LEC_2 | CAN_ESR_LEC_0):
          /* Set CAN error code to BD error */
          hcan->ErrorCode |= HAL_CAN_ERROR_BD;
          break;
      case(CAN_ESR_LEC_2 | CAN_ESR_LEC_1):
          /* Set CAN error code to CRC error */
          hcan->ErrorCode |= HAL_CAN_ERROR_CRC;
          break;
      default:
          break;
    }

    /* Clear Last error code Flag */ 
    hcan->Instance->ESR &= ~(CAN_ESR_LEC);
  }
  
  /* Call the Error call Back in case of Errors */
  if(hcan->ErrorCode != HAL_CAN_ERROR_NONE)
  {
    /* Clear ERRI Flag */ 
    hcan->Instance->MSR = CAN_MSR_ERRI; 
    /* Set the CAN state ready to be able to start again the process */
    hcan->State = HAL_CAN_STATE_READY;

    /* Disable interrupts: */
    /*  - Disable Error warning Interrupt */
    /*  - Disable Error passive Interrupt */
    /*  - Disable Bus-off Interrupt */
    /*  - Disable Last error code Interrupt */
    /*  - Disable Error Interrupt */
    /*  - Disable FIFO 0 message pending Interrupt */
    /*  - Disable FIFO 0 Overrun Interrupt */
    /*  - Disable FIFO 1 message pending Interrupt */
    /*  - Disable FIFO 1 Overrun Interrupt */
    /*  - Disable Transmit mailbox empty Interrupt */
    __HAL_CAN_DISABLE_IT(hcan, CAN_IT_EWG |
                               CAN_IT_EPV |
                               CAN_IT_BOF |
                               CAN_IT_LEC |
                               CAN_IT_ERR |
                               CAN_IT_FMP0|
                               CAN_IT_FOV0|
                               CAN_IT_FMP1|
                               CAN_IT_FOV1|
                               CAN_IT_TME);

    /* Call Error callback function */
    HAL_CAN_ErrorCallback(hcan);
  }  
}

最后,找到无法进入接收中断的原因,是CAN总线出现发送错误的情况,从而触发了错误警告标志位EWGF,进而将关闭了消息挂起中断。

总结

本文简单介绍了在STM32F407上的CAN总线调试过程,解决了一个数据接收的问题,简单整理了一下调试的过程和思路。不过本人能力有限,难免存在错误和纰漏,请不吝赐教,如果文章帮到了你,点赞支持一下👍👍👍

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

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

相关文章

DWF文件怎么用CAD打开?DWF输入CAD步骤

DWF是一种开放、安全的文件格式&#xff0c;它可以将丰富的设计数据高效率地分发给需要查看、评审或打印这些数据的任何人。那么&#xff0c;DWF文件如何打开呢&#xff1f;下面就和小编一起来了解一下DWF输入浩辰CAD软件中的具体操作步骤吧&#xff01; DWF输入CAD中步骤&…

安装CentOS系统

打开 Oracle VM VirtualBox 点击新建 输入名称 点击下一步 点击下一步 点击创建 点击下一步 点击下一步 分配30G硬盘 点击创建 创建成功 点击启动按钮 选择 CentOS 系统 iso 镜像文件 点击启动 按键盘方向键 “上键”&#xff0c;选择第一项 按键盘回车键&#xff0c;然后等待 …

QT搭建MQTT开发环境

QT搭建MQTT开发环境 第一步、明确安装的QT版本 注意&#xff1a; 从QT5.15.0版本开始&#xff0c;官方不再提供离线版安装包&#xff0c;除非你充钱买商业版。 而在这里我使用的QT版本为5.15.2&#xff0c;在线安装了好久才弄好&#xff0c;还是建议使用离线安装的版本 在这里…

代码随想录复习——单调栈篇 每日温度 下一个更大元素12 接雨水 柱状图中最大的矩形

739.每日温度 每日温度 暴力解法双指针 def dailyTemperatures(self, temperatures: List[int]) -> List[int]:n len(temperatures)res [0] * nfor i in range(n):for j in range(i,n):if temperatures[j] < temperatures[i]: continueelse: res[i] j-ibreakreturn …

pytorch 计算混淆矩阵

混淆矩阵是评估模型结果的一种指标 用来判断分类模型的好坏 预测对了 为对角线 还可以通过矩阵的上下角发现哪些容易出错 从这个 矩阵出发 可以得到 acc &#xff01; precision recall 特异度&#xff1f; 目标检测01笔记AP mAP recall precision是什么 查全率是什么 查准率…

【K8S系列】深入解析Pod对象(一)

目录 序言 1.问题引入 1.1 问题描述 2 问题解答 2.1 pod 属性 2.1.1 NodeSelector 2.1.2 HostAliases 2.1.3 shareProcessNamespace 2.1.4 NodeName 2.1.5 其他pod属性 2.2 容器属性 2.2.1 ImagePullPolicy 2.2.2 Lifecycle 3 总结 4. 投票 序言 任何一件事情&am…

一文读懂强化学习!

一.了解强化学习1.1基本概念强化学习是考虑智能体&#xff08;Agent&#xff09;与环境&#xff08;Environment&#xff09;的交互问题&#xff1a;智能体处在一个环境中&#xff0c;每个状态为智能体对当前环境的感知&#xff1b;智能体只能通过动作来影响环境&#xff0c;当…

空间信息智能应用团队研究成果介绍及人才引进

目录1、多平台移动测量技术1.1 车载移动测量系统1.2 机载移动测量系统2、数据处理与应用技术研究2.1 点云与影像融合2.2 点云配准与拼接2.3 点云滤波与分类2.4 道路矢量地图提取2.5 道路三维自动建模2.6 道路路面三维病害分析2.7 多期点云三维变形分析2.8 地表覆盖遥感监测分析…

ChatGPT在安全研究领域的应用实践

引言ChatGPT是一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过理解和学习人类的语言来进行对话&#xff0c;并能进行连续对话。目前ChatGPT已经官方已经更新模型到4.0版本&#xff0c;宣称它是“最先进的系统&#xff0c;能生产更安全和更有用的回复”。当前使用…

wandb:可视化和超参数寻优

参考博客&#xff1a;https://zhuanlan.zhihu.com/p/591047340 1、注册账号 首先&#xff0c;去wandb官网注册一个账号&#xff0c;选择个人使用即可&#xff08;根据个人需要&#xff09; 然后&#xff0c;登录得到一个API key 2、wandb使用 &#xff08;1&#xff09;命令…

Spring框架学习--xml和Annotation方式实现IOC

AnnotationXml的spring-IOC和全Annotation的spring-IOC 文章目录AnnotationXml的spring-IOC和全Annotation的spring-IOC学习目标第二章 基于AnnotationXml的spring-IOC【重点】1、annotationxml【入门案例】(5)【1】目标【2】实现【2.1】创建项目【2.3】改写AccountDaoImpl【2.…

刷题记录(2023.3.14 - 2023.3.18)

[第五空间 2021]EasyCleanup 临时文件包含考点 分析源码&#xff0c;两个特殊的点&#xff0c;一个是 eval&#xff0c;另一个是 include eval 经过了 strlen filter checkNums 三个函数 include 经过了 strlen filter 两个函数 filter 检测是否包含特定的关键字或字符 fun…

【数据结构与算法】用栈实现队列

文章目录&#x1f63b;前言如何用栈实现队列&#xff1f;用栈实现队列整体的实现代码&#x1f63c;写在最后&#x1f63b;前言 &#x1f61d;上一章我们用队列实现了一个栈&#xff08;-> 传送门 <-&#xff09;&#xff0c;而这一章就带大家用栈实现一个队列。 &#x1…

< 每日算法:在排序数组中查找元素的第一个和最后一个位置 >

每日算法 - JavaScript解析&#xff1a;在排序数组中查找元素的第一个和最后一个位置 一、任务描述&#xff1a;> 示例 1> 示例 2> 示例 3二、题意解析三、解决方案&#xff1a;往期内容 &#x1f4a8;一、任务描述&#xff1a; 给你一个按照非递减顺序排列的整数数组…

C++基础算法③——排序算法(选择、冒泡附完整代码)

排序算法 1、选择排序 2、冒泡排序 1、选择排序 基本思想&#xff1a;从头至尾扫描序列&#xff0c;每一趟从待排序元素中找出最小(最大)的一个元素值&#xff0c;然后与第一个元素交换值&#xff0c;接着从剩下的元素中继续这种选择和交换方式&#xff0c;最终得到一个有序…

冲击蓝桥杯-时间问题(必考)

目录 前言&#xff1a; 一、时间问题 二、使用步骤 1、考察小时&#xff0c;分以及秒的使用、 2、判断日期是否合法 3、遍历日期 4、推算星期几 总结 前言&#xff1a; 时间问题可以说是蓝桥杯&#xff0c;最喜欢考的问题了,因为时间问题不涉及到算法和一些复杂的知识&#xf…

第十四届蓝桥杯三月真题刷题训练——第 18 天

目录 第 1 题&#xff1a;排列字母 问题描述 运行限制 代码&#xff1a; 第 2 题&#xff1a;GCD_数论 问题描述 输入格式 输出格式 样例输入 样例输出 评测用例规模与约定 运行限制 第 3 题&#xff1a;选数异或 第 4 题&#xff1a;背包与魔法 第 1 题&#x…

1649_Excel中删除重复的数据

全部学习汇总&#xff1a; GreyZhang/windows_skills: some skills when using windows system. (github.com) 长久时间的开发工作性质导致我对Windows生态下的很多工具没有一个深度的掌握。有时候&#xff0c;别说深度&#xff0c;可能最为浅显的操作都是不熟悉的。这个不仅仅…

JVM学习.02 内存分配和回收策略

1、前言《JVM学习.01 内存模型》篇讲述了JVM的内存布局&#xff0c;其中每个区域是作用&#xff0c;以及创建实例对象的时候内存区域的工作流程。上文还讲到了关于对象存货后&#xff0c;会被回收清理的过程。今天这里就着重讲一下对象实例是如何被清理回收的&#xff0c;以及清…

5.方法(最全C#方法攻略)

目录 5.1 方法的结构 5.2 方法体内部的代码执行 5.3.1 类型推断和Var关键字 5.3.2 嵌套块中的本地变量 5.4 本地常量 5.5 控制流 5.6 方法调用 5.7 返回值 5.8 返回语句和void 方法 5.9 参数 5.9.1 形参 5.9.2 实参 位置参数示例 5.10 值参数 5.11 引用参数 5.12…