RM C板,can1给can2发送数据
1、控制器局域网络:Controller Area Network
2、异步半双工通信
3、总线制
CAN由一对差分对(两条线)CANH和CANL组成
CANH电压比CANL高视为逻辑0(显性电平),否则为逻辑1(隐性电平)
多个设备可以连接到同一条CAN上
总线上的设备通过ID号区分
ID号长度可以为11位标准长度或者29位拓展长度
4、常用标准
①CAN2.0b标准
最大速率1Mbps,一组数据称为一帧,分为数据帧和远程帧,数据帧最多传输8个字节的数据,每一帧都有CRC校验。
②CAN FD标准,很多设备不支持
最大速率可达8Mbps,数据帧最多可传输64字节数据
5、CAN物理层
单片机一般使用类似串口的CAN RX和CAN TX接口驱动CAN
CAN RX/CAN TX需要经过CAN收发器才能被转换成对应的差分电平
一般CAN差分信号的电压为0-5V,也可以是0-3.3V,但不建议使用3.3v
6、CAN总线结构
CAN有两个120Ω的终端电阻,位于CAN布线的两端,每个设备挂载在总线上幸成数个支路
7、CAN时序
太复杂懒得学
8、CAN的帧
ID:ID号,标准11位,扩展29位
RTR:区别远程帧与数据帧,一般为数据帧,设置为0
IDE:区别ID号长度,0的话为11位,1的话为29位
DLC:数据长度,发送多少字节的数据,为0-8或者增强帧的0-64位
CRC:校验部分,CRC16,不用管,stm32自动生成
连续的五个以上相同位中间会插入一个相反位,除结尾外
9、CAN的仲裁
①由于CAN定义2条信号线的电压差代表逻辑0或者逻辑1,CAN的两条信号线实质上等效为串口的一条线
②当总线上连续3位的时间为1且没有正在传输的帧时,视为空闲状态,此时设备才能进行发送
③如果有2个或以上设备同时启动了发送则会进入仲裁
发送0更多的设备会赢得仲裁并继续发送
由于CAN时序的规定,仲裁是很难进入的,只有两个设备在同一Tq内启动发送才会进入仲裁
10、STM32的CAN外设
①FDCAN:仅限H系列和G系列(FDCAN和CAN2.0b)
②bxCAN:标准CAN外设,仅支持CAN2.0b
一般有1-3个CAN,CAN1和CAN3是主CAN,CAN2是从CAN
CAN2在CAN1打开之后才能打开,推荐两个同时打开
11、STM32的CAN时序
f=fapb/(psc*(bs1+bs2+1))
常用参数:用于STM32F407,主频为168MHz时,APB1为42MHz,设置BS1=9,BS2=4,BS3=3,此时得到1MHz的CAN频率
1、板子接线H连L,L连H
2、配置cubemx基础配置
3、点开CAN1和CAN2
4、配置CAN的参数
按照123的顺序配置,否则会报错
5、打开CAN的全部中断
6、设置PA8为输入模式,使用此按键来触发发送
7、生成代码
初始化
void CAN_ConfigFilter(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
sFilterConfig.FilterBank=0; //过滤器编号
sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;//模式
sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;//16位还是32位,此时配置32位
sFilterConfig.FilterIdHigh=0x00;
sFilterConfig.FilterIdLow=0x00;
sFilterConfig.FilterMaskIdHigh=0x00;
sFilterConfig.FilterMaskIdLow=0x00;
sFilterConfig.SlaveStartFilterBank=14;//定值
if(HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig)!=HAL_OK)
{
Error_Handler();
}
sFilterConfig.FilterBank=14; //CAN2过滤器编号
if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan1)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan2)!=HAL_OK)
{
Error_Handler();
}
//打开中断
if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
{
Error_Handler();
}
}
参数定义
uint8_t txDataBuffer[8],rxDataBuffer0[8],rxDataBuffer1[8];
CAN_TxHeaderTypeDef txHeader;;
CAN_RxHeaderTypeDef rxHeader0,rxHeader1;
uint16_t txID=0x20; //发送的ID
uint32_t txMailbox; //发送邮箱的地址
main中按键触发can1发送
while (1)
{
/* USER CODE END WHILE */
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8)==0)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8)==0)
{
txHeader.StdId=txID;
txHeader.IDE=CAN_ID_STD;
txHeader.RTR=CAN_RTR_DATA; //数据帧
txHeader.DLC=8; //8位
*((uint32_t*)(txDataBuffer))=HAL_GetTick(); //发送当前运行的时间
if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=0) //检验是否是空闲状态
{
HAL_CAN_AddTxMessage(&hcan1,&txHeader,txDataBuffer,&txMailbox);
}
}
}
/* USER CODE BEGIN 3 */
}
中断can2接收
//接收到的数据将会在rxHeader结构体和rxDataBuffer中
void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan)
{
if(hcan == &hcan2)
{
HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO0,&rxHeader0,rxDataBuffer0);
}
}
void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan)
{
if(hcan == &hcan2)
{
HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO1,&rxHeader1,rxDataBuffer1);
}
}
1、STM32的bxCAN接收时必须使用过滤器接收
2、根据CAN外设数量的不同有以下情况:
①只有CAN1:CAN1有14个过滤器
②有CAN1和CAN2:CAN1和CAN2共享28个过滤器
③有CAN1-3:CAN1和CAN2共享28个过滤器,CAN3则有独立的14个过滤器
3、过滤器可以过滤CAN总线上帧的ID号,可以不处理不想接受的ID号,直接收想要的ID号
4、掩码
①两个单元分别组成匹配ID和掩码
②被过滤的ID号和匹配ID号会和掩码进行按位与运算后再进行匹配,也就是只有对应的掩码为1的位才会被匹配
③例如:
匹配ID为0x200,掩码为0x000,则所有ID号都能通过
匹配ID为0x200,掩码为0x700,则ID为0x200~0x2FF均可通过
匹配ID为0x200,掩码为0x7FF,则只有0x200能通过
void CAN_ConfigFilter(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
sFilterConfig.FilterBank=0; //过滤器编号,CAN1为0-13
sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK; //模式
sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT; //16位还是32位,此时配置32位
sFilterConfig.FilterIdHigh=0x00;
sFilterConfig.FilterIdLow=0x00;
sFilterConfig.FilterMaskIdHigh=0x00;
sFilterConfig.FilterMaskIdLow=0x00;
sFilterConfig.SlaveStartFilterBank=14; //定值
if(HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig)!=HAL_OK)
{
Error_Handler();
}
//CAN2设置过滤器,FIFO0
sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
sFilterConfig.FilterBank=14; //过滤器编号,CAN2为14-27
sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
sFilterConfig.FilterMode=CAN_FILTERMODE_IDLIST; //模式
sFilterConfig.FilterScale=CAN_FILTERSCALE_16BIT; //16位还是32位,此时配置16位
//过滤0x200 201 202 203这四个ID号,只有当这个id号完全等于完全匹配的时候,才会被过滤掉
//如果想要过滤三个,则写一个不存在的id号,例如0x800
sFilterConfig.FilterIdHigh=0x200<<5;
sFilterConfig.FilterIdLow=0x201<<5;
sFilterConfig.FilterMaskIdHigh=0x202<<5;
sFilterConfig.FilterMaskIdLow=0x203<<5;
sFilterConfig.SlaveStartFilterBank=14; //定值
if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
{
Error_Handler();
}
//CAN2设置过滤器,FIFO1
sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
sFilterConfig.FilterBank=15; //过滤器编号,CAN2为14-27
sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO1; //过滤器给到rx0还是rx1
sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK; //模式
sFilterConfig.FilterScale=CAN_FILTERSCALE_16BIT; //16位还是32位,此时配置16位
//过滤0x200 201 202 203这四个ID号,只有当这个id号完全等于完全匹配的时候,才会被过滤掉
//如果想要过滤三个,则写一个不存在的id号,例如0x800
sFilterConfig.FilterIdHigh=0x200<<5;
sFilterConfig.FilterMaskIdHigh=0x700<<5; //这句和上一句说明过滤的为0x200-0x2FF
sFilterConfig.FilterIdLow=0x201<<5;
sFilterConfig.FilterMaskIdLow=0x203<<5;
sFilterConfig.SlaveStartFilterBank=14; //定值
if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan1)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan2)!=HAL_OK)
{
Error_Handler();
}
//打开中断
if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
{
Error_Handler();
}
}
整理自:CH4.2 CAN 第2讲 过滤器【南工骁鹰嵌入式软件培训】_哔哩哔哩_bilibili