做个网站做什么呢站长工具app下载
断断续续,零星学习这个
首先,在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;//打开外部中断0EA = 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晶振,波特率125KbpsSJA_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,//00xF9,//10xA4,//20xB0,//30x99,//40x92,//50x82,//60xF8,//70x80,//80x90,//90x88,//10-a0x83,//11-b0xC6,//12-c0xA1,//13-d0x86,//14-e0x8E //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;//本程序中需要被设置的参数 4volatile 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 序号00xF9, //1 序号10xA4, //2 序号20xB0, //3 序号30x99, //4 序号40x92, //5 序号50x82, //6 序号60xF8, //7 序号70x80, //8 序号80x90, //9 序号90x88, //A 序号100x83, //B 序号110xC6, //C 序号120xA1, //D 序号130x86, //E 序号140x8E, //F 序号150xFF, //不显示 序号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) //按键服务状态切换 { //按键1case 1:// 加按键 对应朱兆祺学习板的 S1 键switch(ucWd) //在不同的窗口下,设置不同的参数 { //窗口 1 case 1://uiSetData1++;ucTxd_data++;//发送的数据加1if(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;
/* //按键2case 2:// 减按键 对应朱兆祺学习板的 S5 键switch(ucWd) //在不同的窗口下,设置不同的参数 { //窗口 1case 1:uiSetData1--;if(uiSetData1>9999) {uiSetData1=0;//最小值是 0 }ucWd1Update=1;//窗口 1 更新显示 break;//窗口 2case 2:uiSetData2--;if(uiSetData2>9999) {uiSetData2=0;//最小值是 0 }ucWd2Update=1;//窗口 2 更新显示 break;//窗口 3case 3:uiSetData3--;if(uiSetData3>9999) {uiSetData3=0;//最小值是 0 }ucWd3Update=1;//窗口 3 更新显示 break;//窗口 4case 4:uiSetData4--;if(uiSetData4>9999) {uiSetData4=0;//最小值是 0 }ucWd4Update=1;//窗口 4 更新显示 break;}//uiVoiceCnt=const_voice_short;//按键声音触发,滴一声就停ucKeySec=0;//响应按键服务处理程序后,按键编号清零,避免一致触发 break;
*/
/*//按键3case 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 & 0x7fswitch(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;//中断请求标志清0ucPeli_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晶振,波特率125KbpsSJA_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次后
反正咋说呢,想了很久,没想明白,难道自收发的同步显示其实有问题? 就应该有个差值?
还是,移植的那个数码管程序,多了一个变量缘故?