如何设置CAN引脚功能?如何在中断中获取CAN数据?

电子说

1.2w人已加入

描述

① MCU:MCU通过APB总线访问CAN外设。② CAN外设:挂载在MCU的APB总线上,实现基本协议CAN2.0A、扩展协议CAN2.0B、接收滤波器、发送优先级及对CAN FD的支持等,并留出外设访问接口给MCU,以便MCU控制。③ CAN收发器:看其收发器框图,因仅包含CANH、CANL总线,所以TXD发出的CANH、CANL与RXD读出的CANH、CANL是连接在一起的,因此CAN收发器TXD发送出来的总线信号会立即被转换从RXD输出给CAN接口(LBME环回模式使用此特性)

MCU控制器

MCU通过APB总线访问CAN外设,通过配置相关寄存器配置CAN的运行环境,通过写BUF及相关配置位发送CAN帧;通过轮询某些状态位或者中断,读取收到的BUF或者CAN外设目前处于的状态,并依据部分状态作出相应的动作;CAN收发器将CAN外设的CAN_TX高低电平信号转换为CANH、CANL总线信号,并将接收到的CANH、CANL总线信号转换为CAN外设的CAN_RX高低电平信号,该信号输送给CAN外设,CAN外设根据CAN接收滤波器的设置判断是否接收该数据帧等等。

1、查看原理图,看使用哪一个CAN接口。STB使用的引脚

MCU控制器

#define CAN1_TX      (GPIO_PC15)  //pin 75
#define CAN1_RX      (GPIO_PC14)  //pin 74
#define CAN1_STB     (GPIO_PD5)   // pin9

2、进行初始化操作

CAN_InitHardwr();

定义两个结构体变量,CAN_Config和CAN_BaudrateConfig

  1. 初始化硬件接口
    GPIO_SetFunc(CAN1_TX, GPIO_FUNC_1);//设置CAN1引脚复用功能
     GPIO_SetFunc(CAN1_RX, GPIO_FUNC_1);
     GPIO_SetDir(CAN1_STB, GPIO_OUTPUT);//设置CAN1收发器控制为IO控制
     //GPIO_FUNC_1 参考数据手册中“信号多路复用和引脚分配”,使用function 1功能
    
  2. 使能CAN收发器
    CAN1_TRASCVER_NML;//使能CAN收发器
    //#define CAN1_TRASCVER_NML   do{GPIO_ResetPinBits(CAN1_STB);}while(0)
    
  3. 设置波特率和采样点进行配置
/*
   设置波特率为500K,采样点为81.25%.
   tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
   BandRate  = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
   SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
   在已经知道波特率与采样点的情况下,经过计算后:tSeg1 = 13,tSeg2 = 3.
    */
   canBandrateConfig.S_PRESC  = 5;//分频后时钟为8M.
   canBandrateConfig.S_SEG_1  = 11;
   canBandrateConfig.S_SEG_2  = 2;
   canBandrateConfig.S_SJW  = 2;//满足S_SJW <= tSeg2即可.
  1. 过滤器设置:选择哪一个过滤器、指定过滤模式、过滤的ID类型
    16个过滤器中,可随意选择使用哪个,并制定其过滤模式,制定其过滤ID的类型.
     如果一个过滤器只需要接收一个ID,直接可将其设置CODE模式,然后根据ID类型设置过滤类型.
     如果一个过滤器需要接收多个ID,将其设置为MASK模式,并根据这几个ID的实际类型设置过滤ID类型,如果既有STD又有EXT,则应选择FILTER_IDE_STD_EXT_BOTH.
     此处加宏是为了更清楚的说明各种设置是否有效,在实际应用中,可将各种组合放在一起使用.
     #if (RECV_FRM_KIND_SEL == ONLY_RECV_STD_FRM)
     CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//使用CODE模式只接收STD帧
     CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID2);//使用CODE模式只接收STD帧
     #endif
     #if (RECV_FRM_KIND_SEL == ONLY_RECV_EXT_FRM)
     CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID11);//使用CODE模式只接收EXT帧
     CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID12);//使用CODE模式只接收EXT帧
     #endif
     #if (RECV_FRM_KIND_SEL == RECV_STD_EXT_BOTH_FRM)
     CAN_SetFilterParam( 0, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID1 & CAN1_RECV_DATA_ID11));//使用MASK模式接收两种帧
     CAN_SetFilterParam( 1, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID2 & CAN1_RECV_DATA_ID12));//使用MASK模式接收两种帧
     #endif
    
  2. CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//使用CODE模式只接收STD帧
* @prototype CAN_SetFilterParam(uint8_t filterNum, uint8_t filterEn, CAN_FilterMode_TypeDef filterMode, CAN_FilterMask_TypeDef filterMask, uint32_t ID)
  *
  * @param[in] filterNum:过滤器编码,015可用.
  * @param[in] filterEn:过滤器使能状态,1使能,0禁能
  * @param[in] filterMode:CAN_FilterMode_TypeDef已定义.
  * @param[in] filterMask:参考CAN_FilterMask_TypeDef.
  * @param[in] ID
  * @return  void

参数说明:0:选用的过滤器编码

1:1标识使能,0为禁止

CAN_FILTER_CODE_MODE:分code模式和mask模式,code只能接收一个ID,mask可以接收多个ID

FILTER_IDE_STD_ONLY:分标准帧、扩展帧、混合帧

ID:需要过滤的ID,表示这个ID可以通过,单片机可以接收到数据。

  1. 设置can配置
    canConfig.interruptEnable = TRUE;//使能中断
     canConfig.TSSS = TRUE;//使用次发送缓冲区发送
     canConfig.canMode = CAN_MODE_NORMAL;
     canConfig.autoReset = TRUE;//CAN BUSOFF后,自动恢复
     canConfig.filterList = g_canFilterTab;//赋值过滤器设置list
    
  2. 设置回调函数CAN_SetEventCallBack(CAN1, CAN1_IRQnCallBack);
  3. /**
    * @prototype CAN1_IRQnCallBack(uint32_t event, uint32_t wparam, uint32_t lparam)
    *
    * @param[in] ...
    * @return  ...
    *
    * @brief    CAN1 module interrupt handler.
    *    CAN1中断处理函数.
    */
    int32_t CAN1_IRQnCallBack(uint32_t event, uint32_t wparam, uint32_t lparam)
    {
     if (event & CAN_EVENT_RECVMSG)
     {
      if (CAN_IsMsgInReceiveBuf((CAN_Type*)lparam))
            {
                CAN_MessageRead((CAN_Type*)lparam, &g_recvCANMsgInfo);
    
       g_recvedCANDataRdy = TRUE;
            }
     }
    
     return 1;
    }
    
  4. 调用库函数CAN_Initialize()。

CAN_Initialize(CAN1, &canConfig, &canBandrateConfig);//程序引用

CAN_Initialize(CAN_Type *CANx, CAN_Config *config, const CAN_BaudrateConfig *baudrate)//函数原型

参数说明:

  • @param[in] CANx: CAN type pointer
  • @param[in] config: CAN config
  • @param[in] baudrate: CAN baud rate
  • @return 0: no error, 1: Initialize error
void CAN_InitHardwr(void)
{
 CAN_Config canConfig = {0};
 CAN_BaudrateConfig canBandrateConfig = {0};
 
 GPIO_SetFunc(CAN1_TX, GPIO_FUNC_1);//设置CAN1引脚复用功能
 GPIO_SetFunc(CAN1_RX, GPIO_FUNC_1);
 GPIO_SetDir(CAN1_STB, GPIO_OUTPUT);//设置CAN1收发器控制为IO控制
 CAN1_TRASCVER_NML;//使能CAN收发器
 
 /*
 设置波特率为500K,采样点为81.25%.
 tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
 BandRate  = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
 SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
 在已经知道波特率与采样点的情况下,经过计算后:tSeg1 = 13,tSeg2 = 3.
  */
 canBandrateConfig.S_PRESC  = 5;//分频后时钟为8M.
 canBandrateConfig.S_SEG_1  = 11;
 canBandrateConfig.S_SEG_2  = 2;
 canBandrateConfig.S_SJW  = 2;//满足S_SJW <= tSeg2即可.
 
 /* 
 16个过滤器中,可随意选择使用哪个,并制定其过滤模式,制定其过滤ID的类型.
 如果一个过滤器只需要接收一个ID,直接可将其设置CODE模式,然后根据ID类型设置过滤类型.
 如果一个过滤器需要接收多个ID,将其设置为MASK模式,并根据这几个ID的实际类型设置过滤ID类型,如果既有STD又有EXT,则应选择FILTER_IDE_STD_EXT_BOTH.
 
 此处加宏是为了更清楚的说明各种设置是否有效,在实际应用中,可将各种组合放在一起使用.
  */
 #if (RECV_FRM_KIND_SEL == ONLY_RECV_STD_FRM)
 CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//使用CODE模式只接收STD帧
 CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID2);//使用CODE模式只接收STD帧
 #endif
 #if (RECV_FRM_KIND_SEL == ONLY_RECV_EXT_FRM)
 CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID11);//使用CODE模式只接收EXT帧
 CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID12);//使用CODE模式只接收EXT帧
 #endif
 #if (RECV_FRM_KIND_SEL == RECV_STD_EXT_BOTH_FRM)
 CAN_SetFilterParam( 0, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID1 & CAN1_RECV_DATA_ID11));//使用MASK模式接收两种帧
 CAN_SetFilterParam( 1, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID2 & CAN1_RECV_DATA_ID12));//使用MASK模式接收两种帧
 #endif
 
 canConfig.interruptEnable = TRUE;//使能中断
 canConfig.TSSS = TRUE;//使用次发送缓冲区发送
 canConfig.canMode = CAN_MODE_NORMAL;
 canConfig.autoReset = TRUE;//CAN BUSOFF后,自动恢复
 canConfig.filterList = g_canFilterTab;//赋值过滤器设置list
 
 CAN_SetEventCallBack(CAN1, CAN1_IRQnCallBack);
 CAN_Initialize(CAN1, &canConfig, &canBandrateConfig);
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分