📄 can_232.c
字号:
//---------------------------------------------------------------------
//创建日期: 2006年3月17日
//文件名称: can_232.c
//作 者: 边国利
//说 明: 1.本程序是用STC89C52RC芯片的串口接收FT025发送的数据,再将其用CAN
// 总线发送出去,另一方面将从CAN总线上的数据通过串口发送到FT025中
// (CAN总线是用52 CPU外扩SJA1000实现的)
// 2.利用T0的计数器功能将一个1024Hz的方波信号分频为2Hz的方波信号
// 通过一个I/O输出
// 3.利用T1的计数器功能将另一个1024Hz的方波信号分频为2Hz的方波信
// 号通过一个I/O输出
//---------------------------------------------------------------------
#include "Can_232.H"
//#define JINGZHEN_11M
//分频因子:FenPin=(65536-FenPinH*256-FenPinL)*2
//分频公式:fO=fI/FenPin
//512分频
#define FenPinL 0
#define FenPinH 0xFF
//#define CPU_CLK6 //单片机工作于6时钟,如果不声明此变量,则工作于12时钟
//2048分频
//#define FenPinL 0
//#define FenPinH 0xFC
//读取Flash的特殊功能寄存器
sfr WDTRST = 0xE1;
sfr ISP_DATA = 0xE2;
sfr ISP_ADDRH = 0xE3;
sfr ISP_ADDRL = 0xE4;
sfr ISP_CMD = 0xE5;
sfr ISP_TRIG = 0xE6;
sfr ISP_CONTR = 0xE7;
extern void _nop_(void);
#define ISP_BYTE_READ 1 //字节读
#define ISP_BYTE_WRITE 2 //字节写
#define ISP_ERASE 3 //扇区擦除
#define ISP_WAIT_TIME 1 //设置等待时间,40MHz以下0,20MHz以下1,10MHz以下2,5MHz以下3
#define EEP_Start 0x2000 //Stc89c51和Stc89c52芯片的EEPROM起始地址是2000H
#define EEP_Offset 0x0200 //存储最后一次设置标志量
//#define EEP_Start 0x8000 //Stc89c54,Stc89c55和Stc89c58芯片的EEPROM起始地址是8000H
typedef union _I2C_
{
unsigned short i;
unsigned char c[2];
}I2C;
unsigned short OffsetAddr;
I2C OffsetFlag;
unsigned short usTmp;
unsigned char RunStatus;//运行状态
//---------------------------------------------------------------------
//函数名称: EEP_BYTE_READ
//功 能: 从EEPROM中读取一个字节
//参 数: EEP_ADDR:读取地址
//返 回 值: 读回的数据
//作 者: 边国利
//日 期: 2006年7月18日
//---------------------------------------------------------------------
unsigned char EEP_BYTE_READ(unsigned short EEP_ADDR)
{
I2C x;
bit tmpBit;
//字节地址
x.i=EEP_ADDR;
ISP_ADDRH=x.c[0];
ISP_ADDRL=x.c[1];
tmpBit=EA;
EA=0;//关总中断
ISP_CONTR=(0x80|ISP_WAIT_TIME);//允许ISP操作,并设置等待时间
ISP_CMD=ISP_BYTE_READ;
//触发命令
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
ISP_CONTR=0;//出于安全考虑(可以不加)
ISP_CMD=0;//出于安全考虑(可以不加)
EA=tmpBit;//开总中断
return ISP_DATA;
}
//---------------------------------------------------------------------
//函数名称: EEP_BYTE_WRITE
//功 能: 向EEPROM中写一个字节
//参 数: EEP_ADDR:写入地址,c:写入数据
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年7月18日
//---------------------------------------------------------------------
void EEP_BYTE_WRITE(unsigned short EEP_ADDR,unsigned char c)
{
I2C x;
bit tmpBit;
x.i=EEP_ADDR;
//字节地址
ISP_ADDRH=x.c[0];
ISP_ADDRL=x.c[1];
ISP_DATA=c;
tmpBit=EA;
EA=0;//关总中断
ISP_CONTR=(0x80|ISP_WAIT_TIME);//允许ISP操作,并设置等待时间
ISP_CMD=ISP_BYTE_WRITE;
//触发命令
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
ISP_CONTR=0;//出于安全考虑(可以不加)
ISP_CMD=0;//出于安全考虑(可以不加)
EA=tmpBit;
}
//---------------------------------------------------------------------
//函数名称: EEP_ERASE
//功 能: 扇区擦除
//参 数: SectorNo:扇区号,Stc89c51和Stc89c52是1~8,Stc89c54,Stc89c55和Stc89c58是1~58
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年7月18日
//---------------------------------------------------------------------
void EEP_ERASE(unsigned char SectorNo)
{
I2C x;
bit tmpBit;
if(SectorNo>58) return;
SectorNo--;
x.i=EEP_Start+SectorNo*512;
//字节地址
ISP_ADDRH=x.c[0];
ISP_ADDRL=x.c[1];
tmpBit=EA;
EA=0;//关总中断
ISP_CONTR=(0x80|ISP_WAIT_TIME);//允许ISP操作,并设置等待时间
ISP_CMD=ISP_ERASE;
//触发命令
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
ISP_CONTR=0;//出于安全考虑(可以不加)
ISP_CMD=0;//出于安全考虑(可以不加)
EA=tmpBit;
}
//---------------------------------------------------------------------
//函数名称: InitCan
//功 能: 初始化Can控制器
//参 数: 无
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年3月20日
//---------------------------------------------------------------------
void InitCan(void)
{
//进入复位模式;
while((ModeControlReg & RM_RR_Bit)==0)
{
ModeControlReg =RM_RR_Bit;
}
#ifdef CPU_CLK6
ClockDivideReg=CANMode_Bit|CBP_Bit; //CLKOUT引脚输出时钟且2分频,工作模式设
//为PeliCan模式(支持2.0A和2.0B)
#else
ClockDivideReg=CANMode_Bit|CBP_Bit|DivBy1; //CLKOUT引脚输出时钟且不分频,工作模式设
//为PeliCan模式(支持2.0A和2.0B)
#endif
InterruptEnReg=ClrIntEnSJA; //禁止所有中断
//Can_IR=0; //清除中断标志
AcceptCode0Reg=0; //验收代码0
AcceptCode1Reg=0; //验收代码1
AcceptCode2Reg=0; //验收代码2
AcceptCode3Reg=0; //验收代码3
AcceptMask0Reg=0xFF; //验收屏蔽0
AcceptMask1Reg=0xFF; //验收屏蔽1
AcceptMask2Reg=0xFF; //验收屏蔽2
AcceptMask3Reg=0xFF; //验收屏蔽3
#ifdef JINGZHEN_11M
switch(btr)
{
case btr_10k:
//通讯速率设为10K,SJW=1,BTL=19,Sampling point=89.5%
BusTiming0Reg=0x1C;
BusTiming1Reg=0x1F;
break;
case btr_20k:
//通讯速率设为20K,SJW=1,BTL=12,Sampling point=83.3%
BusTiming0Reg=0x16;
BusTiming1Reg=0x18;
break;
case btr_50k:
//通讯速率设为50K,SJW=1,BTL=11,Sampling point=81.8%
BusTiming0Reg=0x09;
BusTiming1Reg=0x17;
break;
case btr_125k:
//通讯速率设为125K,SJW=1,BTL=11,Sampling point=81.8%
BusTiming0Reg=0x03;
BusTiming1Reg=0x17;
break;
case btr_250k:
//通讯速率设为250K,SJW=1,BTL=11,Sampling point=81.8%
BusTiming0Reg=0x01;
BusTiming1Reg=0x17;
break;
default:
//通讯速率设为500K,SJW=1,BTL=11,Sampling point=81.8%
BusTiming0Reg=0x00;
BusTiming1Reg=0x17;
}
#else
switch(btr)
{
case btr_10k:
//通讯速率设为10K,SJW=1,BTL=21,Sampling point=81.0%
BusTiming0Reg=0x25;
BusTiming1Reg=0x3F;
break;
case btr_20k:
//通讯速率设为20K,SJW=1,BTL=21,Sampling point=81.0%
BusTiming0Reg=0x12;
BusTiming1Reg=0x3F;
break;
case btr_50k:
//通讯速率设为50K,SJW=1,BTL=20,Sampling point=85.0%
BusTiming0Reg=0x07;
BusTiming1Reg=0x2F;
break;
case btr_125k:
//通讯速率设为125K,SJW=1,BTL=16,Sampling point=87.5%
BusTiming0Reg=0x03;
BusTiming1Reg=0x1C;
break;
case btr_250k:
//通讯速率设为250K,SJW=1,BTL=16,Sampling point=87.5%
BusTiming0Reg=0x01;
BusTiming1Reg=0x1C;
break;
case btr_500k:
//通讯速率设为500K,SJW=1,BTL=16,Sampling point=87.5%
BusTiming0Reg=0x00;
BusTiming1Reg=0x1C;
break;
case btr_800k:
//通讯速率设为800K,SJW=1,BTL=10,Sampling point=80.0%
BusTiming0Reg=0x00;
BusTiming1Reg=0x16;
break;
case btr_1M:
//通讯速率设为1M,SJW=1,BTL=8,Sampling point=75.0%
BusTiming0Reg=0x00;
BusTiming1Reg=0x14;
break;
}
#endif
//TX0悬空,TX1推挽,TX1的输出极性控制位置1,正常输出模式
OutControlReg = Tx1Float|Tx0PshPull|NormalMode;
//OutControlReg = Tx1PullDn|Tx0PullUp|ClkOutMode;//NormalMode;
//OutControlReg = Tx1PullDn|Tx0PullUp|OCPOL0_Bit|NormalMode;
//RxBufstartAdr=0; //RX缓冲器起始地址
//TxErrCountReg=0x88; //TX错误计数器
//ErrCodeCapReg=0x0D; //错误代码捕捉
//允许数据超载中断,错误警告中断,发送中断,接收中断
//InterruptEnReg=RIE_Bit|TIE_Bit;
InterruptEnReg=/*DOI_Bit|EI_Bit|*/RIE_Bit|TIE_Bit;
//退出复位模式
while((ModeControlReg & RM_RR_Bit) != ClrByte)
{
ModeControlReg = ClrByte;
}
//释放接收缓冲区,清除数据超载位
CommandReg=RRB_Bit|CDO_Bit;
}
//---------------------------------------------------------------------
//函数名称: ReadCanID
//功 能: 读取Can通讯数据帧的11位标志符的低三位
//参 数: 无
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年3月21日
//---------------------------------------------------------------------
//void ReadCanID(void)
//{
// unsigned char i=0;
// Can_ID=P1&0xFC;
// while(i!=Can_ID)
// {
// i=Can_ID;
// _nop_();
// _nop_();
// _nop_();
// _nop_();
// Can_ID=P1&0xFC;
// }
// Can_ID=~Can_ID;
// Can_ID>>=2;
// Can_ID|=BIT6;
//}
//---------------------------------------------------------------------
//函数名称: GetEven
//功 能: 求一个字节的偶校验
//参 数: 待处理的字节
//返 回 值: 处理后的字节
//作 者: 边国利
//日 期: 2006年3月20日
//---------------------------------------------------------------------
unsigned char GetEven(unsigned char a)
{
//偶校验,求校验位
bitChar=a;
B_7=0;
B_7^=B_6;
B_7^=B_5;
B_7^=B_4;
B_7^=B_3;
B_7^=B_2;
B_7^=B_1;
B_7^=B_0;
return bitChar;
}
//---------------------------------------------------------------------
//函数名称: SendData_Can
//功 能: 通过Can总线向外发送数据
//参 数: BlockIndex,要发送的块索引
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年3月27日
//---------------------------------------------------------------------
void SendData_Can(unsigned char data * data BlockIndex)
{
unsigned char i,j;
unsigned char k,tmpBlk;//数据长度;
//中止发送
//CommandReg=AT_Bit;
tmpBlk=*BlockIndex;
(*BlockIndex)++;
i=tmpBlk*8;
j=i+8;
//求数据长度
k=8;
if(j>CAN_SendLen)
{
j=CAN_SendLen;
k=j-i;
*BlockIndex=5;
}
//将数据写到CAN控制器
tmpBlk++;
tmpBlk<<=1;
tmpBlk++;
#ifdef KuoZhan
TxFramInFo=0x80+k; //TX 帧信息,最高位是扩展帧标志,低四位是数据长度
TxBuffer[0]=0;//TX 识别码1,
TxBuffer[1]=0;//TX 识别码2,
TxBuffer[2]=(tmpBlk<<2)|((Can_ID>>5)&3);//TX 识别码3,,高四位是命令识别码,低四位是地址的高四位
TxBuffer[3]=Can_ID<<3;//TX 识别码4,高五位是地址的低五位,低三位无意义
#else
tmpBlk<<=4;
TxFramInFo=k; //TX 帧信息,高四位保持全0,低四位是数据长度
TxBuffer[0]=tmpBlk|Can_ID_H;//TX 识别码1,高四位是命令识别码,低四位是地址的高四位
//TX 识别码2,高三位是地址的低三位,低五位无意义
TxBuffer[1]=Can_ID_L;
#endif
k+=StartNo;
for(j=StartNo;j<k;j++,i++)
{
TxBuffer[j]=CAN_SendBuf[i];
}
//请求发送
CommandReg=AT_Bit|TR_Bit;
}
//---------------------------------------------------------------------
//函数名称: WDT_RST
//功 能: 复位并启动WDT
//参 数: 无
//返 回 值: 无
//作 者: 边国利
//日 期: 2006年3月21日
//---------------------------------------------------------------------
void WDT_RST(void)
{
WDTRST=0x35;
}
//---------------------------------------------------------------------
//函数名称: ReadCanID
//功 能: 读取Can通讯数据帧的11位标志符的低三位
//参 数: 无
//返 回 值: 执行结果
// 0:成功
// 1:不是本机数据
// 2:错误命令
// 3:目前不支持的命令
// 4:出错
// 5:修改CAN波特率,要求重新初始化CAN控制器
//作 者: 边国利
//日 期: 2006年3月21日
//---------------------------------------------------------------------
unsigned char ReadCan(void)
{
unsigned char j,x;
bit aa,bb,cc;
union
{
unsigned long l;
unsigned int mn[2];
//unsigned int mn;
struct
{
unsigned char i;
unsigned char k;
unsigned char m;
unsigned char n;
}yy;
}xx;
//读取中断源
xx.yy.i=InterruptReg;
InterruptReg=0;//清除中断标志
aa=xx.yy.i&RI_Bit;
bb=xx.yy.i&TI_Bit;
//#ifdef KuoZhan
if((!aa)&&(!bb))
bb=1;
//#endif
if(aa)
{//接收到数据
xx.yy.i=RxFramInFo;//读取信息
//帧长度
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -