做网站的上海公司,seo代理计费系统,培训心得体会总结,网络运维个人工作总结接收用到的结构体如下#xff1a;CAN概念#xff1a; 全称Controller Area Network#xff0c;是一种半双工#xff0c;异步通讯。 物理层#xff1a; 闭环#xff1a;允许总线最长40m#xff0c;最高速1Mbps#xff0c;规定总线两端各有一个120Ω电阻#xff0c;闭环… 接收用到的结构体如下CAN概念 全称Controller Area Network是一种半双工异步通讯。 物理层 闭环允许总线最长40m最高速1Mbps规定总线两端各有一个120Ω电阻闭环 开环最大传输距离1Km最高速125Kbps规定每根线串联一个2.2kΩ的电阻开环 CAN协议基本特点 基本特点如下 可多主控制 当CAN总线空闲时所有在总线上的终端都可以发送报文根据标识符CAN ID决定优先级当总线上有两个以上的终端发送消息时对各消息CAN ID的每个位进行逐个仲裁比较。CAN ID值越低报文优先级越高速度快距离远CAN 协议最快可达1Mbps距离小于40m最远可达10KM速率小于 5Kbps CAN 帧种类CAN 通信中包含五种帧种类数据帧、遥控帧、错误帧、过载帧、间隔帧。其中最重要的是数据帧用于通讯节点向外传送数据。数据帧中有数据段用于承载数据的内容一帧可发送0~8个字节的数据MSB先行。 简单了解上述基本特点即可快速上手CAN总线的配置。 显性电平对应“0”隐性电平对应“1”。隐性电平1两条线电压都是2.5V即压差为0显性电平0CAN_High和CAN_Low分别为3.5V和1.5V压差为2V。 总线上只要有一个节点输出显性则总线上为显性电平只有所有节点都是隐性电平总线才为隐性电平 CAN网络由CAN控制器和CAN收发器组成STM32仅集成了CAN控制器。
1、硬件-芯片使用STM32F103Cx系列 cubeMX配置时钟
can外设挂载在APB1上。 一般通信都会打开接收中断在这里打开CAN1 RX0的中断优先级可以通过NVIC进行更改。 CAN 的波特率及位同步
位时序分解 Prescaler预分频确定CAN最小时间单位Tq。
这里以F103C8T6为例APB1时钟为36Mhz 计算波特率的方法36M/分频系数/(BS1 BS2 1) 如图设置波特率是1000Kbps36M / 4 /4 4 1 1M 1000K 波特率计算公式 配置工作模式 CAN数据帧格式 CAN波特率计算小工具
STM32 CAN Baud Rate CalculatorV1.0-STM32 CAN Baud Rate Calculator官方下载_3DM软件 STM32的CAN通信波特率计算器 CANPro协议分析平台软件为CANalyst-II的标配软件 CAN基本函数 函数 功能 HAL_CAN_Start 开启CAN通讯 HAL_CAN_Stop 关闭CAN通讯 HAL_CAN_RequestSleep 使CAN模块完成当前操作后尝试进入休眠模式 HAL_CAN_WakeUp 从休眠模式中唤醒 HAL_CAN_IsSleepActive 检查是否成功处于休眠模式 HAL_CAN_AddTxMessage 向 Tx 邮箱中增加一个消息,并且激活对应的传输请求 HAL_CAN_AbortTxRequest 请求中断传输 HAL_CAN_GetTxMailboxesFreeLevel 查询空闲的发送邮箱个数 HAL_CAN_IsTxMessagePending 检查是否有传输请求在指定的 Tx 邮箱上等待 HAL_CAN_GetRxMessage 从Rx FIFO 收取一个 CAN 帧 HAL_CAN_GetRxFifoFillLevel 查询接收邮箱未读邮箱的个数 STM32HAL库学习——CAN笔记_hal库can_jdhfusk的博客-CSDN博客
发送用到的结构体如下 typedef struct { uint32_t StdId; //标准ID uint32_t ExtId; //扩展ID uint32_t IDE; //用来决定报文是使用标准ID还是扩准ID uint32_t RTR; //用来决定报文是数据帧要是遥控帧 uint32_t DLC; //数据长度取值为0-8 FunctionalState TransmitGlobalTime; //最后这个是时间触发模式用的开启后会自动把时间戳添加到最后两字节的数据中。目前没有用到选择 DISABLE } CAN_TxHeaderTypeDef; StdId 如果将要发送的报文使用标准ID那么这个成员便记录标准ID的值 取值 0x0 ~ 0x7FF ExtId 如果将要发送的报文使用扩展ID那么这个成员便记录扩展ID的值 取值 0x0 ~ 0x1FFFFFFF IDE 用来决定报文使用标准ID还是扩准ID 取值 CAN_ID_STD 或 CAN_ID_EXT RTR 用来决定报文是数据帧要是遥控帧 取值 CAN_RTR_DATA 或 CAN_RTR_REMOTE DLC 用来记录数据帧的数据长度单位字节如果要发送的是遥控帧该成员中的内容不起作用 取值0 ~ 8 TransmitGlobalTime 目前没有用到选择 DISABLE 取值 ENABLE 或 DISABLE 发送用到的函数如下 HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox); CAN_TxHeaderTypeDef can_Tx;
uint8_t sendBuf[5] {hello};
uint32_t box;int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_CAN_Init();HAL_CAN_Start(hcan1);can_Tx.StdId 0x123;can_Tx.ExtId 0;can_Tx.IDE CAN_ID_STD;can_Tx.RTR CAN_RTR_DATA;can_Tx.DLC 5;can_Tx.TransmitGlobalTime DISABLE;while (1){HAL_CAN_AddTxMessage(hcan1, can_Tx, sendBuf, box);HAL_Delay(100);}
}效果每隔100ms发送一条报文 筛选器 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 uint32_t FilterMode; //掩码模式或列表模式 uint32_t FilterScale; //32位或16位 uint32_t FilterActivation; //使能或失能 uint32_t SlaveStartFilterBank; //CAN1和CAN2一起用的时候为CAN2分配筛选器的个数 } CAN_FilterTypeDef; 成员 FilterIdHigh CAN_FiR1寄存器的高16位用于填写筛选码。具体的格式要根据16位、32位掩码模式、列表模式来确定。 取值 0x0 ~ 0xFFFF FilterIdLow CAN_FiR1寄存器的低16位 FilterMaskIdHigh CAN_FiR2寄存器的高16位 FilterMaskIdLow CAN_FiR2寄存器的低16位 FilterFIFOAssignment 通过筛选器的报文存在FIFO0还是FIFO1中 取值CAN_FILTER_FIFO0 或 CAN_FILTER_FIFO1 FilterBank 本次配置的筛选器号 取值对于单CAN为 0 ~ 13对于双CAN为 0 ~ 27 FilterMode 筛选模式掩码模式或列表模式。 取值CAN_FILTERMODE_IDMASK 或 CAN_FILTERMODE_IDMASK FilterScale 筛选码大小16位或32位。 取值CAN_FILTERSCALE_16BIT 或 CAN_FILTERSCALE_32BIT FilterActivation 使能或失能此筛选器。 取值CAN_FILTER_DISABLE 或 CAN_FILTER_ENABLE SlaveStartFilterBank 为从CANCAN2分配的筛选器个数。如果只使用单个CAN可忽略此成员 取值0 ~ 27 填好筛选器结构体然后调用下面这个函数即可生效 HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig); CAN_FilterTypeDef can_Filter {0};can_Filter.FilterIdHigh 0;
can_Filter.FilterIdLow 0;
can_Filter.FilterMaskIdHigh 0;
can_Filter.FilterMaskIdLow 0;
can_Filter.FilterFIFOAssignment CAN_FILTER_FIFO0;
can_Filter.FilterBank 0;
can_Filter.FilterMode CAN_FILTERMODE_IDMASK;
can_Filter.FilterScale CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(hcan1, can_Filter);效果CAN总线上所有的报文都会被接收并存入FIFO0中。
CAN_FilterTypeDef can_Filter {0};can_Filter.FilterIdHigh 0;
can_Filter.FilterIdLow 0;
can_Filter.FilterMaskIdHigh 0;
can_Filter.FilterMaskIdLow 2;
can_Filter.FilterFIFOAssignment CAN_FILTER_FIFO0;
can_Filter.FilterBank 0;
can_Filter.FilterMode CAN_FILTERMODE_IDLIST;
can_Filter.FilterScale CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(hcan1, can_Filter);效果仅接收标准ID为0x0的数据帧和遥控帧并存入FIFO0中。
接收
CAN的接收通常是使用中断方式来实现因为没有DMA而查询法又难以保证实时性因此首先要在CubeMX中打开接收的全局中断。
以看到有两个中断一个是FIFO0收到数据的RX0中断另一个是FIFO1收到数据的RX1中断这里只用到了FIFO0所以只勾选这个。这里也说一说自己的理解由于一个FIFO只能保存3条报文有了两个FIFO就能保存6条报文。我们可以通过筛选器把不同ID的报文装进不同的FIFO比如我们可以让FIFO0来接收关键、重要的报文用FIFO1来接收不那么重要的报文并且这两个中断是独立的我们甚至可以给它们配置不一样的中断优先级。
光打开全局中断还不够我们还需要打开CAN的FIFO消息挂起中断请求也就是CAN外设的中断使能位。
HAL_CAN_ActivateNotification(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[]);参数
*hcan can的句柄由CubeMX自动帮我们定义RxFifo 接收FIFO号。参数 CAN_RX_FIFO0 或 CAN_RX_FIFO1pHeader 接收结构体这里作为输出参数aData[] 接收数组这里作为输出参数
示例
#include stdio.hCAN_RxHeaderTypeDef can_Rx;
uint8_t recvBuf[8];uint8_t uartBuf[64];int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_CAN_Init();MX_USART1_UART_Init()CAN_FilterTypeDef can_Filter {0};can_Filter.FilterIdHigh 0;can_Filter.FilterIdLow 0;can_Filter.FilterMaskIdHigh 0;can_Filter.FilterMaskIdLow 0;can_Filter.FilterFIFOAssignment CAN_FILTER_FIFO0;can_Filter.FilterBank 0;can_Filter.FilterMode CAN_FILTERMODE_IDMASK;can_Filter.FilterScale CAN_FILTERSCALE_32BIT;can_Filter.FilterActivation CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(hcan1, can_Filter);HAL_CAN_ActivateNotification(hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);HAL_CAN_Start(hcan1);while (1){}
}void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{uint16_t len 0;HAL_CAN_GetRxMessage(hcan1, CAN_RX_FIFO0, can_Rx, recvBuf);if(can_Rx.IDE CAN_ID_STD){len sprintf((char *)uartBuf[len], 标准ID%#X; , can_Rx.StdId);}else if(can_Rx.IDE CAN_ID_EXT){len sprintf((char *)uartBuf[len], 扩展ID%#X; , can_Rx.ExtId);}if(can_Rx.RTR CAN_RTR_DATA){len sprintf((char *)uartBuf[len], 数据帧; 数据为);for(int i 0; i can_Rx.DLC; i ){len sprintf((char *)uartBuf[len], %X , recvBuf[i]);}len sprintf((char *)uartBuf[len], \r\n);HAL_UART_Transmit(huart1, uartBuf, len, 100); }else if(can_Rx.RTR CAN_RTR_REMOTE){len sprintf((char *)uartBuf[len], 遥控帧\r\n);HAL_UART_Transmit(huart1, uartBuf, len, 100); }
}效果接收CAN总线上所有数据并将内容通过串口打印出来 STM32 CAN初始化详解 CAN是控制器域网 (Controller Area Network, CAN) 的简称是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的并最终成为国际标准ISO11898。是国际上应用最广泛的现场总线之一。 在北美和西欧CAN总线协议已经成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线并且拥有以CAN为底层协议专为大型货车和重工机械车辆设计的J1939协议。近年来其所具有的高可靠性和良好的错误检测能力受到重视被广泛应用于汽车计算机控制系统和环境温度恶劣、电磁辐射强和振动大的工业环境。 原文链接https://blog.csdn.net/qq_20017379/article/details/125902421 u8 CAN1_Mode_Init(u8 tsjw, u8 tbs2,u8 tbs1, u16 brp, u8 mode)
{/* gpio结构体 */GPIO_InitTypeDef GPIO_InitStructure;/* can 初始化结构体 */CAN_InitTypeDef CAN_InitStructure;/* can过滤器结构体 */CAN_FilterInitTypeDef CAN_FilterInitStructure;/* 使能时钟 */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);/* 初始化gpio设置引脚复用模式推挽速率100上拉*/GPIO_InitStructure.GPIO_Pin GPIO_Pin_11| GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP;GPIO_Init(GPIOA, GPIO_InitStructure);/* 复用pa11 pa12为can功能 */GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);/* 初始化can结构体 *//*事件触发消息传输机制在TTCAN模式下CAN硬件的内部定时器被激活并且被用于产生发送与接收邮箱的)时间戳为了使can满足,适合实时性和可靠性要求特别高或有安全性要求的场合路上各节点取得同步后, 消息只能根据调度表在规定的时间隙传输, 避免了消息传输的冲突、仲裁,消息传 输时延短, 且可预知*/CAN_InitStructure.CAN_TTCMDISABLE;/* 软件自动离线管理ENABLE:一旦硬件检测到128 次11位连续的隐性位则自动退出离线状态将ABOM设1后一旦检测到条件会自动恢复的不需要人工干预如果ABOM位为’1’bxCAN进入离线状态后就自动开启恢复过程。如果ABOM位为’0’软件必须先请求bxCAN进入然后再退出初始化模式随后恢复过程才被开启*/CAN_InitStructure.CAN_ABOMDISABLE;/* 睡眠模式禁用软件通过对CAN_MCR寄存器的SLEEP位置’1’来请求进入这一模式。在该模式下bxCAN的时钟停止了但软件仍然可以访问邮箱寄存器。当bxCAN处于睡眠模式软件必须对CAN_MCR寄存器的INRQ位置’1’并且同时对SLEEP位清’0’才能进入初始化模式。有2种方式可以唤醒(退出睡眠模式)bxCAN通过软件对SLEEP位清’1’或硬件检测到CAN总线的活动。如果CAN_MCR寄存器的AWUM位为’1’一旦检测到CAN总线的活动硬件就自动对SLEEP位清’0’来唤醒bxCAN。如果CAN_MCR寄存器的AWUM位为’0’软件必须在唤醒中断里对SLEEP位清’0’才能退出睡眠状态。注 如果唤醒中断被允许(CAN_IER寄存器的WKUIE位为’1’)那么一旦检测到CAN总线活动就会产生唤醒中断而不管硬件是否会自动唤醒bxCAN。在对SLEEP位清’0’后睡眠模式的退出必须与CAN总线同步当硬件对SLAK位清’0’时就确认了睡眠模式的退出。*/CAN_InitStructure.CAN_AWUMDISABLE;/* 自动重传使能该模式主要用于满足CAN标准中时间触发通信选项的需求。通过对CAN_MCR寄存器的NART位置’1’来让硬件工作在该模式。在该模式下发送操作只会执行一次。如果发送操作失败了不管是由于仲裁丢失或出错硬件都不会再自动发送该报文。*/CAN_InitStructure.CAN_NARTENABLE;/*报文不锁定,新报文覆盖旧报文*/CAN_InitStructure.CAN_RFLMDISABLE;/* 优先级由报文标识符决定本成员用于选择CAN报文发送优先级判定方法用于选择CAN报文发送优先级判定方法*/CAN_InitStructure.CAN_TXFPDISABLE;/*#define CAN_Mode_Normal 正常模式#define CAN_Mode_LoopBack 回环模式 自己发自己收回环模式下它自己的输出端的所有内容都直接传输到自己的输入端输出端的内容同时也会被传输到总线上即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容不接收来自总线上的内容。使用回环模式可以进行自检。#define CAN_Mode_Silent 静默模式静默模式下它自己的输出端的逻辑 0 数据会直接传输到它自己的输入端逻辑1可以被发送到总线所以它不能向总线发送显性位(逻辑 0)只能发送隐性位(逻辑 1)。输入端可以从总线接收内容。由于它只可发送的隐性位不会强制影响总线的状态所以把它称为静默模式。这种模式一般用于监测它可以用于分析总线上的流量但又不会因为发送显性位而影响总线#define CAN_Mode_Silent_LoopBack 静默回环模式回环静默模式是以上两种模式的结合自己的输出端的所有内容都直接传输到自己的输入端并且不会向总线发送显性位影响总线不能通过总线监测它的发送内容。输入端只接收自己发送端的内容不接收来自总线上的内容。这种方式可以在“热自检”时使用即自我检查的时候不会干扰总线*/CAN_InitStructure.CAN_Mode mode;/*重新同步跳跃宽度(SJW) 。定义了在每位中可以延长或缩短多少个时间单元的上限。其值可以编程为1到4个时间单元*/CAN_InitStructure.CAN_SJWtsjw;/*时间段1(BS1)定义采样点的位置。其值可以编程为1到16个时间单元但也可以被自动延长以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。*/CAN_InitStructure.CAN_BS1tbs1;/*时间段2(BS2)定义发送点的位置。其值可以编程为1到8个时间单元但也可以被自动缩短以补偿相位的负向漂移。*/CAN_InitStructure.CAN_BS2tbs2;/*分频率*/CAN_InitStructure.CAN_Prescalerbrp;/* 初始化结构体 */CAN_Init(CAN1, CAN_InitStructure);/* 初始化过滤器 *//*选择过滤器0~13 for one can register*/CAN_FilterInitStructure.CAN_FilterNumber 0;/*屏蔽位模式和标识符列表模式#define CAN_FilterMode_IdMask ((uint8_t)0x00) #define CAN_FilterMode_IdList ((uint8_t)0x01)*/CAN_FilterInitStructure.CAN_FilterModeCAN_FilterMode_IdMask;/* 过滤器的位数#define CAN_FilterScale_16bit ((uint8_t)0x00)#define CAN_FilterScale_32bit ((uint8_t)0x01)*/CAN_FilterInitStructure.CAN_FilterScaleCAN_FilterScale_32bit;/*32位ID 高位*/CAN_FilterInitStructure.CAN_FilterIdHigh0x0000;32??ID/*32位ID 低位*/CAN_FilterInitStructure.CAN_FilterIdLow0x0000;/* 屏蔽位高字节 */CAN_FilterInitStructure.CAN_FilterMaskIdHigh0x0000;/* 屏蔽位低字节 */CAN_FilterInitStructure.CAN_FilterMaskIdLow0x0000;/* 设定接收FIFO */CAN_FilterInitStructure.CAN_FilterFIFOAssignment CAN_Filter_FIFO0;/* 激活过滤组 */CAN_FilterInitStructure.CAN_FilterActivation ENABLE;/* 初始化过滤器 */CAN_FilterInit(CAN_FilterInitStructure);/* 配置can中断*/NVIC_InitTypeDef NVIC_InitStructure;CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);NVIC_InitStructure.NVIC_IRQChannel CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);return 0;
}