⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can.c

📁 stm32初级例程
💻 C
字号:
/*----------------------------------------------------------------------------
QQ: 958664258
21IC用户名:banhushui
交流平台:http://blog.21ic.com/user1/5817/index.html
淘宝店铺:http://shop58559908.taobao.com
旺旺:半壶水电子
编译器版本:MDK4.12
 *---------------------------------------------------------------------------*/

#include <stm32f10x_lib.h>                        // STM32F10x Library Definitions
#include "STM32_Reg.h"                            // STM32 register and bit Definitions
#include "STM32_Init.h"                           // STM32 Initialization
#include "CAN.h"                                  // STM32 CAN adaption layer

CAN_msg CAN_TxMsg;                          // CAN messge for sending
CAN_msg CAN_RxMsg;                          // CAN message for receiving                                

unsigned int CAN_TxRdy = 0;                      // CAN HW ready to transmit a message
unsigned int CAN_RxRdy = 0;                      // CAN HW received a message

/*----------------------------------------------------------------------------
  setup CAN interface
 *----------------------------------------------------------------------------*/
void CAN_setup(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;
   CAN_InitTypeDef CAN_InitStructure;
   GPIO_InitTypeDef GPIO_InitStructure;
   unsigned int brp = stm32_GetPCLK1();
   

   //配置CAN使用的时钟
   /* CAN Periph clock enable */
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
   // enable clock for Alternate Function
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);


   //CAN功能重新映射
   //  AFIO->MAPR   &= 0xFFFF9FFF;                     // reset CAN remap
   //  AFIO->MAPR   |= 0x00004000;                     //   set CAN remap, use PB8, PB9
   GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);
   
   //配置CAN使用的IO口
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   /* Configure CAN pin: RX */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
   GPIO_Init(GPIOB, &GPIO_InitStructure);

   /* Configure CAN pin: TX */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOB, &GPIO_InitStructure);

   //  NVIC->ISER[0] |= (1 << (USB_HP_CAN_TX_IRQChannel  & 0x1F));// enable interrupt
   //  NVIC->ISER[0] |= (1 << (USB_LP_CAN_RX0_IRQChannel & 0x1F));// enable interrupt
   /* Enable CAN RX0 interrupt IRQ channel */
   //配置CAN收发中断
   NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN_RX0_IRQChannel;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

   NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN_TX_IRQChannel;
   NVIC_Init(&NVIC_InitStructure);

   //  CAN->MCR = (CAN_MCR_NART | CAN_MCR_INRQ);       // init mode, disable auto. retransmission
   // Note: only FIFO 0, transmit mailbox 0 used
   //*

   //  CAN_DeInit();
   //配置CAN工作模式,波特率
   CAN_StructInit(&CAN_InitStructure);

   // CAN cell init
   //初始化CAN
   CAN_InitStructure.CAN_TTCM = DISABLE;//禁止时间触发通讯模式
   CAN_InitStructure.CAN_ABOM = DISABLE;//禁止自动离线管理
   CAN_InitStructure.CAN_AWUM = DISABLE;//禁止自动唤醒模式
   CAN_InitStructure.CAN_NART = ENABLE;//允许非自动重传输模式
   CAN_InitStructure.CAN_RFLM = DISABLE;//禁止接收 FIFO锁定模式
   CAN_InitStructure.CAN_TXFP = DISABLE;//禁止发送 FIFO优先级
   CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;//CAN工作在正常模式
   CAN_InitStructure.CAN_SJW = CAN_SJW_4tq;//重新同步跳跃宽度 4 个时间单位
   CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;//时间段1 为12 个时间单位
   CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;//时间段2 为5 个时间单位
   CAN_InitStructure.CAN_Prescaler = (brp / 18) / 500000; //设置波特率
   CAN_Init(&CAN_InitStructure);
   //*/
   
   // Note: only FIFO 0, transmit mailbox 0 used
   // FIFO 0 msg pending, Transmit mbx empty
   //FIFO0发生溢出的情况,FIFO 0的FOVR位被置’1’时,产生中断。
   //发送邮箱0变为空,RQCPx位被置’1’时,产生中断。
   CAN_ITConfig(CAN_IT_FMP0 | CAN_IT_TME, ENABLE); 
   
}


/*----------------------------------------------------------------------------
  leave initialisation mode
 *----------------------------------------------------------------------------*/
void CAN_start (void)  {

  // normal operating mode, reset INRQ
  //使CAN从初始化模式进入正常工作模式
  CAN->MCR &= ~CAN_MCR_INRQ;                      
  while (CAN->MSR & CAN_MCR_INRQ);

}

/*----------------------------------------------------------------------------
  set the testmode
 *----------------------------------------------------------------------------*/
void CAN_testmode (unsigned int testmode) {

  // set testmode
  //设置CAN工作模式
  CAN->BTR &= ~(CAN_BTR_SILM | CAN_BTR_LBKM);     
  CAN->BTR |=  (testmode & (CAN_BTR_SILM | CAN_BTR_LBKM));
}

/*----------------------------------------------------------------------------
  check if transmit mailbox is empty
 *----------------------------------------------------------------------------*/
void CAN_waitReady (void)  {

  // Transmit mailbox 0 is empty
  //发送邮箱空?
  while ((CAN->TSR & CAN_TSR_TME0) == 0);
  CAN_TxRdy = 1;
 
}

/*----------------------------------------------------------------------------
  wite a message to CAN peripheral and transmit it
 *----------------------------------------------------------------------------*/
void CAN_wrMsg (CAN_msg *msg)  {

  // Reset TIR register
  //发送邮箱标识符寄存器复位
  CAN->sTxMailBox[0].TIR  = (unsigned int)0;      
  // Setup identifier information
  //如果是标准帧,标准帧是11位ID(报文识别码)
  if (msg->format == STANDARD_FORMAT)  
  {          //    Standard ID
      CAN->sTxMailBox[0].TIR |= (unsigned int)(msg->id << 21) | CAN_ID_STD;
  }  
  else//如果是扩展帧,扩展帧是29位ID(报文识别码)
  {                                      // Extended ID
      CAN->sTxMailBox[0].TIR |= (unsigned int)(msg->id <<  3) | CAN_ID_EXT;
  }
  // Setup type information
  //如果消息为数据帧
  if (msg->type == DATA_FRAME)  
  {                 // DATA FRAME
      CAN->sTxMailBox[0].TIR |= CAN_RTR_DATA;
  }
  else//数据为远程帧 
  {                                          // REMOTE FRAME
      CAN->sTxMailBox[0].TIR |= CAN_RTR_REMOTE;
  }
  //发送邮箱填充数据                                            // Setup data bytes
  CAN->sTxMailBox[0].TDLR = (((unsigned int)msg->data[3] << 24) | 
                             ((unsigned int)msg->data[2] << 16) |
                             ((unsigned int)msg->data[1] <<  8) | 
                             ((unsigned int)msg->data[0])        );
  CAN->sTxMailBox[0].TDHR = (((unsigned int)msg->data[7] << 24) | 
                             ((unsigned int)msg->data[6] << 16) |
                             ((unsigned int)msg->data[5] <<  8) |
                             ((unsigned int)msg->data[4])        );
  // Setup length
  //设置消息数据长度
  CAN->sTxMailBox[0].TDTR &= ~CAN_TDTxR_DLC;
  CAN->sTxMailBox[0].TDTR |=  (msg->len & CAN_TDTxR_DLC);
  // enable  TME interrupt
  //发送邮箱空中断使能
  CAN->IER |= CAN_IER_TMEIE;
  // transmit message
  //发送消息
  CAN->sTxMailBox[0].TIR |=  CAN_TIxR_TXRQ;       
}

/*----------------------------------------------------------------------------
  read a message from CAN peripheral and release it
 *----------------------------------------------------------------------------*/
void CAN_rdMsg (CAN_msg *msg)  {
  // Read identifier information
  //标识信息
  //如果是标准帧,标准帧是11位ID(报文识别码)
  if ((CAN->sFIFOMailBox[0].RIR & CAN_ID_EXT) == 0) 
  { // Standard ID
    msg->format = STANDARD_FORMAT;
    msg->id     = (u32)0x000007FF & (CAN->sFIFOMailBox[0].RIR >> 21);
  }  
  else//如果是扩展帧,扩展帧是29位ID(报文识别码)
  {                                          // Extended ID
    msg->format = EXTENDED_FORMAT;
    msg->id     = (u32)0x0003FFFF & (CAN->sFIFOMailBox[0].RIR >> 3);
  }
  // Read type information
  //如果消息为数据帧
  if ((CAN->sFIFOMailBox[0].RIR & CAN_RTR_REMOTE) == 0) 
  {
    msg->type =   DATA_FRAME;                     // DATA   FRAME
  }  
  else//数据为远程帧
  {
    msg->type = REMOTE_FRAME;                     // REMOTE FRAME
  }
  // Read length (number of received bytes)
  //消息数据长度
  msg->len = (unsigned char)0x0000000F & CAN->sFIFOMailBox[0].RDTR;
  // Read data bytes
  //从接收邮箱读数据
  msg->data[0] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR);
  msg->data[1] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 8);
  msg->data[2] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 16);
  msg->data[3] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 24);

  msg->data[4] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR);
  msg->data[5] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 8);
  msg->data[6] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 16);
  msg->data[7] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 24);

  // Release FIFO 0 output mailbox
  //释放接收FIFO 0输出邮箱,由于FIFO的特点,软件需要释放输出邮箱才能访问第2个报文
  CAN->RF0R |= CAN_RF0R_RFOM0;                    
}


void CAN_wrFilter (unsigned int id, unsigned char format)  {
  static unsigned short CAN_filterIdx = 0;
         unsigned int   CAN_msgId     = 0;
  // check if Filter Memory is full
  //检查CAN过滤器是否已满
  if (CAN_filterIdx > 13) 
  {                       
    return;
  }
  // Setup identifier information
  //如果是标准帧,标准帧是11位ID(报文识别码)
  if (format == STANDARD_FORMAT)  
  {               // Standard ID
      CAN_msgId  |= (unsigned int)(id << 21) | CAN_ID_STD;
  }  
  else//如果是扩展帧,扩展帧是29位ID(报文识别码)
  {                                      // Extended ID
      CAN_msgId  |= (unsigned int)(id <<  3) | CAN_ID_EXT;
  }
  // set Initialisation mode for filter banks
  //CAN过滤器组工作在初始化模式
  CAN->FMR  |=  CAN_FMR_FINIT;  
  // deactivate filter                  
  CAN->FA1R &=  ~(unsigned int)(1 << CAN_filterIdx); 

  // initialize filter
  // set 32-bit scale configuration 
  //初始化过滤器
  //过滤器位宽为单个32位
  CAN->FS1R |= (unsigned int)(1 << CAN_filterIdx);
  // set 2 32-bit identifier list mode
  //过滤器组x的2个32位寄存器工作在标识符列表模式
  CAN->FM1R |= (unsigned int)(1 << CAN_filterIdx);
  //  32-bit identifier
  //32位标识符
  CAN->sFilterRegister[CAN_filterIdx].FR1 = CAN_msgId; 
  //  32-bit identifier
  //32位标识符
  CAN->sFilterRegister[CAN_filterIdx].FR2 = CAN_msgId; 
  // assign filter to FIFO 0
  //过滤器被关联到FIFO0
  CAN->FFA1R &= ~(unsigned int)(1 << CAN_filterIdx);  
  // activate filter
  //过滤器被激活
  CAN->FA1R  |=  (unsigned int)(1 << CAN_filterIdx);  
  // reset Initialisation mode for filter banks
  //CAN过滤器组工作在正常模式
  CAN->FMR &= ~CAN_FMR_FINIT;                     
  // increase filter index
  //设置的过滤器数量增加
  CAN_filterIdx += 1;
}

/*----------------------------------------------------------------------------
  CAN transmit interrupt handler
  CAN发送中断
 *----------------------------------------------------------------------------*/
void USB_HP_CAN_TX_IRQHandler (void) {
  // request completed mbx 0
  //邮箱0请求完成
  if (CAN->TSR & CAN_TSR_RQCP0) 
  { 
  	// reset request complete mbx 0
  	//复位邮箱0请求
    CAN->TSR |= CAN_TSR_RQCP0;
    // disable  TME interrupt 
    //禁止发送邮箱空中断                   
    CAN->IER &= ~CAN_IER_TMEIE;                   
	
	  CAN_TxRdy = 1; 
  }
}

/*----------------------------------------------------------------------------
  CAN receive interrupt handler
  CAN接收中断
 *----------------------------------------------------------------------------*/
void USB_LP_CAN_RX0_IRQHandler (void) {
  // message pending ?
  //接收到CAN报文,通过判断报文数目判断是否有报文
  if (CAN->RF0R & CAN_RF0R_FMP0) 
  {			     
	  // read the message
	  //接收报文
	  CAN_rdMsg (&CAN_RxMsg); 

    CAN_RxRdy = 1;// set receive flag
  }
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -