📄 can.c
字号:
Drv_CAN_RxBuf[0].RxDBufLen = 0U; /* 缓冲区有效帧数 */
Drv_CAN_RxBuf[0].pRxDBuf = Global_CAN_RxDBuf; /* 缓冲区指针 */
for (i = 1; i < 18; i++)
{
Drv_CAN_RxBuf[i].RxDBufSize = Drv_CAN_RxDBufSize[i]; /* 缓冲区帧数大小 */
Drv_CAN_RxBuf[i].RxDBufLen = 0U; /* 缓冲区有效帧数 */
/* 缓冲区指针 */
pTT = (uint8*)Drv_CAN_RxBuf[i - 1].pRxDBuf;
Drv_CAN_RxBuf[i].pRxDBuf = (stcCANRxData*)(pTT + (Drv_CAN_RxDBufSize[i - 1]
* sizeof(stcCANRxData)));
}
/* 4个通用发送缓冲区设置 */
Drv_CAN_TxBuf[0].TxDBufSize = Drv_CAN_TxDBufSize[0];
Drv_CAN_TxBuf[0].TxDBufLen = 0U;
Drv_CAN_TxBuf[0].TxDBufPos = 0U;
Drv_CAN_TxBuf[0].pTxDBuf = (stcCANTxData*)(&Global_CAN_TxDBuf[0]);
for (i = 1; i < 4; i++)
{
Drv_CAN_TxBuf[i].TxDBufSize = Drv_CAN_TxDBufSize[i];
Drv_CAN_TxBuf[i].TxDBufLen = 0UL;
Drv_CAN_TxBuf[i].TxDBufPos = 0UL;
pTT = (uint8*)Drv_CAN_TxBuf[i - 1].pTxDBuf;
Drv_CAN_TxBuf[i].pTxDBuf = (stcCANTxData*)(pTT + (Drv_CAN_TxDBufSize[i - 1]
* sizeof(stcCANTxData)));
}
}
/************************************************************************************
功能:初始化CAN控制器,包括CAN硬件使能、模式、中断、波特率、出错报警界限、启动CAN
参数:CanNum -- CAN1、CAN2、CAN3或CAN4;
setting -- typedef struct CAN初始化参数结构
{
uint32 mod; CAN工作模式
uint32 ier; 中断使能
uint32 btr; 波特率
uint32 ewl; 出错值
}CAN_Setting;
本函数调用的函数:void CAN_HwEn(eCANNUM CanNum) 硬件使能CAN控制器
__inline void CAN_SoftRst(eCANNUM CanNum) 软件复位CAN控制器
__inline void CAN_SoftEn(eCANNUM CanNum) 软件使能CAN控制器
返回值:无
*************************************************************************************/
void CAN_Init(eCANNUM CanNum, CAN_Setting * setting)
{
uint32 tempCANMOD;
CAN_HwEn(CanNum); /* CAN控制器硬件使能 */
CAN_SoftRst(CanNum); /* CANMOD.RM = 1, CAN控制器复位,禁止CAN,允许向下列寄存器写入数据 */
/* 初始化CAN工作模式 */
tempCANMOD = setting->mod;
tempCANMOD |= 0x01U;
regCANMOD(CanNum) = tempCANMOD;
/* 初始化中断 */
regCANIER(CanNum) = setting->ier;
/* 初始化波特率 */
regCANBTR(CanNum) = setting->btr;
/* 初始化出错报警界限 */
regCANEWL(CanNum) = setting->ewl;
/* CANMOD.RM = 0,启动CAN */
CAN_SoftEn(CanNum);
}
/************************************************************************************
功能:将数据写到发送缓冲区并启动发送(将Buf数据区的内容写入Drv_CAN_TxBuf缓冲区)
参数:CanNum -- CAN1、CAN2、CAN3或CAN4;
Cmd -- typedef enum _send_cmd_ 发送命令
{
NOM_SEND_CMD = 0,
SIG_SEND_CMD = 1,
SLF_SEND_CMD = 2,
SRR_SEND_CMD = 3
}eSend_CMD;
Buf -- 待发送帧缓冲区首地址
nItem -- 待发送帧数
本函数调用的函数:uint32 CAN_WriteTxBuf(eCANNUM CanNum) 发送缓冲区数据
返回值:实际发送帧数
备注:while代码段有待进一步分析
*************************************************************************************/
uint32 CAN_Write(eCANNUM CanNum, eSend_CMD Cmd, stcCANTxData * Buf, uint32 nItem)
{
uint32 i = 0U;
uint32 writeItem = nItem;
/* 发送缓冲区有数据时等待写缓冲区 */
while (Drv_CAN_TxBuf[CanNum].TxDBufPos != Drv_CAN_TxBuf[CanNum].TxDBufLen)
{
i++;
if (i > 0x090000)
{
Drv_CAN_TxBuf[CanNum].TxDBufPos = 0U;
Drv_CAN_TxBuf[CanNum].TxDBufLen = 0U;
return 0U;
}
}
if (writeItem > Drv_CAN_TxBuf[CanNum].TxDBufSize)
{
writeItem = Drv_CAN_TxBuf[CanNum].TxDBufSize;
}
Drv_CAN_TxBuf[CanNum].TxDBufLen = writeItem;
Drv_CAN_TxBuf[CanNum].TxDBufPos = 0U;
/* 将数据写到发送缓冲区 */
if (writeItem != 0)
{
for (i = 0; i < writeItem; i++)
{
Drv_CAN_TxBuf[CanNum].pTxDBuf[i].TxID = Buf[i].TxID;
Drv_CAN_TxBuf[CanNum].pTxDBuf[i].TxDA = Buf[i].TxDA;
Drv_CAN_TxBuf[CanNum].pTxDBuf[i].TxDB = Buf[i].TxDB;
}
SendCMD[CanNum] = Cmd; /* 发送命令 */
CAN_WriteTxBuf(CanNum); /* 启动数据发送 */
}
return (writeItem);
}
/****************************************************************************************************
功能:向CAN发送缓冲区TxBUF写入发送数据并发送
参数:CanNum -- CAN1、CAN2、CAN3或CAN4
本函数调用的函数:__inline void Can_QuitSM(eCANNUM CanNum) CAN退出睡眠模式
调用本函数的函数:uint32 CAN_Write(eCANNUM CanNum, eSend_CMD Cmd, stcCANTxData * Buf, uint32 nItem)
__irq void CAN1_Tx_Exception(void)
__irq void CAN2_Tx_Exception(void)
__irq void CAN3_Tx_Exception(void)
__irq void CAN4_Tx_Exception(void)
返回值:0 -- 发送失败
1 -- 发送成功
备注:发送命令的含义不大理解
*****************************************************************************************************/
uint32 CAN_WriteTxBuf(eCANNUM CanNum)
{
uint32 tempCANSR = regCANSR(CanNum);
uint32 tempCANCMR = 0U;
/* 检查缓冲区的报文是否都已发送 */
if (Drv_CAN_TxBuf[CanNum].TxDBufPos >= Drv_CAN_TxBuf[CanNum].TxDBufLen)
{
Drv_CAN_TxBuf[CanNum].TxDBufLen = 0U;
Drv_CAN_TxBuf[CanNum].TxDBufPos = 0U;
return 0U;
}
if (0 != (tempCANSR & 0x04U)) /* 当CANSR.TBS1 =1(发送缓冲区已释放) 时,才允许向下列寄存器写入数据 */
{
/* TxBuf1中下一条将要发送帧信息的格式:8个数据字节、数据帧、11位标准ID */
regCANTFI1(CanNum) = 0x00080000U;
/* 发送帧,即将缓冲区数据写入发送数据寄存器 */
regCANTID1(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxID;
regCANTDA1(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDA;
regCANTDB1(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDB;
tempCANCMR |= 0x20U; /* CANCMR.STB1 = 1,选择发送Tx缓冲区1 */
}
else if (0 != (tempCANSR & 0x0400U)) /* 当CANSR.TBS2 = 1 时,才允许向下列寄存器写入数据 */
{
/* TxBuf2中下一条将要发送帧信息的格式:8个数据字节、数据帧、11位标准ID */
regCANTFI2(CanNum) = 0x00080000U;
/* 发送帧,即将缓冲区数据写入发送数据寄存器 */
regCANTID2(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxID;
regCANTDA2(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDA;
regCANTDB2(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDB;
tempCANCMR |= 0x40U; /* CANCMR.STB2 = 1,选择发送Tx缓冲区2 */
}
else if (0 != (tempCANSR & 0x040000U)) /* 当CANSR.TBS3 = 1 时,才允许向下列寄存器写入数据 */
{
/* TxBuf3中下一条将要发送帧信息的格式:8个数据字节、数据帧、11位标准ID */
regCANTFI3(CanNum) = 0x00080000U;
/* 发送帧,即将缓冲区数据写入发送数据寄存器 */
regCANTID3(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxID;
regCANTDA3(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDA;
regCANTDB3(CanNum) = Drv_CAN_TxBuf[CanNum].pTxDBuf[Drv_CAN_TxBuf[CanNum].TxDBufPos].TxDB;
tempCANCMR |= 0x80U; /* CANCMR.STB3 = 1,选择发送Tx缓冲区3 */
}
else
{
return 0U;
}
/* 发送命令选择 */
switch (SendCMD[CanNum])
{
case NOM_SEND_CMD: /* 正常发送:CANCMR.TR = 1 */
tempCANCMR |= 0x01U;
break;
case SIG_SEND_CMD: /* 单帧发送:(CANCMR.TR = 1) && (CANCMR.AT = 1) */
tempCANCMR |= 0x03U;
break;
case SLF_SEND_CMD: /* 自检测:(CANMOD.STM = 1) && (CANCMR.SRR = 1) */
case SRR_SEND_CMD: /* 只收不发:(CANMOD.STM = 1) && (CANCMR.SRR = 1) && (CANCMR.AT = 1) */
if ((regCANMOD(CanNum) & 0x04U) == 0) /* CANMOD.STM = 0,应答模式(发送的信息必须被应答才被认可)*/
{
regCANMOD(CanNum) |= 0x01U; /* CANMOD.RM = 1,CAN复位模式 */
regCANMOD(CanNum) |= 0x04U; /* CANMOD.STM = 1 自测模式 */
regCANMOD(CanNum) &= 0xbeU; /* CANMOD.RM = 0,CAN正常工作 */
}
tempCANCMR |= 0x10U; /* CANCMR.SRR = 1,自接收请求 */
if (SendCMD[CanNum] == 3) /* 即SRR_SEND_CMD */
{
tempCANCMR |= 0x02U; /* CANCMR.AT = 1,中止发送 */
}
break;
default: /* 默认为正常发送 */
tempCANCMR |= 0x01U; /* CANCMR.TR = 1,发送请求 */
break;
}
/* 当CANMOD.SM = 1(睡眠模式)时,则退出睡眠状态 */
if ((regCANMOD(CanNum) & 0x10U) != 0)
{
Can_QuitSM(CanNum);
}
(Drv_CAN_TxBuf[CanNum].TxDBufPos)++;
regCANCMR(CanNum) = tempCANCMR;
return 1U;
}
/*******************************************************************************************
功能:读取CAN接收到的数据(将Drv_CAN_RxBuf缓冲区的内容读取到Buf中)
参数:BufNum -- 共18个接收缓冲区:0, 1,…,17
Buf -- 应用程序接收缓冲区首地址
nItem -- 欲读取帧数,如果为零或大于缓冲区的帧数大小,则读取缓冲区内的所有帧
返回值:实际读取的帧数
********************************************************************************************/
uint32 CAN_Read(uint32 BufNum, stcCANRxData * Buf, uint32 nItem)
{
uint32 i = 0U;
uint32 nReadItem = nItem;
regVICIntEnClr |= (3U << 26); /* 关CAN1、CAN2接收中断 */
/* 如果读取的帧数为零或大于缓冲区的帧数大小,则读取缓冲区内的所有帧 */
if ((nReadItem == 0) || (Drv_CAN_RxBuf[BufNum].RxDBufSize < nReadItem))
{
nReadItem = Drv_CAN_RxBuf[BufNum].RxDBufSize;
}
/* 如果缓冲区有效帧数为零,则不读取数据 */
if (Drv_CAN_RxBuf[BufNum].RxDBufLen == 0)
{
nReadItem = 0U;
}
for (i = 0; i < nReadItem; i++)
{
/* 将Drv_CAN_RxBuf缓冲区的内容读取到Buf区中 */
Buf[i].RxID = (Drv_CAN_RxBuf[BufNum].pRxDBuf[i]).RxID;
Buf[i].RxDA = (Drv_CAN_RxBuf[BufNum].pRxDBuf[i]).RxDA;
Buf[i].RxDB = (Drv_CAN_RxBuf[BufNum].pRxDBuf[i]).RxDB;
(Drv_CAN_RxBuf[BufNum].pRxDBuf[i]).RxID = 0; /* 清除缓冲区已读帧的ID,以便接收新的数据 */
Drv_CAN_RxBuf[BufNum].RxDBufLen--;
}
regVICIntEnable |= (3U << 26); /* 开CAN1、CAN2接收中断 */
return nReadItem;
}
/************************************************************************************
功能:清除接收缓冲区中的标志符,以允许接收新的帧
参数:BufNum -- 共18个接收缓冲区:0, 1,…,17
lowerItem -- 接收缓冲区帧的下边界
upperItem -- 接收缓冲区帧的上边界
返回值:1 -- 接收缓冲区已被释放
0 -- 函数输入参数有误,操作失败
*************************************************************************************/
uint32 CAN_ClrRxBuf(uint32 BufNum, uint32 lowerItem, uint32 upperItem)
{
uint32 loop;
if ((upperItem < Drv_CAN_RxBuf[BufNum].RxDBufSize) && (upperItem >= lowerItem))
{
for (loop = lowerItem; loop <= upperItem; loop++)
{
Drv_CAN_RxBuf[BufNum].pRxDBuf[loop].RxID = 0x0U;
}
return 1U;
}
return 0U;
}
/************************************************************************************
功能:将CAN接收到的数据写入接收缓冲区Drv_CAN_RxBuf
参数:CanNum -- CAN1、CAN2、CAN3或CAN4
BufNum -- 接收缓冲区编号,共18个接收缓冲区:0, 1,…,17
FrameNum -- 帧号:0,1,…,7
调用本函数的函数:__irq void CAN1_Rx_Exception(void)
__irq void CAN2_Rx_Exception(void)
__irq void CAN3_Rx_Exception(void)
__irq void CAN4_Rx_Exception(void)
返回值:无
*************************************************************************************/
void CAN_WriteRcvBuf(eCANNUM CanNum, uint32 BufNum, uint32 FrameNum)
{
if ((Drv_CAN_RxBuf[BufNum].pRxDBuf[FrameNum]).RxID == 0)
{
(Drv_CAN_RxBuf[BufNum].pRxDBuf[FrameNum]).RxID = regCANRID(CanNum);
(Drv_CAN_RxBuf[BufNum].pRxDBuf[FrameNum]).RxDA = regCANRDA(CanNum);
(Drv_CAN_RxBuf[BufNum].pRxDBuf[FrameNum]).RxDB = regCANRDB(CanNum);
Drv_CAN_RxBuf[BufNum].RxDBufLen++;
}
}
/************************************************************************************
功能:硬件复位CAN控制器,使CAN模块掉电,用于省电处理
参数:CanNum -- CAN1、CAN2、CAN3或CAN4
返回值:无
*************************************************************************************/
__inline void CAN_HwRst(eCANNUM CanNum)
{
regPCONP &= ~(0x01U << (13 + CanNum));
}
/************************************************************************************
功能:硬件使能CAN控制器(包括将相应的管脚配置为CAN功能)
参数:CanNum -- CAN1、CAN2、CAN3或CAN4
调用本函数的函数:void CAN_Init(eCANNUM CanNum, CAN_Setting * setting) 初始化CAN
返回值:无
*************************************************************************************/
void CAN_HwEn(eCANNUM CanNum)
{
regPCONP |= (0x01U << (13 + CanNum)); /* 使能各CAN控制器 */
/* 管脚功能选择 */
switch(CanNum)
{
case CAN1: /* PINSEL1.19:18 = 01 */
regPINSEL1 &= ~((uint32)0x03 << 18);
regPINSEL1 |= ((uint32)0x01 << 18);
break;
#if CAN_MAX_NUM >= 2
case CAN2: /* PINSEL1.17:14 = 0101 */
regPINSEL1 &= ~((uint32)0x0F << 14);
regPINSEL1 |= ((uint32)0x05 << 14);
break;
#endif
#if CAN_MAX_NUM >= 3
case CAN3: /* PINSEL1.13:10 = 0110 */
regPINSEL1 &= ~((uint32)0x0F << 10);
regPINSEL1 |= ((uint32)0x06 << 10);
break;
#endif
#if CAN_MAX_NUM == 4
case CAN4: /* PINSEL0.27:24 = 1111 */
regPINSEL0 |= ((uint32)0x0F << 24);
break;
#endif
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -