CAN外设初始化(库函数),IO口设置为非开漏上拉模式
/************************************************************************************************
函数名:void CAN_config(void)
函数功能:CAN初始化
参数:无
返回值:无
*************************************************************************************************/
void CAN_config(void)
{
PINSEL_CFG_Type PinCfg;
/*-------------------------------------
* CAN1: select P0.0 as RD1. P0.1 as TD1
* 波特率125000
---------------------------------------*/
PinCfg.Portnum = 0;//GPIO0端口
PinCfg.Pinnum = 0;//GPIO0_0
PinCfg.Funcnum = 1;//设置GPIO管脚功能为CAN功能
PinCfg.OpenDrain = 0;//非开漏模式
PinCfg.Pinmode = 0; //上拉
PINSEL_ConfigPin(&PinCfg);
PinCfg.Pinnum = 1;//GPIO0_1
PINSEL_ConfigPin(&PinCfg);//初始化管脚配置结构体
CAN_Init(LPC_CAN1, 125000);//初始化CAN1 波特率125K
CAN_IRQCmd(LPC_CAN1, CANINT_RIE, ENABLE);//接收中断使能
NVIC_EnableIRQ(CAN_IRQn);//使能中断
CAN_SetAFMode(LPC_CANAF,CAN_AccBP);//验收文件旁路模式
CAN_InitMessage();//初始化发送和接收缓冲区
CAN_SendMsg(LPC_CAN1, &TXMsg);//发送数据
}
其中
CAN_InitMessage();//初始化发送和接收缓冲区
/************************************************************************************************
函数名:void CAN_InitMessage
函数功能:接收和发送缓冲区初始化
参数:无
返回值:无
*************************************************************************************************/
void CAN_InitMessage(void)
{
TXMsg.format = EXT_ID_FORMAT;//扩展帧数据
TXMsg.id = 0x00001234;//id号
TXMsg.len = 8;//数据长度
TXMsg.type = DATA_FRAME;//数据帧
TXMsg.dataA[0] = TXMsg.dataA[1] = TXMsg.dataA[2] = TXMsg.dataA[3] = 0x00000011;
TXMsg.dataB[0] = TXMsg.dataB[1] = TXMsg.dataB[2] = TXMsg.dataB[3] = 0x00000000;
RXMsg.format = 0x00;
RXMsg.id = 0x00;
RXMsg.len = 0x00;
RXMsg.type = 0x00;
RXMsg.dataA[0] = RXMsg.dataA[1] = RXMsg.dataA[2] = RXMsg.dataA[3] = 0x00000000;
RXMsg.dataB[0] = RXMsg.dataB[1] = RXMsg.dataB[2] = RXMsg.dataB[3] = 0x00000000;
}
数据帧是扩展帧还是正常帧是由发送数据结构体定义来决定的
扩展帧的帧ID长度是29位,帧ID的范围是0000 0000-1FFF FFFF。CANopen帧ID最多是11位的,因此是标准帧;可以简单认为CAN标准帧和扩展帧只是在ID的长度上不一样,以能扩展更多的CAN节点,更好地支持上层协议。
解析收到的can消息,首先要使能接收中断。
/*----------------- INTERRUPT SERVICE ROUTINES --------------------------*/
/*********************************************************************//**
* @brief CAN_IRQ Handler, control receive message operation
* param[in] none
* @return none
**********************************************************************/
void CAN_IRQHandler()
{
uint8_t IntStatus;
// uint32_t data1;
/* get interrupt status
* Note that: Interrupt register CANICR will be reset after read.
* So function "CAN_IntGetStatus" should be call only one time
*/
IntStatus = CAN_IntGetStatus(LPC_CAN1);
//check receive interrupt
if((IntStatus>>0)&0x01)
{
CAN_ReceiveMsg(LPC_CAN1,&RXMsg);
CANRcvMsgParse(&RXMsg);
}
}
CAN_ReceiveMsg(LPC_CAN1,&RXMsg);
其中这个语句是库函数中将接受寄存器的数据放入,用户自定义的缓存中。
CANRcvMsgParse(&RXMsg);
/*******************************************************************************************************************************
* 函数介绍:CANRcvMsgParse
* 参数:无
* 返回值:无
* 备注:解析CAN接收数据
*******************************************************************************************************************************/
void CANRcvMsgParse(CAN_MSG_Type *CAN_Msg)
{
uint8 Index = 0;
uint8 i = 0;
// uint8 Buf[16] = {0};
uint8 Buf[8] = {0}; //两个字节
if(CAN_Msg->format != STD_ID_FORMAT)
{
return;
}
if(CAN_Msg->id == SWO_STA_ID+BrdAddr) // 指示灯状态控制
{
for(i = 0;i < 4;i++)
{
Buf[Index++] = CAN_Msg->dataA[i];
}
for(i = 0;i < 4;i++)
{
Buf[Index++] = CAN_Msg->dataB[i];
}
if(BrdAddr==7)
{
targetDistance=(uint16_t)Buf[1]<<8|Buf[2];//数码管显示
BrdValues.Out =Buf[0];
}
else
{
BrdValues.Out =Buf[0];
}
printf("\r\n%#08X",BrdValues.Out);
CANCommTimer.Cnt = 0;
CanStatus = 1;
}
}
自定义的一个can解析函数,将接收缓存的数据放入变量中。至此一个can的接收处理流程完成。
发送
void TaskExBoradsAd2(void)
{
uint8 TxMsg[8] = {0};
if(BrdAddr!=7)
{
TxMsg[0] = BrdValues.ADValue[4] / 256;
TxMsg[1] = BrdValues.ADValue[4] % 256;
TxMsg[2] = BrdValues.ADValue[5] / 256;
TxMsg[3] = BrdValues.ADValue[5] % 256;
CANSendMsg(ADI2_STA_ID+BrdAddr,TxMsg);
}
}
/*******************************************************************************************************************************
* 函数介绍:CANRcvMsgParse
* 参数:uint16 Id:帧ID
* uint8 *Buf:数据变量的地址
* 返回值:无
* 备注:解析CAN接收数据
*******************************************************************************************************************************/
void CANSendMsg(uint16 Id,uint8 *Buf)
{
CAN_MSG_Type Msg;
Msg.format = STD_ID_FORMAT;//TXMsg.format = EXT_ID_FORMAT;
Msg.id = Id;
Msg.len = 8;
Msg.type = DATA_FRAME;
Msg.dataA[0] = Buf[0];
Msg.dataA[1] = Buf[1];
Msg.dataA[2] = Buf[2];
Msg.dataA[3] = Buf[3];
Msg.dataB[0] = Buf[4];
Msg.dataB[1] = Buf[5];
Msg.dataB[2] = Buf[6];
Msg.dataB[3] = Buf[7];
if(CAN_SendMsg(LPC_CAN1, &Msg) != SUCCESS)
{
CAN_SendMsg(LPC_CAN1, &Msg);
}
}
目前没有用到以下
- CAN过滤器
void CAN_setup (uint32_t ctrl) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
if (ctrl == 1) {
LPC_SC->PCONP |= (1 << 13); /* Enable power to CAN1 block */
LPC_PINCON->PINSEL0 |= (1 << 0); /* Pin P0.0 used as RD1 (CAN1) */
LPC_PINCON->PINSEL0 |= (1 << 2); /* Pin P0.1 used as TD1 (CAN1) */
NVIC_EnableIRQ(CAN_IRQn); /* Enable CAN interrupt */
} else {
LPC_SC->PCONP |= (1 << 14); /* Enable power to CAN2 block */
LPC_PINCON->PINSEL0 |= (1 << 9); /* Pin P0.4 used as RD2 (CAN2) */
LPC_PINCON->PINSEL0 |= (1 << 11); /* Pin P0.5 used as TD2 (CAN2) */
NVIC_EnableIRQ(CAN_IRQn); /* Enable CAN interrupt */
}
LPC_CANAF->AFMR = 2; /* By default filter is not used 默认不使用过滤器*/
pCAN->MOD = 1; /* Enter reset mode 进入复位模式,禁能 CAN 操作,可写的寄存器可以写入,终止当前报文的发送/接收*/
pCAN->IER = 0; /* Disable all interrupts */
pCAN->GSR = 0; /* Clear status register ,*/
CAN_cfgBaudrate(ctrl, 500000); /* Set bit timing 波特率设定/
pCAN->IER = 0x0003; /* Enable Tx and Rx interrupt */
}
LPC_SC->PCONP |= (1 << 13); 这句语句的作用是单片机外设使能,直接控制电源供给,类似stm32的RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
void CAN_start (uint32_t ctrl) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
pCAN->MOD = 0; /* Enter normal operating mode */
}