📄 protocolkw2000.c
字号:
/******************************************************************************************
* 目的:KWP2000 协议库函数
* 功能:提供基本 KWP2000 协议操作接口
* 模块依赖:SCI.h Timer.h
* 注意:协议实现部分采用对外查询对内中断方式处理,因为难度太大没有实现对外中断方式的接口
仅在发送和接收之间留下时间空隙,可在发送和接收之间插入代码,但请保证代码执行时间
小于协议规定的桢回送时间 P2(0MS~1000MS),否则接收数据将丢失
Note 2007.10.4. 隐藏BUG 在通讯链路数据回送状态下有数据发送请求将不等待上一次汽车
的链路请求回送完毕直接发送,此时会导致通讯失败,室内实测时还未出现该情况
******************************************************************************************/
#include <stdio.h>
#include "compiler.h"
#include "SCI.h"
#include "Timer.h"
#include "ProtocolKw2000.h"
#include "Cable.h"
#ifdef DEBUGKW2000
#include "Display.h"
#include "Keyboard.h"
#endif
#define T0TIME 5 //定时器初始化时间
static struct KW2000 //模块数据结构
{
unsigned int HTime; //触发高电瓶时间
unsigned int LTime; //触发低电瓶时间
unsigned char hold[20]; //存放保持链路发送数据
unsigned char *Waitsend; //待发送数据
unsigned char *Waitread; //待接收数据
volatile unsigned char Flashset; //发送数据就位标志
volatile unsigned char Readset; //接收数据就位标志
unsigned char Count; //发送计数器
unsigned char Lenth; //数据包长度
unsigned char Chksum; //校验
volatile int MScount; //MS记数
int Btyetime; //字节间距
int HoldT; //链路保持间距
} Tagkw;
/*
**-----------------------------------------------------------------------------------------
** 初始化 KWP2000 协议通讯模块
**-----------------------------------------------------------------------------------------
*/
void KW_Init( )
{
#ifdef DEBUGMODE
DebugString( "KW_Init()" );
#endif
Tagkw.Waitsend = NULL;
Tagkw.Waitread = NULL;
Tagkw.Flashset = 0;
Tagkw.Readset = 1;
Tagkw.Count = 0;
Tagkw.Lenth = 0;
Tagkw.Chksum = 0;
Tagkw.MScount = 0;
Tagkw.Btyetime = 0;
Tagkw.HoldT = 1000;
Tagkw.hold[0] = 0;
Tagkw.HTime = 24;
Tagkw.LTime = 25;
}
/*
**-----------------------------------------------------------------------------------------
** 插入 KWP2000 通讯链路
** KeepDig:协议请求方保持链路样本
** HoldTime: 通讯链路保持时间
** 返回: 1
**-----------------------------------------------------------------------------------------
*/
char KW_Maintain( unsigned char *KeepDig, int HoldTime )
{
#ifdef DEBUGMODE
DebugString( "KW_Maintain()" );
#endif
unsigned char Len;
unsigned char i;
Tagkw.HoldT = HoldTime;
Len = KW_Getlen( KeepDig );
if( Len >= 20 )
{
return FAIL;
}
else
{
//NULL
}
for( i=0; i<Len; i++ )
{
Tagkw.hold[i] = KeepDig[i];
}
return SUCCESS;
}
/*
**-----------------------------------------------------------------------------------------
** 0x55波特触发函数,addr1决定触发ID,PORT为选脚,有成功判定
**-----------------------------------------------------------------------------------------
*/
unsigned char KWIso_link( unsigned char addr1,unsigned char portK,unsigned char portL )
{
#ifdef DEBUGMODE
DebugString( "iso_link()" );
#endif
unsigned char kb2;
unsigned char i=0;
//初始化所需的硬件环境
TimeDestroy( TIMER0 );
TimeStop( TIMER0 );
SCIdestroy();
//选通 L 线
ChanSet( portK,portL );
//打开L线,与K线同步
SCITXD( THIGH ); delay(500); //一段时间的高电平清总线
//发送请求的系统ID号
SCITXD( TLOW ); delay(200); //5波特起始位 //20ms
//发送请求的系统ID号
if( ( addr1&0x01 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );//20ms
if( ( addr1&0x02 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x04 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x08 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x10 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x20 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x40 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
if( ( addr1&0x80 ) != 0 ) SCITXD( THIGH );
else SCITXD( TLOW );
delay( 200 );
SCITXD( THIGH );
delay( 200 ); //结束位 200ms
ChanSet( portK,0 );
//等待0X55回送 记算动态波特率
if( !SCIDynamicBuad() )
{
return FAIL;
}
//接收ECU回应校验拨特率
TimeInit( TIMER0,10 ); //初始化T0 1ms
TimeStart( TIMER0 );
SCIENcontrol( 1 ); //允许读
for( i=0; i<2; i++ ) //等待汽车反还2个K(k1,k2)
{
TimeSet( TIMER0, 0 );
while( !SCIRE() && !TimeBreak( TIMER0,100 ) )
{
//NULL
}
if( TimeBreak( TIMER0,100 ) )
{
return FAIL;
}
kb2 = SCIreadin();
}
//触发完后关闭选择L线
//关闭L线
delay( 30 ); //等待30毫秒
kb2 = ~kb2;
SCIsend(kb2); //将后一个K取反回送给汽车校验当前设定拨特率是否正确
delay( 30 );
return SUCCESS;
}
/*
**-----------------------------------------------------------------------------------------
** KWP2000 快速触发延时设定
** Thigh:快速触发高电瓶延时
** Tlow :快速触发低电瓶延时
**-----------------------------------------------------------------------------------------
*/
void KW_SetLinkTime( unsigned int Thigh, unsigned int Tlow )
{
Tagkw.HTime = Thigh;
Tagkw.LTime = Tlow;
}
/*
**-----------------------------------------------------------------------------------------
** KWP2000 通讯连接
** portK:电缆 K 线
** portL:电缆 L 线
** Buadrate:通讯波特率
** LinkDig:协议请求方通讯连接样本
** SysId:待进入的系统对应触发ID
**-----------------------------------------------------------------------------------------
*/
char KW_Link( unsigned char portK, unsigned char portL, unsigned long Buadrate, unsigned char *LinkDig, unsigned char SysId )
{
#ifdef DEBUGMODE
DebugString( "KW_Link()" );
unsigned char Rig[50];
#endif
unsigned char Temp[20] = { 0, 0, 0, 0, 0, 0 };
int i;
//KW2000快速触发
SCIini( Buadrate ); //SCI 10.4K
TimeInit( TIMER0,5 ); //初始化T0 10ms
//电缆选通
ChanSet( portK,portL );
SCITXD(THIGH); delay(50);
SCITXD(TLOW); delay(Tagkw.LTime); //低电平
SCITXD(THIGH); delay(Tagkw.HTime); //高电平
//关闭 L 线
ChanSet( portK,0 );
//触发请求数据
SCIload( Kw2000Scon );
TimeLoad( TIMER0, Kw2000Time );
TimeStart( TIMER0 );
//发送触发数据
Tagkw.MScount = 0;
Tagkw.Waitsend = LinkDig;
Tagkw.Btyetime = 10;
Tagkw.Lenth = KW_Getlen( LinkDig );
Tagkw.Chksum = 0;
for( i=0; i<Tagkw.Lenth-1; i++ )
{
Tagkw.Chksum += Tagkw.Waitsend[i];
}
Tagkw.Waitsend[i] = Tagkw.Chksum;
Tagkw.Count = 0;
SCIsendin( Tagkw.Waitsend[Tagkw.Count++] ); //发送第一字节
Tagkw.Flashset = 1; //发送数据更新就绪
if( KW_Read( Temp, 800, 20 ) == SUCCESS ) //快速触发成功
{
return SUCCESS;
}
else
{
#ifdef DEBUGKW2000
sprintf( Rig,"%x,%x,%x,%x,%x",Temp[0],Temp[1],Temp[2],Temp[3],Temp[4] );
LcdStr86( 1, 0, Rig, BLACK );
TimeRelease();
SCIRelease();
GetAKey( 0 );
#endif
//NULL
}
TimeRelease();
SCIRelease();
delay( 5000 ); //等待ECU冷却
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -