• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

STM32 CAN通讯实验程序

武飞扬头像
竹烟淮雨
帮助1

目录

STM32 CAN通讯实验

CAN硬件原理图

CAN外设原理图

TJA1050T硬件描述

实验线路图

回环实验

CAN头文件配置

 CAN_GPIO_Config初始化

CAN初始化结构体

CAN筛选器结构体

 接收中断优先级配置

接收中断函数

main文件

实验现象

补充


STM32 CAN通讯实验

CAN硬件原理图

CAN外设原理图

野火STM32F103ZET6霸道板载原理图

学新通

我们的开发板没有使用GPIO外设的复用功能PA11和PA12,而使用了重定义(重映射)功能PB8和PB9

学新通

学新通

TJA1050T硬件描述

学新通

实验线路图

图中为两个霸道开发板,如果使用指南针开发板需要外接CAN收发器和电阻。

学新通

        是否使用RX和TX引脚是根据实际情况来确认是否使用的。如果我们使用回环模式时,在STM32芯片内部的CAN控制器的发送端和接收端就已经通过硬件逻辑连接起来了,比如回环静默模式,根本不用使用STM32的发送和接收引脚。甚至使用回环测试的时候,CAN收发器就算不供电都可以工作。

回环实验

我们配置外设的GPIO功能时,可以参考手册的外设GPIO功能配置

学新通

CAN头文件配置

  1.  
    #ifndef __BSP_CAN_H
  2.  
    #define __BSP_CAN_H
  3.  
     
  4.  
    #include "stm32f10x.h"
  5.  
     
  6.  
     
  7.  
    #define PASS_ID ((uint32_t)0x1314)
  8.  
     
  9.  
     
  10.  
    #define CAN_TX_GPIO_PROT GPIOB
  11.  
    #define CAN_TX_GPIO_PIN GPIO_Pin_9
  12.  
     
  13.  
    #define CAN_RX_GPIO_PORT GPIOB
  14.  
    #define CAN_RX_GPIO_PIN GPIO_Pin_8
  15.  
     
  16.  
    #define CAN_GPIO_CLK RCC_APB2Periph_GPIOB
  17.  
     
  18.  
     
  19.  
     
  20.  
    /*信息输出*/
  21.  
    #define CAN_DEBUG_ON 1
  22.  
     
  23.  
    #define CAN_INFO(fmt,arg...) printf("<<-CAN-INFO->> "fmt"\n",##arg)
  24.  
    #define CAN_ERROR(fmt,arg...) printf("<<-CAN-ERROR->> "fmt"\n",##arg)
  25.  
    #define CAN_DEBUG(fmt,arg...) do{\
  26.  
    if(CAN_DEBUG_ON)\
  27.  
    printf("<<-CAN-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);
  28.  
     
  29.  
    void CAN_Config(void) ;
  30.  
     
  31.  
     
  32.  
    #endif /* __BSP_CAN_H */
  33.  
     
学新通

 CAN_GPIO_Config初始化

  1.  
    void CAN_GPIO_Config(void)
  2.  
    {
  3.  
    GPIO_InitTypeDef GPIO_InitStructure;
  4.  
     
  5.  
    /* 使能CAN时钟 */
  6.  
    RCC_APB1PeriphClockCmd (RCC_APB1Periph_CAN1 , ENABLE );
  7.  
     
  8.  
    /* 使能CAN引脚相关的时钟 */
  9.  
    RCC_APB2PeriphClockCmd ( CAN_GPIO_CLK|RCC_APB2Periph_AFIO, ENABLE );
  10.  
     
  11.  
    //使用PA8 9引脚的第二功能
  12.  
    GPIO_PinRemapConfig (GPIO_Remap1_CAN1 ,ENABLE);
  13.  
     
  14.  
    /* 配置CAN的 引脚,普通IO即可 */
  15.  
    GPIO_InitStructure.GPIO_Pin = CAN_TX_GPIO_PIN;
  16.  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  18.  
    GPIO_Init(CAN_TX_GPIO_PROT, &GPIO_InitStructure);
  19.  
     
  20.  
    /* 配置CAN的 引脚,普通IO即可 */
  21.  
    GPIO_InitStructure.GPIO_Pin = CAN_RX_GPIO_PIN;
  22.  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  23.  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  24.  
    GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
  25.  
     
  26.  
    }
学新通

PB8和PB9使用重映射功能

我们要使用GPIO_PinRemapConfig函数来使能PA8 9引脚的第二功能,此外一定要记得开启相应的AFIO时钟,否则第二功能是无法使用的。

学新通

学新通

CAN初始化结构体

  1.  
    void CAN_Mode_Config(void)
  2.  
    {
  3.  
     
  4.  
    CAN_InitTypeDef CAN_InitTypeStruct;
  5.  
     
  6.  
    CAN_InitTypeStruct.CAN_ABOM = ENABLE;
  7.  
    CAN_InitTypeStruct.CAN_AWUM = ENABLE;
  8.  
    CAN_InitTypeStruct.CAN_Mode = CAN_Mode_LoopBack;//CAN_Mode_Normal;//调试时建议使用回环模式,调试完再改成NORMAL
  9.  
    CAN_InitTypeStruct.CAN_NART = ENABLE; //错误重传
  10.  
    CAN_InitTypeStruct.CAN_RFLM = ENABLE;
  11.  
    CAN_InitTypeStruct.CAN_TTCM = DISABLE;
  12.  
    CAN_InitTypeStruct.CAN_TXFP = DISABLE; //按ID优先级发送
  13.  
     
  14.  
    //配置成1Mbps
  15.  
    CAN_InitTypeStruct.CAN_BS1 = CAN_BS1_5tq;
  16.  
    CAN_InitTypeStruct.CAN_BS2 = CAN_BS2_3tq;
  17.  
    CAN_InitTypeStruct.CAN_SJW = CAN_SJW_2tq;
  18.  
    CAN_InitTypeStruct.CAN_Prescaler = 4;
  19.  
     
  20.  
     
  21.  
    CAN_Init(CAN1,&CAN_InitTypeStruct);
  22.  
     
  23.  
    }
学新通

其中位时序及波特率按照下表配置

学新通

CAN筛选器结构体

  1.  
    void CAN_Filter_Config(void)
  2.  
    {
  3.  
    CAN_FilterInitTypeDef CAN_FilterInitTypeStruct;
  4.  
     
  5.  
    CAN_FilterInitTypeStruct.CAN_FilterActivation = ENABLE;
  6.  
    CAN_FilterInitTypeStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0 ;
  7.  
    CAN_FilterInitTypeStruct.CAN_FilterNumber = 0;
  8.  
    CAN_FilterInitTypeStruct.CAN_FilterScale = CAN_FilterScale_32bit;
  9.  
    CAN_FilterInitTypeStruct.CAN_FilterMode = CAN_FilterMode_IdMask ;
  10.  
     
  11.  
    CAN_FilterInitTypeStruct.CAN_FilterIdHigh = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF0000)>>16;
  12.  
    CAN_FilterInitTypeStruct.CAN_FilterIdLow = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF);
  13.  
     
  14.  
    CAN_FilterInitTypeStruct.CAN_FilterMaskIdHigh = 0xFFFF;
  15.  
    CAN_FilterInitTypeStruct.CAN_FilterMaskIdLow =0xFFFF;
  16.  
     
  17.  
    CAN_FilterInit(&CAN_FilterInitTypeStruct);
  18.  
     
  19.  
    CAN_ITConfig (CAN1,CAN_IT_FMP0,ENABLE);
  20.  
     
  21.  
    }
学新通

其中假如我们要过滤的ID为0x1314

学新通

使用stm32f10x_can.h文件末尾定义的相关宏

学新通

由于使用的是32位筛选器且标识符掩码,所以其中CAN_FilterIdHigh和CAN_FilterIdLow为我们过滤ID格式的高16位和低16位,首先将ID号左移三位,然后或上IDE、RTR位

  1.  
    CAN_FilterInitTypeStruct.CAN_FilterIdHigh = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF0000)>>16;
  2.  
    CAN_FilterInitTypeStruct.CAN_FilterIdLow = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF);

而CAN_FilterMaskIdHigh和CAN_FilterMaskIdLow为要过滤的ID掩码,全为1,表示完全过滤

  1.  
    CAN_FilterInitTypeStruct.CAN_FilterMaskIdHigh = 0xFFFF;
  2.  
    CAN_FilterInitTypeStruct.CAN_FilterMaskIdLow =0xFFFF;

学新通

 接收中断优先级配置

  1.  
    void CAN_NVIC_Config(void)
  2.  
    {
  3.  
     
  4.  
    NVIC_InitTypeDef NVIC_InitStructure;
  5.  
     
  6.  
    /* 配置NVIC为优先级组1 */
  7.  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  8.  
     
  9.  
     
  10.  
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  11.  
    /* 配置抢占优先级 */
  12.  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  13.  
    /* 配置子优先级 */
  14.  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  15.  
    /* 使能中断通道 */
  16.  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  17.  
    NVIC_Init(&NVIC_InitStructure);
  18.  
    }
学新通

在标准库头文件中找到CAN接收数据中断源,我们使用的是接收邮箱0,所以选择USB_LP_CAN1_RX0_IRQn

学新通

使能中断放在CAN筛选器结构体配置中

学新通

接收中断函数

  1.  
    extern CanRxMsg CAN_Rece_Data;
  2.  
    extern uint8_t flag;
  3.  
     
  4.  
    void USB_LP_CAN1_RX0_IRQHandler(void)
  5.  
    {
  6.  
    CAN_Receive(CAN1,CAN_FIFO0, &CAN_Rece_Data);
  7.  
    flag = 1;
  8.  
     
  9.  
    }

要注意的是在CAN里,我们设置完CAN_Receive(CAN1,CAN_FIFO0, &CAN_Rece_Data);之后不需要手动清除接收标志,该函数会自动清除。

flag用于在main函数中判断是否接收到数据,从而做相应的应用处理

学新通

我们也可以再加个判断进一步确认接收数据的准确性

学新通

main文件

  1.  
    #include "stm32f10x.h"
  2.  
    #include "./usart/bsp_usart.h"
  3.  
    #include "./led/bsp_led.h"
  4.  
    #include "./can/bsp_can.h"
  5.  
    #include "./key/bsp_key.h"
  6.  
     
  7.  
    CanRxMsg CAN_Rece_Data;
  8.  
    CanTxMsg CAN_Tran_Data;
  9.  
     
  10.  
    uint8_t flag = 0;
  11.  
     
  12.  
     
  13.  
    void Delay(__IO uint32_t nCount);
  14.  
     
  15.  
    /*
  16.  
    * 函数名:main
  17.  
    * 描述 :主函数
  18.  
    * 输入 :无
  19.  
    * 输出 :无
  20.  
    */
  21.  
    int main(void)
  22.  
    {
  23.  
    LED_GPIO_Config();
  24.  
    LED_BLUE;
  25.  
     
  26.  
    /* 配置串口为:115200 8-N-1 */
  27.  
    USART_Config();
  28.  
    printf("\r\n 这是一个CAN通讯实验 \r\n");
  29.  
     
  30.  
    CAN_Config() ;
  31.  
     
  32.  
    Key_GPIO_Config();
  33.  
    printf("\r\n 按KEY1按键发送数据\r\n");
  34.  
     
  35.  
    while(1)
  36.  
    {
  37.  
    if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
  38.  
    {
  39.  
    uint8_t box;
  40.  
     
  41.  
    CAN_Tran_Data.StdId = 0;
  42.  
    CAN_Tran_Data.ExtId = PASS_ID;
  43.  
    CAN_Tran_Data.RTR = CAN_RTR_Data;//使用数据帧
  44.  
    CAN_Tran_Data.IDE = CAN_Id_Extended ; //使用扩展帧
  45.  
    CAN_Tran_Data.DLC = 1;
  46.  
    CAN_Tran_Data.Data[0] = 10;
  47.  
     
  48.  
    box = CAN_Transmit(CAN1,&CAN_Tran_Data);
  49.  
     
  50.  
    while(CAN_TransmitStatus(CAN1,box) == CAN_TxStatus_Failed);
  51.  
     
  52.  
    printf("\r\n 数据包发送完成\r\n");
  53.  
     
  54.  
    }
  55.  
     
  56.  
     
  57.  
    if(flag == 1)
  58.  
    {
  59.  
    printf("\r\n接收到的数据:%d\r\n",CAN_Rece_Data.Data[0]);
  60.  
    flag = 0;
  61.  
    }
  62.  
    else
  63.  
    {
  64.  
     
  65.  
    }
  66.  
    }
  67.  
    }
  68.  
     
  69.  
    void Delay(__IO uint32_t nCount)
  70.  
    {
  71.  
    for(; nCount != 0; nCount--);
  72.  
    }
学新通

实验现象

学新通

学新通

补充

由于只有一个板子,无法演示双机实验,双机实验只需要将我们的回环实验中的回环模式换成正常模式,然后将程序分别下载到两个开发板即可。

学新通

学完基础的CAN通讯协议之后,如果想要今后从事CAN通讯相关工作,比如工业、汽车领域,我们还需要进一步学习一下CAN OPEN。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgabgbf
系列文章
更多 icon
同类精品
更多 icon
继续加载