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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
#ifndef __RINGBUFFER_H
#define __RINGBUFFER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Header includes -----------------------------------------------------------*/
#include
#include
#include
/* 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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
/* Header includes -----------------------------------------------------------*/
#include "RingBuffer.h"
#include
/* 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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
#ifndef __CAN_H
#define __CAN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Header includes -----------------------------------------------------------*/
#include "stm32f10x.h"
#include
/* 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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
/* 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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
#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
*
* Copyright © 2018 XinLi
*
* 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 .
*
******************************************************************************
*/
/* 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 消息发送缓冲区和接收缓冲区的大小,可以根据应用的需求进行修改,缓冲区使用的是堆内存,需要根据缓冲区大小和应用程序中堆内存使用情况进行配置。