C114通信网  |  通信人家园

技术
2009/3/4 13:21

基于dsPIC33FJ128MC506的CAN通信

电子产品世界  

系统硬件

利用TJA1054作为CAN收发器,dsPIC33FJ128MC506 CAN通讯要注意的是,在处理器和收发器之间要加光耦以隔离两者之间的电源。原理图如图1所示。

系统初始化

Microchip公司的dspPIC33FJ128MC506芯片中ECAN通信模块的初始化分为五个部分:系统工作时钟设置、ECAN接收和发射缓冲区的设置、ECAN波特率的设置、接收过滤寄存器和屏蔽寄存器的设置以及ECAN收发器TJA1054的启动。

图1 dsPIC33FJ128MC506 CAN通讯原理图

系统工作时钟设置

dsPIC33FJ128MC506可以选择多种外部和内部振荡器作为时钟源,并通过时钟控制寄存器OSCCON进行设置。对时钟的选择要在系统的配置存储区(0x800000-0xFFFFFF)进行,在程序中一般通过几句宏指令语句指定。

以下语句选择时钟并禁能看门狗,其他的功能请参看芯片说明书。

_FOSCSEL(FNOSC_PRIPLL); //选用带PLL的主振荡器

_FOSC(POSCMD_HS); // 主振荡器为HS型晶振

_FWDT(FWDTEN_OFF); // 看门狗禁能

下面的函数对系统时钟进行配置, 外部晶振为8MHz,系统工作时钟为40MHz。

void oscConfig(void)

{

CLKDIVbits.PLLPRE = 0; //外设时钟2分频为4M

PLLFBDbits.PLLDIV = 18; //20倍频,为80M

CLKDIVbits.PLLPOST = 0; //外设时钟2分频为40M

while(OSCCONbits.LOCK!=1){ }; //等待设置生效

}

ECAN接收和发射缓冲区的设置

DMA(直接存储器访问)方式是外设SFR与RAM间进行数据复制的非常高效的机制,dsPIC33FJ128MC506的ECAN模块支持DMA传输,共有8个DMA通道可供选择。在此我们选用0和2通道分别作为ECAN1的发射和接收。初始化语句如下:

DMA0通道初始化为ECAN1发射:

void dma0init(void)

{

DMACS0=0; //清DMA控制器状态位

DMA0CON=0x2020; //DMA为外设间接寻址模式,支持从DMA读,并写到外设

DMA0PAD=0x0442; //DMA0PAD下载为ECAN1发射寄存器的地址

DMA0CNT=0x0007; //传输计数寄存器为8

DMA0REQ=0x0046; //DMA外设REQ编号选择位

DMA0STA= __builtin_dmaoffset(ecan1msgBuf); //DMA起始地址位

DMA0CONbits.CHEN=1;

}

DMA2通道初始化为ECAN1接收:

void dma2init(void)

{

DMACS0=0; //清DMA控制器状态位

DMA2CON=0x0020; //DM为外设间接寻址模式,支持从DMA写,并读到外设

DMA2PAD=0x0440; //DMA0PAD下载为ECAN1接收寄存器的地址

DMA2CNT=0x0007; //传输计数寄存器为8

DMA2REQ=0x0022; //DMA外设REQ编号选择位

DMA2STA= __builtin_dmaoffset(&ecan1msgBuf[2][0]); //DMA起始地址位

DMA2CONbits.CHEN=1;

}

上面程序中的“DMA0STA= __builtin_dmaoffset(ecan1msgBuf);”和“ DMA2STA= __builtin_dmaoffset(&ecan1msgBuf[2][0]); ”分别指明了DMA的起始地址位为ecan1msgBuf和(&ecan1msgBuf[2][0],ecan1msgBuf是一个两维数组,在相关头文件中定义,其语句为:

ECAN1缓冲器的设置:

#define ECAN1_MSG_BUF_LENGTH 4 //长度为4个字

//缓冲区为二维数据

typedef unsigned int ECAN1MSGBUF [ECAN1_MSG_BUF_LENGTH][8];

//数组位于DMA空间

extern ECAN1MSGBUF ecan1msgBuf __attribute__((space(dma)));

波特率的设置

正确设置通信波特率必须配置以下几个参数:同步跳转宽度、波特率预分频比、相位段1和相位段2的长度、采样次数及传播时间段的长度。设置程序语句如下:

void ecan1ClkInit(void)

{

/*指定 CAN通信时钟利用系统的指令周期,在此为20MHz,即Fcan=20MHz*/

C1CTRL1bits.CANCKS = 1;

/*规定一个CAN位包含16个TQ,分配如下:*/

C1CFG1bits.SJW = 3; //同步段 = 1TQ

C1CFG2bits.SEG1PH=3; //相位传输段1 = 4TQ

C1CFG2bits.SEG2PHTS = 1; //相位传输段2长度可编程设定

C1CFG2bits.SEG2PH = 3; //相位传输段2 = 4TQ

C1CFG2bits.PRSEG = 6; //传播时间段 = 7TQ

C1CFG2bits.SAM = 0; //采样次数为1次

/*根据上面设置,算出波特率的分频比。这里要注意的是,因为C1CFG1bits.BRP只能填入整数,那么在系统时钟、通讯速率和时间份额三者之间要合理选择,否则通信不会成功。例如:如果系统时钟选用其内部FRC,标称值为7.37M,倍频后的系统时钟为36.85M,采用16个TQ为一个CAN位,假设CAN的通信速率为125K的话,那么根据公式BRP=Fcan/(2*16*125K)-1,计算得出的值为3.6,因为不能整除,所以永远不能得到125K的通信速率。 在此我们取40M的时钟,指令周期为20M,一个CAN位为16个TQ,经计算可得BRP的值为4。*/

C1CFG1bits.BRP =4;

}

接收过滤寄存器和屏蔽寄存器的设置

/* 下面的函数用来设置接收过滤器"n" ,各输入参数的意义分别为:

n-> 过滤器号,范围为[0-15]

identifier-> 合法的标识符

exide -> 是否扩展数据帧,"0" 表示为标准数据帧,"1"表示为扩展数据帧

bufPnt -> 过滤后的信息存放的缓冲区,范围为[0-15]

maskSel -> 关连的屏蔽寄存器[0-3] */

void ecan1WriteRxAcptFilter(int n, long identifier, unsigned int exide, unsigned int bufPnt, unsigned int maskSel)

{

/*定义局部变量*/

unsigned long sid10_0=0, eid15_0=0, eid17_16=0;

unsigned int *sidRegAddr,*bufPntRegAddr,*maskSelRegAddr, *fltEnRegAddr;

/*因为将要设置的特殊寄存器要与别的寄存器共用地址,所以需设置控制位WIN*/

C1CTRL1bits.WIN=1;

/* 根据输入的参数,计算出相应寄存器的地址,包括滤波器n的地址、缓冲指针寄存器地址、相关的屏蔽寄存器的地址及接收过滤使能寄存器的相关位*/

// 接过过滤寄存器的地址

sidRegAddr = (unsigned int *)(&C1RXF0SID + (n << 1));

//报文缓冲区地址

bufPntRegAddr = (unsigned int *)(&C1BUFPNT1 + ((n >> 2)*2) ) ;

//屏蔽寄存器地址

maskSelRegAddr = (unsigned int *)(&C1FMSKSEL1 + ((n >> 3)*2));

//过滤器使能地址

fltEnRegAddr = (unsigned int *)(&C1FEN1);

/* 将ID按规定分配到相关的寄存器中*/

if(exide==1) { //扩展帧的ID

eid15_0 = (identifier & 0xFFFF);

eid17_16= (identifier>>16) & 0x3;

sid10_0 = (identifier>>18) & 0x7FF;

*sidRegAddr=(sid10_0)<<5 + 0x8 + eid17_16;

*(sidRegAddr+2)= eid15_0;

}else{ //标准帧的ID

sid10_0 = (identifier & 0x7FF);

*sidRegAddr=(sid10_0)<<5;

*(sidRegAddr+2)=0;

}

*bufPntRegAddr = (bufPnt << (4*(n&3))); // 写缓冲指针寄存器CiBUFPNTn内容*maskSelRegAddr = (maskSel << (2*(n&7))); // 确定关连屏蔽寄存器

CiFMSKSELn *fltEnRegAddr = (0x1 << n); //使能第n个滤波器

C1CTRL1bits.WIN=0; //恢复寄存器地址选择位

}

/*

下面的函数用来写接收屏蔽寄存器"m" ,各输入参数的意义分别为:

m-> 屏蔽寄存器号[0-3]

identifier->屏蔽位

mide -> "0" 表示无论是标准帧还是扩展帧,屏蔽器都起作用

"1" 表示屏蔽器是否起作用要参照'exide' 位 */

void ecan1WriteRxAcptMask(int m, long identifier, unsigned int mide)

{

/*定义局部变量*/

unsigned long sid10_0=0, eid15_0=0, eid17_16=0;

unsigned int *maskRegAddr;

//因为将要设置的特殊寄存器要与别的寄存器共用地址,所以需设置控制位WIN

C1CTRL1bits.WIN=1;

/* 根据"m"计算出CiRXMmSID 寄存器的地址*/

maskRegAddr = (unsigned int *)(&C1RXM0SID + (m << 2));

/* 将屏敝ID写入到屏蔽寄存器中*/

if(mide==1) { //扩展帧格式

eid15_0 = (identifier & 0xFFFF);

eid17_16= (identifier>>16) & 0x3;

sid10_0 = (identifier>>18) & 0x7FF;

*maskRegAddr=(sid10_0)<<5 + 0x8 + eid17_16;

*(maskRegAddr+2)= eid15_0;

}else{ // 标准帧格式

sid10_0 = (identifier & 0x7FF);

*maskRegAddr=(sid10_0)<<5; *(maskRegAddr+2)=0;

}

C1CTRL1bits.WIN=0;

}

TJA1054的启动

TJA1054是广泛应用的低速容错CAN收发器,其工作启动要按照其说明进行,下面的函数将TJA1054初始化为工作状态。

void TJA1054Init (void)

{

 

给作者点赞
0 VS 0
写得不太好

免责声明:本文仅代表作者个人观点,与C114通信网无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

热门文章
    最新视频
    为您推荐

      C114简介 | 联系我们 | 网站地图 | 手机版

      Copyright©1999-2025 c114 All Rights Reserved | 沪ICP备12002291号

      C114 通信网 版权所有 举报电话:021-54451141