RoboMaster M3508 | 双CAN配置 CAN2不通讯 等问题

前言

最近在做的一个项目需要多个电机相互通讯工作,但是电调ID有限,所以不得不再用CAN2,但是配置好以后,居然连数据都发不出去,终于在今天解决了这个问题,但是debug的过程是如此心酸。

目录

前言

双CAN配置问题

1.can1正常工作,can2不能正常工作

硬件

测试

2.硬件没问题,配置也没问题,can2还是不工作

配置(F4标准库)

can.c

main.c

can_receive.c


 

双CAN配置问题

1.can1正常工作,can2不能正常工作

如果是单独用can2,那么开启时钟的时候,也要把can1开启。

“在can的控制器中,存储访问控制器是由can1控制的,当使用can2的时候,can2要访问存储访问控制器时,必须通过can1才能访问,所以使用can2的时候,can1为主机,can2为从机。所以使用can2时,时钟使能的宏定义是将can1和can2的的时钟都开启的。”

先使能CAN1的时钟,再使能CAN2的时钟 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);//使能CAN2时钟

如果是分别单独配置的,或者同时配置的,查找其他原因。

硬件

一般来说,代码配置好了,发现不工作,70%问题就是硬件哪里有问题。

先用万用表蜂鸣器看一下线的通讯情况;

没问题就看一下CAN_L与CAN_H是不是对的;

测试

配置排查可以通过CAN的模式 CAN_Mode_LoopBack 来测试一下收发,如何可以收到数据说明配置没问题(波特率除外)

这个时候看一下通讯频率对不对,大疆M3508是1M的,那就得按照1M配好,不然回环有收发正常模式也不通讯。

如果频率配对没问题,回环也正常收发,那么就可以重点去检测硬件了。

2.硬件没问题,配置也没问题,can2还是不工作

这个时候也不要头疼,按照我的经验步骤来(血泪教训)

1.使用调试工具检查CAN总线上的数据是否正确发送

如果连收发都没有,你的配置有检查了没有问题,那么极有可能是引脚复用了!!!!

比如说我们配置的是PB5 | PB6,工程里还有其他文件,可以按住Ctrl+F,搜一下RCC_AHB1Periph_GPIOB,看看哪些外设用了PB5或者PB6

如果没有调试工具检查CAN总线,就单独写一个只用CAN通讯的工程,下到单片机里面,看看是否正常通讯,如果单独写的可以工作,你现在的工作工作不了,那极大概率是引脚复用了。

配置(F4标准库)

下面附上我的双can配置

can.c

#include "can.h"
#include "stm32f4xx.h"

//PD0 CAN1_Rx、PD1 CAN1_Tx
uint8_t CAN1_mode_init(uint8_t tsjw, uint8_t tbs2, uint8_t tbs1, uint16_t brp, uint8_t mode)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    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(GPIOD, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);

    //查询中文手册中 CAN主控制寄存器 (CAN_MCR) 有详细解释
    CAN_InitStructure.CAN_TTCM = DISABLE;  //非时间触发模式
    CAN_InitStructure.CAN_ABOM = ENABLE;   //硬件自动离线管理
    CAN_InitStructure.CAN_AWUM = DISABLE;  //睡眠模式通过软件唤醒
    CAN_InitStructure.CAN_NART = DISABLE;  //报文自动重发 
    CAN_InitStructure.CAN_RFLM = DISABLE;  //报文不锁定,新的覆盖旧的
    CAN_InitStructure.CAN_TXFP = DISABLE;  //优先级由报文标识符决定
    CAN_InitStructure.CAN_Mode = mode;     //配置can的工作模式
    CAN_InitStructure.CAN_SJW = tsjw;      //重新同步跳跃宽度
    CAN_InitStructure.CAN_BS1 = tbs1;      //时间段1占用单元数
    CAN_InitStructure.CAN_BS2 = tbs2;      //时间段2占用单元数
    CAN_InitStructure.CAN_Prescaler = brp; //分频系数
    CAN_Init(CAN1, &CAN_InitStructure);

    CAN_FilterInitStructure.CAN_FilterNumber = 0;                       //过滤器0
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;     //屏蔽模式
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;    //过滤器位宽32位
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;                  //32位id
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;              //32位mask
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;//过滤器0关联到fifo
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;              //激活过滤器
    CAN_FilterInit(&CAN_FilterInitStructure);

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN1_NVIC;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    return 0;
}

//PB5 CAN2_Rx、 PB6 CAN2_Tx
uint8_t CAN2_mode_init(uint8_t tsjw, uint8_t tbs2, uint8_t tbs1, uint16_t brp, uint8_t mode)
{

    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
    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(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_CAN2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_CAN2);

    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = ENABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = mode;
    CAN_InitStructure.CAN_SJW = tsjw;
    CAN_InitStructure.CAN_BS1 = tbs1;
    CAN_InitStructure.CAN_BS2 = tbs2;
    CAN_InitStructure.CAN_Prescaler = brp;
    CAN_Init(CAN2, &CAN_InitStructure);

    CAN_FilterInitStructure.CAN_FilterNumber = 14;
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);

    CAN_ITConfig(CAN2, CAN_IT_FMP0, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN2_NVIC;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    return 0;
}

main.c

#include "stm32f4xx.h"
#include "main.h"
#include "delay.h"
#include "can.h"
#include "CAN_receive.h"

extern CanRxMsg rx1_message,rx2_message;
int main(void)
{
    BSP_Init();

	while(1)
	{
		CAN_CMD_Fric(0,100,0,100);
        if(can2_ok){ 
        printf("%d,%d,%d,%d,%d\n",rx2_message.StdId,rx2_message.Data[0],rx2_message.Data[1]);
        can2_ok = 0;
        }
        if(can1_ok){ 
        printf("%d,%d,%d,%d,%d\n",rx1_message.StdId,rx1_message.Data[0],rx1_message.Data[1]);
        can1_ok = 0;
        }
	}
}

void BSP_Init(void)
{
	//中断组4
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

	//CAN通信初始化
	CAN1_mode_init(CAN_SJW_1tq, CAN_BS2_2tq, CAN_BS1_6tq, 5, CAN_Mode_Normal);
    CAN2_mode_init(CAN_SJW_1tq, CAN_BS2_2tq, CAN_BS1_6tq, 5, CAN_Mode_Normal);//CAN_Mode_LoopBack回环模式

}

can_receive.c

#include "CAN_Receive.h"
#include "stm32f4xx.h"
//全局变量
int8_t can1_ok,can2_ok;
CanRxMsg rx1_message,rx2_message;
//can1中断
void CAN1_RX0_IRQHandler(void)
{

    if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
    {
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
        //接收到的数据存在rx1_message中,转移即可
        CAN_Receive(CAN1, CAN_FIFO0, &rx1_message);
        //添加其他处理
        can1_ok=1;
    }
}

//can2中断
void CAN2_RX0_IRQHandler(void)
{

    if (CAN_GetITStatus(CAN2, CAN_IT_FMP0) != RESET)
    {
        CAN_ClearITPendingBit(CAN2, CAN_IT_FMP0);
        //接收到的数据存在rx1_message中,转移即可
        CAN_Receive(CAN2, CAN_FIFO0, &rx2_message);
        //添加其他处理
        can2_ok=1;
    }
}


//can2发送控制命令
void CAN_CMD_Fric(int16_t motor1, int16_t motor2, int16_t motor3, int16_t motor4)
{
    CanTxMsg TxMessage;
    TxMessage.StdId = 0x200;    //根据设备ID自己更改
    TxMessage.IDE = CAN_ID_STD;
    TxMessage.RTR = CAN_RTR_DATA;
    TxMessage.DLC = 0x08;       //数据长度8位
    TxMessage.Data[0] = motor1 >> 8;
    TxMessage.Data[1] = motor1;
    TxMessage.Data[2] = motor2 >> 8;
    TxMessage.Data[3] = motor2;
    TxMessage.Data[4] = motor3 >> 8;
    TxMessage.Data[5] = motor3;
    TxMessage.Data[6] = motor4 >> 8;
    TxMessage.Data[7] = motor4;
	
    CAN_Transmit( CAN2,  &TxMessage );

    // 发送失败检查
    uint8_t transmit_status = CAN_Transmit(CAN2, &TxMessage);
    if (transmit_status != CAN_TxStatus_Ok) {
        // 发送失败,处理错误
        // 可以在此处添加错误处理逻辑
		printf("cuowucuowu\n");
    }
}
//can1发送电机控制命令
void CAN_CMD_CHASSIS(int16_t motor1, int16_t motor2, int16_t motor3, int16_t motor4)
{
    CanTxMsg TxMessage;
    TxMessage.StdId = 0x200;
    TxMessage.IDE = CAN_ID_STD;
    TxMessage.RTR = CAN_RTR_DATA;
    TxMessage.DLC = 0x08;
    TxMessage.Data[0] = motor1 >> 8;
    TxMessage.Data[1] = motor1;
    TxMessage.Data[2] = motor2 >> 8;
    TxMessage.Data[3] = motor2;
    TxMessage.Data[4] = motor3 >> 8;
    TxMessage.Data[5] = motor3;
    TxMessage.Data[6] = motor4 >> 8;
    TxMessage.Data[7] = motor4;

    CAN_Transmit( CAN1,  &TxMessage);
}

这套代码采用中断接收,可以用来移植双can,将配置和接受发送分开了,主函数演示了如何发送接收。

有用就点个赞吧~

如果还有其他问题欢迎留言讨论。

你可能感兴趣的:(单片机,嵌入式硬件)