Chinaunix首页 | 论坛 | 博客
  • 博客访问: 423202
  • 博文数量: 55
  • 博客积分: 167
  • 博客等级: 入伍新兵
  • 技术积分: 1167
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-28 10:20
个人简介

一个算是正常的中国码农!

文章分类

全部博文(55)

文章存档

2014年(1)

2013年(31)

2012年(23)

我的朋友

分类: 嵌入式

2013-07-23 14:14:10

原文地址:stm32 CAN总线例子 作者:zhanghonghu84

利用stm32实现了1个简单的CAN功能,使用了队列缓存
can.c 文件
#include "includes.h"
 
#define GPIO_CAN                   GPIOB
#define RCC_APB2Periph_GPIO_CAN    RCC_APB2Periph_GPIOB
#define GPIO_Pin_RX                GPIO_Pin_8
#define GPIO_Pin_TX                GPIO_Pin_9
#define GPIO_Remap_CAN             GPIO_Remap1_CAN1
#define MAX_MAIL_NUM  3
static u8 CAN_msg_num[MAX_MAIL_NUM];   // 发送邮箱标记
//
 
/**
  * @brief  Configures the CAN, transmit and receive by polling
  * @param  None
  * @retval : PASSED if the reception is well done, FAILED in other case
  */
void CAN_config_init(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  /* CAN register init */
  CAN_DeInit(CAN1);
  CAN_StructInit(&CAN_InitStructure);
  /* CAN cell init */  // 36M 250k速率
  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_Normal;
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1=CAN_BS1_12tq;
  CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;
  CAN_InitStructure.CAN_Prescaler=9;
  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);  
 }

void CAN_init(void)
{
 
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;    
      // 首先打开电源及时钟
    /* GPIO for CAN and GPIO for LEDs clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIO_CAN, ENABLE);
    /* CAN1 Periph clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
   
    /* Enable CAN1 RX0 interrupt IRQ channel */
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    /* Enable CAN1 TX0 interrupt IRQ channel */
    NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN1_TX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    // 然后配置pin
    /* Configure CAN pin: RX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_RX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 //   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CAN, &GPIO_InitStructure);
    /* Configure CAN pin: TX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_TX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CAN, &GPIO_InitStructure);
    // 映射下
    GPIO_PinRemapConfig(GPIO_Remap_CAN , ENABLE);
    // 波特率过滤器初始化
    CAN_config_init(); 
    CAN_ITConfig(CAN1, CAN_IT_FMP0 | CAN_IT_FF0 | CAN_IT_FOV0, ENABLE);  // fifo0中断
    CAN_ITConfig(CAN1, CAN_IT_FMP1 | CAN_IT_FF1 | CAN_IT_FOV1, ENABLE);  // fifo1中断
    CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);                // 发送中断
    CAN_ITConfig(CAN1, CAN_IT_EWG | CAN_IT_EPV | CAN_IT_BOF | CAN_IT_LEC
                     | CAN_IT_ERR | CAN_IT_WKU | CAN_IT_SLK, ENABLE);  // ERR中断
    // CAN缓存初始化
    memset(CAN_msg_num,0,MAX_MAIL_NUM);
    ClearCanQueue();
  
}
int CAN_tx_msg(CanTxMsg TxMessage)
{
    uint8_t TransmitMailbox = 0;
    OS_CPU_SR  cpu_sr = 0;
    TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);
    if(CAN_NO_MB == TransmitMailbox)
    {
        printf("tx can fail\r\n");
        return 0;
    }
    else
    {
        OS_ENTER_CRITICAL();        
        CAN_msg_num[TransmitMailbox] = 1;
        OS_EXIT_CRITICAL();
    }
   
    CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
    return 1;
}

int CAN_tx_data(void)
{
    CanTxMsg TxMessage;
    uint8_t TransmitMailbox = 0;
    OS_CPU_SR  cpu_sr = 0;
    /* transmit */
    TxMessage.StdId=0x6f1;
    TxMessage.RTR=CAN_RTR_DATA;
    TxMessage.IDE=CAN_ID_STD;
    TxMessage.DLC=4;
    TxMessage.Data[0]=0x40;
    TxMessage.Data[1]=0x02;
    TxMessage.Data[2]=0x1a;
    TxMessage.Data[3]=0x80;
    TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);
    if(CAN_NO_MB == TransmitMailbox)
    {
        printf("tx can fail\r\n");
        return 0;
    }
    else
    {
        OS_ENTER_CRITICAL();        
        CAN_msg_num[TransmitMailbox] = 1;
        OS_EXIT_CRITICAL();
    }
   
    CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
    return 1;
}
// 发送中断
void USB_HP_CAN1_TX_IRQHandler(void)
{
    if(CAN_msg_num[0])
    {
        if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP0))
        {
            CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP0);
            CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);
            CAN_msg_num[0] = 0;
        }
    }
  
    if(CAN_msg_num[1])
    {
        if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP1))
        {
            CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP1);
            CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);
            CAN_msg_num[1] = 0;
        }
    }
  
    if(CAN_msg_num[2])
    {
        if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP2))
        {
            CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP2);
            CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);
            CAN_msg_num[2] = 0;
        }
    }
   
}
/**
  * @brief  This function handles USB Low Priority or CAN RX0 interrupts
  *   requests.
  * @param  None
  * @retval : None
  */
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  //  u32 i;
    CanRxMsg RxMessage;
   if(SET == CAN_GetITStatus(CAN1,CAN_IT_FF0))
   {
        CAN_ClearITPendingBit(CAN1,CAN_IT_FF0);
   }
   else if(SET == CAN_GetITStatus(CAN1,CAN_IT_FOV0))
   {
        CAN_ClearITPendingBit(CAN1,CAN_IT_FOV0);
   }
   else
   {
        CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
        InsertCanQueue(RxMessage);
     //   printf("CAN_FIFO0 RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);
     //   printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);  
      //  for(i = 0; i < RxMessage.DLC; i++)
     //   {
     //       printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);
      //  }
     //   printf("\r\n");  
   }  
  
}
void CAN1_RX1_IRQHandler(void)
{
   // u32 i;
    CanRxMsg RxMessage;
   if(SET == CAN_GetITStatus(CAN1,CAN_IT_FF1))
   {
        CAN_ClearITPendingBit(CAN1,CAN_IT_FF1);
   }
   else if(SET == CAN_GetITStatus(CAN1,CAN_IT_FOV1))
   {
        CAN_ClearITPendingBit(CAN1,CAN_IT_FOV1);
   }
   else
   {
        CAN_Receive(CAN1, CAN_FIFO1, &RxMessage);
        InsertCanQueue(RxMessage);
     
      //  printf("CAN_FIFO1 RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);
      //  printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);  
      //  for(i = 0; i < RxMessage.DLC; i++)
      //  {
      //      printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);
      //  }
      //  printf("\r\n");  
   }  
  
}
void CAN1_SCE_IRQHandler(void)
{
   
}
 
 
can.h文件

#ifndef __CAN_H__
#define __CAN_H__

void CAN_init(void);
int CAN_tx_data(void);
int CAN_tx_msg(CanTxMsg TxMessage);
#endif
 
can_queue.c文件
#include "includes.h"
struct _CANQueue CANQueue;
/*******************************************************************
作    者:
版    权: 
函数名称:
函数功能: 清除通信队列
入口参数: 无
返 回 值: 无
相关调用:
备    注:
修改信息:        
********************************************************************/
void ClearCanQueue(void)
{
    int i;
   
    for(i = 0; i < MAX_CAN_SIZE; i++)
    {
        memset(&CANQueue.Elem[i],0,sizeof(CanRxMsg));
    }
            
    CANQueue.front = 0;
    CANQueue.rear = 0;
}
/*******************************************************************
作    者:
版    权: 
函数名称:
函数功能: 判断串口队列是否为空
入口参数:
返 回 值: 1: 空; 0:非空
相关调用:
备    注:
修改信息:        
********************************************************************/
u8 IsEmptyCanQueue(void)
{
   
    if(CANQueue.front == CANQueue.rear)         
    {
        return 1;
    }   
    else
    {
        return 0;   
    }
   
}
/*******************************************************************
作    者:
版    权:
函数名称:
函数功能: 判队列是否满
入口参数:
返 回 值: 1: 满; 0:非满
相关调用:
备    注:
修改信息:        
********************************************************************/
u8 IsFullCanQueue(void)
{
  
    if( CANQueue.front == (CANQueue.rear+1) % MAX_CAN_SIZE)
    {
        return 1;
    }   
    else
    {
        return 0;   
    }
  
}
/*******************************************************************
作    者:
版    权: 
函数名称:
函数功能: 将数据插入队列
入口参数: element:被插元素
返 回 值: 1: 成功; 0:失败
相关调用:
备    注:
修改信息:        
********************************************************************/
u8 InsertCanQueue(CanRxMsg element)
{
    if(!IsFullCanQueue())                               //是否为满
    {
        memcpy(&CANQueue.Elem[CANQueue.rear],&element,sizeof(CanRxMsg));
      
        CANQueue.rear = (CANQueue.rear + 1) % MAX_CAN_SIZE;       
      
        return 1;
    }
    else                       //队列满
    {
       // printf("CAN queue is full\r\n");
        return 0;
    }
}

/*******************************************************************
作    者:
版    权:
函数名称:
函数功能: 重新设置队列头指针
入口参数: head: 新头
返 回 值: 无
相关调用:
备    注:
修改信息:        
********************************************************************/
void SetHeadCanQueue(u16 head)
{
  
    if(CANQueue.front != CANQueue.rear)
    {
        CANQueue.front = head;
    }  
    
}
/*******************************************************************
作    者:
版    权:
函数名称:
函数功能: 取对头
入口参数: head:对头;*element;数据
返 回 值: 1: 成功 0: 失败
相关调用:
备    注:
修改信息:        
********************************************************************/
u8 GetCanQueue(u16 head,CanRxMsg *element)
{
  
    if(head != CANQueue.rear)                //到队列尾
    {
        memcpy(element,&CANQueue.Elem[head],sizeof(CanRxMsg));//得到数据    
        return 1;
    }
    else
    {
        return 0;                               //无指定对头数据
    }       
}
/*******************************************************************
作    者:
版    权:
函数名称:
函数功能: can数据处理
入口参数:
返 回 值:
相关调用:
备    注:
修改信息:        
********************************************************************/
void Can_data_process(void)
{
    u16 head;
 //   u32 i;
    CanRxMsg RxMessage; 
    CanTxMsg TxMessage;
   
   
    head = CANQueue.front;
   
    if(1 == GetCanQueue(head,&RxMessage))
    {
        head = (head + 1) % MAX_CAN_SIZE;     //查询头前滚
        SetHeadCanQueue(head);
      //  printf("RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);
      //  printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);  
      //  for(i = 0; i < RxMessage.DLC; i++)
      //  {
      //      printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);
      //  }
      //  printf("\r\n");
        // 把接收到的数据发回去
        /* transmit */
      //  TxMessage.StdId=RxMessage.StdId;
        TxMessage.StdId=0x5f1;
        TxMessage.RTR=RxMessage.RTR;
        TxMessage.IDE=RxMessage.IDE;
        TxMessage.DLC=RxMessage.DLC; 
        memcpy(TxMessage.Data,RxMessage.Data,TxMessage.DLC);
        CAN_tx_msg(TxMessage);       
       
    }
    else
    {
       // printf("CAN queue is empty\r\n");
    }
   
       
   
}
 
can_queue.h文件
#ifndef CAN_QUEUE_H_
#define CAN_QUEUE_H_
#define MAX_CAN_SIZE 50
struct _CANQueue
{
    CanRxMsg Elem[MAX_CAN_SIZE];
    u16 front;
    u16 rear;
};
void ClearCanQueue(void);
u8 IsEmptyCanQueue(void);
u8 IsFullCanQueue(void);
u8 InsertCanQueue(CanRxMsg element);
void SetHeadCanQueue(u16 head);
u8 GetCanQueue(u16 head,CanRxMsg *element);
void Can_data_process(void);
 
 
 
#endif

阅读(7288) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~