F407和F103实现CAN通信

使用型号:F407VET6、F103C8T6

注意:这里F407使用的是CAN1,使用CAN2的话,也要开启CAN1的外设时钟,因为它们共用筛选器,且由于存储访问控制器由CAN1控制,所以要使用CAN2的时候 必须要使能CAN1的时钟

显示数据:F407使用的是串口来显示数据。F103的话是使用0.96寸OLED来显示数据

波特率:F4和F1波特率都是500KHZ。

1、f407的CAN初始化和FIFO0接收中断函数

CanTxMsg txMsg;       //发送 数据帧 结构体
CanRxMsg rxMsg;      //接收 数据帧 结构体

void Mycan_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    NVIC_InitTypeDef NVIC_InitStrcture;
    
    /* 开启CAN1和GPIOA外设的时钟 */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    
    /* PA11和PA12复用为CAN1引脚 */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);
    
    /* GPIO初始化 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* CAN外设初始化 */
    CAN_InitStructure.CAN_ABOM = ENABLE;     /*  是否使能ABOM自动离线管理功能  */ 
    CAN_InitStructure.CAN_TXFP = DISABLE;            /*  配置TXFP报文优先级的判定方法  */ 
    CAN_InitStructure.CAN_AWUM = ENABLE;            /*  是否使能AWUM自动唤醒功能  */ 
    CAN_InitStructure.CAN_NART = ENABLE;            /*  是否使用NART自动重传功能  */ 
    CAN_InitStructure.CAN_RFLM = DISABLE;            /*  是否使能RELM锁定FIFO功能  */ 
    CAN_InitStructure.CAN_TTCM = DISABLE;            /*  是否使能TTCM时间触发功能  */ 
    CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;   // 42MHZ/(ss+b1+bs2)/psc = 42000000/(1+8+5)/6 = 500khz
    CAN_InitStructure.CAN_BS2 = CAN_BS1_5tq;
    CAN_InitStructure.CAN_Prescaler = 6;

    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

    CAN_Init(CAN1, &CAN_InitStructure);
    
    /* CAN过滤器初始化 */
    CAN_FilterInitStructure.CAN_FilterNumber = 1;                                                  /* 过滤器编号 */
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;                              /* 使能过滤器 */
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;       /* 掩码模式还是列表模式 */
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;    /* 使用哪个FIFO去接收数据 */
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;            /* 过滤器的尺度16位还是32位*/
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;        //不过滤ID
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInit(&CAN_FilterInitStructure);
    
    /* CAN1 FIFO1 接收中断 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStrcture.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStrcture.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStrcture.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStrcture.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&NVIC_InitStrcture);
    
    /* 使用FIFO0接收, 开启FIFO0接收中断 */
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);    
}

extern uint8_t can_Rx0_bit;      //CAN1的FIFO0接收中断标志位

void CAN1_RX0_IRQHandler(void)
{
    if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) == SET)
    {
        can_Rx0_bit = 1;
        CAN_Receive(CAN1, CAN_FIFO0, &rxMsg);
        //不需要手动清除中断标志位,CAN_Receive()时会硬件清除
    }
}

2、f407的main.c

uint8_t can_Rx0_bit = 0; //CAN1的FIFO0接收中断标志位

#define CAN_ID  0x03FF

int main(void)
{
    delay_init(168);
    led_Init();
    key_Init();
    MyUsart1_Init(115200);
    Mycan_Config();
    
    MyUsart1_SendString("------------这是一个CAN回环测试-----------\r\n");
    uint8_t keynum = 0;
    uint8_t value = 0, mailbox;

    while(1)
    {
        keynum = Key_GetNum();
        
        if(keynum == key0)
        {
            for(uint8_t i = 0; i < 8; i++)
            {
                txMsg.Data[i] = value;
                value += 1;
            }
            txMsg.StdId = CAN_ID ;                             /* 标准ID */
            txMsg.ExtId = 0x0000;     /* 拓展ID */
            txMsg.IDE = CAN_Id_Standard;                  /* 是否为拓展ID */        
            txMsg.RTR = CAN_RTR_Data;                         /* 数据帧还是遥控帧 */
            txMsg.DLC = 8;                     /* 数据长度 */
            MyUsart1_SendString("准备发送数据\r\n");
            mailbox = CAN_Transmit(CAN1, &txMsg);    //返回发送的数据存入邮箱的编号
            if(mailbox != CAN_TxStatus_NoMailBox)
            {
                //等待直至发送成功
                while(CAN_TransmitStatus(CAN1, mailbox) != CAN_TxStatus_Ok);
                //给一定时间等待can收发器把数据发送到总线上
                delay_ms(2);
                MyUsart1_SendString("成功发送数据\r\n");
            }
            else
            {
                MyUsart1_SendString("没有空邮箱\r\n");
            }
        }
        if(can_Rx0_bit == 1)
        {
            printf("接收到的数据为:\r\n");
            printf("StdId:0x%x\r\n",rxMsg.StdId);
            printf("ExtId:0x%x\r\n",rxMsg.ExtId);
            printf("IDE:0x%x\r\n",rxMsg.IDE);
            printf("RTR:0x%x\r\n",rxMsg.RTR);
            printf("FMI:%d\r\n",rxMsg.FMI);
            printf("DLC:%d\r\n",rxMsg.DLC);
            printf("Data:");
            for(uint8_t i = 0; i < 8; i++)
            {
                printf("0x%02x  ",rxMsg.Data[i]);
            }
            printf("\r\n");
            can_Rx0_bit = 0;
        }
    }
}

3、f103的CAN初始化和FIFO0接收中断函数

void CAN1_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
    
    //can_rx PA11
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//推缓输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    //can_tx PA12
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//推缓输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    CAN_InitTypeDef CAN_InitStructure;
    CAN_InitStructure.CAN_ABOM = DISABLE;     /*  是否使能ABOM自动离线管理功能  */ 
    CAN_InitStructure.CAN_TXFP = DISABLE;            /*  配置TXFP报文优先级的判定方法  */ 
    CAN_InitStructure.CAN_AWUM = DISABLE;            /*  是否使能AWUM自动唤醒功能  */ 
    CAN_InitStructure.CAN_NART = DISABLE;            /*  是否使用NART自动重传功能  */ 
    CAN_InitStructure.CAN_RFLM = DISABLE;            /*  是否使能RELM锁定FIFO功能  */ 
    CAN_InitStructure.CAN_TTCM = DISABLE;            /*  是否使能TTCM时间触发功能  */ 
    CAN_InitStructure.CAN_SJW =    CAN_SJW_1tq ;                /*  配置SJW(再同步补偿宽度)极限值  */
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;                /*  配置BS1段长度  */ 
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;                /*  配置BS2段长度  */ 
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;            /*  配置CAN的工作模式,回环或正常模式  */ 
    CAN_InitStructure.CAN_Prescaler = 4; /*  配置CAN外设的时钟分频,可以设置为1-1024  */ 
    CAN_Init(CAN1, &CAN_InitStructure);    //36000000/(1+9+8)/4 = 500KHZ
     
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x00ff<<5;                        /*  CAN_FxR1寄存器的高16位  */
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;                                        /*  CAN_FxR1寄存器的低16位  */
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x00ff << 5;                             /*  CAN_FxR2寄存器的高16位  */
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;                                /*  CAN_FxR2寄存器的低16位  */
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;            /*  筛选器模式  */
    CAN_FilterInitStructure.CAN_FilterNumber = 1;                                            /*  筛选器编号  */
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;        /*  设置筛选器的尺度 16位还是32位  */
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;                         /*  是否使能本筛选器  */
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;/*  设置经过筛选后数据存储到哪个接收FIFO  */
    CAN_FilterInit(&CAN_FilterInitStructure);    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStrcture;
    NVIC_InitStrcture.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStrcture.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStrcture.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStrcture.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&NVIC_InitStrcture);

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

}

void USB_LP_CAN1_RX0_IRQHandler(void)
{
    GPIO_ResetBits(GPIOC, GPIO_Pin_13);
    if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) == SET)
    {
        CanRxMsg RxMsg;
        RxMsg.Data[0] = 0;
        RxMsg.Data[1] = 0;
        RxMsg.DLC = 0;
        RxMsg.ExtId = 0;
        RxMsg.FMI = 0;
        RxMsg.IDE = 0;
        RxMsg.RTR = 0;
        RxMsg.StdId = 0;
        
        CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);
        
        OLED_ShowString(2,1,"RxID:");
        OLED_ShowHexNum(2,6, RxMsg.StdId, 4);
        OLED_ShowNum(3,1,RxMsg.Data[0], 4); 
        OLED_ShowNum(3,6,RxMsg.Data[1], 4);
        
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
        
    }
        
}

4、f103的main.c

#define CAN_ID1 0x01FF

int main(void) 
{
    //按键初始化
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//推缓输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推缓输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_Init(GPIOC,&GPIO_InitStructure);
    GPIO_SetBits(GPIOC, GPIO_Pin_13);
    
    OLED_Init();
    CAN1_Config();
    
    uint8_t data1 = 1, data2 = 102;
    
    OLED_ShowString(1,1,"This_ID:");
    OLED_ShowHexNum(1,9, CAN_ID1,4);
    while(1) 
    {
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
        {
            Delay_ms(10);
            while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0){};
            data1 += 2;
            data2 += 2;
            CAN_Send_2Byte(data1, data2, CAN_ID1);  //这个函数在下面
            
        }
    }
}
 

void CAN_Send_2Byte(uint8_t data1, uint8_t data2, uint32_t CAN_id)  
{
    CanTxMsg TxMsg;
    
    //测试 只发了两个数据
    TxMsg.Data[0] = data1;
    TxMsg.Data[1] = data2;
    
    TxMsg.DLC = 2;
    TxMsg.ExtId = 0x0000;
    TxMsg.IDE = CAN_Id_Standard;
    TxMsg.RTR = CAN_RTR_Data;   //数据帧
    TxMsg.StdId = CAN_id;
    
    uint8_t mbox = CAN_Transmit(CAN1, &TxMsg);
    
}

5、实验效果

f4发f1收 效果如下(数据随便发的)

f407发f103收CAN

f1发f4收 效果如下(数据随便发的)

f103发f407收CAN

以上代码本人试过可以正常使用

(有什么不对,请指正,谢谢)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值