STM32
直播中

徐伟

7年用户 924经验值
私信 关注
[问答]

如何使用CAN通讯环回模式测试CAN收发?

如何使用CAN通讯环回模式测试CAN收发?

回帖(1)

刘庸宏

2021-11-8 11:27:21
1 博客内容

      博客内容基于STM32F103 RET6芯片(Keil.STM32F1xx_DFP.2.3.0.pack)+PCA82C250,使用CAN通讯环回模式测试CAN收发。CAN引脚对应PA11(RX)和PA12(TX),使用PB11电压测试数据是否成功。实际测试中PB11输出正常,但PA11和PA12异常,接示波器排查判断PCA82C250硬件故障。
2 STM32芯片、TJA1050、上位机

      STM32芯片引脚电平为3.3V,而CAN逻辑电压为0和2.5V。因此STM32芯片和CAN解析器(eg:周立功_USBCAN/Vector_CANape)之间需要收发器,将TTL电平转CAN逻辑电压。本文使用的收发器为PCA82C250,其中TJA1050和PCA82C250可以相互替换。





3 CAN环回模式、轮询/中断接收模式

      CAN环回模式用于CAN测试,对外发送同时自己接收。





      CAN接收理解两种模式:



  • 轮询接收模式。不论收件箱是否有邮件,都在不停收,直到收到为止。博客内容参考STM32官方帮助文件。文件位置:D:SoftKeilDemoen.stsw-stm32054STM32F10x_StdPeriph_Lib_V3.5.0ProjectSTM32F10x_StdPeriph_ExamplesCANLoopBack。





  • 中断接收模式。CAN接收FIFO(( First Input First Output))寄存器CAN_RF0R,到有消息到达,该寄存器的0和1位会累加(硬件执行),显示消息挂起。通过该位判断是否接收。






中断模式查看挂起消息数量(官方自带库函数):


uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber)
{
  uint8_t message_pending=0;
  /* Check the parameters */
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_CAN_FIFO(FIFONumber));
  if (FIFONumber == CAN_FIFO0)
  {
    message_pending = (uint8_t)(CANx->RF0R&(uint32_t)0x03);
  }
  else if (FIFONumber == CAN_FIFO1)
  {
    message_pending = (uint8_t)(CANx->RF1R&(uint32_t)0x03);
  }
  else
  {
    message_pending = 0;
  }
  return message_pending;
}


4 程序原理
      CAN对外发送(TX)标准ID为0x11的数据帧,长度为2个字节(内容为0xCA,0xFE)。对接收(RX)内容进行判断,如果全部正确,PB11高电平(实际该引脚连接接示波器,未连接LED)。


  if (RxMessage.StdId!=0x11)
  {
    return 0;  
  }


  if (RxMessage.IDE!=CAN_ID_STD)
  {
    return 0;
  }


  if (RxMessage.DLC!=2)
  {
    return 0;  
  }


  if ((RxMessage.Data[0]<<8|RxMessage.Data[1])!=0xCAFE)
  {
    return 0;
  }


5 主程序(Main.c)
//================================================
//    名称:  Main.c
//    作者:  Morven_X
//    版本:  1.1
//    编制:  2021/03/5 23:55
//    更新:  2021/03/08 20:37
//    功能:  基于STM32F103 RET6芯片,使用CAN发送和接收信息
//    简介:  使用回环模式查看CAN发送,使用USBCAN接收数据(失败)
//    Email:  morven_xie@163.com
//================================================




# include "stm32f10x.h"
# include "stm32f10x_gpio.h"
# include "stm32f10x_can.h"
# include "Delay.h"
# include "CAN.h"




int main(void)
{
  LED_Init();
  LED_PB_Init();
  Delay_Init();
  CAN_GPIO_Init();
  NVIC_Configuration();               
  JTAG_Init();
  
  /* Turns selected LED Off */  
  LED_Off_PB11;
  LED_Off_PB12;
  LED_Off_PB13;
  LED_Off_PB14;
  int i;
  int TestRx;
  while (1)
  {
               
                 /* CAN transmit at 125Kb/s and receive by polling in loopback mode */
  TestRx = CAN1_Polling();


  if (TestRx == 0)
  {
    /* Faild to turn on led PB13 */
    LED_On_PB13;
  }
  else
  {
    /*Success to turn on PB11 */
    LED_On_PB11;
  }


    /*PC3-LED_ON */       
        LED_On;
       
        Delay_ms(100);


//         while(i < 0xFFFFF)
//  {
//    i++;
//  }
       
       
        LED_Off_PB11;
    LED_Off_PB12;
        LED_Off;
         
//        while(i >0x01)
//  {
//    i--;
//  }       
        Delay_ms(100);


  }
}


6 CAN程序(CAN.c)
# include "stm32f10x_rcc.h"
# include "stm32f10x_gpio.h"
# include "CAN.h"




void LED_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //使能C口GPIO时钟
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //选择推挽输出
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_6;                                                //指定引脚3
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;                //设置输出速率50MHz//
        GPIO_Init(GPIOC,&GPIO_InitStruct);                                                        //初始化外设GPIOx寄存器
}


void LED_PB_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);  //使能B口GPIO时钟
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //选择推挽输出
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;                //指定引脚
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;                //设置输出速率50MHz//
        GPIO_Init(GPIOB,&GPIO_InitStruct);                                                        //初始化外设GPIOx寄存器
}




void CAN_GPIO_Init(void)
{
                //**********GPIO初始化**********//
        GPIO_InitTypeDef        GPIO_InitStruct;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能A口GPIO时钟
       
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11 ;                                  //指定引脚PA11,CAN_RX上拉输入
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;                //设置输出速率50MHz//
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;        //选择上拉输入
        GPIO_Init(GPIOA,&GPIO_InitStruct);                                                        //初始化外设GPIOA寄存器


        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12 ;                                  //指定引脚PA12,CAN_TX复用推挽
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;                //设置输出速率50MHz//
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //选择推挽输出       
        GPIO_Init(GPIOA,&GPIO_InitStruct);                                                        //初始化外设GPIOA寄存器
}
       






        /**
  * @brief  Configures the NVIC and Vector Table base address.
  * @param  None
  * @retval None
  */
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;


  NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}




void JTAG_Init(void)
{       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //先开启开启AFIO复用时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //使能GPIOB外设时钟
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JTAG,保留SWD(若同时关闭SWD,芯片作废)
}




int CAN1_Polling(void)
{       
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  CanTxMsg TxMessage;
  CanRxMsg RxMessage;
  uint32_t i = 0;
  uint8_t TransmitMailbox = 0;


       
  /* CAN register init */
  CAN_DeInit(CAN1);


  CAN_StructInit(&CAN_InitStructure);
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);


  /* CAN cell init */
  CAN_InitStructure.CAN_TTCM=DISABLE;
  CAN_InitStructure.CAN_ABOM=DISABLE;
  CAN_InitStructure.CAN_AWUM=DISABLE;
  CAN_InitStructure.CAN_NART=DISABLE;
  CAN_InitStructure.CAN_RFLM=DISABLE;
  CAN_InitStructure.CAN_TXFP=DISABLE;
  CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;
  
  /* Baudrate = 125kbps*/
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1=CAN_BS1_2tq;
  CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;
  CAN_InitStructure.CAN_Prescaler=48;
  CAN_Init(CAN1, &CAN_InitStructure);


  /* CAN filter init */


  CAN_FilterInitStructure.CAN_FilterNumber=0;
  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=0;




  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  CAN_FilterInit(&CAN_FilterInitStructure);


  /* transmit */
  TxMessage.StdId=0x11;
  TxMessage.RTR=CAN_RTR_DATA;
  TxMessage.IDE=CAN_ID_STD;
  TxMessage.DLC=2;
  TxMessage.Data[0]=0xCA;
  TxMessage.Data[1]=0xFE;


  TransmitMailbox=CAN_Transmit(CAN1, &TxMessage);
  i = 0;
  while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFFFF))
  {
    i++;
  }


  i = 0;
  while((CAN_MessagePending(CAN1, CAN_FIFO0) < 1) && (i != 0xFFFF))
  {
    i++;
  }
       
       
  /* receive */
  RxMessage.StdId=0x00;
  RxMessage.IDE=CAN_ID_STD;
  RxMessage.DLC=0;
  RxMessage.Data[0]=0x00;
  RxMessage.Data[1]=0x00;
  CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);


  if (RxMessage.StdId!=0x11)
  {
    return 0;  
  }


  if (RxMessage.IDE!=CAN_ID_STD)
  {
    return 0;
  }


  if (RxMessage.DLC!=2)
  {
    return 0;  
  }


  if ((RxMessage.Data[0]<<8|RxMessage.Data[1])!=0xCAFE)
  {
    return 0;
  }
  
  return 1; /* Test Passed */
}


7 CAN头文件(CAN.h)
#ifndef  _CAN_H
#define  _CAN_H


void LED_Init(void);
void LED_PB_Init(void);
void NVIC_Configuration(void);
void CAN_GPIO_Init(void);
void JTAG_Init(void);
int CAN1_Polling(void);


#define LED_On       GPIO_SetBits(GPIOC,GPIO_Pin_3) ;
#define LED_On_PB11  GPIO_SetBits(GPIOB,GPIO_Pin_11) ;
#define LED_On_PB12  GPIO_SetBits(GPIOB,GPIO_Pin_12) ;
#define LED_On_PB13  GPIO_SetBits(GPIOB,GPIO_Pin_13) ;
#define LED_On_PB14  GPIO_SetBits(GPIOB,GPIO_Pin_14) ;


#define LED_Off_PB11 GPIO_ResetBits(GPIOB,GPIO_Pin_11) ;
#define LED_Off_PB12 GPIO_ResetBits(GPIOB,GPIO_Pin_12) ;
#define LED_Off_PB13 GPIO_ResetBits(GPIOB,GPIO_Pin_13) ;
#define LED_Off_PB14 GPIO_ResetBits(GPIOB,GPIO_Pin_14) ;
#define LED_Off      GPIO_ResetBits(GPIOC,GPIO_Pin_3) ;


#endif






举报

更多回帖

发帖
×
20
完善资料,
赚取积分