断断续续,零星学习这个
首先,在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次后
反正咋说呢,想了很久,没想明白,难道自收发的同步显示其实有问题? 就应该有个差值?
还是,移植的那个数码管程序,多了一个变量缘故?