去年年底的时候,一个公司给我打电话,问我最近有没有空,说要请我帮忙做一个基于CAN总

线通讯的东西,我去看了看,是一个数据采集系统,下面是一系列数据采集的智能板卡,上位机是

基于WINBOND的一块486的工业嵌入式控制板,操作系统使用的是WINCE.智能板卡通过工业底板和数据线两种方式和上位机通讯,通信协议选择的是CAN,其中底板上的通信选用高速波特率(1Mbps),数据线选用低速(100kbps).
          去公司的时候,公司给了我一个参考的东西,采用SST单片机+SJA1000的方案构成的智能板卡

,同时告诉我可以自己设计方案.考虑到SST的东西没有用过,P8X591是PLCC封装的,烧写起来不

方便,于是我设计了如下的方案:
          1、智能板卡上的通讯采用AT89S51+两块SJA1000的方式进行;
          2、上位机通过PC104总线和一块CAN控制板卡连接,CAN控制板卡上同样采用AT89S51+两块

SJA1000的方案.AT89S51和上位机通过PC104总线共享内存(使用IDT的双口RAM);
          3、采用西门子的组态软件进行WINCE下的板卡驱动开发;
          由于以前没有做过CAN的东西,于是决定了先调试CAN通信,然后设计板卡的方案.
          方案确定之后,首先是上www.zlgmcu.com上下载了全部的SJA1000和PCA82C250的资料.然后开

始设计电路板.采用了SJA1000应用指南中推荐的方案,采用SJA1000的时钟输出为AT89S51的时钟

,没有采用光电隔离芯片,把TX1接地,TX0和RX0分别连接到PCA82C250的TXD和RXD引脚上,RX1连

接到PCA82C250的VR上;加上了5欧姆的限流电阻和120欧姆的匹配电阻(用110欧姆替代),另外加上

了一个调试用的串口.没有注意而且要命的是把SJA1000的复位引脚和单片机的复位引脚连接到了

一起.
          第一次的板子用的加急,用了三天,结果那次的板子做的极差——连铜皮都翻起来了;我马上

让那个电路板厂重新做了三块.在做板的过程中我发现了复位引脚的错误,SJA1000的文档上提供的

是一个复位电路,但是没有给出电路的详细组成,于是我就误以为和单片机的复位电路是一样的了

.在设计这块电路板的时候,最担心的事情就是SJA1000的输出时钟能不能够驱动AT89S51,如果不

能够驱动,那么一切就OVER了,可惜的是我的担心成为了现实,板子焊好之后系统不工作,在

SJA1000的时钟输入引脚上有信号输入,而且输出时钟也正常,但是单片机就是不工作.于是我先

把SJA1000的复位引脚连线割断,连接到了AT89S51的IO引脚上,再把S51的XTAL的两个引脚连接到

SJA晶体的上,可惜系统还是不工作,这次电路板设计失败了.
          在总结了第一次失败的经验后,参看了21IC上的一个设计,决定把AT89S51和SJA的晶体分开.

并且用单片机的一个IO引脚来控制对SJA的复位.
          第二次的电路板比较成功,焊接好了之后首先测试单片机的串口和LED指示灯,一切OK.然后

就开始测试SJA.ZLG提供了一个BASIC模式下的参考例程,我看了一下,然后又找了本《现场总线

CAN的原理和测试》把SJA的寄存器详细看了看(由于开始的时候比较忙,所以直到这个时候才算是

仔细看了看SJA的内部,至于CAN的基础协议我是根本没有看,这给我后面带来了极大的麻烦).然

后就参考ZLG的程序开始写SJA的测试程序,那个程序写的很大,也很全,因为我想快点把东西给做

出来,于是弄了一个1000多行的程序,以前我的调试程序一般都很小的.写好程序之后就开始测试

,首先测试的是测试寄存器,然后一步步测试下去,在BASIC模式下所有的寄存器都正常,但是在

发送的时候是总是不正常,启动发送之后就一直在发送,状态寄存器的标志位一直处在发送的状态

下,然后就是报总线错误,不知道是怎么会事情,很郁闷,上bbs看了一下.bullfrog告诉我单个

CAN节点发送是成功不了的,如果没有收到接受CAN节点的应答,发送节点就会一直发送,直到超出

错误计数器的允许值使得总线关闭.同时在精华区发现在peli模式下有ECC(错误寄存器),可以跟

踪错误,于是开始看peli模式操作过程.这个东西比较麻烦,zlg没有提供公开的c代码,我找了一

个汇编的作为参考.
          我第一步的目标是自发送,在peli模式下有自发送这种模式,在有匹配电阻的情况下可以进行

单个节点的接收和发送.第一次调试的时候没有成功,给北京zlg打电话,北京分公司说让我给广

州打电话,给广州打电话,几个问题都得到了很好的解答(在此谢谢zlg的工程师了):
          1、自发送的时候必须加上匹配电阻;
          2、5欧的限流电阻可以不需要;
          3、每次发送完成之后
          4、建议使用中止发送来进行单步发送;
          另外他告诉我可以在zlg的论坛上找到很多很有用的东西.
          听了他的建议,我第一件事情就是检查我的电路板,检查的结果让我大吃一惊——我的ch和cl

竟然是短路的,万用表的狂叫不止.一步步检查,发现那个110欧的匹配电阻有问题,万用表碰上

去就叫,于是把那个电阻剪下来,量量还是短路.于是我怀疑把5欧的限流电阻当成了110欧的电阻

,于是把匹配电阻都去掉了.没有想到的是当我把新的110欧电阻拿来的时候,万用表还是叫,这

时候才发现这块万用表在300欧姆以下都要叫,可怜我又打理了n长时间的电路板......
          再仔细阅读了一次peli模式下的操作指南,又仔细阅读了zlg提供的初始化规范,发现在子发

送的时候发送的命令应该是0x10或者是0x12(即CMR寄存器里面有一个专门的控制位是用来控制自发

送的,和普通的发送命令位是不同的).在发现了这个问题之后,自发送一切顺利的通过了.
          接下来就是两个节点的互调了,我首先用自发送程序把两个节点都调试了一下,保证单个节点

发送硬件没有任何问题.然后就用双绞线通过接线端子把两个系统连接到了一起.第一次调试采用

的是1M的波特率(由于ZLG只给出了16M晶体下的BTR0和BTR1的初始值,我在ZLG的论坛上找到了一个

网友自己计算的数值,后来证明这个东西有些问题),没有成功.发送节点通过串口利用串口调试助

手来控制发送,接收节点通过仿真器观察数据.虽然没有发送成功,但是通过串口的反馈数据和仿

真器的观察窗,可以看到ECC寄存器都发生了变化,证明数据线上有数据过去(由于我没有示波器,

只有采用这种办法).于是我改变了两次波特率,最低到了5k,都没有成功,最后我从21IC上的一

篇应用文章上找到了两个参数,这次就成功了,通讯速率20k.现在一切稳定,在写这篇文章的时

候哪几个LED正欢快的闪烁着.
          最后,总结几个经验:
          1、一定要详细的阅读sja的手册和CAN的相关知识;
          2、SJA的复位是低电平,而且不是用一个非们把单片机的RST反相就可以的,有两种解决方式

:第一种是使用单片机的IO引脚来控制SJA的复位引脚,好处是单片机完全控制SJA的复位过程;第

二种是采用适当的复位芯片,ZLG给我推荐的是CAT1161,我没有用过,其好处是同步复位.
          3、在自发送的模式下,需要匹配电阻,而且自发送的启动命令和普通发送的启动命令不相同

;
          4、BRT0和BRT1的选择,和串口通信中只要两个的误差一样就可以了不同,一定要精心选择,

建议SJA的外部晶体选择16M的,这样有利于参考ZLG的标准数值
          5、SJA和其他外部器件连接的时候,数据线在373前后都可以;
          6、最好有一个示波器;
          7、不要太大意的相信万用表的蜂鸣器;
          8、这是从ZLG网站上转载过来的peli模式下的初始化流程
          a)检测硬件连接是否正确        
          b)进入复位状态        
          c)设置时钟分频寄存器        
          d)设置输出控制寄存器    
          e)设置通讯波特率                    
          f)设置代码验收寄存器            
          g)设置代码屏蔽寄存器            
          h)退出复位状态                    
          i)设置工作模式                        
          j)设置中断使能寄存器      
      这是一个自发收程序,采用at89s51+sja1000,分离晶体,at89s51晶体11.0592
      sja1000外部晶体为12M,通过串口进行监控
      ******************************************************

以下为头文件定义
      copyright by alloy

******************************************************

#define SJA_REG_BaseADD 0x7800

#define REG_MODE    XBYTE[SJA_REG_BaseADD + 0x00]
      #define REG_CMD        XBYTE[SJA_REG_BaseADD + 0x01]
      #define REG_SR        XBYTE[SJA_REG_BaseADD + 0x02]
      #define REG_IR        XBYTE[SJA_REG_BaseADD + 0x03]
      #define REG_IR_ABLE    XBYTE[SJA_REG_BaseADD + 0x04]
      #define REG_BTR0    XBYTE[SJA_REG_BaseADD + 0x06]    //05保留
      #define REG_BTR1    XBYTE[SJA_REG_BaseADD + 0x07]
      #define REG_OCR        XBYTE[SJA_REG_BaseADD + 0x08]
      #define REG_TEST    XBYTE[SJA_REG_BaseADD + 0x09]
      #define REG_ALC        XBYTE[SJA_REG_BaseADD + 0x0b]    //0a保留
      #define REG_ECC        XBYTE[SJA_REG_BaseADD + 0x0c]
      #define REG_EMLR    XBYTE[SJA_REG_BaseADD + 0x0d]
      #define REG_RXERR    XBYTE[SJA_REG_BaseADD + 0x0e]
      #define REG_TXERR    XBYTE[SJA_REG_BaseADD + 0x0f]

#define REG_ACR0    XBYTE[SJA_REG_BaseADD + 0x10]
      #define REG_ACR1    XBYTE[SJA_REG_BaseADD + 0x11]
      #define REG_ACR2    XBYTE[SJA_REG_BaseADD + 0x12]
      #define REG_ACR3    XBYTE[SJA_REG_BaseADD + 0x13]
      #define REG_AMR0    XBYTE[SJA_REG_BaseADD + 0x14]
      #define REG_AMR1    XBYTE[SJA_REG_BaseADD + 0x15]
      #define REG_AMR2    XBYTE[SJA_REG_BaseADD + 0x16]
      #define REG_AMR3    XBYTE[SJA_REG_BaseADD + 0x17]

#define REG_RxBuffer0    XBYTE[SJA_REG_BaseADD + 0x10]
      #define REG_RxBuffer1    XBYTE[SJA_REG_BaseADD + 0x11]
      #define REG_RxBuffer2    XBYTE[SJA_REG_BaseADD + 0x12]
      #define REG_RxBuffer3    XBYTE[SJA_REG_BaseADD + 0x13]
      #define REG_RxBuffer4    XBYTE[SJA_REG_BaseADD + 0x14]

#define REG_TxBuffer0    XBYTE[SJA_REG_BaseADD + 0x10]
      #define REG_TxBuffer1    XBYTE[SJA_REG_BaseADD + 0x11]
      #define REG_TxBuffer2    XBYTE[SJA_REG_BaseADD + 0x12]
      #define REG_TxBuffer3    XBYTE[SJA_REG_BaseADD + 0x13]
      #define REG_TxBuffer4    XBYTE[SJA_REG_BaseADD + 0x14]

#define REG_DataBuffer1 XBYTE[SJA_REG_BaseADD + 0x15]
      #define REG_DataBuffer2 XBYTE[SJA_REG_BaseADD + 0x16]
      #define REG_DataBuffer3 XBYTE[SJA_REG_BaseADD + 0x17]
      #define REG_DataBuffer4 XBYTE[SJA_REG_BaseADD + 0x18]
      #define REG_DataBuffer5 XBYTE[SJA_REG_BaseADD + 0x19]
      #define    REG_DataBuffer6 XBYTE[SJA_REG_BaseADD + 0x1a]
      #define REG_DataBuffer7 XBYTE[SJA_REG_BaseADD + 0x1b]
      #define REG_DataBuffer8 XBYTE[SJA_REG_BaseADD + 0x1c]

#define REG_RBSA    XBYTE[SJA_REG_BaseADD + 0x1e]
      #define REG_CDR        XBYTE[SJA_REG_BaseADD + 0x1f]
      #define REG_Receive_Counter    XBYTE[SJA_REG_BaseADD + 0x1d]

#define    OK        1
      #define    Fail    0
      #define ON        1
      #define OFF        0
      #define True    1
      #define False    0

sbit SJARst = P2 ^ 6;                                //复位控制
      sbit LED0 = P1 ^ 0;
      sbit LED1 = P1 ^ 1;
      sbit Key0 = P1 ^ 2;
      sbit Key1 = P1 ^ 3;
      sbit Key2 = P1 ^ 4;
      sbit Key3 = P1 ^ 5;

bit step_flg;
      bit Tx_flg;
      bit Rx_flg;

unsigned char step_counter;
      unsigned char Tx_counter;
      unsigned char PC_RX_Buffer;
      unsigned char temp_data1;
      unsigned char Rx_Buffer[6];

void MCU_Init(void);
      void SJA_Init(void);
      void send(unsigned char S_Data);
      void Serial(void);
      void Delay(unsigned char Delay_time);
      void step(void);

*******************************************************

以下为c的主程序
      copyright by alloy

*******************************************************
      #include
      #include
      #include
      #include
      #include
      main()
      {

unsigned char i;
          MCU_Init();
          SJA_Init();
          REG_MODE = 0x01;                    //进入复位模式

temp_data1 = REG_MODE;
              temp_data1 = temp_data1 & 0x01;
          if(temp_data1  ==  0x01)        //在复位模式中
          {
              REG_BTR0 = 0x85;
              REG_BTR1 = 0xb4;                //100k
              REG_OCR    = 0x1a;
              REG_CDR = 0xc0;
              REG_RBSA = 0x00;

REG_ACR0 = 0xff;
              REG_ACR1 = 0xff;
              REG_ACR2 = 0xff;
              REG_ACR3 = 0xff;

REG_AMR0 = 0xff;
              REG_AMR1 = 0xff;
              REG_AMR2 = 0xff;
              REG_AMR3 = 0xff;

REG_IR_ABLE = 0xff;
          }
          REG_MODE = 0x0c;                    //进入自接收模式
          REG_MODE = 0x0c;

for(i = 0;i<100;i++);
          temp_data1 = REG_Receive_Counter;
          send(temp_data1);
          for(;;)
          {
                  while(Tx_flg == False);
                              Tx_flg = False;
                  Tx_counter++;
                  send(Tx_counter);
                  temp_data1 = REG_SR;
                  while((temp_data1 & 0x10) == 0x10);
                  temp_data1 = REG_SR;
                  if((temp_data1 & 0x04) == 0x04)
                  {
                      REG_RxBuffer0 = 0x08;            //标准帧,长度为8
                      REG_RxBuffer1 = 0xff;
                      REG_RxBuffer2 = 0xff;

REG_RxBuffer3 = 0x01;
                      REG_RxBuffer4 = 0x02;
                      REG_DataBuffer1 = 0x03;
                      REG_DataBuffer2 = 0x04;
                      REG_DataBuffer3 = 0x05;
                      REG_DataBuffer4 = 0x06;
                      REG_DataBuffer5 = 0x07;
                      REG_DataBuffer6 = 0x08;
                      REG_DataBuffer7 = 0x09;
                      REG_DataBuffer8 = 0x0a;
                  }
                  REG_CMD = 0x10;
                  temp_data1 = REG_SR;
                  temp_data1 = temp_data1 & 0x20;
                  while(temp_data1 == 0x20)            //检查是否发送完成
                  {
                      //send(0xaa);
                      temp_data1 = REG_ECC;
                      send(temp_data1);
                      temp_data1 = REG_SR;
                      temp_data1 = temp_data1 & 0x20;
                      //send(temp_data1);
                  }

send(0x66);
                  temp_data1 = REG_ALC;
                  send(temp_data1);
                  temp_data1 = REG_ECC;
                  send(temp_data1);
                  temp_data1 = REG_SR;
                  send(temp_data1);
                  temp_data1 = REG_Receive_Counter;
                  send(temp_data1);

PC_RX_Buffer = 0x77;
                  LED0 = ~LED0;

//            Tx_counter = 0x00;
          }
      }

void MCU_Init(void)
      {
          SJARst = 1;
          LED0 = OFF;
          LED1 = OFF;
          PC_RX_Buffer = 0x77;
          step_counter = 0x00;
          step_flg = False;
          Tx_flg = False;
          temp_data1 = 0x00;
          TMOD = 0x20;
          TH1 = 0xff;
          TL1 = 0xff;
          TR1 = 1;
          SCON = 0x50;
          PCON = 0x80;
          EA = 1;
          ES = 1;
          Tx_counter = 0x00;

}

void SJA_Init(void)
      {
          unsigned char i;
          for(i = 0;i < 125;i++);
          SJARst = 0;
          for(i = 0;i < 125;i++);
          SJARst = 1;
          for(i = 0;i < 125;i++);
      }

void send(unsigned char S_Data)
      {
          SBUF = S_Data;
          while(TI == 0);
          TI =0;
      }

void Serial() interrupt 4 using 2
      {

if(RI == 1)
          {
              PC_RX_Buffer = SBUF;
              RI = 0;
              if(PC_RX_Buffer == 0xaa)
              {
                  send(0x13);
                  Tx_flg = True;
                  PC_RX_Buffer = 0x77;
              }
              else if(PC_RX_Buffer == 0x55)
              {
                  send(0x14);
                  Rx_flg = True;
                  PC_RX_Buffer = 0x77;
              }
              else
              {
                  send(0x15);
                  PC_RX_Buffer = 0x77;
              }
          }

}

SJA1000的调试经历【转】相关推荐

  1. Code:blocks 调试经历,调试成功这其一

    Code:blocks 调试经历,调试成功这其一 小白游览了贴吧 ,又查了百度,终于能调试了 照吧友说的 不要有中文路径 cb里会显示乱码 cb跟其他编译系统不一样,可已单独执行文件,和其他部分编译软 ...

  2. AM5728调试经历(2)

    AM5728调试经历(2) 这次的主要内容是在Linux上安装CCS6.1.3软件.首先可以从TI的官网上下载CCS的安装文件,可以选择在线安装或者下载全部安装包. 在终端解压缩安装包,使用如下命令( ...

  3. AM5728调试经历

    AM5728调试经历(1) 由于本科生毕业设计的要求,研究生导师希望能够尽快的搭建出基于DSP的视觉处理平台,所以选择使用AM5728这样一款高性能的ARM+DSP,笔者是只菜鸟,博文中有些错误还请大 ...

  4. MCP2515+SJA1000通讯调试记录

    一.CAN总线 CAN是控制器局域网络(Controller Area Network, CAN)的简称,是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的,并最终成为国际标准(ISO 118 ...

  5. 关于VCP(Virtual Com Port)拓展的调试经历(一)

    * The Overview 前日,接到老板部署的任务,将现有的基于STM32L151与L432的LoRaWAN程序中添加USB CDC(Communication Device Class)功能,并 ...

  6. 一次SSIS Package的调试经历

    SSIS Package的调试有时是一个非常艰难的过程,由于SSIS 编译器给出的错误信息,可能并不完善,需要程序员根据错误信息抽丝拨茧,寻找错误的根源,进而解决问题. 第一部分:SSIS提供的调试工 ...

  7. FM1288回声消除调试经历

    一.回声消除原理 http://blog.51cto.com/silversand/166095 二.FM1288配置下载 1.通过I2C模式下载 代码例子: 点击打开链接 I2C设备地址" ...

  8. CAN总线之SJA1000芯片调试

    一.SJA1000芯片引脚 Intel模式下的引脚含义 ALE:地址使能,输入引脚 RD:读使能,低有效,输入引脚 WR:写实能,低有效,输入引脚 MODE:can模式选择,1:Intel模式:0:M ...

  9. 一次堆破坏的调试经历

    过程是这样的,在vc debug的过程中,突然弹出了一个assert窗口: Windows has triggered a breakpoint in cs.exe. This may be due ...

最新文章

  1. python【力扣LeetCode算法题库】18-四数之和
  2. 多线程python 客户端fuwuq实现方式_python实现二叉树数据结构的多种遍历方式
  3. c++中 结构体和类的区别
  4. 用VC创建程序启动画面
  5. Thinking in AJAX(二) —— 基于AJAX的WEB设计
  6. 操作系统—内存管理的概念
  7. phpyii框架倒叙_快速入门php框架(Lumen thinkphp Yii)
  8. 重写了GVBASIC模拟器
  9. xpdf 打开 chinapub中文pdf
  10. java extjs combobox_Extjs 教程三 “combobox”
  11. 服务机器人语音对话的实现
  12. java做抽奖小程序_随机抽奖小程序
  13. 虚拟化和禁用安全启动的设置
  14. excel 第15讲:条件格式与公式
  15. 拆弹专家【爆改车间主任】学习笔记(2)小结
  16. TensorFlow2.0-GPU加速
  17. 客户需要生成中文拼音代码,分享PHP生成代码
  18. 种一棵树最好的时间,是十年前,其次是现在
  19. 等保评测要求和评测材料需要哪些 你想知道的全攻略都在这里
  20. call、apply、bind的联系和区别

热门文章

  1. k8s(一)、 1.9.0高可用集群本地离线部署记录
  2. 程序猿面试题:为什么曹操能号令诸侯?
  3. crm客户关系管理系统总结
  4. 明日召开 | Pulsar Summit Asia 2021 本周末线上精彩呈现
  5. 【C++】图书管理系统(完整版)
  6. Nodejs用户登录,退出案例
  7. Lucene 搜索词分词
  8. 悟透JavaScript------------有所感。
  9. GameFramework篇:前言
  10. 拒绝垃圾专业化学:选择正确的专业远比多考几分更重要 ——致全国高考考生和家长的一封信