⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can.c

📁 Arm7
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -