STC89C52+SJA1000自收发程序记录

发布者:雅意盎然最新更新时间:2018-09-09 来源: eefocus关键字:STC89C52  SJA1000  自收发程序 手机看文章 扫描二维码
随时随地手机看文章

项目中需要使用到CAN控制器SJA1000芯片,使用的主控芯片是ARM9,但是在ARM9上怎么调试也不通,不得已,只好先测试下51系列的单片机上是否可以和此芯片协同工作,需要排除芯片的问题,但是发现当你不太了解一个新芯片的时候,若要操作该芯片,而你又没啥经验,是需要费很大的功夫的。所以把过程详细的记录下来,以备复习。关键还是得仔细看芯片数据手册。

使用到的芯片和资料详细列出如下:

1.      主控芯片(STC89C52RC),CAN控制器(SJA1000T),CAN收发器(PCA82C250)似乎PCA82C251更好些

2.      下载对应的芯片手册,以及SJA1000独立的CAN控制器应用指南.pdf。

 

部分电路图:



       其中需要注意的是复位单元设计,最好使用软件复位,我选择的是P2.6复位,另外SJA1000T的/INT端口需要添加上拉电阻,不然会恒为低。另外XTAL1和CLKOUT不连接,STC89C52由独立的11.592MHZ晶振提供频率,其他好像没啥需要特别注意的,只要按照电路图正确连接即可。下来就是编写测试代码。

过程主要参考应用指南,主要步骤如下:


  1. 设置串口工作模式,8n1

  2. 设置使用定时器1

  3. 设置工作方式2和波特率

  4. 启动定时器1,设置接收中断

  5. 设置外部中断优先级和中断方式(下降沿中断门)

  6. 使能全局和外部中断

  7. 复位SJA1000芯片,给引脚RST一个负脉冲。复位后默认是进入复位模式,但是最好还是确认芯片进入复位模式,然后输出提示信息,

  8. 设置时钟分配寄存器,主要是设置PeliCAN模式,接收RX0还是RX1中断

  9. 设置CLKOUT输出,设置验收码寄存器和验收屏蔽寄存器,这两个结合起来来过滤数据包,判断是否需要被本节点接收

  10. 配置总线定时器寄存器,设置发送频率和输出模式,确认进入自接收模式,发送数据

  11. 使用while循环等待中断到来,编译并下载到STC89C52芯片上,测试结果如下图所示:


                          


设计源码:


/*------------------------------------------------------------------------------

HELLO.C

Copyright 1995-2005 Keil Software, Inc.

------------------------------------------------------------------------------*/

 

#include                /* special function register declarations   */

                                  /* for the intended 8051 derivative         */

 

#include                /* prototype declarations for I/O functions */

#include "sja1000_reg.h"    /* sja1000T的寄存器定义文件*/

#include  /* 主要是用于寻址外部存储器*/

 

sbit SJARst = P2 ^ 6; //复位控制                                     

        

/*------------------------------------------------

The main C function.  Program execution starts

here after stack initialization.

------------------------------------------------*/

void main (void) {

 

/*------------------------------------------------

Setup the serial port for 9600 baud at 11.0592MHz.

------------------------------------------------*/

#ifndef MONITOR51

    SCON  = 0x50;        /* SCON: mode 1, 8-bit UART, enable rcvr      */

    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */

    TH1   = 0xFD;                /* TH1:  reload value for 9600 baud @ 11.0595MHZ   */

    TR1   = 1;                  /* TR1:  timer 1 run                          */

    TI    = 1;                  /* TI:   set TI to send first char of UART    */

#endif

PX0=1;                                          //外部中断0高优先级

  IT0=1;                                          //设置INT0为下降沿中断

  EX0=1;                                          //使能INT0中断

 

/*------------------------------------------------

Note that an embedded program never exits (because

there is no operating system to return to).  It

must loop and execute forever.

------------------------------------------------*/

 

   

    printf ("Hello World\n");   /* Print "Hello World" */

SJA_Init();//主要是使芯片复位

/*

Enter the reset Mode

*/

REG_MODE = 0x01; 

while((REG_MODE&0x01)!= 0x01); //确定进入复位模式 

printf("1.Enter the Reset Mode,REG_MODE=0x%.4x\n",REG_MODE);

              

REG_CDR = 0xc8;//设置时钟分频寄存器。CDR.7 = 1,PeliCAN模式;CDR.6(RX0激活,关闭RX1)  fCLKOUT = fOSC/2, CDR.3(Close the CLKOUT)

REG_RBSA = 0x00;//RX缓冲器起始地址    

                   

/*Configure acceptance code and mask register*/                                             

REG_ACR0 = 0xff;//验收码寄存器                       

    REG_ACR1 = 0xff;                            

REG_ACR2 = 0xff;                            

REG_ACR3 = 0xff;                            

                                            

REG_AMR0 = 0xff;//验收屏蔽寄存器,接收任何标识符的数据包         

REG_AMR1 = 0xff;                            

REG_AMR2 = 0xff;                            

REG_AMR3 = 0xff;    

                       

 

/*configure bus timing registers*/

REG_BTR0 = 0x00;                            

REG_BTR1 = 0x14; //100k     

                                   

REG_IR_ABLE = 0x01;//Peli模式中断使能,接收中断使能,发送中断禁止                  

    

REG_OCR = 0x1a;//设置输出模式:正常输出,从TX0口输出;TX1悬空

                                     

REG_MODE = 0x0c; //进入自接收模式.CDR.3(选择单个验收滤波器),CDR.2 (此模式可以检测所有节点)

 

while(REG_MODE != 0x0c);//确定进入自接收模式下

printf("2.Enter the self-test Mode\n",REG_MODE);

 

SJA1000_TxData();//发送数据

printf("\n\n");

//SJA1000_Rx_Display();//接收数据展示

EA = 1;//使能全局中断

while(1);

}

 

 

void SJA1000_TxData(void)

{

while(REG_SR & 0x10);//当SJA1000不处于接收状态时才可继续执行,SR.4==0x1,正在接收,等待

    while(!(REG_SR & 0x08)); //SR.3=0,发送请求未处理完,等待直到SR.3=1

    while(!(REG_SR & 0x04)); //SR.2=0,发送缓冲器被锁。等待直到SR.2=1   

REG_TxBuffer0 = 0x08;//帧信息,标准帧,数据帧,8字节        

                                                          

REG_TxBuffer1 = 0xFF;//标识符1                             

REG_TxBuffer2 = 0xFF;//标识符2                     

                                                

REG_TxBuffer3 = 0x11;//发送数据位:1                       

REG_TxBuffer4 = 0x22;//发送数据位:2                       

REG_TxBuffer5 = 0x33;                                      

REG_TxBuffer6 = 0x44;                                      

REG_TxBuffer7 = 0x55;                                      

REG_TxBuffer8 = 0x66;                                      

REG_TxBuffer9 = 0x77;                                      

REG_TxBuffer10 = 0x88;//here Over                          

                             

  SJA1000_Tx_Display();

REG_CMD = 0x10;//自接收

while(!(REG_SR & 0x08));//检测发送完毕

}

/************************************************************

函数:ex0_int 

说明:中断服务程序

入口:无

返回:无

***********************************************************/

void handle_int(void) interrupt 0 using 1

{

  if(REG_IR & 0x01)      //产生了接收中断

  { 

  #pragma disable

printf( " Received message.\n");

printf( " RBSR3 = %x \n", REG_RxBuffer3 );

printf( " RBSR4 = %x \n", REG_RxBuffer4 );

printf( " RBSR5 = %x \n", REG_RxBuffer5 );     

printf( " RBSR6 = %x \n", REG_RxBuffer6 );     

printf( " RBSR7 = %x \n", REG_RxBuffer7 );     

  printf( " RBSR8 = %x \n", REG_RxBuffer8 );     

printf( " RBSR9 = %x \n", REG_RxBuffer9 );     

printf( " RBSR10 = %x \n",REG_RxBuffer10);   

 

  }  

}

void SJA1000_Tx_Display(void)

{

printf( " TBSR3 = 0x%.4x \n", REG_TxBufferRd3 );  

printf( " TBSR4 = 0x%.4x \n", REG_TxBufferRd4 );  

printf( " TBSR5 = 0x%.4x \n", REG_TxBufferRd5 );  

printf( " TBSR6 = 0x%.4x \n", REG_TxBufferRd6 );  

printf( " TBSR7 = 0x%.4x \n", REG_TxBufferRd7 );  

printf( " TBSR8 = 0x%.4x \n", REG_TxBufferRd8 );  

printf( " TBSR9 = 0x%.4x \n", REG_TxBufferRd9 );  

printf( " TBSR10 = 0x%.4x \n",REG_TxBufferRd10);  

}/*显示发送的信息,之前直接使用发送缓冲区,这种方法是错误的,因为0x10开始的13个寄存器,读的时候是接收缓冲区,写的时候是发送缓冲区*/

 

void SJA_Init(void)                          

{    

//SJA1000复位                                        

unsigned char i;                            

for(i = 0;i < 125;i++);           

SJARst = 0;                                 

for(i = 0;i < 125;i++);//给RST引脚一个低脉冲

SJARst = 1;                                 

for(i = 0;i < 125;i++);                     

}                          


sja1000_reg.h定义:



/*

SJA1000的寄存器有关控制

*/

#ifndef SJA1000_H

#define SJA1000_H

/*指定SJA1000的起始地址为0x7800*/

#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_RxBuffer5 XBYTE[SJA_REG_BaseADD + 0x15]                

#define REG_RxBuffer6 XBYTE[SJA_REG_BaseADD + 0x16]                

#define REG_RxBuffer7 XBYTE[SJA_REG_BaseADD + 0x17]                

#define REG_RxBuffer8 XBYTE[SJA_REG_BaseADD + 0x18]                

#define REG_RxBuffer9 XBYTE[SJA_REG_BaseADD + 0x19]                

#define REG_RxBuffer10 XBYTE[SJA_REG_BaseADD + 0x1a]                

#define REG_RxBuffer11 XBYTE[SJA_REG_BaseADD + 0x1b]                

#define REG_RxBuffer12 XBYTE[SJA_REG_BaseADD + 0x1c]  

 

 /*发送缓冲区*/                                                       

#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_TxBuffer5 XBYTE[SJA_REG_BaseADD + 0x15]                

#define REG_TxBuffer6 XBYTE[SJA_REG_BaseADD + 0x16]                

#define REG_TxBuffer7 XBYTE[SJA_REG_BaseADD + 0x17]                

#define REG_TxBuffer8 XBYTE[SJA_REG_BaseADD + 0x18]                

#define REG_TxBuffer9 XBYTE[SJA_REG_BaseADD + 0x19]                

#define REG_TxBuffer10 XBYTE[SJA_REG_BaseADD + 0x1a]                

#define REG_TxBuffer11 XBYTE[SJA_REG_BaseADD + 0x1b]                

#define REG_TxBuffer12 XBYTE[SJA_REG_BaseADD + 0x1c] 

#define REG_TxBufferRd0 XBYTE[SJA_REG_BaseADD + 0x60]                  

#define REG_TxBufferRd1 XBYTE[SJA_REG_BaseADD + 0x61]                  

#define REG_TxBufferRd2 XBYTE[SJA_REG_BaseADD + 0x62]                  

#define REG_TxBufferRd3 XBYTE[SJA_REG_BaseADD + 0x63]                  

#define REG_TxBufferRd4 XBYTE[SJA_REG_BaseADD + 0x64]                                                                               

#define REG_TxBufferRd5 XBYTE[SJA_REG_BaseADD + 0x65]                

#define REG_TxBufferRd6 XBYTE[SJA_REG_BaseADD + 0x66]                

#define REG_TxBufferRd7 XBYTE[SJA_REG_BaseADD + 0x67]                

#define REG_TxBufferRd8 XBYTE[SJA_REG_BaseADD + 0x68]                

#define REG_TxBufferRd9 XBYTE[SJA_REG_BaseADD + 0x69]                

#define REG_TxBufferRd10 XBYTE[SJA_REG_BaseADD + 0x6a]                

#define REG_TxBufferRd11 XBYTE[SJA_REG_BaseADD + 0x6b]                

#define REG_TxBufferRd12 XBYTE[SJA_REG_BaseADD + 0x6c]  


关键字:STC89C52  SJA1000  自收发程序 引用地址:STC89C52+SJA1000自收发程序记录

上一篇:基于51单片机SJA1000 CAN通讯实现
下一篇:12864液晶显示原理(C程序)

推荐阅读最新更新时间:2024-03-16 16:13

SJA1000硬件电路设计
  首先对CAN总线控制器SJA1000的管脚我们必须熟悉。下面是其各个管脚的功能参数。       各个管脚的符号功能什么的上面的表里介绍的很详细,我就不多废话了。   接着我们看SJA1000的这些管脚在实际电路中是怎么进行连接的,因为只谈SJA1000的硬件电路设计,所以就截一张PIAE提供的电路原理图里关于SJA1000的部分。        下面我们要具体解析这个电路图。   AD0-AD7是地址/数据复用总线。因为这个电路是把SJA1000做外部RAM扩展了,所以它的电路连接也势必要符合外部RAM的连接要求。(特权同学也是第一次接触单片机的外部存储器扩展应用,所以开始的时候
[嵌入式]
基于STC89c52单片机实现8*8led心跳效果
#include reg51.h //此文件中定义了单片机的一些特殊功能寄存器 #include intrins.h typedef unsigned int u16; //对数据类型进行声明定义 typedef unsigned char u8; sbit SRCLK=P3^6; //使用hc595芯片 sbit RCLK=P3^5; //使用hc595芯片 sbit SER=P3^4; //使用hc595芯片 u8 ledduan ={0x00,0x18,0x3c,0x1e,0x1e,0x3c,0x18,0x00}; //小心型 u8 ledwei ={0x7f,0xbf,0xdf,0xef,0xf7
[单片机]
STC89C52单片机继电器实验
///////////////////////////////////////////////////////////////////////// 实现功能:打开实验板上的蜂鸣,响0.3秒,然后关闭0.3秒,然后依次这样循环, 同时在实验板上继电器旁边的发光二极管也会跟随继电器不停地闪烁 实验板型号:KBL-XYD-C52 实验名称: 继电器实验 编写人: 谢应东 编写日期: 2012-4-25 ///////////////////////////////////////////////////////////////////////// #include reg52.h
[单片机]
CAN总线分布式系统适配卡和控制单元设计
    1 CAN总线分布式系统的结构       系统结构如图1所示。本系统由上位监控计算机、CAN总线适配卡和控制单元三部分构成。其中上位监控计算机采用IBM-PC兼容机,主要负责对系统数据的接收与管理、控制命令的发送以及各控制单元动态参数和设备状态实时显示。控制单元以单片机为核心,主要负责对现场环境参数和设备状态进行检测,对采集来的数据进行处理,并对SJA1000进行操作和控制。CAN总线适配卡,可使PC机方便地连接到CAN总线上。它内嵌微处理器、CAN总线控制器、CAN总线收发器和双口RAM。双口RAM作为PC机与CAN总线适配卡的数据共享区,通过设备将其映射成PC机的物理内存,实现CAN与PC机的高速数据交换。C
[嵌入式]
SHARC DSP与SJA1000的CAN总线接口设计
   引言   当前,有一些微处理器将CAN控制器嵌入到系统之中,但是仍有大量人们比较熟悉的微处理器并不带有CAN控制器。采用微处理器和CAN控制器组合的设计成为必要,而且,CAN控制器具有完成CAN总线通信协议所要求的全部必要功能,因此,CAN控制器与其它微处理器的接口设计成为设计CAN总线系统的首要工作。本文重点介绍以SHARC DSP为核心的、基于SJA1000的CAN总线接口设计。 图1 SJA1000和CAN总线的连接 图2 ADSP21062和SJA1000的简化设计图 图3 基于CPLD的ADSP21062和SJA1000设计图 图4 CPLD的逻辑图 SJA1000简介   SJA1000
[应用]
STC89C52之中断系统 ---- 51单片机的核心 自学笔记
一、中断系统 1.1、概念 cpu在处理某一事件A时,发生了另外一事件B请求cpu迅速去处理(中断发生); cup暂时中断当前的工作,转去处理事件B(中断响应和中断服务); 待cup将事件B处理完毕后,再回到原来事件A被中断的地方继续处理事件A(中断返回); 这一过程称为中断。 引起CPU中断的根源,称为中断源。中断源向CPU提出的中断请求。cup暂时中断原来的事务A,转去处理事件B。对事件B 处理完毕后,再回到原来被中断的地方(即:断点)称为中断返回,实现上述中断功能的部件称为中断系统。 1.2、中断系统的功能与优点 解决了快速主机与慢速i/o设备的数据传送问题。 分时操作:cpu可以为多个io设备服务,
[单片机]
<font color='red'>STC89C52</font>之中断系统 ---- 51单片机的核心 自学笔记
8051单片机实战分析(以STC89C52RC为例) | 04 - 蜂鸣器驱动
蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此需要一定的电流才能驱动它,单片机IO引脚输出的电流较小,单片机输出的TTL电平基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路。三极管的作用为驱动,通过三极管放大驱动电流,从而可以让蜂鸣器发出声音。 有源蜂鸣器和无源蜂鸣器的区别: 这里的“源”不是指电源。而是指震荡源。 也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。 而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。 有源蜂鸣器往往比无源的贵,就是因为里面多个震荡电路。 有源蜂鸣器示意图: 无源蜂鸣器示意图: 无源蜂鸣器的优点是:
[单片机]
8051单片机实战分析(以<font color='red'>STC89C52</font>RC为例) | 04 - 蜂鸣器驱动
STC89C52单片机的定时器使用
//////////////////////////////////////////////////////////////////////// 实现功能: 配置定时器2的相关寄存器,使其实现定时器中断功能,然后根据中断 的周期频率实现准确的时钟系统,在数码管上显示实现 实验板型号:BS-XYD-C52 实验名称: 定时器2实现时钟系统 编写人: 谢应东 编写日期: 2012-4-28 ///////////////////////////////////////////////////////////////////////// #include reg52.h #def
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved