当前位置: 首页 > news >正文

CAN通信

文章目录

  • 接线方式
  • 电平格式
  • 收发模式
    • 常规模式(多用)
    • 回环模式
    • 静默模式
    • 回环静默模式
  • CubeMX
  • 开启
  • 发送
  • 筛选器
    • 四种筛选模式
  • 接收

接线方式

  • 总线接法
  • 每个设备引I出两根线,一根是CAN_H,一根是CANL(当然也有单线CAN但速度低);不同设备的CAN_H接到一起,CAN_L接到一起
  • CAN_H和CAN_L用120Ω电阻连接在一起,防止信号不稳定,响应速度变慢等问题在这里插入图片描述

电平格式

  • 差分信号传输,在长距离传输时可保证信号质量
  • 码元1被编码成CAN_H与CAN_L电平相同,称为隐性电平,一般两根线电平均为2.5V
  • 码元0被编码成CAN_H与CAN_L电平不同,称为显性电平,一般CAN_H为3.5V,CAN_L为1.5V在这里插入图片描述

收发模式

常规模式(多用)

  • 向总线发送
  • 向总线接收

回环模式

  • 向总线和本机发送
  • 不从总线接收仅从本机接收

静默模式

  • 不向总线发送仅向本机发送
  • 从总线和本机接收

回环静默模式

  • 不向总线发送
  • 不向总线发送
  • 自收自发
  • 一般用于自检

CubeMX

  • CAN挂载在APB1的外设上
  • 最主要是配置波特率,等于时钟频率/分频/3个time之和

f407主频168M,apb1外设42M
在这里插入图片描述

在这里插入图片描述

  • 时间触发模式:会自动为报文生成时间戳
  • 自动总线关闭管理
  • 自动唤醒模式:使能后,当CAN外设在休眠状态时如果CAN总线有数据,则自动唤醒CAN外设。
  • 自动重发:使能后,如果因为仲裁失败(总线冲突)或是其他原因导致发送失败,会自动重发。建议使能。
  • 接收FIFO锁定模式:如果使能,当接收FIFO满时,下一条数据会被丢失。如果不使能,则覆盖前面的数据。
  • 发送FIFO优先级:当发送邮箱中同时有多个帧,是按照先进先出的顺序发送还是按照ID的优先级发送。如果不使能,则按照ID优先级发送。

记得打开中断
在这里插入图片描述

开启

! ! !记得开启can! ! !
HAL_CAN_Start(CAN_HandleTypeDef *hcan)
如果用中断
__HAL_CAN_ENABLE_IT()

发送

  • CAN协议总共定义了5种类型的帧,但我们能人为发送的其实只有数据帧和遥控帧。如果我们要发送数据帧,则还要定义数据的长度。
    发送用到的结构体如下:
typedef struct
{uint32_t StdId;    //标准IDuint32_t ExtId;    //扩展IDuint32_t IDE;      //用来决定报文是使用标准ID还是扩准IDuint32_t RTR;      //用来决定报文是数据帧要是遥控帧uint32_t DLC;      //数据长度,取值为0-8FunctionalState TransmitGlobalTime; 
//最后这个是时间触发模式用的,开启后会自动把时间戳添加到最后两字节的数据中。目前没有用到,选择 DISABLE 
} CAN_TxHeaderTypeDef;
  1. StdId:如果将要发送的报文使用标准ID,那么这个成员便记录标准ID的值
    • 取值:0x0 ~ 0x7FF
  2. ExtId:如果将要发送的报文使用扩展ID,那么这个成员便记录扩展ID的值
    • 取值:0x0 ~ 0x1FFFFFFF
  3. IDE:用来决定报文使用标准ID还是扩准ID
    • 取值:CAN_ID_STDCAN_ID_EXT
  4. RTR:用来决定报文是数据帧要是遥控帧
    • 取值:CAN_RTR_DATACAN_RTR_REMOTE
  5. DLC:用来记录数据帧的数据长度,单位字节(如果要发送的是遥控帧,该成员中的内容不起作用)
    • 取值:0 ~ 8
  6. TransmitGlobalTime:目前没有用到,选择 DISABLE
    • 取值:ENABLEDISABLE

结构体中的 .IDE 成员是用来决定报文是使用标准ID还是扩准ID,如果这个成员等于 CAN_ID_STD ,也就是使用标准ID,此时 .ExtId 中的内容就不起作用了;反之亦然。

发送函数

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);
  1. *hcan:can的句柄,由CubeMX自动帮我们定义
  2. *pHeader:发送结构体
  3. aData[]:要发送的数据
  4. *pTxMailbox:发送这条报文用的是哪个邮箱,这个作为输出参数。(因为STM32的CAN外设拥有三个发送邮箱,库函数会帮我们找到空的邮箱并把一帧报文装进去,这个参数便记录用到的邮箱号,具体怎么用目前还不清楚。因为CAN总线可能拥挤或是报文被抢占,因此数据并不是填到FIFO中就能马上发出去的,而是要等到合适的时机才能发出去)

筛选器

  • 不配置筛选器就无法接收数据
  • CAN总线上可以挂载多个节点,需要忽略掉无关ID的报文。筛选器用来筛选不同ID的报文,只有通过筛选的报文才会被存入接收FIFO中。
  • 对于CAN1、CAN2一同使用的时候,两个CAN共用28个筛选器组。如果只使用了CAN1,则只有14个筛选器组能够使用。​ 一个筛选器组共有两个32位的寄存器

四种筛选模式

  1. 32位掩码模式
    此模式下筛选寄存器1 (CAN_FiR1) 用来存放ID,筛选寄存器2 (CAN_FiR2) 用来存放此ID的掩码。掩码为1的位一定要匹配ID所对应的位,掩码为0的位则ID此位为1还是0都可以。如果收到匹配成功的ID,则放入接收FIFO。
  2. 32位列表模式
    列表模式就相当于白名单,只有收到与白名单一模一样的ID时才能通过匹配。此模式下筛选寄存器1存储一条ID,筛选寄存器2存储另一条ID。也就是说此模式可以存放两条32位的白名单。
  3. 16位掩码模式
    此模式与前面的32位掩码模式类似,只不过筛选码从原来的32位变成了16位,对扩展ID筛选能力变弱了。但这种模式可以存放两条ID及两条掩码。
  4. 16位列表模式
    此模式可以存放4条16位的ID。

结构体

typedef struct
{uint32_t FilterIdHigh;          //CAN_FiR1寄存器的高16位uint32_t FilterIdLow;           //CAN_FiR1寄存器的低16位uint32_t FilterMaskIdHigh;      //CAN_FiR2寄存器的高16位uint32_t FilterMaskIdLow;       //CAN_FiR2寄存器的低16位uint32_t FilterFIFOAssignment;  //通过筛选器的报文存在FIFO0还是FIFO1中uint32_t FilterBank;            //此次配置用的是哪个筛选器。用单CAN的取值为0-13,双CAN为 0 ~ 27uint32_t FilterMode;            //掩码模式或列表模式,取值:CAN_FILTERMODE_IDMASK 或 CAN_FILTERMODE_IDLISTuint32_t FilterScale;           //32位或16位,取值:CAN_FILTERSCALE_16BIT 或 CAN_FILTERSCALE_32BITuint32_t FilterActivation;      //使能或失能此筛选器uint32_t SlaveStartFilterBank;  //CAN1和CAN2一起用的时候,为CAN2分配筛选器的个数
} CAN_FilterTypeDef;

填好筛选器结构体,然后调用下面这个函数即可生效:

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);

接收

  • CAN的接收通常是使用中断方式来实现(因为没有DMA,而查询法又难以保证实时性)
  • 打开CAN的FIFO消息挂起中断请求(也就是CAN外设的中断使能位)。
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
//等效于
__HAL_CAN_ENABLE_IT(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  • 当CAN收到了符合筛选器的报文时,就会触发这个中断,我们便可以在这个中断回调函数中接收并处理收到的报文。(由于FIFO0和FIFO1用到的中断函数是独立的,因此这里的回调函数也是不一样的,要看清楚是FIFO0的还是1的)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &can_Rx, recvBuf);
}

接收用到的结构体如下:
不过这个结构体并不需要我们来赋值,而是作为接收函数的输出参数。

typedef struct
{uint32_t StdId;    uint32_t ExtId;    uint32_t IDE;      uint32_t RTR;      uint32_t DLC;      uint32_t Timestamp; uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;
  • Timestamp :只有使能了时间触发模式才有用,记录时间戳
  • FilterMatchIndex :这条报文被接收是通过哪个筛选器

接收函数

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);
  1. *hcan:can的句柄,由CubeMX自动帮我们定义
  2. RxFifo:接收FIFO号。参数:CAN_RX_FIFO0CAN_RX_FIFO1
  3. pHeader:接收结构体,这里作为输出参数
  4. aData[]:接收数组,这里作为输出参数

相关文章:

  • Twin Builder 中的电池等效电路模型仿真
  • 如何在 Vue3 中更好地使用 Typescript
  • 【计算机网络 第8版】谢希仁编著 第四章网络层 地址类题型总结
  • Spring Boot操作MongoDB的完整示例大全
  • 《算法导论(第4版)》阅读笔记:p9-p9
  • OSCP - Proving Grounds - NoName
  • P1782 旅行商的背包 Solution
  • vue3在使用@import “./index.scss“报错
  • 用 GRPO 魔法点亮Text2SQL 的推理之路:让模型“思考”得更像人类
  • FastJson 转 Jackson 指南
  • Codeforces Round 1023 (Div. 2) ABC
  • 一种基于条件生成对抗网络(cGAN)的CT重建算法
  • 美团Java高级配送员面经分享|玩梗版
  • Xshel工具介绍
  • 提示词优化:检索历史提示确定方向→生成候选提示并控制修改幅度→基于准确率迭代优化
  • 前端流行框架Vue3教程:14. 组件传递Props效验
  • Java工具学习
  • AI教你学VUE——Gemini版
  • 洛谷---P1629 邮递员送信
  • JavaScript学习教程,从入门到精通,jQuery 单击页面显示自定义动画、元素删除操作、随机抽奖、随机选图并放大语法知识点(37)
  • 湖北十堰市委副秘书长管聪履新丹江口市代市长
  • 特朗普要征100%关税,好莱坞这批境外摄制新片能躲过吗?
  • 经济日报:仅退款应平衡各方权益
  • 五一假期天气将大转变,南方新一轮降雨来袭
  • 阿根廷发生5.8级地震
  • 美商界报告:全美超86万岗位依赖对华出口,关税将重创美国出口商