STM32F1(CAN)

                                          STM32F1(CAN)

GitHub 倉庫:https://github.com/XinLiGH/STM32F1xx_CAN_Example

PS:博文不再更新,後續更新會在 GitHub 倉庫進行。

 

1,開發環境

1,固件庫:STM32F10x_StdPeriph_Lib_V3.5.0

2,編譯器:ARMCC V5.06

3,IDE:Keil uVision5

4,操作系統:Windows 10 專業版

 

2,程序源碼

RingBuffer.h 文件

/**
  ******************************************************************************
  * @file    RingBuffer.h
  * @author  XinLi
  * @version v1.1
  * @date    15-January-2018
  * @brief   Header file for RingBuffer.c module.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

#ifndef __RINGBUFFER_H
#define __RINGBUFFER_H

#ifdef __cplusplus
extern "C" {
#endif

/* Header includes -----------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

/* Macro definitions ---------------------------------------------------------*/
#define RING_BUFFER_MALLOC(size)  malloc(size)
#define RING_BUFFER_FREE(block)   free(block)

/* Type definitions ----------------------------------------------------------*/
typedef struct
{
  uint8_t *buffer;
  uint32_t size;
  uint32_t in;
  uint32_t out;
}RingBuffer;

/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
RingBuffer *RingBuffer_Malloc(uint32_t size);
void RingBuffer_Free(RingBuffer *fifo);

uint32_t RingBuffer_In(RingBuffer *fifo, void *in, uint32_t len);
uint32_t RingBuffer_Out(RingBuffer *fifo, void *out, uint32_t len);

/* Function definitions ------------------------------------------------------*/

/**
  * @brief  Removes the entire FIFO contents.
  * @param  [in] fifo: The fifo to be emptied.
  * @return None.
  */
static inline void RingBuffer_Reset(RingBuffer *fifo)
{
  fifo->in = fifo->out = 0;
}

/**
  * @brief  Returns the size of the FIFO in bytes.
  * @param  [in] fifo: The fifo to be used.
  * @return The size of the FIFO.
  */
static inline uint32_t RingBuffer_Size(RingBuffer *fifo)
{
  return fifo->size;
}

/**
  * @brief  Returns the number of used bytes in the FIFO.
  * @param  [in] fifo: The fifo to be used.
  * @return The number of used bytes.
  */
static inline uint32_t RingBuffer_Len(RingBuffer *fifo)
{
  return fifo->in - fifo->out;
}

/**
  * @brief  Returns the number of bytes available in the FIFO.
  * @param  [in] fifo: The fifo to be used.
  * @return The number of bytes available.
  */
static inline uint32_t RingBuffer_Avail(RingBuffer *fifo)
{
  return RingBuffer_Size(fifo) - RingBuffer_Len(fifo);
}

/**
  * @brief  Is the FIFO empty?
  * @param  [in] fifo: The fifo to be used.
  * @retval true:      Yes.
  * @retval false:     No.
  */
static inline bool RingBuffer_IsEmpty(RingBuffer *fifo)
{
  return RingBuffer_Len(fifo) == 0;
}

/**
  * @brief  Is the FIFO full?
  * @param  [in] fifo: The fifo to be used.
  * @retval true:      Yes.
  * @retval false:     No.
  */
static inline bool RingBuffer_IsFull(RingBuffer *fifo)
{
  return RingBuffer_Avail(fifo) == 0;
}

#ifdef __cplusplus
}
#endif

#endif /* __RINGBUFFER_H */

RingBuffer.c 文件

/**
  ******************************************************************************
  * @file    RingBuffer.c
  * @author  XinLi
  * @version v1.1
  * @date    15-January-2018
  * @brief   Ring buffer module source file.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

/* Header includes -----------------------------------------------------------*/
#include "RingBuffer.h"
#include <string.h>

/* Macro definitions ---------------------------------------------------------*/
#define min(a, b)  (((a) < (b)) ? (a) : (b))

/* Type definitions ----------------------------------------------------------*/
/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
static bool is_power_of_2(uint32_t x);
static uint32_t roundup_pow_of_two(uint32_t x);

/* Function definitions ------------------------------------------------------*/

/**
  * @brief  Allocates a new FIFO and its internal buffer.
  * @param  [in] size: The size of the internal buffer to be allocated.
  * @note   The size will be rounded-up to a power of 2.
  * @return RingBuffer pointer.
  */
RingBuffer *RingBuffer_Malloc(uint32_t size)
{
  RingBuffer *fifo = RING_BUFFER_MALLOC(sizeof(RingBuffer));

  if(fifo != NULL)
  {
    if(is_power_of_2(size) != true)
    {
      if(size > 0x80000000UL)
      {
        RING_BUFFER_FREE(fifo);
        return NULL;
      }

      size = roundup_pow_of_two(size);
    }

    fifo->buffer = RING_BUFFER_MALLOC(size);

    if(fifo->buffer == NULL)
    {
      RING_BUFFER_FREE(fifo);
      return NULL;
    }

    fifo->size = size;
    fifo->in = fifo->out = 0;
  }

  return fifo;
}

/**
  * @brief  Frees the FIFO.
  * @param  [in] fifo: The fifo to be freed.
  * @return None.
  */
void RingBuffer_Free(RingBuffer *fifo)
{
  RING_BUFFER_FREE(fifo->buffer);
  RING_BUFFER_FREE(fifo);
}

/**
  * @brief  Puts some data into the FIFO.
  * @param  [in] fifo: The fifo to be used.
  * @param  [in] in:   The data to be added.
  * @param  [in] len:  The length of the data to be added.
  * @return The number of bytes copied.
  * @note   This function copies at most @len bytes from the @in into
  *         the FIFO depending on the free space, and returns the number
  *         of bytes copied.
  */
uint32_t RingBuffer_In(RingBuffer *fifo, void *in, uint32_t len)
{
  len = min(len, RingBuffer_Avail(fifo));

  /* First put the data starting from fifo->in to buffer end. */
  uint32_t l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
  memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), in, l);

  /* Then put the rest (if any) at the beginning of the buffer. */
  memcpy(fifo->buffer, (uint8_t *)in + l, len - l);

  fifo->in += len;

  return len;
}

/**
  * @brief  Gets some data from the FIFO.
  * @param  [in] fifo: The fifo to be used.
  * @param  [in] out:  Where the data must be copied.
  * @param  [in] len:  The size of the destination buffer.
  * @return The number of copied bytes.
  * @note   This function copies at most @len bytes from the FIFO into
  *         the @out and returns the number of copied bytes.
  */
uint32_t RingBuffer_Out(RingBuffer *fifo, void *out, uint32_t len)
{
  len = min(len, RingBuffer_Len(fifo));

  /* First get the data from fifo->out until the end of the buffer. */
  uint32_t l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
  memcpy(out, fifo->buffer + (fifo->out & (fifo->size - 1)), l);

  /* Then get the rest (if any) from the beginning of the buffer. */
  memcpy((uint8_t *)out + l, fifo->buffer, len - l);

  fifo->out += len;

  return len;
}

/**
  * @brief  Determine whether some value is a power of two.
  * @param  [in] x: The number to be confirmed.
  * @retval true:   Yes.
  * @retval false:  No.
  * @note   Where zero is not considered a power of two.
  */
static bool is_power_of_2(uint32_t x)
{
  return (x != 0) && ((x & (x - 1)) == 0);
}

/**
  * @brief  Round the given value up to nearest power of two.
  * @param  [in] x: The number to be converted.
  * @return The power of two.
  */
static uint32_t roundup_pow_of_two(uint32_t x)
{
  uint32_t b = 0;

  for(int i = 0; i < 32; i++)
  {
    b = 1UL << i;

    if(x <= b)
    {
      break;
    }
  }

  return b;
}

CAN.h 文件

/**
  ******************************************************************************
  * @file    CAN.h
  * @author  XinLi
  * @version v1.0
  * @date    24-June-2018
  * @brief   Header file for CAN.c module.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

#ifndef __CAN_H
#define __CAN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Header includes -----------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>

/* Macro definitions ---------------------------------------------------------*/

/******************************* CAN1 Configure *******************************/
#define CAN1_TX_BUFFER_SIZE        (16)
#define CAN1_RX_BUFFER_SIZE        (16)

#define CAN1_TX_GPIO_CLOCK         RCC_APB2Periph_GPIOB
#define CAN1_RX_GPIO_CLOCK         RCC_APB2Periph_GPIOB

#define CAN1_TX_GPIO_PORT          GPIOB
#define CAN1_RX_GPIO_PORT          GPIOB

#define CAN1_TX_GPIO_PIN           GPIO_Pin_9
#define CAN1_RX_GPIO_PIN           GPIO_Pin_8

#define CAN1_IRQ_PREEMPT_PRIORITY  (0)
#define CAN1_IRQ_SUB_PRIORITY      (0)

#define CAN1_PORT_REMAP()          GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE)
/******************************************************************************/

#ifdef STM32F10X_CL
/******************************* CAN2 Configure *******************************/
#define CAN2_TX_BUFFER_SIZE        (16)
#define CAN2_RX_BUFFER_SIZE        (16)

#define CAN2_TX_GPIO_CLOCK         RCC_APB2Periph_GPIOB
#define CAN2_RX_GPIO_CLOCK         RCC_APB2Periph_GPIOB

#define CAN2_TX_GPIO_PORT          GPIOB
#define CAN2_RX_GPIO_PORT          GPIOB

#define CAN2_TX_GPIO_PIN           GPIO_Pin_13
#define CAN2_RX_GPIO_PIN           GPIO_Pin_12

#define CAN2_IRQ_PREEMPT_PRIORITY  (0)
#define CAN2_IRQ_SUB_PRIORITY      (0)

#define CAN2_PORT_REMAP()          GPIO_PinRemapConfig(GPIO_Remap_CAN2 , DISABLE)
/******************************************************************************/
#endif /* STM32F10X_CL */

/* Type definitions ----------------------------------------------------------*/
typedef enum
{
  CAN_WorkModeNormal   = CAN_Mode_Normal,
  CAN_WorkModeLoopBack = CAN_Mode_LoopBack
}CAN_WorkMode;

typedef enum
{
  CAN_BaudRate1000K = 6,
  CAN_BaudRate500K  = 12,
  CAN_BaudRate250K  = 24,
  CAN_BaudRate125K  = 48,
  CAN_BaudRate100K  = 60,
  CAN_BaudRate50K   = 120,
  CAN_BaudRate20K   = 300,
  CAN_BaudRate10K   = 600
}CAN_BaudRate;

/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
void CAN_Configure(CAN_TypeDef *CANx, CAN_WorkMode WorkMode, CAN_BaudRate BaudRate, uint32_t StdId, uint32_t ExtId);
void CAN_Unconfigure(CAN_TypeDef *CANx);

void CAN_SetTransmitFinishCallback(CAN_TypeDef *CANx, void (*Callback)(void));
void CAN_SetReceiveFinishCallback(CAN_TypeDef *CANx, void (*Callback)(void));

uint32_t CAN_SetTransmitMessage(CAN_TypeDef *CANx, CanTxMsg *Message, uint32_t Number);
uint32_t CAN_GetReceiveMessage(CAN_TypeDef *CANx, CanRxMsg *Message, uint32_t Number);

uint32_t CAN_GetUsedTransmitBufferSize(CAN_TypeDef *CANx);
uint32_t CAN_GetUsedReceiveBufferSize(CAN_TypeDef *CANx);
uint32_t CAN_GetUnusedTransmitBufferSize(CAN_TypeDef *CANx);
uint32_t CAN_GetUnusedReceiveBufferSize(CAN_TypeDef *CANx);

bool CAN_IsTransmitBufferEmpty(CAN_TypeDef *CANx);
bool CAN_IsReceiveBufferEmpty(CAN_TypeDef *CANx);
bool CAN_IsTransmitBufferFull(CAN_TypeDef *CANx);
bool CAN_IsReceiveBufferFull(CAN_TypeDef *CANx);

void CAN_ClearTransmitBuffer(CAN_TypeDef *CANx);
void CAN_ClearReceiveBuffer(CAN_TypeDef *CANx);

bool CAN_IsTransmitMessage(CAN_TypeDef *CANx);

/* Function definitions ------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif /* __CAN_H */

CAN.c 文件

/**
  ******************************************************************************
  * @file    CAN.c
  * @author  XinLi
  * @version v1.0
  * @date    24-June-2018
  * @brief   CAN module driver.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

/* Header includes -----------------------------------------------------------*/
#include "CAN.h"
#include "RingBuffer.h"

/* Macro definitions ---------------------------------------------------------*/
/* Type definitions ----------------------------------------------------------*/
/* Variable declarations -----------------------------------------------------*/
static volatile bool can1InitFlag     = false;
static volatile bool can1TransmitFlag = false;

static volatile void (*can1TransmitFinishCallback)(void) = 0;
static volatile void (*can1ReceiveFinishCallback)(void)  = 0;

static RingBuffer *can1TxBuffer = 0;
static RingBuffer *can1RxBuffer = 0;

#ifdef STM32F10X_CL
static volatile bool can2InitFlag     = false;
static volatile bool can2TransmitFlag = false;

static volatile void (*can2TransmitFinishCallback)(void) = 0;
static volatile void (*can2ReceiveFinishCallback)(void)  = 0;

static RingBuffer *can2TxBuffer = 0;
static RingBuffer *can2RxBuffer = 0;
#endif /* STM32F10X_CL */

/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
/* Function definitions ------------------------------------------------------*/

/**
  * @brief  CAN configure.
  * @param  [in] CANx:     Where x can be 1 or 2 to select the CAN peripheral.
  * @param  [in] WorkMode: Work mode.
  * @param  [in] BaudRate: Communication baud rate.
  * @param  [in] StdId:    Filter standard frame ID.
  * @param  [in] ExtId:    Filter extended frame ID.
  * @return None.
  */
void CAN_Configure(CAN_TypeDef *CANx, CAN_WorkMode WorkMode, CAN_BaudRate BaudRate, uint32_t StdId, uint32_t ExtId)
{
  GPIO_InitTypeDef      GPIO_InitStructure      = {0};
  CAN_InitTypeDef       CAN_InitStructure       = {0};
  CAN_FilterInitTypeDef CAN_FilterInitStructure = {0};
  NVIC_InitTypeDef      NVIC_InitStructure      = {0};
  
  if(CANx == CAN1)
  {
    if(can1InitFlag == false)
    {
      can1InitFlag = true;
      
      can1TransmitFlag = false;
      
      can1TransmitFinishCallback = 0;
      can1ReceiveFinishCallback  = 0;
      
      can1TxBuffer = RingBuffer_Malloc(sizeof(CanTxMsg) * CAN1_TX_BUFFER_SIZE);
      can1RxBuffer = RingBuffer_Malloc(sizeof(CanRxMsg) * CAN1_RX_BUFFER_SIZE);
      
#ifdef STM32F10X_CL
      if(can2InitFlag == false)
#endif /* STM32F10X_CL */
      {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
      }
      
      RCC_APB2PeriphClockCmd(CAN1_TX_GPIO_CLOCK | CAN1_RX_GPIO_CLOCK | RCC_APB2Periph_AFIO, ENABLE);
      
      GPIO_InitStructure.GPIO_Pin   = CAN1_TX_GPIO_PIN;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(CAN1_TX_GPIO_PORT, &GPIO_InitStructure);
      
      GPIO_InitStructure.GPIO_Pin   = CAN1_RX_GPIO_PIN;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
      GPIO_Init(CAN1_RX_GPIO_PORT, &GPIO_InitStructure);
      
      CAN1_PORT_REMAP();
      
      CAN_InitStructure.CAN_Prescaler = BaudRate;
      CAN_InitStructure.CAN_Mode      = WorkMode;
      CAN_InitStructure.CAN_SJW       = CAN_SJW_1tq;
      CAN_InitStructure.CAN_BS1       = CAN_BS1_3tq;
      CAN_InitStructure.CAN_BS2       = CAN_BS2_2tq;
      CAN_InitStructure.CAN_TTCM      = DISABLE;
      CAN_InitStructure.CAN_ABOM      = ENABLE;
      CAN_InitStructure.CAN_AWUM      = DISABLE;
      CAN_InitStructure.CAN_NART      = ENABLE;
      CAN_InitStructure.CAN_RFLM      = DISABLE;
      CAN_InitStructure.CAN_TXFP      = ENABLE;
      
      CAN_DeInit(CAN1);
      CAN_Init(CAN1, &CAN_InitStructure);
      
      CAN_FilterInitStructure.CAN_FilterIdHigh         = (uint16_t)((((StdId<<18)|ExtId)<<3)>>16);
      CAN_FilterInitStructure.CAN_FilterIdLow          = (uint16_t)(((StdId<<18)|ExtId)<<3);
      CAN_FilterInitStructure.CAN_FilterMaskIdHigh     = (~((uint16_t)((((StdId<<18)|ExtId)<<3)>>16)))&0xFFFF;
      CAN_FilterInitStructure.CAN_FilterMaskIdLow      = (~((uint16_t)(((StdId<<18)|ExtId)<<3)))&0xFFF8;
      CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
      CAN_FilterInitStructure.CAN_FilterNumber         = 0;
      CAN_FilterInitStructure.CAN_FilterMode           = CAN_FilterMode_IdMask;
      CAN_FilterInitStructure.CAN_FilterScale          = CAN_FilterScale_32bit;
      CAN_FilterInitStructure.CAN_FilterActivation     = ENABLE;
      CAN_FilterInit(&CAN_FilterInitStructure);
      
      CAN_ITConfig(CAN1, CAN_IT_TME | CAN_IT_FMP0 |CAN_IT_FF0 | CAN_IT_FOV0 | CAN_IT_FMP1 | CAN_IT_FF1 | CAN_IT_FOV1 |
                         CAN_IT_WKU | CAN_IT_SLK  |CAN_IT_EWG | CAN_IT_EPV  | CAN_IT_BOF  | CAN_IT_LEC | CAN_IT_ERR, DISABLE);
      CAN_ITConfig(CAN1, CAN_IT_TME | CAN_IT_FMP0, ENABLE);
      
#ifdef STM32F10X_CL
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_TX_IRQn;
#else
      NVIC_InitStructure.NVIC_IRQChannel                   = USB_HP_CAN1_TX_IRQn;
#endif /* STM32F10X_CL */
      
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN1_IRQ_PREEMPT_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority        = CAN1_IRQ_SUB_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      
#ifdef STM32F10X_CL
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_RX0_IRQn;
#else
      NVIC_InitStructure.NVIC_IRQChannel                   = USB_LP_CAN1_RX0_IRQn;
#endif /* STM32F10X_CL */
      
      NVIC_Init(&NVIC_InitStructure);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == false)
    {
      can2InitFlag = true;
      
      can2TransmitFlag = false;
      
      can2TransmitFinishCallback = 0;
      can2ReceiveFinishCallback  = 0;
      
      can2TxBuffer = RingBuffer_Malloc(sizeof(CanTxMsg) * CAN2_TX_BUFFER_SIZE);
      can2RxBuffer = RingBuffer_Malloc(sizeof(CanRxMsg) * CAN2_RX_BUFFER_SIZE);
      
      if(can1InitFlag == false)
      {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
      }
      
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);
      RCC_APB2PeriphClockCmd(CAN2_TX_GPIO_CLOCK | CAN2_RX_GPIO_CLOCK | RCC_APB2Periph_AFIO, ENABLE);
      
      GPIO_InitStructure.GPIO_Pin   = CAN2_TX_GPIO_PIN;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(CAN2_TX_GPIO_PORT, &GPIO_InitStructure);
      
      GPIO_InitStructure.GPIO_Pin   = CAN2_RX_GPIO_PIN;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
      GPIO_Init(CAN2_RX_GPIO_PORT, &GPIO_InitStructure);
      
      CAN2_PORT_REMAP();
      
      CAN_InitStructure.CAN_Prescaler = BaudRate;
      CAN_InitStructure.CAN_Mode      = WorkMode;
      CAN_InitStructure.CAN_SJW       = CAN_SJW_1tq;
      CAN_InitStructure.CAN_BS1       = CAN_BS1_3tq;
      CAN_InitStructure.CAN_BS2       = CAN_BS2_2tq;
      CAN_InitStructure.CAN_TTCM      = DISABLE;
      CAN_InitStructure.CAN_ABOM      = ENABLE;
      CAN_InitStructure.CAN_AWUM      = DISABLE;
      CAN_InitStructure.CAN_NART      = ENABLE;
      CAN_InitStructure.CAN_RFLM      = DISABLE;
      CAN_InitStructure.CAN_TXFP      = ENABLE;
      
      CAN_DeInit(CAN2);
      CAN_Init(CAN2, &CAN_InitStructure);
      
      CAN_FilterInitStructure.CAN_FilterIdHigh         = (uint16_t)((((StdId<<18)|ExtId)<<3)>>16);
      CAN_FilterInitStructure.CAN_FilterIdLow          = (uint16_t)(((StdId<<18)|ExtId)<<3);
      CAN_FilterInitStructure.CAN_FilterMaskIdHigh     = (~((uint16_t)((((StdId<<18)|ExtId)<<3)>>16)))&0xFFFF;
      CAN_FilterInitStructure.CAN_FilterMaskIdLow      = (~((uint16_t)(((StdId<<18)|ExtId)<<3)))&0xFFF8;
      CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
      CAN_FilterInitStructure.CAN_FilterNumber         = 14;
      CAN_FilterInitStructure.CAN_FilterMode           = CAN_FilterMode_IdMask;
      CAN_FilterInitStructure.CAN_FilterScale          = CAN_FilterScale_32bit;
      CAN_FilterInitStructure.CAN_FilterActivation     = ENABLE;
      CAN_FilterInit(&CAN_FilterInitStructure);
      
      CAN_ITConfig(CAN2, CAN_IT_TME | CAN_IT_FMP0 |CAN_IT_FF0 | CAN_IT_FOV0 | CAN_IT_FMP1 | CAN_IT_FF1 | CAN_IT_FOV1 |
                         CAN_IT_WKU | CAN_IT_SLK  |CAN_IT_EWG | CAN_IT_EPV  | CAN_IT_BOF  | CAN_IT_LEC | CAN_IT_ERR, DISABLE);
      CAN_ITConfig(CAN2, CAN_IT_TME | CAN_IT_FMP0, ENABLE);
      
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN2_TX_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN2_IRQ_PREEMPT_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority        = CAN2_IRQ_SUB_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN2_RX0_IRQn;
      NVIC_Init(&NVIC_InitStructure);
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  CAN unconfigure.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return None.
  */
void CAN_Unconfigure(CAN_TypeDef *CANx)
{
  NVIC_InitTypeDef NVIC_InitStructure = {0};
  
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      can1InitFlag = false;
      
#ifdef STM32F10X_CL
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_TX_IRQn;
#else
      NVIC_InitStructure.NVIC_IRQChannel                   = USB_HP_CAN1_TX_IRQn;
#endif /* STM32F10X_CL */
      
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN1_IRQ_PREEMPT_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority        = CAN1_IRQ_SUB_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelCmd                = DISABLE;
      NVIC_Init(&NVIC_InitStructure);
      
#ifdef STM32F10X_CL
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_RX0_IRQn;
#else
      NVIC_InitStructure.NVIC_IRQChannel                   = USB_LP_CAN1_RX0_IRQn;
#endif /* STM32F10X_CL */
      
      NVIC_Init(&NVIC_InitStructure);
      
      CAN_DeInit(CAN1);
      
#ifdef STM32F10X_CL
      if(can2InitFlag == false)
#endif /* STM32F10X_CL */
      {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, DISABLE);
      }
      
      can1TransmitFlag = false;
      
      can1TransmitFinishCallback = 0;
      can1ReceiveFinishCallback  = 0;
      
      RingBuffer_Free(can1TxBuffer);
      RingBuffer_Free(can1RxBuffer);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      can2InitFlag = false;
      
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN2_TX_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CAN2_IRQ_PREEMPT_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority        = CAN2_IRQ_SUB_PRIORITY;
      NVIC_InitStructure.NVIC_IRQChannelCmd                = DISABLE;
      NVIC_Init(&NVIC_InitStructure);
      
      NVIC_InitStructure.NVIC_IRQChannel                   = CAN2_RX0_IRQn;
      NVIC_Init(&NVIC_InitStructure);
      
      CAN_DeInit(CAN2);
      
      if(can1InitFlag == false)
      {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, DISABLE);
      }
      
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, DISABLE);
      
      can2TransmitFlag = false;
      
      can2TransmitFinishCallback = 0;
      can2ReceiveFinishCallback  = 0;
      
      RingBuffer_Free(can2TxBuffer);
      RingBuffer_Free(can2RxBuffer);
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  CAN set transmit finish callback.
  * @param  [in] CANx:     Where x can be 1 or 2 to select the CAN peripheral.
  * @param  [in] Callback: Callback.
  * @return None.
  */
void CAN_SetTransmitFinishCallback(CAN_TypeDef *CANx, void (*Callback)(void))
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      can1TransmitFinishCallback = (volatile void (*)(void))Callback;
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      can2TransmitFinishCallback = (volatile void (*)(void))Callback;
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  CAN set receive finish callback.
  * @param  [in] CANx:     Where x can be 1 or 2 to select the CAN peripheral.
  * @param  [in] Callback: Callback.
  * @return None.
  */
void CAN_SetReceiveFinishCallback(CAN_TypeDef *CANx, void (*Callback)(void))
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      can1ReceiveFinishCallback = (volatile void (*)(void))Callback;
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      can2ReceiveFinishCallback = (volatile void (*)(void))Callback;
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  CAN set transmit message.
  * @param  [in] CANx:    Where x can be 1 or 2 to select the CAN peripheral.
  * @param  [in] Message: The address of the message to be transmit.
  * @param  [in] Number:  The number of the message to be transmit.
  * @return The number of message transmit.
  */
uint32_t CAN_SetTransmitMessage(CAN_TypeDef *CANx, CanTxMsg *Message, uint32_t Number)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      uint32_t available = RingBuffer_Avail(can1TxBuffer) / sizeof(CanTxMsg);
      
      if(available > Number)
      {
        Number = RingBuffer_In(can1TxBuffer, Message, sizeof(CanTxMsg) * Number) / sizeof(CanTxMsg);
      }
      else
      {
        Number = RingBuffer_In(can1TxBuffer, Message, sizeof(CanTxMsg) * available) / sizeof(CanTxMsg);
      }
      
      if(Number > 0)
      {
        if(can1TransmitFlag == false)
        {
          can1TransmitFlag = true;
          
          CanTxMsg canTxMsg = {0};
          RingBuffer_Out(can1TxBuffer, &canTxMsg, sizeof(canTxMsg));
          CAN_Transmit(CAN1, &canTxMsg);
        }
      }
      
      return Number;
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      uint32_t available = RingBuffer_Avail(can2TxBuffer) / sizeof(CanTxMsg);
      
      if(available > Number)
      {
        Number = RingBuffer_In(can2TxBuffer, Message, sizeof(CanTxMsg) * Number) / sizeof(CanTxMsg);
      }
      else
      {
        Number = RingBuffer_In(can2TxBuffer, Message, sizeof(CanTxMsg) * available) / sizeof(CanTxMsg);
      }
      
      if(Number > 0)
      {
        if(can2TransmitFlag == false)
        {
          can2TransmitFlag = true;
          
          CanTxMsg canTxMsg = {0};
          RingBuffer_Out(can2TxBuffer, &canTxMsg, sizeof(canTxMsg));
          CAN_Transmit(CAN2, &canTxMsg);
        }
      }
      
      return Number;
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  CAN get receive message.
  * @param  [in] CANx:    Where x can be 1 or 2 to select the CAN peripheral.
  * @param  [in] Message: To store the address of the receive message.
  * @param  [in] Number:  To read the number of the received message.
  * @return The number of message obtained.
  */
uint32_t CAN_GetReceiveMessage(CAN_TypeDef *CANx, CanRxMsg *Message, uint32_t Number)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return RingBuffer_Out(can1RxBuffer, Message, sizeof(CanRxMsg) * Number) / sizeof(CanRxMsg);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return RingBuffer_Out(can2RxBuffer, Message, sizeof(CanRxMsg) * Number) / sizeof(CanRxMsg);
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  Get the size of the CAN transmit buffer used.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return Used the size of the transmit buffer.
  */
uint32_t CAN_GetUsedTransmitBufferSize(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return RingBuffer_Len(can1TxBuffer) / sizeof(CanTxMsg);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return RingBuffer_Len(can2TxBuffer) / sizeof(CanTxMsg);
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  Get the size of the CAN receive buffer used.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return Used the size of the receive buffer.
  */
uint32_t CAN_GetUsedReceiveBufferSize(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return RingBuffer_Len(can1RxBuffer) / sizeof(CanRxMsg);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return RingBuffer_Len(can2RxBuffer) / sizeof(CanRxMsg);
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  Get the size of the CAN transmit buffer unused.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return Unused the size of the transmit buffer.
  */
uint32_t CAN_GetUnusedTransmitBufferSize(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return RingBuffer_Avail(can1TxBuffer) / sizeof(CanTxMsg);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return RingBuffer_Avail(can2TxBuffer) / sizeof(CanTxMsg);
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  Get the size of the CAN receive buffer unused.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return Unused the size of the receive buffer.
  */
uint32_t CAN_GetUnusedReceiveBufferSize(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return RingBuffer_Avail(can1RxBuffer) / sizeof(CanRxMsg);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return RingBuffer_Avail(can2RxBuffer) / sizeof(CanRxMsg);
    }
  }
#endif /* STM32F10X_CL */
  
  return 0;
}

/**
  * @brief  Is the CAN transmit buffer empty?
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @retval true:      The transmit buffer is empty.
  * @retval false:     The transmit buffer is not empty.
  */
bool CAN_IsTransmitBufferEmpty(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return !(RingBuffer_Len(can1TxBuffer) / sizeof(CanTxMsg));
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return !(RingBuffer_Len(can2TxBuffer) / sizeof(CanTxMsg));
    }
  }
#endif /* STM32F10X_CL */
  
  return false;
}

/**
  * @brief  Is the CAN receive buffer empty?
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @retval true:      The receive buffer is empty.
  * @retval false:     The receive buffer is not empty.
  */
bool CAN_IsReceiveBufferEmpty(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return !(RingBuffer_Len(can1RxBuffer) / sizeof(CanRxMsg));
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return !(RingBuffer_Len(can2RxBuffer) / sizeof(CanRxMsg));
    }
  }
#endif /* STM32F10X_CL */
  
  return false;
}

/**
  * @brief  Is the CAN transmit buffer full?
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @retval true:      The transmit buffer is full.
  * @retval false:     The transmit buffer is not full.
  */
bool CAN_IsTransmitBufferFull(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return !(RingBuffer_Avail(can1TxBuffer) / sizeof(CanTxMsg));
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return !(RingBuffer_Avail(can2TxBuffer) / sizeof(CanTxMsg));
    }
  }
#endif /* STM32F10X_CL */
  
  return false;
}

/**
  * @brief  Is the CAN receive buffer full?
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @retval true:      The receive buffer is full.
  * @retval false:     The receive buffer is not full.
  */
bool CAN_IsReceiveBufferFull(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return !(RingBuffer_Avail(can1RxBuffer) / sizeof(CanRxMsg));
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return !(RingBuffer_Avail(can2RxBuffer) / sizeof(CanRxMsg));
    }
  }
#endif /* STM32F10X_CL */
  
  return false;
}

/**
  * @brief  Clear the CAN transmit buffer.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return None.
  */
void CAN_ClearTransmitBuffer(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      RingBuffer_Reset(can1TxBuffer);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      RingBuffer_Reset(can2TxBuffer);
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  Clear the CAN receive buffer.
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @return None.
  */
void CAN_ClearReceiveBuffer(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      RingBuffer_Reset(can1RxBuffer);
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      RingBuffer_Reset(can2RxBuffer);
    }
  }
#endif /* STM32F10X_CL */
}

/**
  * @brief  Is the CAN transmit a message?
  * @param  [in] CANx: Where x can be 1 or 2 to select the CAN peripheral.
  * @retval true:      Is transmit a message.
  * @retval false:     Not transmit a message.
  */
bool CAN_IsTransmitMessage(CAN_TypeDef *CANx)
{
  if(CANx == CAN1)
  {
    if(can1InitFlag == true)
    {
      return can1TransmitFlag;
    }
  }
  
#ifdef STM32F10X_CL
  if(CANx == CAN2)
  {
    if(can2InitFlag == true)
    {
      return can2TransmitFlag;
    }
  }
#endif /* STM32F10X_CL */
  
  return false;
}

/**
  * @brief  This function handles CAN1 TX Handler.
  * @param  None.
  * @return None.
  */
#ifdef STM32F10X_CL
void CAN1_TX_IRQHandler(void)
#else
void USB_HP_CAN1_TX_IRQHandler(void)
#endif /* STM32F10X_CL */
{
  if(CAN_GetITStatus(CAN1, CAN_IT_TME) != RESET)
  {
    CAN_ClearITPendingBit(CAN1, CAN_IT_TME);
    
    CanTxMsg canTxMsg = {0};
    uint8_t  number   = RingBuffer_Out(can1TxBuffer, &canTxMsg, sizeof(canTxMsg)) / sizeof(canTxMsg);
    
    if(number > 0)
    {
      CAN_Transmit(CAN1, &canTxMsg);
    }
    else
    {
      can1TransmitFlag = false;
      
      if(can1TransmitFinishCallback != 0)
      {
        can1TransmitFinishCallback();
      }
    }
  }
}

/**
  * @brief  This function handles CAN1 RX0 Handler.
  * @param  None.
  * @return None.
  */
#ifdef STM32F10X_CL
void CAN1_RX0_IRQHandler(void)
#else
void USB_LP_CAN1_RX0_IRQHandler(void)
#endif /* STM32F10X_CL */
{
  if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
  {
    CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
    
    CanRxMsg canRxMsg = {0};
    CAN_Receive(CAN1, CAN_FIFO0, &canRxMsg);
    
    if(RingBuffer_Avail(can1RxBuffer) / sizeof(CanRxMsg) > 0)
    {
      RingBuffer_In(can1RxBuffer, &canRxMsg, sizeof(canRxMsg));
    }
    
    if(can1ReceiveFinishCallback != 0)
    {
      can1ReceiveFinishCallback();
    }
  }
}

#ifdef STM32F10X_CL
/**
  * @brief  This function handles CAN2 TX Handler.
  * @param  None.
  * @return None.
  */
void CAN2_TX_IRQHandler(void)
{
  if(CAN_GetITStatus(CAN2, CAN_IT_TME) != RESET)
  {
    CAN_ClearITPendingBit(CAN2, CAN_IT_TME);
    
    CanTxMsg canTxMsg = {0};
    uint8_t  number   = RingBuffer_Out(can2TxBuffer, &canTxMsg, sizeof(canTxMsg)) / sizeof(canTxMsg);
    
    if(number > 0)
    {
      CAN_Transmit(CAN2, &canTxMsg);
    }
    else
    {
      can2TransmitFlag = false;
      
      if(can2TransmitFinishCallback != 0)
      {
        can2TransmitFinishCallback();
      }
    }
  }
}

/**
  * @brief  This function handles CAN2 RX0 Handler.
  * @param  None.
  * @return None.
  */
void CAN2_RX0_IRQHandler(void)
{
  if(CAN_GetITStatus(CAN2, CAN_IT_FMP0) != RESET)
  {
    CAN_ClearITPendingBit(CAN2, CAN_IT_FMP0);
    
    CanRxMsg canRxMsg = {0};
    CAN_Receive(CAN2, CAN_FIFO0, &canRxMsg);
    
    if(RingBuffer_Avail(can2RxBuffer) / sizeof(CanRxMsg) > 0)
    {
      RingBuffer_In(can2RxBuffer, &canRxMsg, sizeof(canRxMsg));
    }
    
    if(can2ReceiveFinishCallback != 0)
    {
      can2ReceiveFinishCallback();
    }
  }
}
#endif /* STM32F10X_CL */

main.h 文件

/**
  ******************************************************************************
  * @file    main.h
  * @author  XinLi
  * @version v1.0
  * @date    24-June-2018
  * @brief   Header file for main.c module.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Header includes -----------------------------------------------------------*/
#include "stm32f10x.h"

/* Macro definitions ---------------------------------------------------------*/
/* Type definitions ----------------------------------------------------------*/
/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
/* Function definitions ------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

main.c 文件

/**
  ******************************************************************************
  * @file    main.c
  * @author  XinLi
  * @version v1.0
  * @date    24-June-2018
  * @brief   Main program body.
  ******************************************************************************
  * @attention
  *
  * <h2><center>Copyright &copy; 2018 XinLi</center></h2>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  ******************************************************************************
  */

/* Header includes -----------------------------------------------------------*/
#include "main.h"
#include "CAN.h"

#ifdef _RTE_
#include "RTE_Components.h"
#endif

#ifdef RTE_CMSIS_RTOS2
#include "cmsis_os2.h"
#endif

/* Macro definitions ---------------------------------------------------------*/
/* Type definitions ----------------------------------------------------------*/
/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
static CanTxMsg canTxMsg = {0};
static CanRxMsg canRxMsg = {0};

/* Function declarations -----------------------------------------------------*/
static void SystemClock_Config(void);

/* Function definitions ------------------------------------------------------*/

/**
  * @brief  Main program.
  * @param  None.
  * @return None.
  */
int main(void)
{
  /* Configure the system clock to 72 MHz */
  SystemClock_Config();
  SystemCoreClockUpdate();

  /* Add your application code here */
  CAN_Configure(CAN1, CAN_WorkModeLoopBack, CAN_BaudRate250K, 0xAA55, 0x55AA);

#ifdef RTE_CMSIS_RTOS2
  /* Initialize CMSIS-RTOS2 */
  osKernelInitialize();

  /* Create thread functions that start executing, 
  Example: osThreadNew(app_main, NULL, NULL); */

  /* Start thread execution */
  osKernelStart();
#endif

  /* Infinite loop */
  while(1)
  {
    canTxMsg.StdId = 0xAA55;
    canTxMsg.ExtId = 0x55AA;
    canTxMsg.IDE   = CAN_ID_STD;
    canTxMsg.RTR   = CAN_RTR_DATA;
    canTxMsg.DLC   = 8;
    
    canTxMsg.Data[0]++;
    canTxMsg.Data[1]++;
    canTxMsg.Data[2]++;
    canTxMsg.Data[3]++;
    canTxMsg.Data[4]++;
    canTxMsg.Data[5]++;
    canTxMsg.Data[6]++;
    canTxMsg.Data[7]++;
    
    CAN_SetTransmitMessage(CAN1, &canTxMsg, 1);
    
    while(CAN_IsReceiveBufferEmpty(CAN1) == true);
    
    CAN_GetReceiveMessage(CAN1, &canRxMsg, 1);
  }
}

/**
  * @brief  System Clock Configuration.
  *         The system Clock is configured as follow : 
  *            System Clock source            = PLL (HSE)
  *            SYSCLK(Hz)                     = 72000000
  *            HCLK(Hz)                       = 72000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 2
  *            APB2 Prescaler                 = 1
  *            HSE Frequency(Hz)              = 8000000
  *            HSE PREDIV1                    = 1
  *            PLLMUL                         = 9
  *            Flash Latency(WS)              = 2
  * @param  None.
  * @return None.
  */
static void SystemClock_Config(void)
{
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration */
  /* RCC system reset */
  RCC_DeInit();
  
  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);
  
  /* Wait till HSE is ready */
  ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();
  
  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
    
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); 
    
    /* PCLK1 = HCLK / 2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* Configure PLLs */
#ifdef STM32F10X_CL
    /* PLL2 configuration: PLL2CLK = (HSE(8MHz) / 2) * 10 = 40MHz */
    RCC_PREDIV2Config(RCC_PREDIV2_Div2);
    RCC_PLL2Config(RCC_PLL2Mul_10);
    
    /* Enable PLL2 */
    RCC_PLL2Cmd(ENABLE);
    
    /* Wait till PLL2 is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET);
    
    /* PLL configuration: PLLCLK = (PLL2(40MHz) / 5) * 9 = 72MHz */
    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
#else
    /* PLLCLK = HSE(8MHz) * 9 = 72MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
#endif

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);
    
    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08);
  }
  else
  {
    /* Disable HSE */
    RCC_HSEConfig(RCC_HSE_OFF);
    
    /* Enable HSI */
    RCC_HSICmd(ENABLE);
    
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
    /* Flash 1 wait state */
    FLASH_SetLatency(FLASH_Latency_1);
    
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); 
    
    /* PCLK1 = HCLK */
    RCC_PCLK1Config(RCC_HCLK_Div1);
    
    /* Configure PLLs */
    /* PLLCLK = HSI(8MHz) / 2 * 9 = 36MHz */
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_9);
    
    /* Enable PLL */
    RCC_PLLCmd(ENABLE);
    
    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08);
  }
}

#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name.
  * @param  line: assert_param error line source number.
  * @return None.
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  
  /* Infinite loop */
  while(1)
  {
  }
}
#endif

 

3,注意

CAN 消息發送緩衝區和接收緩衝區的大小,可以根據應用的需求進行修改,緩衝區使用的是堆內存,需要根據緩衝區大小和應用程序中堆內存使用情況進行配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章