提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、网络拓扑图
- 二、数据库文件设计
- 四、Panel设计
- 五、CAPL代码实现
- 六、Automation Sequences
- 七、分析窗口设置
- 八、Trace窗口与Logging
- 九、Desktop布局
- 十、工程运行测试
前言
继续学习《CANoe开发从入门到精通》,实现第二个例程。
由于篇幅原因,且在《一步一步动手实现CANoe例程》中有详细的步骤,本例程中数据库文件设计、系统变量及Panel设计就不再面面俱到的展开。
例程主要实现的功能如下:
(1)控制面板:通过调节钥匙锁车/开锁按钮、引擎钥匙旋钮、离合器档位切换、刹车模拟开关、危险警示灯按钮、左转右转按钮、引擎速度滑动条和车速滑动条等控件,模拟IPC需要的测试条件。
(2)显示面板:接收来自总线的报文,显示引擎信息、车速信息、离合器档位信息和车灯的状态等。
(3)添 加 Automation Sequences 功 能 实 现 Signal 和 System Variable的自动变化。
(4)添加Graphic窗口和State Tracker追踪窗口等,便于分析和检测等相关活动。
一、网络拓扑图
网络由仪表单元(IPC)、网关(Gateway)、车身控制器(BCM)三部分组成;
网络拓扑如下图所示:
二、数据库文件设计
1、以Vector_IL_Basic Template为模板创建一个名称为VehicleSystem的CAN数据库。将它的Protocol设置为CAN。
2、右击Network Nodes,新建BCM、IPC、Gateway三个网络节点。如下图所示:
3、右击Message,新建报文,参数设置如下所示:
4、右击Signal,新建信号,参数设置如下所示:
5、在CANdb++工具栏上,单击Value Tables图标,进入Value Tables界面,在空白处右击,创建Value Table如下:
在Value Descriptions中参数设置如下所示:
至此,例程需要的DBC文件已经完成,将其导入仿真工程后如下所示:
三、设置系统变量
1、在CANoe主界面中选择Environment→System Variables,在左上侧空白窗口中单击鼠标右键系统变量,需要定义的系统变量列表及属性设置如下:
2、部分变量需要自己实现Value Table,
以Gear_Status为例,Value Table实现方法如下:
2.1、Values Table下拉选择Custom,如下图所示:
2.2、点击Value Table Items右侧的图标,进入Value Table编辑界面,如下图所示:
修改Value和Description为需要设置的值,如下所示:
完成后如下所示:
四、Panel设计
需要设计两个面板,用于模拟相关操作和数据的显示。
注意,以下列出的控件属性均为重要属性,未提及的属性将采用默认设置。
1、control面板主要用于模拟来自实际中BCM和Gateway的相关操作,面板的设计效果如下图所示:
控件列表及重要属性按照《CANoe开发从入门到精通》第292页来设定。
2、IPC面板主要用于模拟实际的仪表盘显示功能,设计效果如下图所示:
控件列表及重要属性按照《CANoe开发从入门到精通》第297页来设定。
设计时的图片素材在CANoe提供的Sample Configurations 16.4.4文件夹下搜索而来,部分素材和书上例程素材不同,稍作修改即可。
比如,引擎温度显示,书上例程左侧还有个温度刻度表,设计时选择Meter 1。我搜的图片没有,就加个简单的Input/Output Box 1来显示。
五、CAPL代码实现
1、IPC.can
IPC.can主要实现了报文的发送机制。当车在锁车状态时,报文不能通过IL层发送,解锁后周期性报文便可以通过IL层发送出去。
/*@!Encoding:936*/
includes
{
}
variables
{
int busflag = 0;
}
on preStart
{
ILControlInit();
ILControlStop();
}
on signal_update LockStatus
{
if(this!=busflag)
{
if(this==1)
{
ILControlStart();
}
else if(this==0)
{
ILControlStop();
}
busflag = this;
}
}
on signal_update Gear
{
@Cluster::Gear_Status = this;
}
2、BCM.can
在BCM.can中主要实现了转向灯的动态闪烁;
/*@!Encoding:936*/
includes
{
}
variables
{
msTimer msTcrank;
msTimer msTIL;
int flashPeriod=500;
int turnLightStatus;
msTimer msTleftflash,msTrightflash;
message Driver_Info Msgdriver;
}
on preStart
{
ILControlInit();
ILControlStop();
}
on sysvar_update Vehicle_Key::Key_State
{
$Ignition_Info::KeyState=@this;
if(@this==3)
{
@Vehicle_Control::Speed_Up=0;
setTimer(msTcrank, 800);
}
}
on timer msTcrank
{
$KeyState=2;
@sysvar::Vehicle_Key::Key_State=2;
}
on sysvar_update Vehicle_Key::Car_Driver
{
if(@this==1)
{
Msgdriver.byte(0)=0;
}
else if(@this==2)
{
Msgdriver.byte(0)=0x1;
}
output(Msgdriver);
}
on sysvar_update Vehicle_Key::Unlock_Car
{
if(@this==1)
{
ILControlStart();
$LockStatus=1;
@Vehicle_Key::Car_Driver=2;
}
}
on sysvar_update Vehicle_Key::Lock_Car
{
if(@this==1)
{
$LockStatus=0;
setTimer(msTIL,1500);
}
}
on timer msTIL
{
ILControlStop();
}
void LightOFF(void)
{
$VehicleLight=0;
turnLightStatus=0;
$LightStatus=0;
}
on sysvar Vehicle_Control::Left_Turn_Enable
{
if(@this==1)
{
@sysvar::Vehicle_Control::Right_Turn_Enable=0;
$VehicleLight=1;
turnLightStatus=1;
settimer(msTleftflash,flashPeriod);
}
else
{
if(@Vehicle_Control::Right_Turn_Enable==0 && @Vehicle_Control::Hazards_Enable==0)
{
LightOFF();
}
cancelTimer(msTleftflash);
@Cluster::Left_Turn_Indicator=0;
}
}
on timer msTleftflash
{
$LightStatus=!$LightStatus;
@Cluster::Left_Turn_Indicator=!@Cluster::Left_Turn_Indicator;
setTimer(msTleftflash,flashPeriod);
}
on sysvar Vehicle_Control::Right_Turn_Enable
{
if(@this==1)
{
@sysvar::Vehicle_Control::Left_Turn_Enable=0;
$VehicleLight=2;
turnLightStatus=2;
setTimer(msTrightflash,flashPeriod);
}
else
{
if(@Vehicle_Control::Left_Turn_Enable==0 && @Vehicle_Control::Hazards_Enable==0)
{
LightOFF();
}
cancelTimer(msTrightflash);
@Cluster::Right_Turn_indicator=0;
}
}
on timer msTrightflash
{
$LightStatus=!$LightStatus;
@Cluster::Right_Turn_indicator=!@Cluster::Right_Turn_indicator;
settimer(msTrightflash,flashPeriod);
}
on sysvar Vehicle_Control::Hazards_Enable
{
if(@this==1)
{
$VehicleLight=3;
@Cluster::Left_Turn_Indicator=1;
@Cluster::Right_Turn_indicator=1;
setTimer(msTleftflash,flashPeriod);
setTimer(msTrightflash,flashPeriod);
}
else
{
$VehicleLight=turnLightStatus;
switch(turnLightStatus)
{
case 1:
cancelTimer(msTrightflash);
@Cluster::Right_Turn_indicator=0;
break;
case 2:
cancelTimer(msTleftflash);
@Cluster::Left_Turn_Indicator=0;
break;
case 0:
cancelTimer(msTrightflash);
cancelTimer(msTleftflash);
$LightStatus=0;
@Cluster::Right_Turn_indicator=0;
@Cluster::Left_Turn_Indicator=0;
break;
}
}
}
3、Gateway.can
Gateway.can 中 , 根 据 Automation Sequences 中 System variable的变化,动态改变车速、引擎转速、油温和油量的值。该程序中车速、引擎转速、油温、油量变化因子只是为了配合Panel面板中可变化范围或可视化效果而增加的。
/*@!Encoding:936*/
includes
{
}
variables
{
msTimer msTVehSpeedDown;
msTimer msTEngSpeedDown;
dword WritePage;
int busflag=0;
}
on preStart
{
ILControlInit();
ILControlStop();
writeLineEx(WritePage,1,"--------This demo demonstrated the CAN bus suimulation!!--------");
writeLineEx(0,1,"Press <1> to start/stop CAN_logging");
}
on key '1'
{
int flag;
if(flag==0)
{
flag=1;
write("CAN logging starts");
startlogging("CAN_Logging",500);
}
else
{
flag=0;
write("CAN logging ends");
stopLogging("CAN_Logging",1000);
}
}
on signal_update LockStatus
{
if(this!=busflag)
{
if(this==1)
{
ILControlStart();
}
else if(this==0)
{
ILControlStop();
}
busflag=this;
}
}
on sysvar Vehicle_Control::Gear
{
$Gear=@this;
}
void EngineData_Init(void)
{
$VehicleSpeed=0;
$EngSpeed=0;
$EngTemp=0;
$PetrolLevel=0;
}
on signal_update KeyState
{
if(this==0)
{
EngineData_Init();
}
if(this>0)
{
$PetrolLevel=255;
}
}
on sysvar_update Vehicle_Control::Eng_Speed
{
if(@Vehicle_Key::Key_State==2)
{
$EngineData::EngSpeed=@this;
}
else
$EngineData::EngSpeed=0;
}
on sysvar_update Vehicle_Control::Veh_Speed
{
if((@Vehicle_Control::Gear==3)&&(@Vehicle_Key::Key_State==2))
{
$VehicleData::VehicleSpeed=@this;
}
else
{
$VehicleData::VehicleSpeed=0;
}
}
on sysvar_update Vehicle_Control::Speed_Up
{
if(@this<50)
{
$EngTemp=@this*1.5;
}
else
{
$EngTemp=75;
}
if(@this<30)
{
$PetrolLevel=@this*8.5;
}
else
{
$PetrolLevel=255;
}
$VehicleSpeed=@this;
$EngSpeed=@this*40;
if(@this>120)
{
@this=60;
}
}
on sysvar Vehicle_Control::Brake
{
int i;
if(@this==1)
{
$GearLock=0;
setTimer(msTVehSpeedDown,20);
setTimer(msTEngSpeedDown,2);
}
else
{
$GearLock=1;
cancelTimer(msTVehSpeedDown);
cancelTimer(msTEngSpeedDown);
}
}
on timer msTVehSpeedDown
{
@Vehicle_Control::Veh_Speed=@Vehicle_Control::Veh_Speed-1;
setTimer(this,50);
if(@Vehicle_Control::Veh_Speed<=0)
{
cancelTimer(msTVehSpeedDown);
@Vehicle_Control::Veh_Speed=0;
}
}
on timer msTEngSpeedDown
{
@Vehicle_Control::Eng_Speed=@Vehicle_Control::Eng_Speed-40;
setTimer(this,50);
if(@Vehicle_Control::Eng_Speed<=0)
{
cancelTimer(msTEngSpeedDown);
@Vehicle_Control::Eng_Speed=0;
}
}
书上的程序,下图红框的判断觉得有点问题,做了修改
六、Automation Sequences
利用Automation Sequences,可以方便地实现system variables、environment variables或者signals的变化事件序列,同时也可以检查、判断当前变量或信号的值。在本实例中,创建一个名为Vehicle的Automation Sequences,其主要功能是改变变量的值来触发特定的功能。
在CANoe主界面,选择Simulation→Automation,在弹出的菜单Visual Sequences下空白处单击鼠标右键并在菜单中选择New,输入该Sequences的名称为Vehicle。单击工具栏中的Edit图标,开始编辑该Sequence。按照下表参数来设定:
在工具栏中单击RepeatSequence periodically图标和Start Sequence on measurement start图标使Vehicle自动序列能够在开始测量后自动循环运行。
七、分析窗口设置
1.Graphics窗口
在 CANoe 主界面选择 Analysis→Graphics→New GraphicWindow,输入名称为Signal Observe。该窗口左边信号列表栏中单
击选择Add Signals,在弹出的窗口中选择信号KeyState,同样地加入信号VehicleLight和VehicleSpeed。在Signal Observe窗口工具栏中单击Select y-axis view图标 ,在下拉表中选中Show All Y-Axis,这样上面添加的三个Signal就将显示在同一窗口中,如下图所示:
鼠标滚轮可以放大缩小坐标刻度,调整好坐标,方便后续观察。
2、State Tracker窗口
在 CANoe 菜 单 栏 中 选 择 Analysis→State Tracker→New State Tracker Window,输入名称为Signal State。在该窗口左边信号列表栏中单击鼠标右键并在菜单中选择Add Variables,添加系统变量Vehicle_Control中的Gear和Brake。在该窗口左边信号列表栏中单击鼠标右键并在菜单中选择Add Database Objects→Signals,添加信号VehicleLight ,如下图所示:
3、Data窗口
Data窗口中可以添加信号和系统变量,此例添加了Driver、EngSpeed、EngTemp、KeyState和VehicleSpeed五个信号,以及Left_Turn_Enable、
Right_Turn_Enable、Key_State和Gear_Status四个系统变量,如下图所示:
八、Trace窗口与Logging
Trace窗口帮助用户实时查看和分析总线上的数据。Logging记录下了整个仿真过程中的数据,在大数据量或长时间的测试情况下,使得用户可以在离线状态下查看总线的活动情况,同时,Logging功能记录的数据可以在CANoe中进行回放,对于总线上问题的复现起到了十分重要的作用。
在CANoe主界面下,进入Analysis选项卡,在Measurement Setup窗口中设置Trace窗口、Logging窗口。
1、右键Logging,选择Name,更名为CAN_Logging。设置Configuration,设置参数如下:
Logging右侧箭头指向一个Logging文件加,可以设置Logging文件保存位置。
2、创建CAN_Trace的Trace模块。
九、Desktop布局
点击下图红箭头所指,可以新增Desktop。
1、添加一个名为CAN的Desktop布局,将Control和IPC两个面板加进去,并设定为MDI Windows模式。同时添加Write窗口和Test Automation Sequences窗口,都设定为MDI Windows模式。布局好后效果图如下:
2、在Analysis的Desktop布局中添加Data、CAN Statistics、Signal State Tracker和Signal Observe等窗口
3、在Configuration的Desktop布局视图中保留Simulation Setup和Measurement Setup窗口,如下图所示:
4、在Trace的Desktop布局视图中保留Write、CAN Trace和Trace窗口,如下图所示:
十、工程运行测试
回到CANoe的Home界面,设置为仿真环境,点击Start开始仿真测试,结果如下:
CANoe仿真工程开发演示