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

断断续续,零星学习这个

首先,在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                  //配置为下拉
#define Tx1PullUp         0x80                 //配置为上拉
#define Tx1PshPull        (0x40|0x80)       //配置为推挽
            /*TX0 的输出管脚配置*/
#define OCPOL0_BIT        0x04                      //输出极性控制位
#define Tx0Float          0x00                      //配置为悬空
#define Tx0PullDn         0x08                      //配置为下拉
#define Tx0PullUp         0x10                      //配置为上拉
#define Tx0PshPull        (0x10|0x08)                    //配置为推挽

#define SJA_TEST   XBYTE[SJA_BASE_ADR + 0x09]         //测试寄存器

/********************************
 * #define SJA_10   XBYTE[SJA_BASE_ADR + 0x0a]   寄存器功能保留
 ********************************/

/**********************
其他寄存器及其位定义
************************/
#define SJA_ALC      XBYTE[SJA_BASE_ADR + 0x0b]		//仲裁丢失捕捉寄存器
#define SJA_ECC      XBYTE[SJA_BASE_ADR + 0x0c]		//错误捕捉寄存器
#define SJA_EWLR     XBYTE[SJA_BASE_ADR + 0x0d]		//错误报警限制寄存器
#define SJA_RXERR    XBYTE[SJA_BASE_ADR + 0x0e]		//RX 错误计数器寄存器
#define SJA_TXERR    XBYTE[SJA_BASE_ADR + 0x0f]		//TX 错误计数器寄存器

/**********************
验收滤波器寄存器及其位定义
************************/
#define SJA_ACR0     XBYTE[SJA_BASE_ADR + 0x10]		//验收代码0寄存器
#define SJA_ACR1     XBYTE[SJA_BASE_ADR + 0x11]		//验收代码1寄存器
#define SJA_ACR2     XBYTE[SJA_BASE_ADR + 0x12]		//验收代码2寄存器
#define SJA_ACR3     XBYTE[SJA_BASE_ADR + 0x13]		//验收代码3寄存器

#define SJA_AMR0     XBYTE[SJA_BASE_ADR + 0x14]		//验收屏蔽0寄存器
#define SJA_AMR1     XBYTE[SJA_BASE_ADR + 0x15]		//验收屏蔽1寄存器
#define SJA_AMR2     XBYTE[SJA_BASE_ADR + 0x16]		//验收屏蔽2寄存器
#define SJA_AMR3     XBYTE[SJA_BASE_ADR + 0x17]		//验收屏蔽3寄存器

/**********************
TX缓冲器地址定义
************************/
#define SJA_TBSR0    XBYTE[SJA_BASE_ADR + 0x10]
#define SJA_TBSR1    XBYTE[SJA_BASE_ADR + 0x11]
#define SJA_TBSR2    XBYTE[SJA_BASE_ADR + 0x12]
#define SJA_TBSR3    XBYTE[SJA_BASE_ADR + 0x13]
#define SJA_TBSR4    XBYTE[SJA_BASE_ADR + 0x14]
#define SJA_TBSR5    XBYTE[SJA_BASE_ADR + 0x15]
#define SJA_TBSR6    XBYTE[SJA_BASE_ADR + 0x16]
#define SJA_TBSR7    XBYTE[SJA_BASE_ADR + 0x17]
#define SJA_TBSR8    XBYTE[SJA_BASE_ADR + 0x18]
#define SJA_TBSR9    XBYTE[SJA_BASE_ADR + 0x19]
#define SJA_TBSR10   XBYTE[SJA_BASE_ADR + 0x1a]
#define SJA_TBSR11   XBYTE[SJA_BASE_ADR + 0x1b]
#define SJA_TBSR12   XBYTE[SJA_BASE_ADR + 0x1c]

/**********************
RX缓冲器地址定义
************************/
#define SJA_RBSR0    XBYTE[SJA_BASE_ADR + 0x10]
#define SJA_RBSR1    XBYTE[SJA_BASE_ADR + 0x11]
#define SJA_RBSR2    XBYTE[SJA_BASE_ADR + 0x12]
#define SJA_RBSR3    XBYTE[SJA_BASE_ADR + 0x13]
#define SJA_RBSR4    XBYTE[SJA_BASE_ADR + 0x14]
#define SJA_RBSR5    XBYTE[SJA_BASE_ADR + 0x15]
#define SJA_RBSR6    XBYTE[SJA_BASE_ADR + 0x16]
#define SJA_RBSR7    XBYTE[SJA_BASE_ADR + 0x17]
#define SJA_RBSR8    XBYTE[SJA_BASE_ADR + 0x18]
#define SJA_RBSR9    XBYTE[SJA_BASE_ADR + 0x19]
#define SJA_RBSR10   XBYTE[SJA_BASE_ADR + 0x1a]
#define SJA_RBSR11   XBYTE[SJA_BASE_ADR + 0x1b]
#define SJA_RBSR12   XBYTE[SJA_BASE_ADR + 0x1c]

#define SJA_RMC      XBYTE[SJA_BASE_ADR + 0x1d]           //RX 信息计数器 寄存器
#define SJA_RBSA     XBYTE[SJA_BASE_ADR + 0x1e]            //RX 缓冲区起始地址 寄存器

/**********************
时钟分频寄存器地址定义
************************/
#define SJA_CDR       XBYTE[SJA_BASE_ADR + 0x1f]		 //时钟分频 寄存器
#define CLKOff_BIT        0x08                     //时钟关闭位,时钟输出管脚控制位
#define RXINTEN_BIT       0x20                      //用于接收中断的管脚TX1
#define CBP_BIT           0x40                      //CAN 比较器旁路控制位
#define CANMode_BIT       0x80                     //CAN 模式控制位

#endif



然后是我移植修改的代码(我把两个.H 都放在一起了)

/*********************************文件注释*******************************
  * @project(项目)			
  xxx
  
  * @file(文件名)       	 	
  main.c 
  
  * @Description(说明)    	
  	实现功能:
  	一共有4个窗口。每个窗口显示一个参数。
		第8,7,6,5位数码管显示当前窗口,P-1代表第1个窗口,P-2代表第2个窗口,P-3代表第3个窗口,P-4代表第1个窗口。
		第4,3,2,1位数码管显示当前窗口被设置的参数。范围是从0到9999。
		有三个按键。
		一个是加按键,按下此按键会依次增加当前窗口的参数。
		一个是减按键,按下此按键会依次减少当前窗口的参数。
		一个是切换窗口按键,按下此按键会依次循环切换不同的窗口。
		并且要求被设置的数据不显示为0的高位。
		比如参数是12时,不能显示“0012”,只能第4,3位不显示,第2,1位显示“12”。
		
		功能: CEPARK CAN开发板-CAN自收发实验
		*说明:数码管从右到左分别是1~4位。
		*      数码管1、2位显示发送的数据,3、4位显示接收到的数据。
		*      每按一次中断按键发送数据值增一。
*芯片:STC89C52RC

  * @author(作者)      		
  qw
  
  * @version(版本号)   		
  V1.0
  
  * @date(日期)           	
  2023-1-28
  
  * @Company(公司)
  
  * @History(历史修改记录)
  
*跳线:无
 
*版本:CEPARK CAN总线开发板v3.0
  <author> <time> <version > <desc>				      
*******************************************************************************/
/*
开场白:
上一节在第4,3,2,1位显示设置的参数时,还有一点小瑕疵。
比如设置参数等于56时,实际显示的是“0056”,也就是高位为0的如果不显示,效果才会更好。
这一节要教会大家两个知识点:
第一个:在上一节Smg_Service()函数里略作修改,把高位为0的去掉不显示。
第二个:加深熟悉鸿哥首次提出的“一二级菜单显示理论”:
凡是人机界面显示,不管是数码管还是液晶屏,都可以把显示的内容分成不同的窗口来显示,
每个显示的窗口中又可以分成不同的局部显示。
其中窗口就是一级菜单,用ucWd变量表示。局部就是二级菜单,用ucPart来表示。
不同的窗口,会有不同的更新显示变量ucWdXUpdate来对应,表示整屏全部更新显示。
不同的局部,也会有不同的更新显示变量ucWdXPartYUpdate来对应,表示局部更新显示。

*/
#include <reg52.h>
#include <absacc.h>

/**********************
 字符符号类型缩写
************************/
#define u8    unsigned char
#define u16   unsigned short int
#define u32   unsigned long int
#define s8     signed char
#define s16    signed short int
#define s32    signed long int
#define u64   unsigned long long int
#define s64    signed long long int


/**********************
SJA1000 寄存器配置
************************/

/*CAN总线SJA1000寄存器地址定义(用的是PeliCAN模式,扩展帧EFF模式)*/
//为什么地址上0xFE00
//FE是因为我们有16位的地址线。P0口是低8位地址,P2口是高8位地址。
//而P20是接的CS端一定要是为0,所以地址是FE.
//定义SJA1000的基址
//#define SJA_BaseAdr  0X7F00 //决定CS接到P2口的那个管脚,这样定义就是P2.7
//#define SJA_BaseAdr  0XFE00 //决定CS接到P2口的那个管脚,这样定义就是P2.0

#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                  //配置为下拉
#define Tx1PullUp         0x80                 //配置为上拉
#define Tx1PshPull        (0x40|0x80)       //配置为推挽
            /*TX0 的输出管脚配置*/
#define OCPOL0_BIT        0x04                      //输出极性控制位
#define Tx0Float          0x00                      //配置为悬空
#define Tx0PullDn         0x08                      //配置为下拉
#define Tx0PullUp         0x10                      //配置为上拉
#define Tx0PshPull        (0x10|0x08)                    //配置为推挽

#define SJA_TEST   XBYTE[SJA_BASE_ADR + 0x09]         //测试寄存器

/********************************
 * #define SJA_10   XBYTE[SJA_BASE_ADR + 0x0a]   寄存器功能保留
 ********************************/

/**********************
其他寄存器及其位定义
************************/
#define SJA_ALC      XBYTE[SJA_BASE_ADR + 0x0b]		//仲裁丢失捕捉寄存器
#define SJA_ECC      XBYTE[SJA_BASE_ADR + 0x0c]		//错误捕捉寄存器
#define SJA_EWLR     XBYTE[SJA_BASE_ADR + 0x0d]		//错误报警限制寄存器
#define SJA_RXERR    XBYTE[SJA_BASE_ADR + 0x0e]		//RX 错误计数器寄存器
#define SJA_TXERR    XBYTE[SJA_BASE_ADR + 0x0f]		//TX 错误计数器寄存器

/**********************
验收滤波器寄存器及其位定义
************************/
#define SJA_ACR0     XBYTE[SJA_BASE_ADR + 0x10]		//验收代码0寄存器
#define SJA_ACR1     XBYTE[SJA_BASE_ADR + 0x11]		//验收代码1寄存器
#define SJA_ACR2     XBYTE[SJA_BASE_ADR + 0x12]		//验收代码2寄存器
#define SJA_ACR3     XBYTE[SJA_BASE_ADR + 0x13]		//验收代码3寄存器

#define SJA_AMR0     XBYTE[SJA_BASE_ADR + 0x14]		//验收屏蔽0寄存器
#define SJA_AMR1     XBYTE[SJA_BASE_ADR + 0x15]		//验收屏蔽1寄存器
#define SJA_AMR2     XBYTE[SJA_BASE_ADR + 0x16]		//验收屏蔽2寄存器
#define SJA_AMR3     XBYTE[SJA_BASE_ADR + 0x17]		//验收屏蔽3寄存器

/**********************
TX缓冲器地址定义
************************/
#define SJA_TBSR0    XBYTE[SJA_BASE_ADR + 0x10]
#define SJA_TBSR1    XBYTE[SJA_BASE_ADR + 0x11]
#define SJA_TBSR2    XBYTE[SJA_BASE_ADR + 0x12]
#define SJA_TBSR3    XBYTE[SJA_BASE_ADR + 0x13]
#define SJA_TBSR4    XBYTE[SJA_BASE_ADR + 0x14]
#define SJA_TBSR5    XBYTE[SJA_BASE_ADR + 0x15]
#define SJA_TBSR6    XBYTE[SJA_BASE_ADR + 0x16]
#define SJA_TBSR7    XBYTE[SJA_BASE_ADR + 0x17]
#define SJA_TBSR8    XBYTE[SJA_BASE_ADR + 0x18]
#define SJA_TBSR9    XBYTE[SJA_BASE_ADR + 0x19]
#define SJA_TBSR10   XBYTE[SJA_BASE_ADR + 0x1a]
#define SJA_TBSR11   XBYTE[SJA_BASE_ADR + 0x1b]
#define SJA_TBSR12   XBYTE[SJA_BASE_ADR + 0x1c]

/**********************
RX缓冲器地址定义
************************/
#define SJA_RBSR0    XBYTE[SJA_BASE_ADR + 0x10]
#define SJA_RBSR1    XBYTE[SJA_BASE_ADR + 0x11]
#define SJA_RBSR2    XBYTE[SJA_BASE_ADR + 0x12]
#define SJA_RBSR3    XBYTE[SJA_BASE_ADR + 0x13]
#define SJA_RBSR4    XBYTE[SJA_BASE_ADR + 0x14]
#define SJA_RBSR5    XBYTE[SJA_BASE_ADR + 0x15]
#define SJA_RBSR6    XBYTE[SJA_BASE_ADR + 0x16]
#define SJA_RBSR7    XBYTE[SJA_BASE_ADR + 0x17]
#define SJA_RBSR8    XBYTE[SJA_BASE_ADR + 0x18]
#define SJA_RBSR9    XBYTE[SJA_BASE_ADR + 0x19]
#define SJA_RBSR10   XBYTE[SJA_BASE_ADR + 0x1a]
#define SJA_RBSR11   XBYTE[SJA_BASE_ADR + 0x1b]
#define SJA_RBSR12   XBYTE[SJA_BASE_ADR + 0x1c]

#define SJA_RMC      XBYTE[SJA_BASE_ADR + 0x1d]           //RX 信息计数器 寄存器
#define SJA_RBSA     XBYTE[SJA_BASE_ADR + 0x1e]           //RX 缓冲区起始地址 寄存器

/**********************
时钟分频寄存器地址定义
************************/
#define SJA_CDR       XBYTE[SJA_BASE_ADR + 0x1f]		 //时钟分频 寄存器
#define CLKOff_BIT        0x08                     //时钟关闭位,时钟输出管脚控制位
#define RXINTEN_BIT       0x20                      //用于接收中断的管脚TX1
#define CBP_BIT           0x40                      //CAN 比较器旁路控制位
#define CANMode_BIT       0x80                     //CAN 模式控制位


/**********************
定义标识符
************************/

#define FrameNum      13  //一帧字节数

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

#define SmgPort 	P0			//数码管段seg的引脚-即控制7段加一点,形成不同形状
#define SmgCtrl 	P2	        //数码管公共位com的引脚-即选择控制点不点这个数码管

//#define const_voice_short 40 //蜂鸣器短叫的持续时间

#define KEY_FILTER_TIME1 20 //按键去抖动延时的时间
//#define KEY_FILTER_TIME2 20 //按键去抖动延时的时间
//#define KEY_FILTER_TIME3 20 //按键去抖动延时的时间




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

sbit KEY_INPUT1=P3^2;//INT0按键为计数按键--也可以是普通按键

//sbit KEY_INPUT1=P1^0;
//sbit KEY_INPUT2=P1^1;
//sbit KEY_INPUT3=P1^2;

//sbit beep_dr=P2^7;//蜂鸣器的驱动 IO 口

//sbit led_dr=P3^5;//作为中途暂停指示灯 亮的时候表示中途暂停
sbit LED_RED=P1^0;  
sbit LED_GER=P1^1; 

//sbit dig_hc595_sh_dr=P2^3; //数码管的 74HC595 程序
//sbit dig_hc595_st_dr=P2^4;
//sbit dig_hc595_ds_dr=P2^5;

//sbit hc595_sh_dr=P2^0;//LED 灯的 74HC595 程序
//sbit hc595_st_dr=P2^1;
//sbit hc595_ds_dr=P2^2;
volatile unsigned char ucDisBuff[4];

volatile unsigned char ucPeli_TXD_StatusTemp; //接收数据状态缓存
volatile unsigned char ucPeli_RXD_StatusTemp; //发送数据状态缓存

volatile unsigned char bdata ucRegister_StatusTemp;//寄存器数据状态缓存


volatile unsigned char ucTxd_Flag=0;      //数据发送处理标志
volatile unsigned char ucRxd_Flag=0;      //数据接收处理标志

volatile unsigned char ucACRR[4];   //定义数组ACRR,存贮接受代码寄存器内容
volatile unsigned char ucAMRR[4]; //定义数组AMRR,存贮接受屏蔽代码寄存器内容

volatile unsigned char ucRX_buffer[FrameNum];  //接收的数据
volatile unsigned char ucTX_buffer[FrameNum];  //接收的数据
volatile unsigned char ucTxd_data=0;//CAN总线要发送的数据,也是要在数码管1-2位置显示的数据
volatile unsigned char ucRxd_data=0;//CAN总线要接收的数据,也是要在数码管3-4位置显示的数据

volatile unsigned char ucKeySec=0;//被触发的按键编号

//按键1
volatile unsigned int uiKeyTimeCnt1=0;//按键去抖动延时计数器
volatile unsigned char ucKeyLock1=0;//按键触发后自锁的变量标志

//按键2
//unsigned int uiKeyTimeCnt2=0;//按键去抖动延时计数器
//unsigned char ucKeyLock2=0;//按键触发后自锁的变量标志

//按键3
//unsigned int uiKeyTimeCnt3=0;//按键去抖动延时计数器
//unsigned char ucKeyLock3=0;//按键触发后自锁的变量标志

//蜂鸣器
volatile unsigned int uiVoiceCnt=0;//蜂鸣器鸣叫的持续时间计数器

//数码管要显示的内容
volatile unsigned char ucDigShow1;//第 1 位数码管要显示的内容
volatile unsigned char ucDigShow2;//第 2 位数码管要显示的内容
volatile unsigned char ucDigShow3;//第 3 位数码管要显示的内容
volatile unsigned char ucDigShow4;//第 4 位数码管要显示的内容
//unsigned char ucDigShow5;//第 5 位数码管要显示的内容
//unsigned char ucDigShow6;//第 6 位数码管要显示的内容
//unsigned char ucDigShow7;//第 7 位数码管要显示的内容
//unsigned char ucDigShow8;//第 8 位数码管要显示的内容

//数码管是否显示小数点

volatile unsigned char ucDigDot1;//数码管 1 的小数点是否显示的标志
volatile unsigned char ucDigDot2;//数码管 2 的小数点是否显示的标志
volatile unsigned char ucDigDot3;//数码管 3 的小数点是否显示的标志
volatile unsigned char ucDigDot4;//数码管 4 的小数点是否显示的标志
//unsigned char ucDigDot5;//数码管 5 的小数点是否显示的标志
//unsigned char ucDigDot6;//数码管 6 的小数点是否显示的标志
//unsigned char ucDigDot7;//数码管 7 的小数点是否显示的标志
//unsigned char ucDigDot8;//数码管 8 的小数点是否显示的标志

volatile unsigned int uiSetData1=0;//本程序中需要被设置的参数 1
volatile unsigned int uiSetData2=0;//本程序中需要被设置的参数 2
volatile unsigned int uiSetData3=0;//本程序中需要被设置的参数 3
volatile unsigned int uiSetData4=0;//本程序中需要被设置的参数 4

volatile unsigned char ucTemp1=0; //中间过渡变量
volatile unsigned char ucTemp2=0; //中间过渡变量
volatile unsigned char ucTemp3=0; //中间过渡变量
volatile unsigned char ucTemp4=0; //中间过渡变量


volatile unsigned char ucDigShowTemp=0;//临时中间变量

volatile unsigned char ucDisplayDriveStep=1;//动态扫描数码管的步骤变量

volatile unsigned char ucWd1Update=1;//窗口 1 更新显示标志
volatile unsigned char ucWd2Update=0;//窗口 2 更新显示标志
volatile unsigned char ucWd3Update=0;//窗口 3 更新显示标志
volatile unsigned char ucWd4Update=0;//窗口 4 更新显示标志

volatile unsigned char ucWd=1;//本程序的核心变量,窗口显示变量。类似于一级菜单的变量。代表显示不同的窗口。



//转换表,里面的16个数据,转换成二进制后,第7位数据都是1默认不显示小数点(共阳).
//编码规则是gfedcba ,其中g为小数点,控制dp
//数码管是abcdefg
code u8 Cu8DigTable[]=
{
	0xC0,  //0       序号0
	0xF9,  //1       序号1
	0xA4,  //2       序号2
	0xB0,  //3       序号3
	0x99,  //4       序号4
	0x92,  //5       序号5
	0x82,  //6       序号6
	0xF8,  //7       序号7
	0x80,  //8       序号8
	0x90,  //9       序号9
	0x88,		//A			序号10
	0x83,		//B			序号11
	0xC6,		//C			序号12
	0xA1,		//D			序号13
	0x86,		//E			序号14
	0x8E,		//F			序号15
	0xFF,  //不显示  序号16	
};


void Init_Sys();  //MCU初始化
void Init_Peripheral(); //外围设备初始化
void Delay_Short(unsigned int uiDelayshort);
void Delay_Long(unsigned int uiDelaylong);


//驱动数码管的74HC595
//void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);

void Smg_Scan();//显示数码管字模的驱动函数
void Smg_Service();//显示的窗口菜单服务程序
void LED_Disp_Seg7();//显示子函数
void Led_Show(unsigned char, unsigned char);


//驱动LED的74HC595
//void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
void T0timer_Service();//定时中断函数

void Key_Service();//按键服务的应用程序
void key_Scan();//按键扫描函数 放在定时中断里

void Peli_TXDService(void); //发送处理函数
void Peli_RXDService(void); //接收处理函数

void Peli_TXDScan(void);//CAN发送子任务函数
void Peli_RXDScan(void);//CAN接收子驱动函数


void main() 
{
	Init_Sys();
	Delay_Short(10);
	Init_Peripheral();
	
	while(1) 
	{
		
		Key_Service();//按键服务的应用程序		
		Peli_TXDService(); //发送处理函数
	  Peli_RXDService(); //接收处理函数
		Smg_Service();//显示的窗口菜单服务程序	
		//Led_Show(0, ucTxd_data);
		//Led_Show(1,ucRxd_data);
		
	}
}

void key_Scan()//按键扫描函数 放在定时中断里 
{
   //按键1扫描
	if(KEY_INPUT1==1)//IO 是高电平,说明按键没有被按下,这时要及时清零一些标志位 
	{
		ucKeyLock1=0;//按键自锁标志清零		
		uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。		
	} 
	else if(ucKeyLock1==0)//有按键按下,且是第一次被按下 
	{
		uiKeyTimeCnt1++;//累加定时中断次数		
		
		if(uiKeyTimeCnt1>KEY_FILTER_TIME1) 
		{
			uiKeyTimeCnt1=0;
			ucKeyLock1=1;//自锁按键置位,避免一直触发			
			
			ucKeySec=1;//触发 1 号键			
		}
	}
}	
/*
	 //按键2扫描
	if(KEY_INPUT2==1)//IO 是高电平,说明按键没有被按下,这时要及时清零一些标志位 
	{
		ucKeyLock2=0;//按键自锁标志清零		
		uiKeyTimeCnt2=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。		
	} else if(ucKeyLock2==0)//有按键按下,且是第一次被按下 
	{
		uiKeyTimeCnt2++;//累加定时中断次数		
		if(uiKeyTimeCnt2>KEY_FILTER_TIME2) 
		{
			uiKeyTimeCnt2=0;
			ucKeyLock2=1;//自锁按键置位,避免一直触发			
			ucKeySec=2;//触发 2 号键			
		}
	}
	 //按键3扫描
	if(KEY_INPUT3==1)//IO 是高电平,说明按键没有被按下,这时要及时清零一些标志位 
	{
		ucKeyLock3=0;//按键自锁标志清零		
		uiKeyTimeCnt3=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。		
	} else if(ucKeyLock3==0)//有按键按下,且是第一次被按下 
	{
		uiKeyTimeCnt3++;//累加定时中断次数		
		if(uiKeyTimeCnt3>KEY_FILTER_TIME3) 
		{
			uiKeyTimeCnt3=0;
			ucKeyLock3=1;//自锁按键置位,避免一直触发			
			ucKeySec=3;//触发 3 号键			
		}
	}
}
*/

void Key_Service() //按键服务的应用程序 
{
	switch(ucKeySec) //按键服务状态切换 
	{	//按键1
		case 1:// 加按键 对应朱兆祺学习板的 S1 键
		switch(ucWd) //在不同的窗口下,设置不同的参数 
		{   //窗口 1 
			case 1:
			      //uiSetData1++;

			      ucTxd_data++;//发送的数据加1

				 
			
	 				 			
	 			if(ucTxd_data>99) //最大值是 9999 
	 			{
	 				ucTxd_data= 99;
	 			}

				uiSetData1 = ucTxd_data;   //存储计数结果,并为待发送的数据
				 
				ucTxd_Flag = 1; // //发送标志置1,准备发生

				
	 			ucWd1Update=1;//窗口 1 更新显示			
			break;
/*
			//窗口 2 
			case 2:
					uiSetData2++;
			if(uiSetData2>9999) //最大值是 9999 
			{
				uiSetData2=9999;
			}
			ucWd2Update=1;//窗口 2 更新显示			
			break;
			//窗口 3 
			case 3:
					uiSetData3++;
			if(uiSetData3>9999) //最大值是 9999 
			{
				uiSetData3=9999;
			}
			ucWd3Update=1;//窗口 3 更新显示			
			break;
			//窗口 4 
			case 4:
					uiSetData4++;
			if(uiSetData4>9999) //最大值是 9999 
			{
				uiSetData4=9999;
			}
			ucWd4Update=1;//窗口 4 更新显示			
			break;
*/
		}
		//uiVoiceCnt=const_voice_short;//按键声音触发,滴一声就停。		
		ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发		
		break;
/*		
		//按键2
		case 2:// 减按键 对应朱兆祺学习板的 S5 键
		switch(ucWd) //在不同的窗口下,设置不同的参数 
		{	//窗口 1
			case 1:
			uiSetData1--;
			if(uiSetData1>9999) 
			{
				uiSetData1=0;//最小值是 0				
			}
			ucWd1Update=1;//窗口 1 更新显示			
			break;
			//窗口 2
			case 2:
			uiSetData2--;
			if(uiSetData2>9999) 
			{
				uiSetData2=0;//最小值是 0				
			}
			ucWd2Update=1;//窗口 2 更新显示			
			break;
			//窗口 3
			case 3:
			uiSetData3--;
			if(uiSetData3>9999) 
			{
				uiSetData3=0;//最小值是 0				
			}
			ucWd3Update=1;//窗口 3 更新显示			
			break;
			//窗口 4
			case 4:
			uiSetData4--;
			if(uiSetData4>9999) 
			{
				uiSetData4=0;//最小值是 0				
			}
			ucWd4Update=1;//窗口 4 更新显示			
			break;
			
		}
		//uiVoiceCnt=const_voice_short;//按键声音触发,滴一声就停
		ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发		
		break;
*/
/*
		//按键3
		case 3:// 切换窗口按键 对应朱兆祺学习板的 S9 键
		ucWd++;//切换窗口		
		if(ucWd>4) 
		{
			ucWd=1;
		}
		switch(ucWd) //在不同的窗口下,在不同的窗口下,更新显示不同的窗口 
		{
			case 1:
				ucWd1Update=1;//窗口 1 更新显示
			
			break;
			case 2:
				ucWd2Update=1; //窗口 2 更新显示		
			break;
			case 3:
				ucWd3Update=1;//窗口 3 更新显示			
			break;
			case 4:
				ucWd4Update=1;//窗口 4 更新显示			
			break;
		}
		uiVoiceCnt=const_voice_short;//按键声音触发,滴一声就停。		
		ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发		
		break;
*/
	}
}



/* 注释二:
*鸿哥首次提出的"一二级菜单显示理论":
*凡是人机界面显示,不管是数码管还是液晶屏,都可以把显示的内容分成不同的窗口来显示,
*每个显示的窗口中又可以分成不同的局部显示。其中窗口就是一级菜单,用ucWd变量表示。
*局部就是二级菜单,用ucPart来表示。不同的窗口,会有不同的更新显示变量ucWdXUpdate来对应,
*表示整屏全部更新显示。
*不同的局部,也会有不同的更新显示变量ucWdXPartYUpdate来对应,表示局部更新显示。
*/

void Smg_Service() //显示的窗口菜单服务程序 
{
	switch(ucWd) //本程序的核心变量,窗口显示变量。类似于一级菜单的变量。代表显示不同的窗口。 
	{
		case 1: //窗口1:显示 P--1 窗口的数据
		if(ucWd1Update==1) //窗口 1 要全部更新显示 
		{
			ucWd1Update=0;//及时清零标志,避免一直进来扫描	
			
			//ucDigShow8=12;//第 8 位数码管显示 P		-           ucTemp8=16;  //显示空	
			//ucDigShow7=11;//第 7 位数码管显示-					ucTemp7=16;  //显示空
			//ucDigShow6=1;//第 6 位数码管显示 1					ucTemp6=16;  //显示空
			//ucDigShow5=10;//第 5 位数码管显示无				     ucTemp5=16;  //显示空

			//分解数据
			//ucTemp4=uiSetData1/1000;//取千位
           // ucTemp3=uiSetData1%1000/100;  //取百位

			ucTemp4=uiSetData2%100/10;    //取十位
      ucTemp3=uiSetData2%10;	     //取个位
            
      ucTemp2=uiSetData1%100/10;    //取十位
      ucTemp1=uiSetData1%10;	     //取个位
			
			//把数据分配到数码管
			//第 4 位数码管要显示的内容
			/*if(uiSetData1<1000) 
			{
				ucDigShow4=10;//如果小于 1000,千位显示无				
			} 
			else 
			{
				ucDigShow4=ucTemp4;//第 4 位数码管要显示的内容				
			}
			
			
			//第 3位数码管要显示的内容
			if(uiSetData1<100) 
			{
				ucDigShow3=10;//如果小于 100,百位显示无				
			} 
			else 
			{
				ucDigShow3=ucTemp3;//第 3 位数码管要显示的内容				
			}
			*/
			

			//第 4 位数码管要显示的内容
			if(uiSetData2<10) 
			{
				ucDigShow4=16;//如果小于 16,十位显示无			这里根据 数据表来的,也可以填10	
			} 
			else 
			{
				ucDigShow4=ucTemp4;//第 4 位数码管要显示的内容				
			}



			//第 3 位数码管要显示的内容
			ucDigShow3=ucTemp3;//第 3位数码管要显示的内容			


			
			//第 2 位数码管要显示的内容
			if(uiSetData1<10) 
			{
				ucDigShow2=16;//如果小于 16,十位显示无				
			} 
			else 
			{
				ucDigShow2=ucTemp2;//第 2 位数码管要显示的内容				
			}

			//第 1 位数码管要显示的内容
			ucDigShow1=ucTemp1;//第 1 位数码管要显示的内容			
		}
		break;
		
/*
		//就使用一个窗口,2,3,4窗口可以关闭
		case 2: //显示 P--2 窗口的数据
		if(ucWd2Update==1) //窗口 2 要全部更新显示 
		{
			ucWd2Update=0;//及时清零标志,避免一直进来扫描		
			ucDigShow8=12;//第 8 位数码管显示 P			
			ucDigShow7=11;//第 7 位数码管显示-			
			ucDigShow6=2;//第 6 位数码管显示 2		
			ucDigShow5=10;//第 5 位数码管显示无			
			ucTemp4=uiSetData2/1000;//分解数据			
			ucTemp3=uiSetData2%1000/100;
			ucTemp2=uiSetData2%100/10;
			ucTemp1=uiSetData2%10;
			if(uiSetData2<1000) 
			{
				ucDigShow4=10;//如果小于 1000,千位显示无				
			} else 
			{
				ucDigShow4=ucTemp4;//第 4 位数码管要显示的内容				
			}
			if(uiSetData2<100) 
			{
				ucDigShow3=10;//如果小于 100,百位显示无				
			} else 
			{
				ucDigShow3=ucTemp3;//第 3 位数码管要显示的内容				
			}
			if(uiSetData2<10) 
			{
				ucDigShow2=10;//如果小于 10,十位显示无				
			} else 
			{
				ucDigShow2=ucTemp2;//第 2 位数码管要显示的内容				
			}
			ucDigShow1=ucTemp1;//第 1 位数码管要显示的内容			
		}
		break;
		case 3: //显示 P--3 窗口的数据
		if(ucWd3Update==1) //窗口 3 要全部更新显示 
		{
			ucWd3Update=0;//及时清零标志,避免一直进来扫描			
			ucDigShow8=12;//第 8 位数码管显示 P			
			ucDigShow7=11;//第 7 位数码管显示-			
			ucDigShow6=3;//第 6 位数码管显示 3		
			ucDigShow5=10;//第 5 位数码管显示无			
			ucTemp4=uiSetData3/1000;//分解数据			
			ucTemp3=uiSetData3%1000/100;
			ucTemp2=uiSetData3%100/10;
			ucTemp1=uiSetData3%10;
			if(uiSetData3<1000) 
			{
				ucDigShow4=10;//如果小于 1000,千位显示无			
			}
			else
			{
				ucDigShow4=ucTemp4;//第 4 位数码管要显示的内容				
			}
			if(uiSetData3<100) 
			{
				ucDigShow3=10;//如果小于 100,百位显示无
				
			} else 
			{
				ucDigShow3=ucTemp3;//第 3 位数码管要显示的内容				
			}
			if(uiSetData3<10) 
			{
				ucDigShow2=10;
				//如果小于 10,十位显示无
			} else 
			{
				ucDigShow2=ucTemp2;//第 2 位数码管要显示的内容				
			}
			ucDigShow1=ucTemp1;//第 1 位数码管要显示的内容			
		}
		break;
		case 4: //显示 P--4 窗口的数据
		if(ucWd4Update==1) //窗口 4 要全部更新显示 
		{
			ucWd4Update=0;//及时清零标志,避?庖恢苯瓷?		
			ucDigShow8=12;//第 8 位数码管显示 P			
			ucDigShow7=11;//第 7 位数码管显示-						
			ucDigShow6=4;//第 6 位数码管显示 4			
			ucDigShow5=10;//第 5 位数码管显示无			
			ucTemp4=uiSetData4/1000;//分解数据			
			ucTemp3=uiSetData4%1000/100;
			ucTemp2=uiSetData4%100/10;
			ucTemp1=uiSetData4%10;
			if(uiSetData4<1000) 
			{
				ucDigShow4=10;//如果小于 1000,千位显示无				
			} else 
			{
				ucDigShow4=ucTemp4;//第 4 位数码管要显示的内容				
			}
			if(uiSetData4<100) 
			{
				ucDigShow3=10;//如果小于 100,百位显示无				
			} else 
			{
				ucDigShow3=ucTemp3;//第 3 位数码管要显示的内容				
			}
			if(uiSetData4<10) 
			{
				ucDigShow2=10;//如果小于 10,十位显示无				
			} else 
			{
				ucDigShow2=ucTemp2;//第 2 位数码管要显示的内容				
			}
			ucDigShow1=ucTemp1;//第 1 位数码管要显示的内容			
		}
		break;
*/
	}
}

/* 注释一:
* 动态驱动数码管的原理是,在八位数码管中,在任何一个瞬间,每次只显示其中一位数码管,
* 另外的七个数码管通过设置其公共位com为高电平来关闭显示,
* 只要切换画面的速度足够快,人的视觉就分辨不出来,感觉八个数码管 是同时亮的。
* 以下dig_hc595_drive(xx,yy)函数,
* 其中第一个形参xx是驱动数码管段seg的引脚,第二个形参yy是驱动 数码管公共位com的引脚。
*/


void Smg_Drive() 
{
	//以下程序,如果加一些数组和移位的元素,还可以压缩容量。
	//但是鸿哥追求的不是容量,而是清晰的讲解思路
	//共阴数码管--	想让第7位置1,其它位保持不变,只需跟十六进制的0x80相“或”:b=b | 0x80
      //共阳数码管-- 想让第7位清零,其它位保持不变,只需跟十六进制的0x7f相“与”:b=b & 0x7f
	switch(ucDisplayDriveStep) 
	{
		case 1: //显示第 1 位
		ucDigShowTemp=Cu8DigTable[ucDigShow1];   //根据要显示的内容取数
		
		if(ucDigDot1==1)         //判断是否要小数点
		{
			ucDigShowTemp=ucDigShowTemp& 0x7f;//显示小数点			
		}
		
		//dig_hc595_drive(ucDigShowTemp,0xfe);
		 
		SmgPort = ucDigShowTemp;      // 送P0端口
		SmgCtrl = SmgCtrl & 0x7f;          //打开数码管
		Delay_Short(50);    //打开一会儿,这里数据越大,越亮
		SmgCtrl = SmgCtrl | 0xf0;  //关闭
		
		break;

		
		case 2: //显示第 2 位
		ucDigShowTemp=Cu8DigTable[ucDigShow2];    //根据要显示的内容取数
		
		if(ucDigDot2==1) //判断是否要小数点
		{
			ucDigShowTemp=ucDigShowTemp& 0x7f;//显示小数点		
		}
		
		//dig_hc595_drive(ucDigShowTemp,0xfd);
		
		SmgPort = ucDigShowTemp;      // 送P0端口
		SmgCtrl = SmgCtrl & 0xbf;          //打开数码管		
		Delay_Short(50);    //打开一会儿,这里数据越大,越亮
		SmgCtrl = SmgCtrl | 0xf0;  //关闭
		
		break;
		
		case 3: //显示第 3 位
		ucDigShowTemp=Cu8DigTable[ucDigShow3]; //根据要显示的内容取数
		
		if(ucDigDot3==1) //判断是否要小数点
		{
			ucDigShowTemp=ucDigShowTemp& 0x7f; //显示小数点			
		}
		
		//dig_hc595_drive(ucDigShowTemp,0xfb);

		SmgPort = ucDigShowTemp;      // 送P0端口
		SmgCtrl = SmgCtrl & 0xdf;          //打开数码管
		Delay_Short(50);    //打开一会儿,这里数据越大,越亮
		SmgCtrl = SmgCtrl | 0xf0;  //关闭
		
		break;
		
		case 4: //显示第 4 位
		ucDigShowTemp=Cu8DigTable[ucDigShow4]; //根据要显示的内容取数
		
		if(ucDigDot4==1) //判断是否要小数点
		{
			ucDigShowTemp=ucDigShowTemp& 0x7f;//显示小数点			
		}
		
		//dig_hc595_drive(ucDigShowTemp,0xf7);
		
		SmgPort = ucDigShowTemp;      // 送P0端口
		SmgCtrl = SmgCtrl & 0xef;          //打开数码管
		Delay_Short(50);    //打开一会儿,z这里数据越大,越亮
		SmgCtrl = SmgCtrl | 0xf0;  //关闭
		
		break;
/*		
		case 5: //显示第 5 位
		ucDigShowTemp=Cu8DigTable[ucDigShow5];
		if(ucDigDot5==1) 
		{
			ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点			
		}
		dig_hc595_drive(ucDigShowTemp,0xef);
		break;
		case 6: //显示第 6 位
		ucDigShowTemp=Cu8DigTable[ucDigShow6];
		if(ucDigDot6==1) 
		{
			ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点			
		}
		dig_hc595_drive(ucDigShowTemp,0xdf);
		break;
		
		case 7: //显示第 7 位
		ucDigShowTemp=Cu8DigTable[ucDigShow7];
		if(ucDigDot7==1) 
		{
			ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点			
		}
		dig_hc595_drive(ucDigShowTemp,0xbf);
		break;
		
		case 8: //显示第 8 位
		ucDigShowTemp=Cu8DigTable[ucDigShow8];
		if(ucDigDot8==1) 
		{
			ucDigShowTemp=ucDigShowTemp|0x80;//显示小数点			
		}
		dig_hc595_drive(ucDigShowTemp,0x7f);
		break;
*/
	}
	ucDisplayDriveStep++;
	if(ucDisplayDriveStep>4) //扫描完 44 个数码管后,重新从第一个开始扫描 
	{
		ucDisplayDriveStep=1;
	}
}



/*
//数码管的 74HC595 驱动函数
void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01) 
{
	unsigned char i;
	unsigned char ucTempData;
	dig_hc595_sh_dr=0;
	dig_hc595_st_dr=0;
	ucTempData=ucDigStatusTemp16_09;//先送高 8 位	
	for (i=0;i<8;i++) 
	{
		if(ucTempData>=0x80)
			dig_hc595_ds_dr=1; 
		else 
			dig_hc595_ds_dr=0;
		dig_hc595_sh_dr=0;//SH 引脚的上升沿把数据送入寄存器		
		Delay_Short(1);
		dig_hc595_sh_dr=1;
		Delay_Short(1);
		ucTempData=ucTempData<<1;
	}
	ucTempData=ucDigStatusTemp08_01;//再先送低 8 位	
	for (i=0;i<8;i++) 
	{
		if(ucTempData>=0x80)
			dig_hc595_ds_dr=1; 
		else 
			dig_hc595_ds_dr=0;
		dig_hc595_sh_dr=0;//SH 引脚的上升沿把数据送入寄存器		
		Delay_Short(1);
		dig_hc595_sh_dr=1;
		Delay_Short(1);
		ucTempData=ucTempData<<1;
	}
	dig_hc595_st_dr=0;//ST 引脚把两个寄存器的数据更新输出到 74HC595 的输出引脚上并且锁存起来	
	Delay_Short(1);
	dig_hc595_st_dr=1;
	Delay_Short(1);
	dig_hc595_sh_dr=0;//拉低,抗干扰就增强	
	dig_hc595_st_dr=0;
	dig_hc595_ds_dr=0;
}
//LED 灯的 74HC595 驱动函数
void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01) 
{
	unsigned char i;
	unsigned char ucTempData;
	hc595_sh_dr=0;
	hc595_st_dr=0;
	ucTempData=ucLedStatusTemp16_09;//先送高 8 位		
	for (i=0;i<8;i++) 
	{
		if(ucTempData>=0x80)
			hc595_ds_dr=1; 

		else 
			hc595_ds_dr=0;
		hc595_sh_dr=0;//SH 引脚的上升沿把数据送入寄存器		
		Delay_Short(1);
		hc595_sh_dr=1;
		Delay_Short(1);
		ucTempData=ucTempData<<1;
	}
	ucTempData=ucLedStatusTemp08_01;//再先送低 8 位	
	for (i=0;i<8;i++) 
	{
		if(ucTempData>=0x80)
			hc595_ds_dr=1; 
		else 
			hc595_ds_dr=0;
		hc595_sh_dr=0;//SH 引脚的上升沿把数据送入寄存器		
		Delay_Short(1);
		hc595_sh_dr=1;
		Delay_Short(1);
		ucTempData=ucTempData<<1;
	}
	hc595_st_dr=0;//ST 引脚把两个寄存器的数据更新输出到 74HC595 的输出引脚上并且锁存起来	
	Delay_Short(1);
	hc595_st_dr=1;
	Delay_Short(1);
	hc595_sh_dr=0;//拉低,抗干扰就增强	
	hc595_st_dr=0;
	hc595_ds_dr=0;
}
*/


//数码管显示函数2
//void LED_Disp_Seg7()
//{
//   SmgCtrl = SmgCtrl | 0xf0;

//   DisBuff[0]   = Txd_data%10;//取个位数
//   DisBuff[1]   = Txd_data%100/10; //取十位数
//	
//   DisBuff[2]   = Rxd_data%10;	   //百位数
//   DisBuff[3]   = Rxd_data%100/10; //千位数
//  
//   SmgPort = Cu8DigTable[DisBuff[0]];
//   SmgCtrl = SmgCtrl & 0x7f;
//   Delay(5);
//   SmgCtrl = SmgCtrl | 0xf0;

//   SmgPort = Cu8DigTable[DisBuff[1]];
//   SmgCtrl = SmgCtrl & 0xbf;
//   Delay(5);
//   SmgCtrl = SmgCtrl | 0xf0;

//   SmgPort = Cu8DigTable[DisBuff[2]];
//   SmgCtrl = SmgCtrl & 0xdf;
//   Delay(5);
//   SmgCtrl = SmgCtrl | 0xf0;

//   SmgPort = Cu8DigTable[DisBuff[3]];
//   SmgCtrl = SmgCtrl & 0xef;
//   Delay(5);
//   SmgCtrl = SmgCtrl | 0xf0;
//}

//数码管显示函数3
//http://blog.chinaunix.net/uid/22889411/cid-2388-list-4.html
/*这个显示有点绕
from(1_4):数码管显示起始位置(从右到左),number:显示的数(数码管上采用10进制显示)

//void Smg_Show(uchar from,uchar number)  
//{
//    uchar GetCode,temp_l;
//    uchar temp_h=0x7f;                  //初值:0111 1111
//    temp_h = _cror_(temp_h,from-1);   //右移, 
										//确定从哪一位开始显示,即确定高四位
//    temp_h = temp_h & 0xf0;           //取高四位
//    temp_l = P2 & 0x0f;               //取P2的低四位,这里是想不动的继承低4位的数据。
//    P2 = temp_h | temp_l;             //设定P2口

//    if(number==0)
//    {
//        P0 = led[0];
//        Delay(10);
//        P0 = 0xff;
//    }        
//    else
//    {
//        while(number)
//        {
//	         GetCode = number%10 ;
//	         number /= 10;
//           P0 = led[GetCode] ;
//	         Delay(10);
//					
//					
//           temp_h = P2 & 0xf0;               // 与 1111 0000 ,低四位 清0 ,即保持高四位,取P2的高四位 
//           temp_h = temp_h | 0x0f;           //取P2的高四位后,再或 0000 1111 拼装 temp_h,进行位选
//	         temp_h = _cror_(temp_h,1);
//	         temp_h = temp_h & 0xf0;             //取高四位
//    		 temp_l = P2 & 0x0f;               //取P2的低四位
//           P0 = 0xff;
//           P2 = temp_h | temp_l;             //设定P2口
//        }
//    }
//	
//}

*/
https://www.360docs.net/doc/10803116.html
//void Led_Show(unsigned char  wela,unsigned char number)
//{
//	unsigned char digit;
//	unsigned char temp;

//	//第三个数码管,单独加上小数点
//	
//	//没想到怎么写
//	
//	if(wela) //高位显示,即数码管 1-2
//	{
//		temp = 0x7b; //temp=0111 1011B
//	}
//	else//低位显示,即数码管 3-4
//	{
//		temp = 0xde; //temp=1101 1110B
//	}

//	
//	//数码管个位显示
//	digit = number%10;
//	SmgPort = Cu8DigTable[digit];
//	SmgCtrl =(temp | 0x0f) & SmgCtrl;//开个位,或0->保留其本身,保留了高四位,
//	Delay_Short(5);
//	SmgCtrl = 0xff;
//	SmgPort = 0xff; //关闭个位

数码管十位显示
//       if( number < 10)   //先判断十位要不要显示,就是数据大于10不?
//       	{
//			SmgCtrl = 0xff;
//	    }
//	   else
//	   	{
//			digit = number%100/10;
//			//SmgPort = Cu8DigTable[digit]+0x7f;//这样写,2个十位都加了小数点,+0x80 ,是共阴, 7f 是共阳
//			SmgPort = Cu8DigTable[digit];
//			SmgCtrl =((temp << 4)|0x0f)& SmgCtrl;  //开十位,左移四位,原本的低四位到高四位	,
//			Delay_Short(5);
//			SmgPort = 0xff;
//			SmgCtrl = 0xff;//关闭十位
//	   	}
//	
//}

//发送处理
void Peli_TXDService() //	定义发送处理函数程序
						//主要是检测发送标志状态位,如果置位,则准备数据,进行发送数据处理
						//并且调用发送函数
{

	if( 1 == ucTxd_Flag ) //	若Txd_flag = 1,则要求进行数据的发送处理
	{
		Delay_Short(1);		//	延时
		ucTxd_Flag = 0;	//	Txd_flag 清零,以便下次查询
		//ucTX_buffer[5] = Txd_data;	 有些程序有这句话有些没有,为啥?
		Peli_TXDScan();//调用CAN发送子任务函数,发送数据帧
				
		Delay_Short(1);		//延时
		Delay_Short(1);		//发送 扩展 数据帧 后,SJA1000将产生接收中断
	 }
}

//接受处理
void Peli_RXDService()
{
	if(ucRxd_Flag)      //	vGu8Rxd_Flag = 0,表示无数据可以接收
												//	vGu8Rxd_Flag = 1,表示有数据可以接收
    {
        EX1 = 0;			//	关闭外部中断

        ucRxd_Flag = 0;	//	RXD_flag 清零,以便下次查询
			
        ucRxd_data = ucRX_buffer[5];  //	CAN总线接收的数据,也是要在数码管3和4位置显示的数据
        
        uiSetData2 = ucRxd_data;    //接收的数据送到数码管的显示内容缓存中
		
				EX1 = 1;			//	重新开启外部中断
     }
}


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

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

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

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

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

    SJA_CMR = SRR_BIT;//置位自发送接收请求
}

//接收数据函数,在中断服务程序中调用
void Peli_RXDScan() interrupt 2
{
		
    EX1 = 0;//关CPU中断
    IE1 = 0;//中断请求标志清0
	
    ucPeli_RXD_StatusTemp = SJA_IR;
	
    if(ucPeli_RXD_StatusTemp & RI_BIT)
    {//IR.0 = 1 接收中断
        ucRX_buffer[0] =  SJA_RBSR0;
        ucRX_buffer[1] =  SJA_RBSR1;
        ucRX_buffer[2] =  SJA_RBSR2;
        ucRX_buffer[3] =  SJA_RBSR3;
        ucRX_buffer[4] =  SJA_RBSR4;
        ucRX_buffer[5] =  SJA_RBSR5;
        ucRX_buffer[6] =  SJA_RBSR6;
        ucRX_buffer[7] =  SJA_RBSR7;
        ucRX_buffer[8] =  SJA_RBSR8;
        ucRX_buffer[9] =  SJA_RBSR9;
        ucRX_buffer[10] = SJA_RBSR10;
        ucRX_buffer[11] = SJA_RBSR11;
        ucRX_buffer[12] = SJA_RBSR12;

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

    EX1 = 1;//打开CPU中断
}


void T0timer_Service() interrupt 1 
{
	TF0=0;//清除中断标志	
	TR0=0;//关中断	
	
	key_Scan();//按键扫描函数	
	Smg_Drive();//数码管字模的驱动函数	
/*	
	if(uiVoiceCnt!=0) 
	{
		uiVoiceCnt--;//每次进入定时中断都自减 1,直到等于零为止。才停止鸣叫		
		beep_dr=0;//蜂鸣器是 PNP 三极管控制,低电平就开始鸣叫

	} else 
	{	
		beep_dr=1;		
	}
*/	
	
	
	TH0=0xfe;//重装初始值(65535-500)=65035=0xfe0b	
	TL0=0x0b;
	TR0=1;//开中断	
}
void Delay_Short(unsigned int uiDelayshort) 
{
	unsigned int i;
	for (i=0;i<uiDelayshort;i++) 
	{
		;//一个分号相当于执行一条空语句		
	}
}
void Delay_Long(unsigned int uiDelaylong) 
{
	unsigned int i;
	unsigned int j;
	for (i=0;i<uiDelaylong;i++) 
	{
		for (j=0;j<500;j++) //内嵌循环的空指令数量 
		{
			;//一个分号相当于执行一条空语句			
		}
	}
}
void Init_Sys() //第一区 初始化单片机 
{
		SJA_RST = 0;//SJA1000复位有效
		Delay_Short(10);	//延时
    SJA_RST = 1;//CAN总线复位管脚,复位无效
    SJA_CS = 0;//CAN总线片选有效
	
    EX1 = 1;//外部中断1使能;CAN总线接收中断
    IT1 = 0;//CAN总线接收中断,低电平触发
		PX1=1;  // 外部中断最高优先级
	
    //IT0 = 1;//外部中断0负边沿触发
    //EX0 = 1;//打开外部中断0
	
	//定时器0配置
		TMOD=0x01;//设置定时器 0 为工作方式 1	
	//TH0=0xfc;   
	//TL0=0x66;   
	
		TH0=0xfe;//重装初始值(65535-500)=65035=0xfe0b	
		TL0=0x0b;

	//中断配置	
		ET0=1;		//定时器0中断使能
		TR0=1;			//开定时器0 	
    EA = 1; //打开总中断

	//led_dr=0;//关闭独立 LED 灯	
	//beep_dr=1;//用 PNP 三极管控制蜂鸣器,输出高电平时不叫。	
	//hc595_drive(0x00,0x00);//关闭所有经过另外两个 74HC595 驱动的 LED 灯	
	
}
void Init_Peripheral() //第二区 初始化外围 
{
	//static  u8 bdata sGu8Register_Status;
	
	ucACRR[0]  = 0x11;
	ucACRR[1]  = 0x22;
	ucACRR[2]  = 0x33;
	ucACRR[3]  = 0x44;	//设置节点1的接收代码寄存器值
	ucAMRR[0]  = 0xff;	
	ucAMRR[1]  = 0xff;
	ucAMRR[2]  = 0xff;
	ucAMRR[3]  = 0xff;	//设置节点1的屏蔽代码寄存器值
    do
    {//  .0=1---reset MODRe,进入复位模式,以便设置相应的寄存器
     //防止未进入复位模式,重复写入
     	SJA_MOD = RM_BIT |AFM_BIT;
			ucRegister_StatusTemp = SJA_MOD ;
    }
    while(!(ucRegister_StatusTemp & 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;//=0xaa 配置输出控制寄存器
    SJA_CMR  = RRB_BIT;//释放接收缓冲器

    SJA_ACR0  = ucACRR[0];
    SJA_ACR1  = ucACRR[1];
    SJA_ACR2  = ucACRR[2];
    SJA_ACR3  = ucACRR[3];//初始化标示码	 验收代码寄存器

    SJA_AMR0  = ucAMRR[0];
    SJA_AMR1  = ucAMRR[1];
    SJA_AMR2  = ucAMRR[2];
    SJA_AMR3  = ucAMRR[3];//初始化掩码  验收屏蔽寄存器

    do	//确保进入自接收模式
    {	
			SJA_MOD   = STM_BIT;
			ucRegister_StatusTemp  = SJA_MOD;
    }
    while( !(ucRegister_StatusTemp & STM_BIT) );
	
	
	
	ucDigDot1=0;	
	ucDigDot2=0;
	ucDigDot3=0;
	ucDigDot4=0;
	ucDigDot5=0;
	//ucDigDot6=0;
	//ucDigDot7=0;
	//ucDigDot8=0; //小数点全部不显示	

	
	EA=1;//开总中断	
	ET0=1;//允许定时中断	
	TR0=1;//启动定时中断	
	
}

这是源代码按了2次后

这是修改后的代码按了2次后

反正咋说呢,想了很久,没想明白,难道自收发的同步显示其实有问题? 就应该有个差值?

还是,移植的那个数码管程序,多了一个变量缘故?

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

属鼠的金牛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值