利用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