收藏 分享(赏)

如何一步一步建立can通讯.doc

上传人:cjc2202537 文档编号:208491 上传时间:2018-03-24 格式:DOC 页数:11 大小:102KB
下载 相关 举报
如何一步一步建立can通讯.doc_第1页
第1页 / 共11页
如何一步一步建立can通讯.doc_第2页
第2页 / 共11页
如何一步一步建立can通讯.doc_第3页
第3页 / 共11页
如何一步一步建立can通讯.doc_第4页
第4页 / 共11页
如何一步一步建立can通讯.doc_第5页
第5页 / 共11页
点击查看更多>>
资源描述

1、1CAN 通讯的优点在此就不多说了,10 公里,5Kb/s 的速度是能保证的。 第一步:硬件环境的建立。 这里采用的是 SJA1000 作为总线控制器,CTM8251 模块作为总线驱动器。MCU 采用的是 MEGA16:利用 I/O 口模拟数据总线,当然也可以使用有总线的 MCU:MCS-51,MEGA8515 等。 原理图如下: 第二步:SJA1000 的控制 首先阅读下 SJA1000 的手册,基本了解下 SJA1000 的结构,主要是寄存器方面的。还要了解下 CAN 总线方面的东西:BasicCAN ,Peli CAN,远程帧,数据帧等等 SJA1000 工作之前需要配置一下,才能正常工

2、作,没有经过配置的 SJA1000 回拉坏总线的:组成网络的时候,如果其中有的 SJA1000 没有正确配置,这个设备会干扰总线,使其它设备的数据发送不出去。 怎么才能控制 SJA1000 呢,请看下面的 SJA1000 读写的时序图: 2写的时序 根据时序要求,可以利用 I/O 口模拟总线了: /*读 SJA1000*/ uint Read_SJA1000(uint address) uchar data; 3asm(“nop“); ALE_off; WR_on; RD_on; CAN_cs_on; DDRA=0xff; /数据口为输出 PORTA=address; /输出数据的地址 asm

3、(“nop“);/delay5us(1); ALE_on; asm(“nop“);/delay5us(1); /DDRA=0xff; /数据口为输出 PORTA=address; /输出数据的地址 /再次输出地址,确保一致。 asm(“nop“);/delay5us(1); ALE_off; /delay5us(1); CAN_cs_off; RD_off; asm(“nop“);/delay5us(2); asm(“nop“); DDRA=0x00; /数据口为输入 PORTA=0xff; /上拉 asm(“nop“); data=PINA; /获得数据 asm(“nop“);/delay5

4、us(1); RD_on; CAN_cs_on; asm(“nop“);/delay5us(2); /dog(); return data; /*写 SJA10000*/ void Write_SJA1000(uint address,uint data) asm(“nop“); /uint temp1,temp2; DDRA=0xff; /数据口为输出 PORTA=address; /输出数据的地址 CAN_cs_on; ALE_off; WR_on; RD_on; asm(“nop“);/delay5us(1); ALE_on; asm(“nop“);/delay5us(1); /DDRA

5、=0xff; /数据口为输出 4PORTA=address; /输出数据的地址 再次输出地址,确保数据准确 asm(“nop“);/delay5us(1); ALE_off; /delay5us(1); CAN_cs_off; WR_off; asm(“nop“);/delay5us(1); asm(“nop“); /DDRA=0xff; PORTA=data; /输出数据 asm(“nop“);/delay5us(2); WR_on; PORTA=data; /再次输出数据,取保一致 CAN_cs_on; asm(“nop“);/delay5us(2); asm(“nop“); /dog()

6、; 现在可以读写 SJA1000 了。 配置 SJA1000 需要使 SJA1000 进入复位模式,然后对一些寄存器写入数据。在这里,CAN 使用 Pelican 模式,速率为 5K,双滤波工作, /*CAN 复位初始化*/ void CAN_Init(void) uchar i_temp=0,j_temp=0; CLI(); /Read_SJA1000(CAN_IR); /读中断寄存器,清除中断位 Write_SJA1000(CAN_MOD,0x01); while(!(Read_SJA1000(CAN_MOD) dog(); Write_SJA1000(CAN_CDR,0xc8); /配置

7、时钟分频寄存器-Pelican,CBP=1 , /关闭 TX1 中断与时钟输出 Write_SJA1000(CAN_AMR0,0xff); /配置验收屏蔽 AMR0=0FFH Write_SJA1000(CAN_AMR1,0x00); /配置验收屏蔽 AMR1=000H Write_SJA1000(CAN_AMR2,0xff); /配置验收屏蔽 AMR2=0FFH Write_SJA1000(CAN_AMR3,0x00); /配置验收屏蔽 AMR3=000H Write_SJA1000(CAN_ACR1,0x00); /配置验收代码 ACR1=0:广播 Write_SJA1000(CAN_AC

8、R3,addr); /配置验收代码 ACR3=地址 Write_SJA1000(CAN_BTR0,0x7f); /配置总线定时-5kbps Write_SJA1000(CAN_BTR1,0xff); 5Write_SJA1000(CAN_OCR,0x1a); /配置输出控制 Write_SJA1000(CAN_EWLR,0xff); /配置错误报警限制为 255 do Write_SJA1000(CAN_MOD,0x00); /进入工作模式双滤波 dog(); while(Read_SJA1000(CAN_MOD) / 确认复位标志是否被删除 Write_SJA1000(CAN_TXB+4,I

9、D3); /配置发送缓冲区的 ID3- Write_SJA1000(CAN_IER,0x07); /配置 SJA10000 中断- 错误报警/ 发送/接收中断 SEI(); 在这之前,需要获取设备的地址,就是读取拨码开关各个脚的电平。需要注意的是,SJA1000 使用的是双滤波模式,响应地址有:广播的:0x00,还有自己的地址:0x*。为什么要这么做呢,一个系统中,主机的地址一般是 0X00,从机地址从 0X01 开始,这里面如果有两个从机的地址一样,就很可能产生一些混乱。从机一旦多了起来,查找地址相同的设备就有些麻烦了。 在程序的初始化的时候,进行 SJA1000 的配置。 第三部:工作程序

10、 接下来,做的工作就是 CAN 试发送,别小看这个试发送,这可是解决地址重复的问题的哦,还能检测 CAN 网络是否正常。 /*CAN 第一次发送 通讯地址测试 2e*/ void CAN_first_send(void) /uchar add_temp=0; uchar a_temp=0; uchar SR_temp; asm(“nop“); /延时 NET_LED_on; /打开网络灯 do a_temp=Read_SJA1000(CAN_SR);/读 CAN_SR,直到 SR.2=1:CPU 可以发送数据 dog(); while(!(a_temp /关 CAN 中断,即总中断 Write

11、_SJA1000(CAN_TXB+0,0xc0); /发送远程帧 0xc0 Write_SJA1000(CAN_TXB+1,0x00); /发送转接器地址 Write_SJA1000(CAN_TXB+2,addr); /发送传感器地址 Write_SJA1000(CAN_TXB+3,0x2e); /发送命令码 0x2e Write_SJA1000(CAN_TXB+4,ID3); /发送 ID3 Write_SJA1000(CAN_CMR,0x01); /启动发送, /网络故障错误在中断中处理,短接 H、L ,按复位,先亮绿灯,后黄灯亮 asm(“nop“); 6/SEI(); SJA1000

12、的中断引脚接到 MEGA16 的 INT1 上,需要在程序初始化的时候,配置一些INT1,使 MCU 能响应 SJA1000 的中断。 数据发送前,点亮网络指示灯,什么时候熄灭它呢,在发送中断中熄灭它。 下面看看 MCU 对 SJA1000 中断的一些处理:在这里只处理:接收中断、发送中断、总线关闭中断。 #pragma interrupt_handler can_int:3 void can_int(void) asm(“nop“); CAN_IR_temp=Read_SJA1000(CAN_IR); /读取中断寄存器 if(CAN_IR_temp if(RxBuffer0=0x80) /地

13、址测试数据帧 reload(); /数据帧中有和自己相同的地址 if(RxBuffer0=0xc0) / 远程帧则释放接收缓冲区 type=RxBuffer3; /读命令码 /处理命令码 if(type=0x30) if(type=0x34) CAN_now_value_send();type=0; /传瞬时值数据 if (type=0x27) reload(); type=0;/装置复位 if(type=0x2e) active();type=0; /通讯地址测试 Write_SJA1000(CAN_CMR,0x04); /释放接收缓冲区 if(CAN_IR_temp /关闭网络灯 ERR_

14、LED_off; /关闭故障灯 CANBE_JSQ=0; /复位总线关闭计数器 7asm(“nop“); if(CAN_IR_temp if(CAN_SR_temp /关闭次数加 1 if(CANBE_JSQ=CANBE_C) /总线关闭次数到达设定次数 NET_LED_off; /关闭网络灯 ERR_LED_on; /打开故障灯 CANBE_JSQ=0; /复位总线关闭计数器 do Write_SJA1000(CAN_MOD,0x00); /重新进入工作模式 while(Read_SJA1000(CAN_MOD)/等待进入工作模式 Write_SJA1000(CAN_CMR,0x01); /

15、启动 CAN 重新发送 CANBE_JSQ=CANBE_C; /防止 CANBE_JSQ 溢出 asm(“nop“); 中断程序中,对命令码等于 0x2e 的处理程序是:active(); active()程序如下: /*通讯地址测试 2EH*/ void active(void) 8uchar temp1,temp2; asm(“nop“); /延时 NET_LED_on; /打开网络灯 CLI(); /关 CAN 中断,即总中断 do temp1=Read_SJA1000(CAN_SR);/读 CAN_SR,直到 SR.2=1:CPU 可以发送数据 dog(); while(!(temp1

16、 Write_SJA1000(CAN_TXB+0,0x80); /发送数据帧 0x80 temp2=Read_SJA1000(CAN_RXB+1); Write_SJA1000(CAN_TXB+1,temp2); /发送转接器地址 Write_SJA1000(CAN_TXB+2,addr); /发送传感器地址 Write_SJA1000(CAN_TXB+3,0x2e); /发送命令码 0x2e Write_SJA1000(CAN_TXB+4,ID3); /发送 ID3 Write_SJA1000(CAN_CMR,0x01); /启动发送 SEI(); /开中断 asm(“nop“); 大家仔细

17、看看 active()程序的内容,发送了一个没有数据的数据帧:0X80,再回过头看看中断处理函数,里面有这段程序, if(RxBuffer0=0x80) /地址测试数据帧 reload(); /数据帧中有和自己相同的地址 reload(); 程序很简单,就是停止喂狗,等待复位。复位之后呢,它会进行试发送,哈哈,接下来的两个地址相同的设备就“打架”起来了,现象就是一个设备不断复位,一个设备通讯灯不断闪烁。怎么样,很容易就判断出哪两个地址重复了。 命令码等于 0x27 时,设备复位,一般是主机发送这个远程帧。 0x34 时,发送数据: /*瞬时值发送 34H*/ void CAN_now_valu

18、e_send(void) /uchar a_temp=0; uchar c_temp=0; js_now_send_value(); /计算需要发送的瞬间数值 asm(“nop“); /延时 NET_LED_on; /打开网络灯 do b_temp=Read_SJA1000(CAN_SR); /读 CAN_SR,直到 SR.2=1:CPU 可以发送数据 dog(); 9 while(!(b_temp /关 CAN 中断,即总中断 Write_SJA1000(CAN_TXB+0,0x84); /发送数据帧 0x84 Write_SJA1000(CAN_TXB+1,RxBuffer1); /发送转

19、接器地址 Write_SJA1000(CAN_TXB+2,addr); /发送传感器地址 Write_SJA1000(CAN_TXB+3,0x34); /发送命令码 0x34 Write_SJA1000(CAN_TXB+4,ID3); /发送 ID3 Write_SJA1000(CAN_TXB+5,CBDJ_Send_L); / Write_SJA1000(CAN_TXB+6,CBDJ_Send_H); / Write_SJA1000(CAN_TXB+7,GD_Send_L); / Write_SJA1000(CAN_TXB+8,GD_Send_H); / Write_SJA1000(CAN_

20、CMR,0x01); /启动发送 SEI(); /开中断 asm(“nop“); 发送了一个数据帧,这个数据帧有四字节的数据。 CAN 的数据帧最多支持有 8 个字节的数据帧,如果数据较多,可以分为多个数据帧,在命令码里面区分这些数据帧。 第四步:建立自己的 CAN 通讯网络。 主机可以是一台有 CAN 接口的计算机,一般在计算机上装一个 CAN 接口卡,有 ISA 接口的,比如 PCL-841;PCI 接口的。CAN 卡的销售商都会提供驱动,依靠驱动里面的函数,来控制 CAN 卡,此项不是专长,不好多说,反正就是这个思路。 好了,昨天从南京回来的路上,就考虑发个 CAN 的东西。咱们这个论坛,目前还没有多少关于 CAN 的帖子,意在抛砖引玉本坛高手很多,尤其是有很多潜水的高高手 - 程序中的一些 DEFINE /*引脚信号定义*/ #define CS_1 (PORTB|= (14 ) /AD7705 片选 #define CS_0 (PORTB IO_Init(); /I/O 口初始化 INT1_Init(); GET_add(); /获取地址,地址为 0,反复获取地址,直到不为 0。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 教育学

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报