【STM32】HAL库 之 CAN 开发指南

基于stm32 f407vet6芯片 使用hal库开发 can
简单讲解一下can的基础使用

CubeMX配置

在这里插入图片描述
这里打开CAN1 并且设置好波特率和NVIC相关的配置
波特率使用波特率计算器软件

在这里插入图片描述
使用采样率最高的这段 填入

在这里插入图片描述
得到波特率1M bit/s

然后编写代码
环形缓冲区

#include "driver_buffer.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"RingBuffer USERRxDataBuffer1; //定义用户缓冲区
RingBuffer USERRxDataBuffer2;/* 初始化环形缓冲区 */
int Driver_Buffer_Init(ptRingBuffer buffer, uint16_t size)
{if (buffer == NULL || size == 0)return -1;            /* 判断合法性 */if (buffer->fifo == NULL) /* 判断是否为内存大小空*/{buffer->fifo = (uint8_t *)malloc(size); /* 动态分配内存 */if (buffer->fifo == NULL){//printf("Malloc %d bytes failed.\r\n", size);return -1;}}buffer->pw = buffer->pr = 0;buffer->buf_size = size;return 0;
}/* 环形缓冲区写一个字节 */
int Driver_Buffer_Write(ptRingBuffer buffer, const uint8_t data)
{if (buffer == NULL || buffer->fifo == NULL)return -1; /* 判断合法性 */int i = (buffer->pw + 1) % buffer->buf_size;if (i != buffer->pr) /* 判断是否写满 */{buffer->fifo[buffer->pw] = data; /* */buffer->pw = i;                  /* 重置写指针 */return 0;}return -1;
}/* 环形缓冲区写多个字节 */
int Driver_Buffer_WriteBytes(ptRingBuffer buffer, const uint8_t *data_stream, uint8_t len)
{int i;if (buffer == NULL || buffer->fifo == NULL)return -1; /* 判断合法性 */if (data_stream == NULL || len == 0)return -1;for (i = 0; i < len; i++){if (Driver_Buffer_Write(buffer, data_stream[i]) != 0)break;}return i;
}/* 环形缓冲区 读一个字节 */
int Driver_Buffer_Read(ptRingBuffer buffer, uint8_t *data)
{if (buffer == NULL || buffer->fifo == NULL)return -1; /* 判断合法性 */if (data == NULL)return -1;if (buffer->pr == buffer->pw)return -1; /* 满 */*data = buffer->fifo[buffer->pr];buffer->pr = (buffer->pr + 1) % buffer->buf_size; /* 自增 */return 0;
}/* 环形缓冲区 读多个字节 */
int Driver_Buffer_ReadBytes(ptRingBuffer buffer, uint8_t *data_stream, uint8_t len)
{int i = 0;if (buffer == NULL || buffer->fifo == NULL)return -1; /* 判断合法性 */if (data_stream == NULL || len == 0)return -1;for (i = 0; i < len; i++){if (Driver_Buffer_Read(buffer, &data_stream[i]) != 0)break;}return i;
}/*  清空环形缓冲区 */
int Driver_Buffer_Clean(ptRingBuffer buffer)
{if (buffer == NULL || buffer->fifo == NULL)return -1;                             /* 判断合法性 */memset(buffer->fifo, 0, buffer->buf_size); /* 清空 */buffer->pr = buffer->pw = 0;               /* 归零 */return 0;
}
/*** @brief 更新数据到数组* @param buffer* @param data_stream* @return 返回更新的数据长度*/
int Driver_Buffer_RefreshData(ptRingBuffer buffer, uint8_t *data_stream)
{uint16_t len = 0;if (buffer->pw == buffer->buf_size)buffer->pw = 0;while (buffer->pw != buffer->pr){data_stream[len++] = buffer->fifo[buffer->pr];buffer->fifo[buffer->pr] = 0;buffer->pr++;if (buffer->pr >= buffer->buf_size)buffer->pr = 0;if (len >= buffer->buf_size)break;}return len;
}
#ifndef __DRIVER_BUFFER_H
#define __DRIVER_BUFFER_H#include "stdint.h"
typedef struct{uint8_t *fifo;uint16_t pw; /*写地址*/uint16_t pr;uint16_t buf_size;}RingBuffer,*ptRingBuffer;extern RingBuffer USERRxDataBuffer1;
extern RingBuffer USERRxDataBuffer2;int Driver_Buffer_Init(ptRingBuffer buffer, uint16_t size);int Driver_Buffer_Write(ptRingBuffer buffer, const uint8_t data);int Driver_Buffer_WriteBytes(ptRingBuffer buffer, const uint8_t *data_stream, uint8_t len);int Driver_Buffer_Read(ptRingBuffer buffer, uint8_t *data);int Driver_Buffer_ReadBytes(ptRingBuffer buffer, uint8_t *data_stream, uint8_t len);int Driver_Buffer_Clean(ptRingBuffer buffer);int Driver_Buffer_RefreshData(ptRingBuffer buffer, uint8_t *data_stream);#endif
#include "driver_can.h"
#include "can.h"
#include "driver_buffer.h"#include <stdio.h> //使用printf函数
#include <stdint.h>HAL_StatusTypeDef CAN_Init(void)
{HAL_StatusTypeDef result = HAL_OK;Driver_Buffer_Init(&USERRxDataBuffer1, 256);                       /* 开辟环形缓冲区空间 */result = CAN_Filter_Config_Scale32_IdMask(&hcan1, 0x100, 0x100); // 过滤器设置return result;
}HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdMask(CAN_HandleTypeDef *hcan, uint32_t id, uint32_t mask)
{HAL_CAN_Stop(hcan); // 停止canHAL_StatusTypeDef result = HAL_OK;CAN_FilterTypeDef sFilterConfig;/* 配置过滤器参数 */sFilterConfig.FilterBank = 0;                      // 过滤器组编号(0-27)sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  // 掩码模式(或列表模式)sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位位宽// ID分解(右移13位取高16位,左移3位处理IDE/RTR位)sFilterConfig.FilterIdHigh = (id >> 13) & 0xFFFF;sFilterConfig.FilterIdLow = (id << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/// 掩码设置为0xFFFF0000(匹配前16位)sFilterConfig.FilterMaskIdHigh = (mask >> 13) & 0xFFFF;sFilterConfig.FilterMaskIdLow = (mask << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收FIFO选择sFilterConfig.FilterActivation = ENABLE;           // 启用过滤器sFilterConfig.SlaveStartFilterBank = 14;            // 双CAN时从过滤器组起始编号  单can无意义/* 应用过滤器配置 */if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK){Error_Handler();}result = HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断result = HAL_CAN_Start(hcan);                                             // 启动CAN外设return result;
}/* 32位列表模式 */
HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdList(CAN_HandleTypeDef *hcan, uint32_t id1, uint32_t id2)
{HAL_CAN_Stop(hcan); // 停止canHAL_StatusTypeDef result = HAL_OK;CAN_FilterTypeDef sFilterConfig;/* 基础参数配置 */sFilterConfig.FilterBank = 0;                      // 使用过滤器组0(CAN1默认组0-13)sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;  // 列表模式,需精确匹配IDsFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位位宽,支持标准帧和扩展帧sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0sFilterConfig.FilterActivation = ENABLE;           // 启用过滤器sFilterConfig.SlaveStartFilterBank =14;            // CAN2使用过滤器组14-27/* 设置两个目标扩展ID(0x18F60000和0x18F60001) */uint32_t target_id1 = id1 | CAN_ID_EXT; // 扩展帧需设置IDE位uint32_t target_id2 = id2 | CAN_ID_EXT;// 扩展ID分解:高16位右移13位,低16位左移3位(IDE/RTR位对齐)sFilterConfig.FilterIdHigh = (target_id1 >> 13) & 0xFFFF;sFilterConfig.FilterIdLow = (target_id1 << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/sFilterConfig.FilterMaskIdHigh = (target_id2 >> 13) & 0xFFFF; // 第二个ID的高16位sFilterConfig.FilterMaskIdLow = (target_id2 << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*//* 应用过滤器配置 */if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK){Error_Handler();}HAL_CAN_Start(hcan);   HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断// 启动CAN外设return result;
}HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdMask(CAN_HandleTypeDef *hcan, uint16_t id, uint16_t mask)
{HAL_CAN_Stop(hcan); // 停止canHAL_StatusTypeDef result = HAL_OK;CAN_FilterTypeDef sFilterConfig;/* 配置过滤器参数 */sFilterConfig.FilterBank = 0;                      // 过滤器组编号(0-27)sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  // 掩码模式(或列表模式)sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 32位位宽sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0sFilterConfig.FilterActivation = ENABLE;           // 启用过滤器sFilterConfig.SlaveStartFilterBank = 0;            // CAN2使用过滤器组14-27// 标准帧ID左移5位对齐(STID[10:0]占高11位)sFilterConfig.FilterIdHigh = (id << 5);       // ID高16位寄存器(实际存储前11位)sFilterConfig.FilterIdLow = 0x0000;           // ID低16位寄存器(未使用)sFilterConfig.FilterMaskIdHigh = (mask << 5); // 掩码高16位寄存器sFilterConfig.FilterMaskIdLow = 0x0000;       // 掩码低16位寄存器(未使用)/* 应用过滤器配置 */if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK){Error_Handler();}// 启动CAN外设HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断HAL_CAN_Start(hcan);      return result;
}/* 16位列表模式 */
HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdList(CAN_HandleTypeDef *hcan, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4)
{HAL_CAN_Stop(hcan); // 停止canHAL_StatusTypeDef result = HAL_OK;CAN_FilterTypeDef sFilterConfig;/* 基础参数配置 */sFilterConfig.FilterBank = 0;                     // 使用过滤器组0(CAN1默认组0-13)sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式,需精确匹配IDsFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0sFilterConfig.FilterActivation = ENABLE;           // 启用过滤器sFilterConfig.SlaveStartFilterBank = 0;            // CAN2使用过滤器组14-27sFilterConfig.FilterIdHigh = id1 << 5;             // 标准ID 0x100sFilterConfig.FilterIdLow = id2 << 5;              // 标准ID 0x101sFilterConfig.FilterMaskIdHigh = id3 << 5;         // 标准ID 0x102sFilterConfig.FilterMaskIdLow = id4 << 5;          // 标准ID 0x103/* 应用过滤器配置 */if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK){Error_Handler();}HAL_CAN_Start(hcan);                                             // 启动CAN外设HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断return result;
}/** @brief  发送一帧CAN数据* @param  hcan: CAN句柄指针* @param  id: 报文标识符(标准ID或扩展ID)* @param  data: 数据缓冲区指针(最大8字节)* @param  len: 数据长度(0-8)* @param  isExtId: 是否为扩展ID(1=扩展帧,0=标准帧)* @retval HAL状态:HAL_OK=成功,其他=失败*/
HAL_StatusTypeDef CAN_Send_Frame(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *data, uint8_t len, uint8_t isExtId)
{CAN_TxHeaderTypeDef txHeader;uint32_t mailbox;HAL_StatusTypeDef result = HAL_OK;/* 校验参数合法性 */if (len > 8 || data == NULL)return HAL_ERROR;/* 配置报文头部 */if (isExtId){txHeader.ExtId = id;       // 扩展IDtxHeader.IDE = CAN_ID_EXT; // 扩展帧标识}else{txHeader.StdId = id;       // 标准IDtxHeader.IDE = CAN_ID_STD; // 标准帧标识}txHeader.RTR = CAN_RTR_DATA;           // 数据帧(非远程请求)txHeader.DLC = len;                    // 数据长度码txHeader.TransmitGlobalTime = DISABLE; // 不记录全局时间戳/* 提交发送请求 */result = HAL_CAN_AddTxMessage(hcan, &txHeader, data, &mailbox);while (HAL_CAN_GetTxMailboxesFreeLevel(hcan) != 3) // 3 个邮箱都为空;                                                  /*等待发送完成 防止丢包*/return result;
}/* CAN发送多帧数据 */
void CAN_Send_Data(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *buf, uint32_t len, uint8_t isExtId)
{uint32_t transmission_times = 0; /* 发送次数 */uint32_t remian_bytes = 0;       /* 剩余字节 */uint32_t frame_length = 0;       /* 帧长度 */frame_length = 8;                /* 标准can最大8 */transmission_times = len / frame_length;remian_bytes = len % frame_length;int i = 0;while (i < transmission_times){CAN_Send_Frame(hcan, id, buf + i * frame_length, frame_length, isExtId);i++;}if (remian_bytes > 0) // 尾帧{CAN_Send_Frame(hcan, id, buf + transmission_times * frame_length, remian_bytes, isExtId);}
}/* CAN 接收数据 */
uint32_t CAN_Receive_Message(CAN_HandleTypeDef *hcan, uint32_t RxFifo, uint8_t *buf)
{CAN_RxHeaderTypeDef RxHeader;if (HAL_CAN_GetRxFifoFillLevel(hcan, RxFifo) == 0) // 检查邮箱{return 0; // 没有数据}HAL_CAN_GetRxMessage(hcan, RxFifo, &RxHeader, buf);return RxHeader.DLC; // 返回接收长度
}/*** @brief 接收FIFO0的回调函数 (中断方式)* @param hcan*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{uint8_t can_rec_data[8];uint32_t len = 0;len = CAN_Receive_Message(hcan, CAN_RX_FIFO0, can_rec_data);Driver_Buffer_WriteBytes(&USERRxDataBuffer1, can_rec_data, len); /*将收到的数据写到缓冲区*/char buffer[10] = "";char *ptr = buffer;for (size_t i = 0; i < 8; i++){ptr += sprintf(ptr, "%02X ", can_rec_data[i]); // 将元素转为十六进制字符串}//usb_printf("%s\n", buffer); // 一次性输出整个字符串
}//void MX_CAN_Init(void)
//{
//  CAN_FilterTypeDef    sFilterConfig;
//  
//  /*CANµ¥Ԫ³õʼ»¯*/
//  
//  hCAN.Instance = CANx;                     /* CAN͢ɨ */
//  hCAN.Init.Prescaler = 3;                  /* BTR-BRP ²¨̘Š·ֆµƷ  ¶¨ҥÁˊ±¼䵥ԪµĊ±¼䳤¶Ƞ42/(1+10+3)/3=1Mbps */
//  hCAN.Init.Mode = CAN_MODE_NORMAL;         /* ս³£¹¤׷ģʽ */
//  hCAN.Init.SyncJumpWidth = CAN_SJW_1TQ;    /* BTR-SJW ֘Ђͬ²½̸Ծ¿񲀠2¸öʱ¼䵥Ԫ */
//  hCAN.Init.TimeSeg1 = CAN_BS1_10TQ;         /* BTR-TS1 ʱ¼䶎1 ռӃÁ˶¸öʱ¼䵥Ԫ */
//  hCAN.Init.TimeSeg2 = CAN_BS2_3TQ;         /* BTR-TS1 ʱ¼䶎2 ռӃÁ˳¸öʱ¼䵥Ԫ */
//  hCAN.Init.TimeTriggeredMode = DISABLE;    /* MCR-TTCM  ¹رՊ±¼䴥·¢ͨЅģʽʹĜ */
//  hCAN.Init.AutoBusOff = ENABLE;            /* MCR-ABOM  ה¶¯À돟¹܀𚠯
//  hCAN.Init.AutoWakeUp = ENABLE;            /* MCR-AWUM  ʹӃה¶¯»½Бģʽ */
//  hCAN.Init.AutoRetransmission = DISABLE;   /* MCR-NART  ½ûֹ±¨΄ה¶¯֘´«	  DISABLE-ה¶¯֘´« */
//  hCAN.Init.ReceiveFifoLocked = DISABLE;    /* MCR-RFLM  ½ӊՆIFO ˸¶¨ģʽ  DISABLE-ҧ³öʱЂ±¨΄»Ḳ¸ǔ­Ӑ±¨΄ */
//  hCAN.Init.TransmitFifoPriority = DISABLE; /* MCR-TXFP  ·¢ˍFIFOӅψ¼¶ DISABLE-Ӆψ¼¶ȡ¾öӚ±¨΄±ꊾ·û */
//  HAL_CAN_Init(&hCAN);
//  
//  /*CAN¹ý‹Ʒ³õʼ»¯*/                  
//  sFilterConfig.FilterBank = 0;                      /* ¹ý‹Ʒש0 */
//  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  /* ¹¤׷Ԛ±ꊶ·ûƁ±Ύ»ģʽ */
//  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; /* ¹ý‹Ʒλ¿펪µ¥¸ö32λ¡£*/
//  sFilterConfig.FilterIdHigh = (((uint32_t)0x1314<<3)&0xFFFF0000)>>16;;               /* Ҫ¹ý‹µĉD¸ߎ» */
//  sFilterConfig.FilterIdLow = (((uint32_t)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;; /* Ҫ¹ý‹µĉDµ͎» */
//  sFilterConfig.FilterMaskIdHigh = 0xFFFF;           /* ¹ý‹Ʒ¸߱6λÿλ±ؐ놥Ť */
//  sFilterConfig.FilterMaskIdLow = 0xFFFF;            /* ¹ý‹Ʒµͱ6λÿλ±ؐ놥Ť */
//  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;  /* ¹ý‹Ʒ±»¹؁ªµ½FIFO 0 */
//  sFilterConfig.FilterActivation = ENABLE;            /* ʹĜ¹ý‹Ʒ */ 
//  sFilterConfig.SlaveStartFilterBank = 0;             /* ӃÀ´ѡԱ´ӹý‹ƷµļĴ憷±຅ */   
//  
//  HAL_CAN_ConfigFilter(&hCAN, &sFilterConfig);
//  
//  
//}
#ifndef __DRIVER_CAN_H__
#define __DRIVER_CAN_H__#include "main.h"HAL_StatusTypeDef CAN_Init(void);HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdMask(CAN_HandleTypeDef *hcan, uint32_t id, uint32_t mask);HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdList(CAN_HandleTypeDef *hcan, uint32_t id1, uint32_t id2);HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdMask(CAN_HandleTypeDef *hcan, uint16_t id, uint16_t mask);HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdList(CAN_HandleTypeDef *hcan, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4);HAL_StatusTypeDef CAN_Send_Frame(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *data, uint8_t len, uint8_t isExtId);void CAN_Send_Data(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *buf, uint32_t len, uint8_t isExtId);uint32_t CAN_Receive_Message(CAN_HandleTypeDef *hcan, uint32_t RxFifo, uint8_t *buf);#endif

提供了32位掩码和列表 16位掩码和列表的过滤器

编写应用层代码

void  APP_User_Task(void)
{for(int i =0 ;i<8;i++){buf[i] = i;}/*发送丢包测试*/	for(int i =0 ;i<1024;i++){tx_Pathping[i] = i%256;}CAN_Send_Data(&hcan1,0x100,tx_Pathping,1024,1);for(;;){/*接收丢包测试*/if(Driver_Buffer_RefreshData(&USERRxDataBuffer1,tx_buf)){tx_buf[7] = 0xa5;CAN_Send_Data(&hcan1,0x5A,tx_buf,8,1);}}
}	

实验效果

在这里插入图片描述
一开机就输出了128帧数据 可以看到数据都是连续的没有丢包

然后发送1024帧数据 可以看到也没有丢包

在这里插入图片描述
发送的数据接收到环形缓冲区 然后读出数据打印

此工程代码已经在STM32F407VET6 和STM32F103CBT6芯片上都验证过了 没有太大问题

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

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

相关文章

《Scientific Reports撤稿门技术节分析》——从图像篡改检测到学术伦理重建的技术透视

2023年以来&#xff0c;《Scientific Reports》等开放获取期刊频繁曝出大规模撤稿事件&#xff0c;涉及数据造假、图像重复、AI生成内容篡改等技术性学术不端行为。本文以技术视角切入&#xff0c;系统分析撤稿事件背后的技术动因、检测手段漏洞、学术出版体系的技术短板及应对…

Client请求Grpc服务报错

现象&#xff1a;err: rpc error: code Unimplemented desc 背景&#xff1a;调用链路A->B->C&#xff0c;A是一个Http协议的接口&#xff0c;B也是一个Http协议的接口&#xff0c; 但C是一个Grpc协议的接口。 解决思路&#xff1a;查看C服务对应的proto&#xff0c;比…

机器学习课程设计报告 —— 基于口红数据集的情感分析

目录 一、课程设计目的 二、数据预处理及分析 2.1 数据预处理 2.2 数据分析 三、特征选择 3.1 特征选择的重要性 3.2 如何进行特征选择 3.3 特征选择的依据 3.4 数据集的划分 四、模型训练与模型评估 4.1 所有算法模型不调参 4.2 K-近邻分类模型 4.3 GaussianNB模…

Flutter 实现6个验收码输入框

开箱即用&#xff0c;初始化时就唤起键盘&#xff0c;并选中第一个 import package:flutter/material.dart;import dart:async; // 引入 Timer 类class VerificationCode extends StatefulWidget {final String phoneNumber;const VerificationCode({super.key, required this.…

如何查看服务器有几张GPU

要查看服务器上有多少张 GPU&#xff0c;你可以使用以下几种方法&#xff1a; 1.1 使用 nvidia-smi工具&#xff08;针对 NVIDIA GPU&#xff09;&#xff1a; 如果你的服务器上安装了 NVIDIA GPU 驱动程序&#xff0c;那么可以使用 nvidia-smi 命令查看详细的 GPU 信息。 n…

3099. 哈沙德数

​题目来源&#xff1a; LeetCode题目&#xff1a;3099. 哈沙德数 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 按要求求和判断即可。 解题代码&#xff1a; #python3 class Solution:def sumOfTheDigitsOfHarshadNumber(self, x: int) -> int:sumDigi…

数字化回归本质:第一性原理驱动的制造业转型与AI+云PLM系统实践

2014年&#xff0c;埃隆马斯克在南加州大学商学院的毕业演讲上&#xff0c;留下了一场5分钟的精彩分享&#xff0c;他将自己对工作和人生的思考总结为五个要点&#xff0c;其中一点说到了他的决策方式&#xff1a; “也许你听我说过&#xff0c;要从物理学的角度思考问题&…

仿DeepSeek AI问答系统完整版(带RAG本地知识库+联网搜索+深度思考) +springboot+vue3

今天教大家如何设计一个企业级的 deepseek问答 一样的系统 , 基于目前主流的技术&#xff1a;前端vue3&#xff0c;后端springboot。同时还带来的项目的部署教程。 系统的核心功能 1. 支持本地上传文档知识库&#xff0c;RAG技术。 支持的文档有txt&#xff0c;doc&#xff0c…

27、请求处理-【源码分析】-怎么改变默认的_method

27、请求处理-【源码分析】-怎么改变默认的_method 要改变 Spring Boot 中默认的 _method 参数&#xff0c;可以通过以下步骤实现&#xff1a; #### 原理分析 Spring Boot 中默认的 HiddenHttpMethodFilter 用于将表单中的 _method 参数值映射为实际的 HTTP 方法&#xff08;如…

欧拉角转为旋转矩阵

外旋是固定坐标系&#xff0c;内旋是动态坐标系。外旋和内旋具有等价性。 固定坐标系依次绕xyz轴旋转&#xff0c;旋转矩阵 动态坐标系依次绕zyx轴旋转&#xff0c;旋转矩阵 numpy和scipy计算对比 import numpy as np from numpy import sin, cos, pi # 抑制科学计数法&#…

【AI学习笔记】Coze平台实现生成小红书热门多图笔记

背景前摇&原视频教程&#xff1a; 最近总是在小红书上刷到多图组成的养生小妙招、效率提升小tips、退休奶奶疗愈语录等等这样的图文笔记&#xff0c;而且人物图像一眼就是AI画的。 当时我以为这个排版和文字是人工的&#xff0c;就让AI保持角色一致性画了下图&#xff0c;…

如何选择自动化编程平台

从事自动化行业的工作者都知道&#xff0c;做PLC编程需要PLC编程软件&#xff0c;做HMI可视化需要HMI编程软件&#xff0c;做SCADA需要SCADA编程软件&#xff0c;做DCS需要DCS软件&#xff0c;做仿真调试需要仿真软件。这些软件有国外的、国内的&#xff0c;有传统自动化厂商开…

Bug 背后的隐藏剧情

Bug 背后的隐藏剧情 flyfish 1. 「bug」&#xff1a;70多年前那只被拍进史书的飞蛾 故事原型&#xff1a;1947年哈佛实验室的「昆虫命案」 1947年的计算机长啥样&#xff1f;像一间教室那么大&#xff0c;塞满了几万根继电器&#xff08;类似老式开关&#xff09;&#xff…

如何将通话记录从Android传输到Android

“如何将通话记录从 Android 转移到 Android&#xff1f;我换了一部新的 Android 手机&#xff0c;想要将通话记录复制到其中。”您需要将通话记录从 Android 传输到 Android 是一种常见的情况&#xff0c;因为通话记录是手机上最重要的数据之一。幸运的是&#xff0c;如果您从…

Android 云手机横屏模式下真机键盘遮挡输入框问题处理

一、背景 打开横屏应用,点击云机EditText输入框,输入框被键盘遮挡,如下图&#xff1a; 未打开键盘状态: 点击第二个输入框,键盘遮挡了输入框&#xff1a; 二、解决方案&#xff08;推荐第三中方案,博主采用的也是第三种方案&#xff09; 博主这里整理了三种方案&#xff1a;…

进程IO之 进程

一、进程相关概念 1.什么是进程 程序&#xff1a;静态的&#xff0c;编译好的可执行文件&#xff0c;存放在磁盘中的指令和数据的集合 进程&#xff1a;动态的&#xff0c;是程序的一次执行过程&#xff0c;是独立的可调度的任务 2.进程的特点 &#xff08;1&#xff09;对…

Condition源码解读(二)

本章我们继续将Condition的最后一个方法signal方法&#xff0c;如果前面没有看过的可以点击LockSupport与Condition解析来看看Condition解读的前半部分。 signal方法&#xff1a; public final void signal() {if (!AbstractQueuedLongSynchronizer.this.isHeldExclusively())…

股票收益率的计算

首先&#xff0c;需要从 Tushare.pro 注册一个账号并调用其API获取股票日线数据&#xff08;具体操作请查看官网&#xff09;。 以通过调用tushare获取股票000001(平安银行)的股票数据为例&#xff0c;这里不设置日期&#xff0c;那么默认获取Tushare提供的所有历史数据。也可…

《算法笔记》13.2小节——专题扩展->树状数组(BIT) 问题 D: 数列-训练套题T10T3

数列(sequence.pas/c/cpp) - 问题描述 一个简单的数列问题&#xff1a;给定一个长度为n的数列&#xff0c;求这样的三个元素ai, aj, ak的个数&#xff0c;满足ai < aj > ak&#xff0c;且i < j < k。 - 输入数据 第一行是一个整数n(n < 50000)。 第二行n个整…

C# Windows Forms应用程序-001

目录 项目概述 主要组件及功能 类定义 控件声明 构造函数 Dispose 方法 InitializeComponents 方法 控件配置详解 Button 控件 (button1) TextBox 控件 (textBox1) GroupBox 控件 (groupBox1) Label 控件 (label1 至 label5) OpenFileDialog 控件 (openFileDialog1…