历史上的今天
今天是:2024年09月09日(星期一)
2018年09月09日 | 基于C8051F040单片机的CAN总线通信
2018-09-09 来源:eefocus
硬件部分
硬件部分电路结构如下:
CAN收发模块原本采用的是ATA6660高速CAN收发芯片,电路连接如下:
设计电路为:当单片机发送数据时,D18闪烁,并将数据传送给ATA6660芯片;当ATA6660芯片接受到总线上的数据时,D17闪烁,并将数据传送给单片机。
实际调试时,发现C8051F040单片机既没办法发送数据到总线上,也没办法从总线上接收到数据。
用示波器对电路检测发现,当单片机需要发送数据时,ATA6660芯片的TXD引脚上能检测到数据,且D18闪烁。示波器检测总线上的电压,没有变化。PC端显示总线上的数据为FE。当PC端给总线发送数据时,总线上能检测到电压的变化,而ATA6660芯片的RXD引脚电压为0。故怀疑为CAN收发部分硬件存在问题。
因此,将CAN收发模块换为直接购买的TJA1050CAN收发模块,电路如下图所示。通过测试,CAN模块工作正常。而单片机能够成功发送数据,接收数据失败。
对比前后两个电路可以发现,区别在于CAN收发芯片的RS引脚。ATA6660芯片的RS引脚悬空,而TJA1050芯片的RS引脚接地。
查阅ATA6660芯片数据手册,发现RS引脚的功能为Switch Standby Mode/Normal Mode。而Standy Mode的解释为:
故使用ATA6660模块时无法正常收发数据。而正确的电路应为:
软件部分
程序参考自童长飞编著的《C8051F系列单片机开发与C语言编程》例程12-1。
1.基本设置
int n;
//看门狗禁止
WDTCN = 0x07;
WDTCN = 0xDE;
WDTCN = 0xAD;
SFRPAGE = 0x0F;
//交叉开关使能,但没有进行外围设备配置
XBR0 = 0x00;
XBR1 = 0x00;
XBR2 = 0x40;
XBR3 = 0x00;
//管脚输出配置,P0口为开漏输出,其中P0.6接上拉电阻,P0为数字输入口
SFRPAGE = 0x0F;
P0MDOUT = 0x00;
P1MDIN = 0xFF;
//晶振配置
OSCXCN = 0x77;//选择外部晶振22.1MHz。
//系统时钟为外部时钟二分频:22.1 MHz / 2 = 11.05 MHz
for (n = 0; n < 255; n++);
while ((OSCXCN & 0x80) == 0);
CLKSEL |= 0x01;
2.CAN消息对象清零
void clear_msg_objects (void) //将所有消息清零
{
uchar i;
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF1CMDMSK;
CAN0DATL = 0xFF;
for (i=1;i<33;i++)
{
CAN0ADR = IF1CMDRQST;
CAN0DATL = i;
}
}
3.CAN发送初始化
void init_msg_object_TX (char MsgNum,uint id)
{
uint temp;
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF1CMDMSK; //指向IF1 Command Mask Registers
CAN0DAT = 0x00b3;
/* IF1 Command Mask Registers =0x00b3
WR/RD=1,Mask=0,Arb=1,Control=1,ClrIntPnd=0,TxRqst=0,DataA=1,DataB=1,一次发送8字节数据*/
CAN0ADR = IF1ARB1;
CAN0DAT = 0x0000;
/*IF1 Arbitration Registers1 =0x0000,即ID15-0=0*/
temp=id<<2;//标准id为ID28-ID18,所以要左移2位
temp&=0x1fff;
temp|=0xa000;
CAN0DAT = temp; //地址自增,指向IF1 Arbitration Registers2
/*IF1 Arbitration Registers2=101(id)00b
MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=1,为发送*/
CAN0DAT = 0x0088;
/*IF1 Message Control Registers=0x0088
NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=0,RmtEn=0,TxRqst=0
EoB=1,DLC3-0=1000,即数据长度为8*/
CAN0ADR = IF1CMDRQST;
CAN0DAT = MsgNum;
/*IF1 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
4.CAN接收初始化
void init_msg_object_RX (char MsgNum,uchar id)
{
uint temp;
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF2CMDMSK;
CAN0DAT = 0x00fb;
/* IF2 Command Mask Registers =0x00fb
WR/RD=1,Mask=1,Arb=1,Control=1,ClrIntPnd=1,TxRqst=0,DataA=1,DataB=1,一次接收8字节数据*/
CAN0ADR = IF2MSK1;
CAN0DAT = 0x0000;
CAN0DAT = 0x0000;
CAN0ADR = IF2ARB1;
CAN0DAT = 0x0000;
/*IF2 Arbitration Registers1 =0x0000,即ID15-0=0*/
temp=id<<2;//标准id为ID28-ID18,所以要左移2位
temp&=0x1fff;
temp|=0x8000;
CAN0DAT = temp;
/*IF2 Arbitration Registers2=100(id)00b
MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=0,为接收*/
CAN0DAT = 0x0488;
/*IF2 Message Control Registers=0x0488
NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=1,接收中断使能;RmtEn=0,TxRqst=0
EoB=1,DLC3-0=1000,即数据长度为8*/
CAN0ADR = IF2CMDRQST;
CAN0DATL = MsgNum;
/*IF2 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
5.CAN波特率设置
Calculation of the CAN bit timing :
System clock f_sys = 22.1184 MHz/2 = 11.0592 MHz.
System clock period t_sys = 1/f_sys = 90.422454 ns.
CAN time quantum tq = t_sys (at BRP = 0)
Desired bit rate is 1 MBit/s, desired bit time is 1000 ns.
Actual bit time = 11 tq = 996.65ns ~ 1000 ns
Actual bit rate is 1.005381818 MBit/s = Desired bit rate+0.5381%
CAN bus length = 10 m, with 5 ns/m signal delay time.
Propagation delay time : 2*(transceiver loop delay + bus line delay) = 400 ns
(maximum loop delay between CAN nodes)
Prop_Seg = 5 tq = 452 ns ( >= 400 ns).
Sync_Seg = 1 tq
Phase_seg1 + Phase_Seg2 = (11-6) tq = 5 tq
Phase_seg1 <= Phase_Seg2, => Phase_seg1 = 2 tq and Phase_Seg2 = 3 tq
SJW = (min(Phase_Seg1, 4) tq = 2 tq
TSEG1 = (Prop_Seg + Phase_Seg1 - 1) = 6
TSEG2 = (Phase_Seg2 - 1) = 2
SJW_p = (SJW - 1) = 1
Bit Timing Register = BRP + SJW_p*0x0040 = TSEG1*0x0100 + TSEG2*0x1000 = 2640
Clock tolerance df :
A: df < min(Phase_Seg1, Phase_Seg2) / (2 * (13*bit_time - Phase_Seg2))
B: df < SJW / (20 * bit_time)
A: df < 2/(2*(13*11-3)) = 1/(141-3) = 1/138 = 0.7246%
B: df < 2/(20*11) = 1/110 = 0.9091%
Actual clock tolerance is 0.7246% - 0.5381% = 0.1865% (no problem for quartz)
SFRPAGE = CAN0_PAGE;
CAN0CN=0X41;
CAN0ADR=BITREG;
CAN0DAT=0x2640;//调波特率
6.发送函数
void transmit (char MsgNum)
{ uchar num;
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF1CMDMSK;
CAN0DAT = 0x0087;
/* IF1 Command Mask Registers =0x0087
WR/RD=1,Mask=0,Arb=0,Control=0,ClrIntPnd=0,TxRqst=1,DataA=1,DataB=1,一次发送8字节数据*/
CAN0ADR = IF1DATA1;
/*将8字节数据写入IF1*/
for(num=0;num<4;num++)
{
CAN0DATH=sdata[2*num+1];
CAN0DATL=sdata[2*num];
}
CAN0ADR = IF1CMDRQST;
CAN0DATL = MsgNum; //将以上配置写入MsgNum号CAN消息
}
7.接收函数
void receive_data (uchar MsgNum)
{
uchar i;
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF2CMDMSK;
CAN0DATL = 0x0f;
/* IF1 Command Mask Registers =0xxx0f
WR/RD=0,Mask=0,Arb=0,Control=0,ClrIntPnd=1,NewDat=1,DataA=1,DataB=1,一次发送8字节数据*/
CAN0ADR = IF2CMDRQST;
CAN0DATL = MsgNum; //指向MsgNum号消息
CAN0ADR = IF2DATA1;
for(i=0;i<4;i++)
rdata[i].tempval=CAN0DAT;//接收数据
isnewdata=1;
}
最后现象:单片机发送成功,PC端能成功接收发送的数据。而单片机接收CAN总线数据时异常。TJA1050芯片的RXD引脚能检测到电压变化,而单片机Status Register寄存器中RxOk位为‘1’,但没有产生接收中断,接收消息对象中的数据也未改变。
其中0x02为发送消息对象,0x04为接收消息对象。
CAN0STA为Status Register寄存器中低8位。RxOk为‘1’。
将单片机设置为测试模式,CAN Control Register寄存器中Test位置1。使用回路静音模式时,将CAN Test Register寄存器LBack和Silent同时置1,使TX与RX自身形成回路,单片机自发自收。结果为单片机接收不到自己发送的数据。
使用测试模式中的基本模式时,将CAN Test Register寄存器Basic位置1。此模式下,控制器不使用消息内存,即控制器不使用32个消息对象,而是将IF1寄存器作为发送缓存区,将IF2寄存器作为接收缓存区。此模式下,单片机发送数据正常,接收数据时,IF2寄存器缓存区接收到的数据不正确。
上一篇:单片机软件定时器的使用方法
史海拾趣
|
请教一下这个电路的U4A是什么类型的电路呢,怎么分析它呢,VSR/VAR是用电阻分压得到的一个稳定电压,在这起什么作用呢,还有他的输出为什么要接一个R24与C3的RC滤波呢,再接到比较器呢? 还有就是U4C是由单片机控制的上半周锯齿波发生器,这个我明 ...… 查看全部问答> |
|
我最近想实现s3c2440的USB device,哪位高手有经验,帮帮忙! 我最近想实现s3c2440的USB device,不知道有没有高手实现过,给点帮助,谢谢了,不是在Linux下,不带操作系统的。… 查看全部问答> |
|
Bios密码跟登陆密码不是一个,也就是说现在还是能正常使用。但还是挺闹心的,大家帮帮忙想想办法啊! 拿到厂里去的方法就不要说了,这个我也知道,我希望是一个我自己能解决的办法!先谢谢大家了! 我是新手,分不多,大家体谅啊!!… 查看全部问答> |
|
在ce6.0 nleddrvr.dll是如何生成的呢?在$CEROOT\\PUBLIC\\COMMON\\OAK\\DRIVERS\\NLEDDRVR目录生成的是nleddrvr_lib.lib。 SYSGEN_NLED = 1,SOURCE文件中 WINCETARGETFILES=dummy 就生成了?过程是怎样的呢?… 查看全部问答> |
|
在多媒体、通信等计算复杂度高的应用中,为了满足制造费用、功耗、性能以及实时性等诸多**条件的要求,嵌入式系统程序往往需要特殊设计。这使得设计师在设计面向特定应用的嵌入式软件时,需要有一套切实可行的编程准则。而在实际程序设计中,工程师 ...… 查看全部问答> |
|
我想用DAM做USRAT1 发送,在发送下一个数据包之前,首先应该判断上一个数据包是否发送完毕。或者一个DMA通道分时复用IIC和USART通信,需要对上次的传输是否完成进行判断。使用了下面的判断语句:while (DMA_GetFlagStatus(DMA1_FLAG ...… 查看全部问答> |
|
地址宽度21位,是20-0?显示是21-0这个地方有没有问题,以前版本是地址宽度22,才是21~0。 [ 本帖最后由 tianma123 于 2012-4-27 11:20 编辑 ]… 查看全部问答> |




