搜索
bottom↓
回复: 16

独立CAN芯片SJA1000的读写函数问题?

[复制链接]

出0入0汤圆

发表于 2009-12-7 21:20:21 | 显示全部楼层 |阅读模式
#define startadd 0x7F00 //SJA1000的首地址
unsigned char read_sja(unsigned char addr)     //读SJA1000状态寄存器子程序
{
    unsigned char *sja_address = (unsigned char *)startadd;
    sja_address = sja_address + addr;
    return (*(sja_address));
}

void write_sja(unsigned char addr,unsigned char val)     //写SJA1000控制寄存器子程序
{
    unsigned char *sja_address = (unsigned char *)startadd;
    sja_address = sja_address + addr;
    *(sja_address) = val;
}

读写程序如上,原理图如下。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2009-12-7 21:28:39 | 显示全部楼层

(原文件名:243543656.jpg)

我是用ATMEGA128硬件访问的,AD[0:7]接PA[0:7]。外部存储器使能是对的,就是在初始化SJA1000时,程序停在while()循环内。

出0入0汤圆

 楼主| 发表于 2009-12-8 14:16:09 | 显示全部楼层
请路过的高手帮忙回答一下,谢谢!!!!!!!!

出0入0汤圆

发表于 2009-12-8 14:29:03 | 显示全部楼层
先这样定义好寄存器的地址
#define CAN_MOD     (*(volatile unsigned char *)0xfb00)      //模式寄存器
#define CAN_CMR     (*(volatile unsigned char *)0xfb01)      //命令寄存器 只写
#define CAN_SR      (*(volatile unsigned char *)0xfb02)      //状态寄存器 只读
#define CAN_IR      (*(volatile unsigned char *)0xfb03)      //中断寄存器 只读
#define CAN_IER     (*(volatile unsigned char *)0xfb04)      //中断使能寄存器
#define CAN_BTR0    (*(volatile unsigned char *)0xfb06)      //总线定时寄存器0
#define CAN_BTR1    (*(volatile unsigned char *)0xfb07)      //总线定时寄存器1  

那么对它们的读写这样就可以了。
   CAN_MOD=0x01;         

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

出0入0汤圆

发表于 2009-12-8 22:05:39 | 显示全部楼层
老大,你要写程序模拟intel时序吧,RD WR ALE你怎么没控制啊

好有楼上的方法是用51控制 的方法吧

出0入0汤圆

发表于 2009-12-8 22:08:54 | 显示全部楼层
LZ仔细研究下,把程序发上来参考参考啊

出0入0汤圆

 楼主| 发表于 2009-12-8 23:01:08 | 显示全部楼层
/*******************************************************************************功能说明:   计算SJA1000在电路中的实际地址:基址+内部寄存器地址
其它说明:   以下的定义为SJA1000的内部寄存器的地址,不可修改
           各寄存器的具体功能清参阅sja1000的数据手册
*******************************************************************************/
#define startadd 0x7F00 //SJA1000的首地址
// 控制寄存器
#define         MODE      0x00       //内部控制寄存器
#define         CMR       0x01       //命令寄存器
#define         SR        0x02       //状态寄存器
#define         IR        0x03       //中断寄存器
#define         IER       0x04       //中断使能寄存器
#define         BTR0      0x06       //总线定时寄存器0
#define         BTR1      0x07       //总线定时寄存器1
#define         OCR       0x08       //输出控制寄存器
#define         TEST      0x09       //测试寄存器

#define         RESVER1   0x0A       //保留1
#define         ALC       0x0B       //仲裁丢失捕捉
#define         ECC       0x0C       //错误代码捕捉
#define         EWLR      0x0D       //错误报警限额

#define         RXERR     0x0E       //接收错误计数器
#define         TXERR     0x0F       //发送错误计数器

#define         ACR0      0x10       //验收代码寄存器
#define         ACR1      0x11       //验收代码寄存器
#define         ACR2      0x12       //验收代码寄存器
#define         ACR3      0x13       //验收代码寄存器
#define         AMR0      0x14       //验收屏蔽寄存器
#define         AMR1      0x15       //验收屏蔽寄存器
#define         AMR2      0x16       //验收屏蔽寄存器
#define         AMR3      0x17       //验收屏蔽寄存器


// 发送缓冲区寄存器
#define         TXD_FID       0x10       //发送缓冲区1
#define         TXD_ID1       0x11       //发送缓冲区2
#define         TXD_ID2       0x12       //发送缓冲区3
#define         TXD_ID3       0x13       //发送缓冲区4
#define         TXD_ID4       0x14       //发送缓冲区5
#define         TXBuffer1     0x15       //发送缓冲区6
#define         TXBuffer2     0x16       //发送缓冲区7
#define         TXBuffer3     0x17       //发送缓冲区8
#define         TXBuffer4     0x18       //发送缓冲区9
#define         TXBuffer5     0x19       //发送缓冲区10
#define         TXBuffer6     0x1A       //发送缓冲区11
#define         TXBuffer7     0x1B       //发送缓冲区12
#define         TXBuffer8     0x1C       //发送缓冲区13

// 接收缓冲区寄存器
#define         RXD_FID       0x10       //接收缓冲区1
#define         RXD_ID1       0x11       //接收缓冲区2
#define         RXD_ID2       0x12       //接收缓冲区3
#define         RXD_ID3       0x13       //接收缓冲区4
#define         RXD_ID4       0x14       //接收缓冲区5
#define         RXBuffer1     0x15       //接收缓冲区6
#define         RXBuffer2     0x16       //接收缓冲区7
#define         RXBuffer3     0x17       //接收缓冲区8
#define         RXBuffer4     0x18       //接收缓冲区9
#define         RXBuffer5     0x19       //接收缓冲区10
#define         RXBuffer6     0x1A       //接收缓冲区11
#define         RXBuffer7     0x1B       //接收缓冲区12
#define         RXBuffer8     0x1C       //接收缓冲区13

#define         RMC           0x1D       //RX报文计数器
#define         RBSA          0x1E       //接收缓冲区起始地址
#define         CDR           0x1F       //时钟分频寄存器

/*******************************************************************************
功能说明:   CAN控制器SJA1000通讯波特率.SJA1000的晶振为必须为16MHZ
其它说明:
*******************************************************************************/
#define         BTR0_Rate_20k      0x53          //20KBPS的预设值
#define         BTR1_Rate_20k      0x2F          //20KBPS的预设值
#define         BTR0_Rate_40k      0x87          //40KBPS的预设值
#define         BTR1_Rate_40k      0xFF          //40KBPS的预设值
#define         BTR0_Rate_50k      0x47          //50KBPS的预设值
#define         BTR1_Rate_50k      0x2F          //50KBPS的预设值
#define         BTR0_Rate_80k      0x83          //80KBPS的预设值
#define         BTR1_Rate_80k      0xFF          //80KBPS的预设值
#define         BTR0_Rate_100k     0x43          //100KBPS的预设值
#define         BTR1_Rate_100k     0x2f          //100KBPS的预设值
#define         BTR0_Rate_125k     0x03          //125KBPS的预设值
#define         BTR1_Rate_125k     0x1c          //125KBPS的预设值
#define         BTR0_Rate_200k     0x81          //200KBPS的预设值
#define         BTR1_Rate_200k     0xFA          //200KBPS的预设值
#define         BTR0_Rate_250k     0x01          //250KBPS的预设值
#define         BTR1_Rate_250k     0x1c          //250KBPS的预设值
#define         BTR0_Rate_400k     0x80          //400KBPS的预设值
#define         BTR1_Rate_400k     0xfa          //400KBPS的预设值
#define         BTR0_Rate_500k     0x00          //500KBPS的预设值
#define         BTR1_Rate_500k     0x1c          //500KBPS的预设值
#define         BTR0_Rate_666k     0x80          //666KBPS的预设值
#define         BTR1_Rate_666k     0xb6          //666KBPS的预设值
#define         BTR0_Rate_800k     0x00          //800KBPS的预设值
#define         BTR1_Rate_800k     0x16          //800KBPS的预设值
#define         BTR0_Rate_1000k    0x00          //1000KBPS的预设值
#define         BTR1_Rate_1000k    0x14          //1000KBPS的预设值

/*******************************************************************************
功能说明:   定义系统参数
其它说明:   无
*******************************************************************************/
// 本地的IP地址
#define    Local_IP1   1    // IP地址最高位
#define    Local_IP2   2
#define    Local_IP3   3
#define    Local_IP4   4    // IP地址最低位

// 本地的CAN标识
#define    REG_ACR1_FID  Local_IP4   // 滤波器的标识符最高位
#define    REG_ACR2_FID  Local_IP3
#define    REG_ACR3_FID  Local_IP2
#define    REG_ACR4_FID  Local_IP1   // 滤波器的标识符最低位
#define    REG_AMR1_FID  0x00        // 滤波器的屏蔽符最高位
#define    REG_AMR2_FID  0x00
#define    REG_AMR3_FID  0x03
#define    REG_AMR4_FID  0x07        // 滤波器的屏蔽符最低位

// 发往目标CAN标识
#define    SEND_ACR1_FID   Local_IP4   // 滤波器的最高位
#define    SEND_ACR2_FID   Local_IP3
#define    SEND_ACR3_FID   Local_IP2
#define    SEND_ACR4_FID   Local_IP1   // 滤波器的最低位

// 模式参数
#define    REG_MODE_DATA         0x0C    // 模式控制器:     单滤波器、自检测模式
#define    REG_TEST_DATA         0xAA    // 测试值
#define    REG_CDR_DATA          0x88    // 时分控制的值:    PeilCAN模式、CLOCK无效
#define    REG_INTENABLE_DATA    0x83    // 中断使能控制的值: 总线错误中断、发送中断、接收中断
#define    REG_OCR_DATA          0x1A    // 输出控制的值:

// 定义命令字
#define    TXD_ONE_CMD      0x03    // 产生一次报文发送,当错误时不再生发(单次发送)
#define    TXD_CMD          0x01    // 发送请求命令,当错误时可重发
#define    T_R_CMD          0x12    // 产生一次自接收性质的报文发送,发送错误时不会重发
#define    AT_CMD           0x02    // 中止发送命令
#define    RRB_CMD          0x04    // 释放接收缓冲区
#define    COS_CMD          0x08    // 数据溢出清除命令
unsigned char TransBuffer[13];
unsigned char RxBuffer[];
unsigned char *sja_address=(unsigned char *)startadd;

unsigned char read_sja(unsigned char addr)                                    //读SJA1000状态寄存器子程序
{
        sja_address=(unsigned char *)startadd;
        sja_address=sja_address+addr;
        return (*(sja_address));
}

void write_sja(unsigned char addr,unsigned char val)            //写SJA1000控制寄存器子程序
{
        sja_address=(unsigned char *)startadd;
        sja_address=sja_address+addr;
        *(sja_address)=val;
}


void SJA1000_init(void)            
{
    //CLI();
       
    write_sja(MODE,0x01);
        read_sja(IR);                                        //读取CAN的中断标识
        while(!(read_sja(MODE)&0x01))        //检测SJA1000是否达到复位工作模式
        {
           write_sja(MODE,0x01);                //进入复位工作模式
        }
        delay_us(5);                                     //延时约5us
        write_sja(CDR,0xC8);            //PeliCAN 模式,禁能CLOCKOUT引脚
        delay_us(5);                                     //延时约5us
        write_sja(BTR0,0x53);                 //设置时钟分频器,20k
        write_sja(BTR1,0x2F);                 
        write_sja(OCR,0x1a);                 //输出控制
        write_sja(RXERR,0x00);                       
        write_sja(TXERR,0x00);
        write_sja(ECC,0x00);
        write_sja(RBSA,0x00);                        //缓存器起始地址寄存器设置为0
       
        write_sja(ACR0,0x00);                 //acceptcode default ffffffff
        write_sja(ACR1,0x00);
        write_sja(ACR2,0x00);
        write_sja(ACR3,0x00);           //配置验收代码ACR3地址

        write_sja(AMR0,0xff);                          //acceptmask default ffffffff
        write_sja(AMR1,0xff);
        write_sja(AMR2,0xff);
        write_sja(AMR3,0xff);

        write_sja(IER,0x01);            //接收中断使能
        write_sja(CMR,0x0c);                          //清除数据溢出和释放接收缓冲器;
        do
        {
           write_sja(MODE,0x00);                 //设置SJA1000工作模式,双滤波接收工作模式
        }
        while((read_sja(MODE)&0x01));        //确认复位标志是否被删除                     
        //SEI();
}
void CanTransmit(void)
{
        unsigned char status;
        CLI();                                                          //关中断               
        TransBuffer[0]=0x88;               
        TransBuffer[1]=0x00;       
        TransBuffer[2]=0x00;       
        TransBuffer[3]=0x00;       
        TransBuffer[4]=0x00;       
        TransBuffer[5]=0x01;       
        TransBuffer[6]=0x02;       
        TransBuffer[7]=0x03;       
        TransBuffer[8]=0x04;       
        TransBuffer[9]=0x05;       
        TransBuffer[10]=0x06;       
        TransBuffer[11]=0x07;       
        TransBuffer[12]=0xaa;                                          
        while(!(read_sja(SR)&0x04));   //wait until reg2^2==1 ,即判断发送缓冲器的状态
        write_sja(TXD_FID,TransBuffer[0]);                   //扩展帧,数据长度为8个字节
        write_sja(TXD_ID1,TransBuffer[1]);
        write_sja(TXD_ID2,TransBuffer[2]);
        write_sja(TXD_ID3,TransBuffer[3]);
        write_sja(TXD_ID4,TransBuffer[4]);
        write_sja(TXBuffer1,TransBuffer[5]);
        write_sja(TXBuffer2,TransBuffer[6]);
        write_sja(TXBuffer3,TransBuffer[7]);
        write_sja(TXBuffer4,TransBuffer[8]);
        write_sja(TXBuffer5,TransBuffer[9]);
        write_sja(TXBuffer6,TransBuffer[10]);
        write_sja(TXBuffer7,TransBuffer[11]);
        write_sja(TXBuffer8,TransBuffer[12]);
        write_sja(CMR,0x01);                  //发送请求命令
        while(!(read_sja(SR) & 0x08));//检测SR.3位,判断发送是否完成
        SEI();                                                      //开中断
}
unsigned char Receive(void)
{
        unsigned char result=0;
        unsigned char status,number,sff,j;
        unsigned char mp=RXD_FID;
    status=read_sja(SR);
        if((status&0xc3)!=0)                    //读取总线脱离、错误状态、接收溢出、有数据等位
        {
                if((status&0x80)==0x80)
                {
                        write_sja(MODE,0x00);
                        return 0;
                }
                if((status&0x02)==0x02)
                {
                        write_sja(CMR,0x0c);
                        return 0;
                }
               
                if((status&0x01)==0x01)
                {
                        if((read_sja(RXD_FID)&0x40)==0x40)  //如果RTR=1,为远程帧
                        {
                                write_sja(CMR,0x04);                  //则释放FXFIFO
                        }
                        else                                                          //为0,则是数据帧
                        {
                                sff=read_sja(RXD_FID)&0x80;          //取第一个字节的最高位
                                number=(read_sja(RXD_FID)&0x0f);//取第一个字节的低四位,即数据长度
                                if ((sff&0x80)==0x80)                  //判断是标准帧还是扩展帧
                                number=number+5;                          //扩展帧,则帧的总长度加5(13字节)
                                else
                                number=number+3;                          //标准帧,则帧的总长度加3(11字节)
                                for(j=0;j<number;j++)                  //读取数据
                                {
                                        RxBuffer[j]=read_sja(RXD_FID);
                                        mp++;
                                }
                                result=1;                                        //读取到正确的数据则返回TRUE
                                write_sja(CMR,0x04);                  //最后释放FXFIFO
                        }
                }
        }
        return result;
}       
       
       
以上是“SJA1000.h”部分

出0入0汤圆

 楼主| 发表于 2009-12-8 23:10:06 | 显示全部楼层
基本上是修改这个帖子的程序。“http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=598348&bbs_page_no=1&search_mode=1&search_text=CAN调试成功,特上传资料与大家共享&bbs_id=1000”
下面是我整个的程序:
点击此处下载 ourdev_512166.rar(文件大小:42K) (原文件名:SJA1000.rar)

出0入0汤圆

 楼主| 发表于 2009-12-8 23:15:59 | 显示全部楼层
问题出现在SJA1000初始化子函数“void SJA1000_init(void) ”中的while查询语句:
while(!(read_sja(MODE)&0x01)) //检测SJA1000是否达到复位工作模式
{
   write_sja(MODE,0x01); //进入复位工作模式
}

这句话始终为真!请各位大侠帮忙看看哈,谢谢!!

出0入0汤圆

 楼主| 发表于 2009-12-9 16:44:28 | 显示全部楼层
大侠,知道的加我QQ:752791687

出0入0汤圆

发表于 2009-12-9 17:17:55 | 显示全部楼层
不能进入复位模式,
1.检查SJA1000的时钟,CLKOUT 有脉冲输出不?有时候换换晶振就好了。
2.CPU与SJA1000的连接线是否正常,遇到过cpu的数据线因为焊接原因,导致数据一直不正常;
3.读写SJA1000的寄存器,参考3楼的写法就行,和51的一样,前提:开M128的总线;

出0入0汤圆

发表于 2009-12-10 10:34:07 | 显示全部楼层
while(!(read_sja(MODE)&0x01)) //检测SJA1000是否达到复位工作模式

MODE的zui低位为1的时候,进入了复位模式。。((read_sja(MODE)&0x01))为1.

取反后为假,退出while语句,

正确啊,


还有问一下,你的自收发实验成功没?能否正确读出sja1000寄存器的值?

出0入0汤圆

 楼主| 发表于 2009-12-24 18:07:08 | 显示全部楼层
【回复】: erxun 老孟
  
  老孟大侠,请您看一下我上面的原理图是否有错?缺少16M晶振,我已经加上了。现在,我怀疑我的硬件有误!请您指点……

出0入0汤圆

发表于 2011-10-2 10:43:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-10-12 10:53:46 | 显示全部楼层
mark 好东西

出0入0汤圆

发表于 2012-10-23 15:58:58 | 显示全部楼层
楼主的现在好了没有?

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-7-23 10:25

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

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