搜索
bottom↓
回复: 324

如何一步一步建立CAN通讯

  [复制链接]

出0入0汤圆

发表于 2007-6-13 16:44:58 | 显示全部楼层 |阅读模式
CAN通讯的优点在此就不多说了,10公里,5Kb/s的速度是能保证的。

第一步:硬件环境的建立。

    这里采用的是SJA1000作为总线控制器,CTM8251模块作为总线驱动器。MCU采用的是MEGA16:利用I/O口模拟数据总线,当然也可以使用有总线的MCU:MCS-51,MEGA8515等。

    原理图如下:



第二步:SJA1000的控制

    首先阅读下SJA1000的手册,基本了解下SJA1000的结构,主要是寄存器方面的。还要了解下CAN总线方面的东西:BasicCAN,Peli CAN,远程帧,数据帧等等……

    SJA1000工作之前需要配置一下,才能正常工作,没有经过配置的SJA1000回拉坏总线的:组成网络的时候,如果其中有的SJA1000没有正确配置,这个设备会干扰总线,使其它设备的数据发送不出去。

    怎么才能控制SJA1000呢,请看下面的SJA1000读写的时序图:

   

    写的时序

   

    根据时序要求,可以利用I/O口模拟总线了:

    //**************************读SJA1000*************************//

uint Read_SJA1000(uint address)

{

  uchar data;

  asm("nop");   

  ALE_off;

  WR_on;

  RD_on;

  CAN_cs_on;

  DDRA=0xff;          //数据口为输出

  PORTA=address;     //输出数据的地址

  asm("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");//delay5us(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=0xff;          //数据口为输出

  PORTA=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();

}

    现在可以读写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)&0x01))//保证进入复位模式,bit0.0不为1,再写CAN_MOD

    {

    Write_SJA1000(CAN_MOD,0x01);

        dog();

    }

   Write_SJA1000(CAN_CDR,0xc8);    //配置时钟分频寄存器-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_ACR3,addr);   //配置验收代码ACR3=地址

   Write_SJA1000(CAN_BTR0,0x7f);   //配置总线定时--5kbps

   Write_SJA1000(CAN_BTR1,0xff);

   Write_SJA1000(CAN_OCR,0x1a);    //配置输出控制

   Write_SJA1000(CAN_EWLR,0xff);   //配置错误报警限制为255

   do

   {

   Write_SJA1000(CAN_MOD,0x00); //进入工作模式双滤波   

   dog();

   }   

   while((Read_SJA1000(CAN_MOD))&0x01);     // 确认复位标志是否被删除

   Write_SJA1000(CAN_TXB+4,ID3);  //配置发送缓冲区的ID3-

   Write_SJA1000(CAN_IER,0x07);   //配置SJA10000中断-错误报警/发送/接收中断   

   SEI();

}

    在这之前,需要获取设备的地址,就是读取拨码开关各个脚的电平。需要注意的是,SJA1000使用的是双滤波模式,响应地址有:广播的:0x00,还有自己的地址:0x**。为什么要这么做呢,一个系统中,主机的地址一般是0X00,从机地址从0X01开始,这里面如果有两个从机的地址一样,就很可能产生一些混乱。从机一旦多了起来,查找地址相同的设备就有些麻烦了。

  在程序的初始化的时候,进行SJA1000的配置。

第三部:工作程序

  接下来,做的工作就是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&0x04))

   CLI();                            //关CAN中断,即总中断

  

  Write_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");

  //SEI();

}

SJA1000的中断引脚接到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&0x01)   //接收中断

   {  

    Get_RXB_temp();

                     

    if(RxBuffer[0]==0x80)     //地址测试数据帧

          {

           reload(); //数据帧中有和自己相同的地址

          }   

        if(RxBuffer[0]==0xc0)  // 远程帧则释放接收缓冲区

          {

                type=RxBuffer[3];  //读命令码



                //处理命令码

      

           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&0x02)  //发送中断

   {

        NET_LED_off;   //关闭网络灯

    ERR_LED_off;   //关闭故障灯

        CANBE_JSQ=0;   //复位总线关闭计数器

    asm("nop");   

   }

  if(CAN_IR_temp&0x04)  //错误报警中断(仅有总线关闭处理)

   {         //读状态寄存器,SR.7总线关闭:CAN控制器不参与总线活动

     CAN_SR_temp=Read_SJA1000(CAN_SR);

     

          if(CAN_SR_temp&0x80)

          {

          CANBE_JSQ=CANBE_JSQ+1; //关闭次数加1

          if(CANBE_JSQ<CANBE_C)      //关闭次数小于设定值

            {

                do

              {

                       Write_SJA1000(CAN_MOD,0x00); //重新进入工作模式

                       

                       }   

          while((Read_SJA1000(CAN_MOD))&0x01);//等待进入工作模式  

                  Write_SJA1000(CAN_CMR,0x01);  //启动CAN重新发送

            }

          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))&0x01);//等待进入工作模式

                   Write_SJA1000(CAN_CMR,0x01);  //启动CAN重新发送

                   CANBE_JSQ=CANBE_C;  //防止CANBE_JSQ溢出

                  

                 }

          }

     asm("nop");

   }

}



中断程序中,对命令码等于0x2e的处理程序是:active();

active()程序如下:

//************************通讯地址测试2EH***********************//

void active(void)

{

uchar temp1,temp2;

  asm("nop");                          //延时

  NET_LED_on;   //打开网络灯

  CLI();  //关CAN中断,即总中断

  do

  {

  temp1=Read_SJA1000(CAN_SR);//读CAN_SR,直到SR.2=1:CPU可以发送数据

  dog();

  }        

  while(!(temp1&0x04));                              



  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");



}

大家仔细看看 active()程序的内容,发送了一个没有数据的数据帧:0X80,再回过头看看中断处理函数,里面有这段程序,    if(RxBuffer[0]==0x80)     //地址测试数据帧

          {

           reload(); //数据帧中有和自己相同的地址

          }   

reload(); 程序很简单,就是停止喂狗,等待复位。复位之后呢,它会进行试发送,哈哈,接下来的两个地址相同的设备就“打架”起来了,现象就是一个设备不断复位,一个设备通讯灯不断闪烁。怎么样,很容易就判断出哪两个地址重复了。

   命令码等于0x27时,设备复位,一般是主机发送这个远程帧。

   0x34时,发送数据:

//************************瞬时值发送 34H*********************//

void CAN_now_value_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();

  }     

  while(!(b_temp&0x04))

   CLI();                            //关CAN中断,即总中断



  Write_SJA1000(CAN_TXB+0,0x84);      //发送数据帧0x84

  Write_SJA1000(CAN_TXB+1,RxBuffer[1]);     //发送转接器地址

  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_CMR,0x01);       //启动发送

  SEI();                            //开中断

  asm("nop");



}

    发送了一个数据帧,这个数据帧有四字节的数据。

    CAN的数据帧最多支持有8个字节的数据帧,如果数据较多,可以分为多个数据帧,在命令码里面区分这些数据帧。

   

第四步:建立自己的CAN通讯网络。

    主机可以是一台有CAN接口的计算机,一般在计算机上装一个CAN接口卡,有ISA接口的,比如PCL-841;PCI接口的。CAN卡的销售商都会提供驱动,依靠驱动里面的函数,来控制CAN卡,此项不是专长,不好多说,反正就是这个思路。



    好了,昨天从南京回来的路上,就考虑发个CAN的东西。咱们这个论坛,目前还没有多少关于CAN的帖子,意在抛砖引玉…………本坛高手很多,尤其是有很多潜水的高高手~~~~

--------------------

程序中的一些DEFINE

//******************引脚信号定义***************************//

#define CS_1        (PORTB|= (1<<4 ))      //AD7705片选

#define CS_0        (PORTB&= ~(1<<4 ))

#define DRDY  (PINB&0x08)               //AD转换DRDY信号输入

#define NET_LED_off (PORTB|= (1<<0 ))      //网络故障灯高电平,熄灭

#define NET_LED_on (PORTB&= ~(1<<0 ))     //网络故障灯低电平,点亮

#define ERR_LED_off (PORTB|= (1<<1 ))      //装置故障灯高电平,熄灭

#define ERR_LED_on (PORTB&= ~(1<<1 ))     //装置故障灯低电平,点亮

#define DOG_on (PORTB|= (1<<2 ))          //看门狗高

#define DOG_off (PORTB&= ~(1<<2 ))         //看门狗低

#define WR_on (PORTD|= (1<<0 ))           //WR高

#define WR_off (PORTD&= ~(1<<0))          //WR低

#define RD_on (PORTD|= (1<<1 ))           //RD高

#define RD_off (PORTD&= ~(1<<1))          //RD低

#define CAN_cs_on (PORTD|= (1<<4 ))       //CAN高

#define CAN_cs_off (PORTD&= ~(1<<4))      //CAN低

#define ALE_on (PORTD|= (1<<2 ))          //ALE高

#define ALE_off (PORTD&= ~(1<<2))         //ALE低

#define FALSE 0

#define TRUE 1

#define CANBE_C 6                       //总线关闭次数设定值

//*******************CAN寄存器地址**************************//

#define CAN_MOD     0      //模式寄存器

#define CAN_CMR     1      //命令寄存器 只写

#define CAN_SR      2      //状态寄存器 只读

#define CAN_IR      3      //中断寄存器 只读

#define CAN_IER     4      //中断使能寄存器

#define CAN_BTR0    6      //总线定时寄存器0

#define CAN_BTR1    7      //总线定时寄存器1

#define CAN_OCR     8      //输出控制寄存器

#define CAN_TEST    9      //测试寄存器

#define CAN_ALC     11     //仲裁丢失寄存器

#define CAN_ECC     12     //错误代码捕捉寄存器

#define CAN_EWLR    13     //错误报警限制寄存器

#define CAN_EXERR   14     //RX错误计数寄存器

#define CAN_TXERR   15     //TX错误计数寄存器

#define CAN_ACR0    16     //验收码寄存器0

#define CAN_ACR1    17     //验收码寄存器1

#define CAN_ACR2    18     //验收码寄存器2

#define CAN_ACR3    19     //验收码寄存器3

#define CAN_AMR0    20     //验收屏蔽寄存器0

#define CAN_AMR1    21     //验收屏蔽寄存器1

#define CAN_AMR2    22     //验收屏蔽寄存器2

#define CAN_AMR3    23     //验收屏蔽寄存器3

#define CAN_TXB     16     //发送缓冲区首地址(工作模式)

#define CAN_RXB     16     //接收缓冲区首地址(工作模式)

#define CAN_RMC     29     //RX信息计数器

#define CAN_RBSA    30     //RX缓冲区起始地址寄存器

#define CAN_CDR     31     //时钟分频器

#define ID3         00      //ID3

-----------------------------

初始化程序

uchar main_ch=0;

IO_Init();           //I/O口初始化

INT1_Init();

GET_add();           //获取地址,地址为0,反复获取地址,直到不为0。

NET_LED_on;

ERR_LED_on;          //初始化中,点亮故障灯和通讯灯,

delay50ms(2);

dog();

delay50ms(2);

dog();

delay50ms(2);

dog();

CAN_Init();          //CAN初始化

NET_LED_off;

ERR_LED_off;

SEI();

CAN_first_send();    //CAN试发送

delay50ms(1);

dog();   

void GET_add(void)  //地址获取程序

{

  uchar add_temp=0,add_temp1=0,add_temp2=0,add_temp3=0,addr_temp=0;

   do

   {

      dog();

      NET_LED_on;

      ERR_LED_on;

      add_temp1=PINC&0xc3;      

      add_temp2=add_temp1>>4;       

          add_temp1=add_temp1&0x03;  

      add_temp3=(PIND&0xe0)>>1;

          add_temp=add_temp1+add_temp2+add_temp3;

      add_temp=(~add_temp)&0x7f;

          addr=add_temp;

          delay50ms(2);  

   }

   while(addr==0);

  

}
-----此内容被erxun于2007-06-13,16:45:33编辑过

出0入0汤圆

发表于 2007-6-13 16:59:58 | 显示全部楼层
写的不错~谢谢~有没有一些关于can的协议方面的资料,我们原来只用到了can的收发器,协议是自定义的,经千米线测试,传输距离不如rs485通信效果好,但是没有上升到协议层~

出0入0汤圆

 楼主| 发表于 2007-6-13 17:54:54 | 显示全部楼层





-----此内容被erxun于2007-06-13,18:39:13编辑过

出0入0汤圆

 楼主| 发表于 2007-6-13 18:40:55 | 显示全部楼层
协议很简单,也就很好用,

出0入0汤圆

发表于 2007-6-13 19:04:27 | 显示全部楼层
好东西!

出0入0汤圆

发表于 2007-6-13 20:17:41 | 显示全部楼层
非常好,正好要研究一下CAN总线,谢谢楼主。



【1楼】 soulmate  说CAN总线的传输距离不如RS485?理论上说应该是CAN总线要优于RS485的啊,到底是怎么回事呢?

出0入8汤圆

发表于 2007-6-13 22:53:25 | 显示全部楼层
学CAN不必要这么复杂。找个带CAN接口的MCU,硬件就只要MCU能干活就可以满足了。要是实在要用M16这些不带CAN的,可以找Microchip申请免费的MCP2515和MCP2551,一个是SPI接口的CAN Control,另一个是CAN收发器。SPI总会用吧,SJA1000的并行接口会难道很多初学的,学CAN Bus用不着在这上面费老大劲。21ic上Zlg的CAN Bus论坛,总是能看到有人在问SJA1000的硬件连接。用MCP2515,Microchip也提供了免费的库文件,源代码和应用笔记也可以在PIC的网站上下载。



对于协议有很多,像我现在在用的SEA J1939啊,其它的还有DeviceNet等太多了,lz能给出代码,不管如何顶一下还是要的
-----此内容被Grant于2007-06-13,22:56:04编辑过

出0入0汤圆

 楼主| 发表于 2007-6-14 08:08:04 | 显示全部楼层
并行接口虽然很多,但是要比SPI容易操作吧,对于总线外扩的MCU,直接就对SJA1000操作了.并行接口是最基础的接口了,用MEGA16主要是为了体现如何精确模拟总线的时序.

出0入0汤圆

发表于 2007-6-14 08:53:16 | 显示全部楼层
太感谢了!

出0入0汤圆

发表于 2007-6-14 09:04:32 | 显示全部楼层
同意6楼。avr+MCP2515,或者直接CAN32。

出0入0汤圆

发表于 2007-6-14 09:51:47 | 显示全部楼层
那位大侠有SAE1939协办议呀,能不能发我一份学学

出0入0汤圆

 楼主| 发表于 2007-6-14 10:04:32 | 显示全部楼层
CAN32\64\128本来是计划采用的,一体化的MCU.但是货源不稳定啊,没有SJA1000这么稳定的供货,而且价格上也没有优势.产品上量了,不得不考虑这些了......

    如果是仅仅个人开发使用,当然是CAN32这样的选型好了......

    新品出来,在中国得等上几年才能有稳定的供货,让人很不爽!

出0入0汤圆

发表于 2007-6-14 18:16:01 | 显示全部楼层
如果用两个M16进行CAN通信,但CAN控制器不同,一个为MCP2515,一个为SJA,这样可以实现通信吗?

出0入8汤圆

发表于 2007-6-14 20:34:46 | 显示全部楼层
没有问题,两个都支持CAN 2.0B,标准帧与扩展帧都一样,可以通讯。CAN控制器能不能互相通讯主要取决与它支持的协议,一般就CAN2.0A和2.0B,协议是应用层,与这无关。



带CAN接口的控制器很多,供货好的,价格好的,交期好的有好多,看你怎么选了。

出0入0汤圆

发表于 2007-7-6 15:47:59 | 显示全部楼层
根据搂住的思路,调试can总线碰到一个问题

想请教楼主:



unsigned char SJAconnect_judge(void)

{

    Write_SJA1000(0x09,0xAA);                //写AA到测试寄存器(地址09)

    if(Read_SJA1000(0x09)==0xAA){

        return 1;                           //连接正常

    }

    else{

        return 0;                           //连接故障

    }  

}



我这个程序能返回 1 证明读写SJA1000 OK

但是



unsigned char setting_SJA_workingmode(void)

{

     unsigned char mode_data;  

     mode_data=Read_SJA1000(CAN_MOD);

     mode_data&=0xFE;

     Write_SJA1000(CAN_MOD,mode_data);

     

     if((Read_SJA1000(CAN_MOD)&0x01)==0)

        return 1;                 //置工作模式成功

   

     else

        return 0;                  //置工作模式失败

}



总是返回 0 。SJA1000 的复位脚 是高电平。



有点不明白啦

出0入0汤圆

发表于 2007-7-6 21:35:11 | 显示全部楼层
收藏了。

出0入0汤圆

发表于 2007-7-8 02:09:28 | 显示全部楼层
老孟,有个问题想请教你!



我参考了你的程序,写了读写程序。然后往测试寄存器里面写入一个数据,然后读出该数据进行比较测试。我写入0xAA或者0xBB都可以正确读出,但是我写入比如0xEE,0xFF,0x77等数据,读出来的数据就完全不一样了。



这个大概是哪里有问题?

出0入0汤圆

 楼主| 发表于 2007-7-8 15:19:40 | 显示全部楼层
估计是读写问题,在这个程序开始垒的时候,就是时序的微小差距,

还有就是SJA1000的接口速度是有限制的,太高了,就不行了,我的程序的MCU是7.***MHZ的,

现在做的CAN通讯是M128+SJA1000.估计进行SJA1000的时候就要增大分频系数了,

出0入0汤圆

发表于 2008-2-5 18:31:22 | 显示全部楼层
老孟:你好!
    请问从机的地址是由拨码开关确定的吗?比如从机有100个,每个从机的拨码开关位置不一样,如果是这样不是很麻烦吗?开关容易拨错啊。

出0入0汤圆

发表于 2008-2-5 20:47:47 | 显示全部楼层
仔细学习中...

出0入0汤圆

发表于 2008-2-6 15:55:35 | 显示全部楼层
我用51(CPLD)+SJA1000+82C250做过几个CAN的电路板,通信距离是问题,我的波特率到16K了,通信距离才可以达到1000m。

出0入0汤圆

发表于 2008-2-6 19:23:17 | 显示全部楼层
好贴,保存了,谢谢,祝各位网友新年愉快!

出0入0汤圆

发表于 2008-2-7 09:39:51 | 显示全部楼层
can总线的驱动模块,怎么搞的?直接买周立功的?多少银子?

出0入0汤圆

发表于 2008-2-7 10:03:27 | 显示全部楼层
关注

出0入10汤圆

发表于 2008-2-8 21:12:25 | 显示全部楼层
留个记号,要好好研究研究

出0入0汤圆

 楼主| 发表于 2008-2-9 19:19:33 | 显示全部楼层
我做的从机   事利用拨码开关来确定地址的,这样比较直观,现场工人维护起来方便。更换的时候,新的地址拨成和旧的一样就可以了。
驱动模块,周立功的.38元这样,有好几种,工业级,汽车级,带保护,不带保护。,5v的,3.3v的.
可以申请样片的哦~~~~~,

出0入0汤圆

发表于 2008-2-9 20:26:05 | 显示全部楼层
学习中

出0入0汤圆

发表于 2008-2-9 22:53:11 | 显示全部楼层
谢榭,25楼。

出0入0汤圆

发表于 2008-2-17 14:48:40 | 显示全部楼层
好东西!

出0入0汤圆

发表于 2008-2-18 14:02:43 | 显示全部楼层
收藏一下!

出0入0汤圆

发表于 2008-2-18 16:04:28 | 显示全部楼层
正在做毕业设计,就是做can总线。非常感谢楼主!

出0入0汤圆

发表于 2008-3-2 15:29:42 | 显示全部楼层
也是毕设,其中一个要求是带CAN的,谢了

出0入0汤圆

发表于 2008-3-4 09:49:09 | 显示全部楼层
uint Read_SJA1000(uint address)
{
  uchar data;
  asm("nop");   
  ALE_off;
  WR_on;
  RD_on;
  CAN_cs_on;
  DDRA=0xff;          //数据口为输出
  PORTA=address;     //输出数据的地址
  asm("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");//delay5us(1);
  RD_on;
  CAN_cs_on;
  asm("nop");//delay5us(2); ***********************************************************************************
  //dog();
  return data;
}

带有*号的部分程序,根据时序图,当CAN_cs_off、  RD_off;此刻DDRA=0xff,PORTA=address,而此刻SJA1000经过延时为数据输出状态
延时时刻为delay5us(2),根据时序图延时时间为Trlqv,根据查资料,Trlqv最大时间为50ns,微秒级的延时肯定超过纳秒,如果此刻根据上一次PORTA 是输出的状态,如果PORTA的输出数据与SJA1000有冲突,可能会对芯片不利喔,不知道楼主注意到没有,我是根据理论数据推算出来的。
想DDRA=0x00,提到CAN_cs_off前面,不知道可行否

出0入0汤圆

 楼主| 发表于 2008-3-4 11:39:30 | 显示全部楼层
应该是可以的,
这个程序是经过考验的,使用起来没有任何异常,呵呵

出0入0汤圆

发表于 2008-3-4 12:38:55 | 显示全部楼层
收藏一下

出0入0汤圆

发表于 2008-3-5 08:56:14 | 显示全部楼层
谢谢LZ!!

出0入0汤圆

发表于 2008-3-5 23:02:51 | 显示全部楼层
关注

出0入46汤圆

发表于 2008-3-5 23:08:21 | 显示全部楼层
好东西!

出0入0汤圆

发表于 2008-3-5 23:15:01 | 显示全部楼层
收藏

出0入0汤圆

发表于 2008-3-13 10:59:42 | 显示全部楼层
真不错

出0入0汤圆

发表于 2008-3-14 16:54:06 | 显示全部楼层
用拨码开关有点麻烦了,还占那么多IO口,节点少的话还好弄,多的话那要对着说明书拨开关吗??改成类似电视机遥控器那样,可以按两位数的键盘阵,改由键盘驱动芯片驱动好一些!

出0入0汤圆

发表于 2008-3-17 12:44:51 | 显示全部楼层
按照你的程序和电路,模拟了一下,发现数据传输是正常的,但故障处理这一块还不明白,也没有模拟出来。

例如: 地址相同时候的问题,其中一个会自己复位,但复位次数不多,就转入正常了,之后可以数据传输了。

//reload(); 程序很简单,就是停止喂狗,等待复位。复位之后呢,它会进行试发送,哈哈,接下来的两个地址相同的设备就“打架”起来了,现象就是一个设备不断复位,一个设备通讯灯不断闪烁。怎么样,很容易就判断出哪两个地址重复了。 //

现象模拟不出来, 请教楼主!

出0入0汤圆

发表于 2008-3-17 14:11:40 | 显示全部楼层
51就是不爽,只有UART,其他全部要软件虚拟

出0入0汤圆

发表于 2008-5-9 20:54:54 | 显示全部楼层
收藏

出10入95汤圆

发表于 2008-5-9 21:41:16 | 显示全部楼层
很好的帖子。谢谢楼主!

出0入0汤圆

发表于 2008-5-10 00:35:07 | 显示全部楼层
带CAN控制器MCU+收发器,正用,方便

出0入0汤圆

发表于 2008-5-10 08:42:45 | 显示全部楼层
mark...

出0入0汤圆

发表于 2008-5-10 09:35:06 | 显示全部楼层
好贴

出0入0汤圆

发表于 2008-5-10 15:49:52 | 显示全部楼层
做个记号!

出0入0汤圆

发表于 2008-5-10 16:02:18 | 显示全部楼层
没有做过。但是不明白,为什么SJ1000T的RX1脚要接地呢。。???

出0入0汤圆

发表于 2008-5-10 16:53:11 | 显示全部楼层
CTM8251打算用,是很不错,内部带DC-DC隔离,而且通讯也带隔离。

就是erxun 老孟说买的38元的价格还是比较贵的。。。

目前好像没有更好的隔离方案了。

出0入0汤圆

发表于 2008-5-26 13:51:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-5-26 15:32:56 | 显示全部楼层
感谢,标记

出0入0汤圆

发表于 2008-5-26 15:58:25 | 显示全部楼层
收藏了

出0入0汤圆

发表于 2008-8-15 08:28:11 | 显示全部楼层
刚好用到.非常感谢楼主.

出0入0汤圆

发表于 2008-8-15 08:31:53 | 显示全部楼层
收藏

出0入0汤圆

发表于 2008-8-15 08:36:36 | 显示全部楼层
谢谢,收藏了。

出0入0汤圆

发表于 2008-8-15 08:56:46 | 显示全部楼层
can的距离和效率确实是远远不如485的,实际上can的优势不在于速度和效率,而在可靠性和协议上的

出0入0汤圆

发表于 2008-8-15 09:05:00 | 显示全部楼层
很好很强大

出0入0汤圆

发表于 2008-8-20 11:23:33 | 显示全部楼层

出0入0汤圆

发表于 2008-8-27 15:44:46 | 显示全部楼层
MARK

出0入0汤圆

发表于 2008-9-3 11:29:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-9-3 11:55:20 | 显示全部楼层
也MARK下

出0入0汤圆

发表于 2008-9-3 14:46:54 | 显示全部楼层
记号备用

出0入0汤圆

发表于 2008-9-3 22:01:56 | 显示全部楼层
收了.

出0入0汤圆

发表于 2009-4-23 21:58:09 | 显示全部楼层
感觉很不错,学习一下!谢谢楼主

出0入0汤圆

发表于 2009-4-23 22:40:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-23 22:56:34 | 显示全部楼层

出0入0汤圆

发表于 2009-4-24 12:02:05 | 显示全部楼层
16楼,寄存器的有些位读是恒为1的。你如果在这些位写入0,读出的也为1,所以写入和读出是不一样的。
另外:SJA1000的时序操作是ns级的,与晶振没有关系。
第二个问题是因为缺少软件复位吧。

出0入0汤圆

发表于 2009-4-24 12:28:55 | 显示全部楼层
实用,详细

出0入0汤圆

发表于 2009-4-24 13:20:46 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-4-24 15:55:44 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-4-24 16:10:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-27 09:07:15 | 显示全部楼层
我也正想做CAN,学习!

出0入0汤圆

发表于 2009-5-4 20:55:46 | 显示全部楼层
学习了

出0入0汤圆

发表于 2009-5-23 21:52:35 | 显示全部楼层
Mark

出0入0汤圆

发表于 2009-6-30 06:47:31 | 显示全部楼层
十分感谢

出0入0汤圆

发表于 2009-6-30 08:42:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-30 09:17:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-22 22:12:29 | 显示全部楼层
老孟一出,必出精品。

出0入0汤圆

发表于 2009-7-23 00:07:21 | 显示全部楼层
谢谢 lz

出0入0汤圆

发表于 2009-7-23 10:14:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-23 10:44:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-23 16:22:19 | 显示全部楼层
3ks

出0入0汤圆

发表于 2009-7-23 17:03:18 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-7-23 18:08:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-23 19:55:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-9 13:36:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-10 14:48:00 | 显示全部楼层
厉害,学学

出0入0汤圆

发表于 2009-8-19 18:02:22 | 显示全部楼层
有时间学习

出0入0汤圆

发表于 2009-8-21 15:37:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-21 15:49:18 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-19 20:55:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-19 22:19:55 | 显示全部楼层
Mark

出0入0汤圆

发表于 2009-10-19 23:06:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-19 23:30:47 | 显示全部楼层
mark一下 慢慢看

出0入0汤圆

发表于 2009-10-20 01:00:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-20 01:12:12 | 显示全部楼层
这里做个标记。。。嘿

出0入0汤圆

发表于 2009-10-23 23:03:12 | 显示全部楼层
最近在搞CAN,正在收集CAN方面的资料,谢谢楼主!

出0入4汤圆

发表于 2009-10-23 23:47:00 | 显示全部楼层
学习啦!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-9 03:21

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表