手把手教你学CAN总线学习笔记-SJA1000+STC89C52(二)(2024年2月2日)

博主在SJA1000+STC89C52硬件电路上进行自收发开发,原计划用开发板和TJA1050模块实现,未成功后改用CAN开发板。期间参考吴坚鸿大神源码,修改程序后出现显示问题,发的数字和收的数字差值改变,博主对此现象原因存疑。

断断续续,零星学习这个

首先,在SJA1000+STC89C52硬件电路上,来回折腾近好久

本来是想着开发板+TJA1050模块,用杜邦线链接,先实现自收发。

结果死活不会自收发,没办法,只能去掏了2块CAN开发板.

总算有点进度,记录如下:

(1-期间,重新拜读了吴坚鸿大神的源码,并且使用了相关按键和数码管部分的源码)

出现了一直很神奇的现象,不知道缘由,待高手路过指点一下

我先说下现象情况

 原来单片机开发板程序 显示的数字相同, 改了之后,显示收的数字比发大了1。
一步步的替换也试过,按键部分替换后正常,就是替换到数码管部分:

按第一下后,发的数字是1 ,收的数字还是0,再按一后,发的数字是2,收的数字成了1,

(原先是:按一下后,发的数字是1,收的数字也是1.)

首先是源程序

/*************************************************
*功能: CEPARK CAN开发板-CAN自收发实验
*说明:数码管从右到左分别是1~4位。
*      数码管1、2位显示发送的数据,3、4位显示接收到的数据。
*      每按一次中断按键发送数据值增一。
*芯片:STC89C52RC
*跳线:无

****************************************************/ 
#include <reg52.h>
#include "sjapelican.h"
#include "config.h"

//INT0按键为计数按键
void INT0_Data(void) interrupt 0
{
    EA = 0;
    Txd_data++; //存储计数结果,并为待发送的数据
	Peli_TXD();
    EA = 1;
}
//接收数据函数,在中断服务程序中调用
void Peli_RXD(void) interrupt 2
{

    uint8 data Status;
    EA = 0;//关CPU中断

    Status = SJA_IR;
    if(Status & RI_BIT)
    {//IR.0 = 1 接收中断
        RX_buffer[0] =  SJA_RBSR0;
        RX_buffer[1] =  SJA_RBSR1;
        RX_buffer[2] =  SJA_RBSR2;
        RX_buffer[3] =  SJA_RBSR3;
        RX_buffer[4] =  SJA_RBSR4;
        RX_buffer[5] =  SJA_RBSR5;
        RX_buffer[6] =  SJA_RBSR6;
        RX_buffer[7] =  SJA_RBSR7;
        RX_buffer[8] =  SJA_RBSR8;
        RX_buffer[9] =  SJA_RBSR9;
        RX_buffer[10] =  SJA_RBSR10;
        RX_buffer[11] =  SJA_RBSR11;
        RX_buffer[12] =  SJA_RBSR12;

        SJA_CMR = RRB_BIT;
        Status = SJA_ALC;//释放仲裁随时捕捉寄存器
        Status = SJA_ECC;//释放错误代码捕捉寄存器
    }
    SJA_IER = RIE_BIT;// .0=1--接收中断使能;

	Rxd_data = RX_buffer[5];

    EA = 1;//打开CPU中断
}
//CPU初始化
void MCU_Init(void)
{
	
	SJA_RST = 0;//SJA1000复位有效
	mDelay(10);	//延时
    SJA_RST = 1;//CAN总线复位管脚,复位无效
    SJA_CS = 0;//CAN总线片选有效
    EX1 = 1;//外部中断1使能;CAN总线接收中断
    IT1 = 0;//CAN总线接收中断,低电平触发
    IT0 = 1;//外部中断0负边沿触发
    EX0 = 1;//打开外部中断0
    EA = 1; //打开总中断
}
//主函数
void main(void)
{
	MCU_Init();
    Peli_Init();
 //   mDelay(1);
    while(1)	 LED_Disp_Seg7();  //数码管显示函数
}

//SJA1000 的初始化
void Peli_Init(void)
{
    uint8 bdata Status;
    do
    {//  .0=1---reset MODRe,进入复位模式,以便设置相应的寄存器
     //防止未进入复位模式,重复写入
     	SJA_MOD = RM_BIT |AFM_BIT;
		Status = SJA_MOD ;
    }
    while(!(Status & RM_BIT));

    SJA_CDR  = CANMode_BIT|CLKOff_BIT;// CDR.3=1--时钟关闭, .7=0---basic CAN, .7=1---Peli CAN	   时钟分频
    SJA_BTR0 = 0x03;
    SJA_BTR1 = 0x1c;//16M晶振,波特率125Kbps
    SJA_IER  = RIE_BIT;// .0=1--接收中断使能;  .1=0--关闭发送中断使能
    SJA_OCR  = NormalMode|Tx0PullDn|OCPOL1_BIT|Tx1PullUp;// 配置输出控制寄存器
    SJA_CMR  = RRB_BIT;//释放接收缓冲器

    SJA_ACR0  = 0x11;
    SJA_ACR1  = 0x22;
    SJA_ACR2  = 0x33;
    SJA_ACR3  = 0x44;//初始化标示码	 验收代码寄存器

    SJA_AMR0  = 0xff;
    SJA_AMR1  = 0xff;
    SJA_AMR2  = 0xff;
    SJA_AMR3  = 0xff;//初始化掩码  验收屏蔽寄存器

    do	//确保进入自接收模式
    {	
	SJA_MOD   = STM_BIT;
	Status  = SJA_MOD;
     }
    while( !(Status & STM_BIT) );

}

//发送数据函数
void Peli_TXD( void )
{
    uint8 data Status;
//初始化标示码头信息
    TX_buffer[0] = 0x88;//.7=0扩展帧;.6=0数据帧; .3=1数据长度
    TX_buffer[1] = 0x01;//本节点地址
    TX_buffer[2] = 0x02;//
    TX_buffer[3] = 0x03;//
    TX_buffer[4] = 0x04;//

//初始化发送数据单元
    TX_buffer[5]  = Txd_data;
    TX_buffer[6]  = 0x22;
    TX_buffer[7]  = 0x33;
    TX_buffer[8]  = 0x44;//
    TX_buffer[9]  = 0x55;//
    TX_buffer[10] = 0x66;//
    TX_buffer[11] = 0x77;//
    TX_buffer[12] = 0x88;//

    do
    {
        Status = SJA_SR;
				LED_RED = 0;
    }
    while( Status & RS_BIT);  //SR.4=1 正在接收,等待
    
    do
    {
        Status = SJA_SR;
				LED_RED = 0;
    }
    while(!(Status & TCS_BIT)); //SR.3=0,发送请求未处理完,等待

    do
    {
        Status = SJA_SR;
				LED_RED = 0;
    }
    while(!(Status & TBS_BIT)); //SR.2=0,发送缓冲器被锁。等待
		
		LED_RED = !LED_RED;
		LED_GER = !LED_GER;

    SJA_TBSR0  = TX_buffer[0];
    SJA_TBSR1  = TX_buffer[1];
    SJA_TBSR2  = TX_buffer[2];
    SJA_TBSR3  = TX_buffer[3];
    SJA_TBSR4  = TX_buffer[4];
    SJA_TBSR5  = TX_buffer[5];
    SJA_TBSR6  = TX_buffer[6];
    SJA_TBSR7  = TX_buffer[7];
    SJA_TBSR8  = TX_buffer[8];
    SJA_TBSR9  = TX_buffer[9];
    SJA_TBSR10 = TX_buffer[10];
    SJA_TBSR11 = TX_buffer[11];
    SJA_TBSR12  = TX_buffer[12];

    SJA_CMR = SRR_BIT;//置位自发送接收请求
}
//延时函数
void mDelay(uint16 mtime)
{
	for(; mtime > 0; mtime--)
	{
		uint8 j = 244;
		while(--j);
	}
}
//数码管显示函数
void LED_Disp_Seg7()
{
   LedCtrl = LedCtrl | 0xf0;

   DisBuff[0]   = Txd_data%10;//取个位数
   DisBuff[1]   = Txd_data%100/10; //取十位数
   DisBuff[2]   = Rxd_data%10;	   //百位数
   DisBuff[3]   = Rxd_data%100/10; //千位数
  
   LedPort = LED_Disp[DisBuff[0]];
   LedCtrl = LedCtrl & 0x7f;
   mDelay(5);
   LedCtrl = LedCtrl | 0xf0;

   LedPort = LED_Disp[DisBuff[1]];
   LedCtrl = LedCtrl & 0xbf;
   mDelay(5);
   LedCtrl = LedCtrl | 0xf0;

   LedPort = LED_Disp[DisBuff[2]];
   LedCtrl = LedCtrl & 0xdf;
   mDelay(5);
   LedCtrl = LedCtrl | 0xf0;

   LedPort = LED_Disp[DisBuff[3]];
   LedCtrl = LedCtrl & 0xef;
   mDelay(5);
   LedCtrl = LedCtrl | 0xf0;
}

#ifndef __CONFIG_H__
#define __CONFIG_H__

#define Fclk      11059200UL		 /*使用11.0592M晶体*/
#define BAUD      9600UL		     /*波特率定义为9600*/

#define uint8    unsigned char
#define uint16   unsigned short int
#define uint32   unsigned long int
#define int8     signed char
#define int16    signed short int
#define int32    signed long int
#define uint64   unsigned long long int
#define int64    signed long long int

#endif
#ifndef __SJAPELICAN_H__
#define __SJAPELICAN_H__
#include <absacc.h>
#include "config.h"

//数码管段码显示:0~f,不亮
uint8 code LED_Disp[] = 
{
		0xC0,//0
		0xF9,//1
		0xA4,//2
		0xB0,//3
	  0x99,//4
		0x92,//5
		0x82,//6
		0xF8,//7
	  0x80,//8
		0x90,//9
		0x88,//10-a
		0x83,//11-b
	  0xC6,//12-c
	  0xA1,//13-d
	  0x86,//14-e
	  0x8E //15-f
};

//sfr LedPort = 0x80;	 //段选段P0
//sfr LedCtrl = 0xa0;	 //位选段P2

#define  LedPort  P0   //段选段P0  ---   要显示的数字
#define  LedCtrl  P2    //段选段P2  ---  选择那个数码管

uint8 DisBuff[4];

#define     FrameNum      13//一帧字节数

uint8       RX_buffer[FrameNum];  //接收的数据
uint8       TX_buffer[FrameNum];  //接收的数据
uint8       Txd_data = 0;//CAN总线要发送的数据,也是要在数码管1-2位置显示的数据
uint8       Rxd_data = 0;//CAN总线要接收的数据,也是要在数码管3-4位置显示的数据


sbit SJA_RST = P2^3;//SJA1000复位管脚
sbit SJA_CS  = P2^0;//SJA1000片选管脚

sbit LED_RED=P1^0;  
sbit LED_GER=P1^1;  
						
void MCU_Init(void);  //CPU初始化
void Peli_Init(void); // 初始化CAN总线芯片
void Peli_TXD(void);//CAN发送子函数
void mDelay(uint16 mtime);//延时子函数
void LED_Disp_Seg7();//显示子函数


#define SJA_BASE_ADR     0xfe00	 //寄存器地址的基址

//SJA1000寄存器地址定义,作用在Peli模式,扩展帧方式
/**********************
模式控制寄存器及其位定义
************************/
#define SJA_MOD   XBYTE[SJA_BASE_ADR + 0x00]

#define RM_BIT     0x01  //复位模式请求位
#define LOM_BIT    0x02  //只听模式位
#define STM_BIT    0x04  //自检模式位
#define AFM_BIT    0x08  //验收滤波器模式位
#define SM_BIT     0x10  //睡眠模式位

/**********************
命令寄存器及其位定义
************************/
#define SJA_CMR    XBYTE[SJA_BASE_ADR + 0x01]
#define TR_BIT         0x01       //发送请求位
#define AT_BIT         0x02        //中止发送位
#define RRB_BIT        0x04        //释放接收缓冲器位
#define CDO_BIT        0x08        //清除数据溢出位
#define SRR_BIT        0x10        //自身接收请求位

/**********************
状态寄存器及其位定义
************************/
#define SJA_SR     XBYTE[SJA_BASE_ADR + 0x02]
#define RBS_BIT           0x01                    //接收缓冲器状态位
#define DOS_BIT           0x02                     //数据溢出状态位
#define TBS_BIT           0x04                      //发送缓冲器状态位
#define TCS_BIT           0x08                      //发送完成状态位
#define RS_BIT            0x10                    //接收状态位
#define TS_BIT            0x20                     //发送状态位
#define ES_BIT            0x40                   //错误状态位
#define BS_BIT            0x80                    //总线状态位

/**********************
中断寄存器及其位定义
************************/
#define SJA_IR     XBYTE[SJA_BASE_ADR + 0x03]
#define RI_BIT            0x01                     //接收中断位
#define TI_BIT            0x02                      //发送中断位
#define EI_BIT            0x04                      //错误警告中断位
#define DOI_BIT           0x08                     //数据溢出中断位
#define WUI_BIT           0x10                      //唤醒中断位
#define EPI_BIT           0x20                      //错误消极中断位
#define ALI_BIT           0x40                     //仲裁丢失中断位
#define BEI_BIT           0x80                    //总线错误中断位

/**********************
中断使能寄存器及其位定义
************************/
#define SJA_IER    XBYTE[SJA_BASE_ADR + 0x04]
#define RIE_BIT           0x01                     //接收中断使能位
#define TIE_BIT           0x02                      //发送中断使能位
#define EIE_BIT           0x04                      //错误警告中断使能位
#define DOIE_BIT          0x08                      //数据溢出中断使能位
#define WUIE_BIT          0x10                      //唤醒中断使能位
#define EPIE_BIT          0x20                      //错误消极中断使能位
#define ALIE_BIT          0x40                      //仲裁丢失中断使能位
#define BEIE_BIT          0x80                     //总线错误中断使能位


#define SJA_BTR0   XBYTE[SJA_BASE_ADR + 0x06]	  //总线定时器0寄存器
#define SJA_BTR1   XBYTE[SJA_BASE_ADR + 0x07]	  //总线定时器1寄存器
#define SAM_BIT           0x80               //采样模式位;0==总线被采样1次;1== 总线被采样3次

/**********************
输出控制寄存器及其位定义
************************/
#define SJA_OCR    XBYTE[SJA_BASE_ADR + 0x08]
           /*OCMODE1 ,OCMODE0 */
#define BiPhaseMode       0x00                      //双相输出模式
#define NormalMode        0x02                  //正常输出模式
#define ClkOutMode        (0x01|0x02)       //时钟输出模式
           /*TX1 的输出管脚配置*/
#define OCPOL1_BIT        0x20                  //输出极性控制位
#define Tx1Float          0x00                      //配置为悬空
#define Tx1PullDn         0x40            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

属鼠的金牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值