一步一步动手实现CANoe例程

news2024/9/21 19:03:02

最近在学习CANoe,记录下学习路程,方便后续查看。参考《CANoe开发从入门到精通》和CANoe软件内附带的Easy例程,一步步去实现这个例程,稍加优化。

一、创建仿真工程

打开CANoe 16 SP4进入主界面,单击File→New可以看到CANoe提供的工程模板,如下图所示:
在这里插入图片描述
双击选择模板CAN 500kBaud 1ch,将生成一个空白的支持单通道的CAN总线仿真工程。将该工程命名为Demo.cfg,并将其保存在文件夹Demo下。Demo下面分别创建文件夹CANdb、Panels和Nodes。

二、总线数据库设计

1、在CANoe主界面,单击Tools,选择CANdb++ Editor,单击进入Vector CANdb++ Editor界面

2、选择File→Create Database命令新建数据库文件,此时可以查
看到软件自带的数据库模板,如下图所示:
在这里插入图片描述
选择Vector_IL_Basic Template.dbc作为模板,创建一个文件名为Demo.dbc的数据库,并将其保存到上面已创建的仿真项目Demo的文件夹CANdb中,如下图所示:
在这里插入图片描述

3、右击Networks下的Demo,选择Edit Network进入总线属性编辑,如下图所示:
在这里插入图片描述
处将Definition中的Protocol属性改为CAN总线。确定后退出。

4、右击Network Nodes,在快捷菜单中选择New,新建一个Name为Engine的网络节点,Address设为0x1,如下图所示。
在这里插入图片描述

同样的方法,再创建一个名称为Light的节点和一个名称为Display的节点,并保存。如下图所示:
在这里插入图片描述

可以看到当定义了一个网络节点后,CANdb++会自动添加一个相同名字的ECU,并且二者之间是相互关联的。(在CAN数据库中并不能直接创建ECU, CANdb++会在创建网络节点的同时,创建一个名称相同的ECU)

5、右击Message选择New,创建一个名为EngineState的报文,选择标准CAN(CAN Standard)报文,标识符为(ID)0x123,数据长度(DLC)为2,如下图所示:
在这里插入图片描述

在Transmitters选项卡下单击Add按钮,将Engine添加到发送节点。在
Transmitters设定界面中指定了该报文由节点Engine发送,如下图所示:
在这里插入图片描述

用同样的方法,创建名为LightState的报文,选择标准CAN(CAN Standard)报文,标识符(ID)为0x321,数据长度(DLC)为1,发送节点为Light。

创建完成后,在左边导航区中,EngineState与LightState报文已经被添加到节点Engine和Light下,在右边栏中显示了这两个报文的属性,如下图所示:
在这里插入图片描述

6、右击Signal选择New,创建信号EngineSpeed,在Defintion选项卡下设置Length为15b,Byte Order为Intel,Unit为r.p.m.,Value Type为Signed, Maximum为5000,其他设置可以使用默认值,如下图所示:
在这里插入图片描述

在Messages选项卡,点击Add,将该信号关联到报文EngineState中,如下图所示:

用相同方法,按下表属性,添加信号OnOff、FlashLight和HeadLight。
在这里插入图片描述

7、单击左侧栏中的Network Nodes,右击Display,选择Edit Node,在弹出的对话框中,选择Mapped Rx Sig.选项卡,单击Add按钮,将信号EngineSpeed添加到其中,如下图所示:
在这里插入图片描述
同样的方法,设置节点Engine和Light的各个信号,下图为设置完毕后的效果图:
在这里插入图片描述

同时注意下,上图右边各信号的Startbit值,因为EngineSpeed和OnOff是组合一起两个字节,FlashLight和HeadLight在一个字节里的不同位。如果因为加入先后顺序导致值与上图不一致的,可直接单击Startbit值修改。

8、在左侧Messages下双击之前创建的EngineState报文并切换到Attributes选项卡,将GenMsgCycleTime 改为100 , 此报文的周期就被改为100 ms, 同时需要将此报文的GenMsgSendType(报文发送类型)相应地改为Cyclic(周期性的),修改完毕如下图所示:
在这里插入图片描述
同样地,需要将LightState报文也改为周期性报文,周期为100ms。

9、在CANdb++工具栏上,单击Value Tables图标在这里插入图片描述
进入Value Tables界面,在空白处右击,选择New,创建一个名为VtSig_OnOff的Value Table,在Value Descriptions选项卡中,单击Add按钮,新增两个值,如下图所示:
在这里插入图片描述
10、Value Table创建完毕后,可以将对应的信号或环境变量关联到数值表。在左侧Signals双击信号 OnOff ,在 Definition 选 项 卡 中 将 Value Table 选 择 为 上 面 创 建 的VtSig_OnOff,如下图所示:
在这里插入图片描述

到此,总线数据库设计完成。

11、返回CANoe主界面,在Simulation Setup的系统视图中,右击Database选择Import Wizard命令,在弹出的对话框中选择Demo数据库,并将节点Display、Light和Engine添加到Assigned nodes中,如下图所示:
在这里插入图片描述
单击下一步按钮直到出现完成按钮,即可完成Demo数据库的导入,最终Simulation
Setup窗口中可以看到数据库中创建的Display、Light和Engine三个仿真节点,如下图所示:
在这里插入图片描述

至此,数据库已经被成功创建和导入。

三、设置系统变量

1、在CANoe主界面中选择Environment→System Variables,如下图所示:
在这里插入图片描述
2、在左上侧空白窗口中单击鼠标右键选择New ,新建一个Name为EngineStateSwitch的系统变量,Namespace为Engine,设置初始值、最大最小值,如下图:
在这里插入图片描述
3、使用同样的方法创建其他两个系统变量:EngineSpeedDspMeter和EngineSpeedEntry,创建完毕后如下图所示:
在这里插入图片描述
4、使用同样的方法创建Namespace为Lights的两个系统变量HazardLightsSwitch和LightDisplay,创建完毕后如下图所示:
在这里插入图片描述
至此,系统变量设置完成。

四、创建仿真Panel

1、在CANoe主菜单上选择Tools→Panel Designer进入面板设计界面。

2、设计控制界面
2.1、在Panel Designer界面上选择File→New→Panel打开一个新的面板,默认名为Panel1,如下图所示:
在这里插入图片描述
2.2、右侧找到Toolbox选项卡打开,里面有所有的控件。如下图所示:
在这里插入图片描述
2.3、添加2个Group Box到左侧Panel内,调整好大小,并通过右侧Toolbox旁的Properties选项卡设置Text为Engine和Light。面板的布局效果如下图所示:
在这里插入图片描述
2.4、添加一个Switch/Indicator控件到Engine组合框内,调整好大小。并在右侧Properties选项卡设置控件参数如下:
在这里插入图片描述

Image File选择的是一个两种状态的按钮图片,这些图片素材在CANoe提供的Sample Configurations 16.4.4文件夹下搜索*.bmp找到。

Symbol Filter那里有两个可选项,Signal和Variable。选择Signal时,Symbol可选项为总线数据库设计时信号。选择Variable时,Symbol可选项为设置的系统变量。
此处Symbol为EngineStateSwitch,需要先设置Symbol Filter为Variable。

2.5、添加一个Track Bar控件到Engine组合框内,调整好大小。并在右侧Properties选项卡设置控件参数如下:
在这里插入图片描述

2.6、在Switch/Indicator和Track Bar控件上方分别添加Static Text,修改Text为Igniti、Speed。

2.7、用同样的方法,在Light组合框内,添加两个Switch/Indicator和两个Static Text,分别命名为Head和Hazard。两个Switch/Indicator参数设置如下:
在这里插入图片描述
在这里插入图片描述
完成后的效果图如下:
在这里插入图片描述

至此,控制面板设计完成,点击保存,将Panel1重命名为Control并保存到仿真项目Demo的文件夹Panels中。

2.8、点击上方的Check按钮,查看Panel设计是否有误,如果有错误或者警告会在Output窗口中输出。

3、设计显示界面
3.1、在Panel Designer界面上选择File→New→Panel打开一个新的面板,默认名为Panel2.

3.2、添加2个Group Box到左侧Panel内,调整好大小,并通过右侧Toolbox旁的Properties选项卡设置Text为Engine和Light。面板的布局效果如下图所示:
在这里插入图片描述
3.3、在Engine组合框中,添加Switch/Indicator,设置参数如下:
在这里插入图片描述
3.4、在Engine组合框中,添加Analog Gauge,并设置参数如下:
在这里插入图片描述
3.5、在Engine组合框中,添加Input/Output Box,设置参数如下:
在这里插入图片描述

Input/Output Box后,在添加一个Static Text,Test设置为r.p.m。设置好后,Engine内效果如下:
在这里插入图片描述

3.6、在Light组合框内添加Picture Box控件,调整好大小,然后设置参数如下:
在这里插入图片描述
3.7、在车辆图片左、右灯位置,各添加一个Switch/Indicator,参数设置如下:
在这里插入图片描述
在这里插入图片描述
注意左右灯的位置,调整好大小。完成后,Light组合框内效果如下图:
在这里插入图片描述
3.8、调整好两个组合框大小及位置,显示的背景色也要设置下,不然仿真运行时效果不好,设置背景色如下:
在这里插入图片描述
然后将Panel2重命名为Display并保存到仿真项目Demo的文件夹Panels中。效果如下:
在这里插入图片描述

3.9、点击上方的Check按钮,查看Panel设计是否有误,如果有错误或者警告会在Output窗口中输出。

至此,所以Panel设计完成。

五、添加CAPL程序

1、回到CANoe主界面,在Simulation Setup窗口的网络视图中,鼠标双击需要添加CAPL程序的节点Engine,会创建一个新的CAPL程序。在弹出窗口中选择要保存的路径(Demo/Nodes)并命名文件名称为Engine.can。代码如下:

/*@!Encoding:936*/

//处理系统变量EngineStateSwitch变化事件
on sysvar sysvar::Engine::EngineStateSwitch
{
  $EngineState::OnOff = @this;
  write("OnOff %d", $EngineState::OnOff);
  if(@this)   //Control界面中的Igniti开关是否打开
    $EngineState::EngineSpeed = @sysvar::Engine::EngineSpeedEntry;
  else
    $EngineState::EngineSpeed = 0;
}

//处理系统变量EngineSpeedEntry变化事件
on sysvar sysvar::Engine::EngineSpeedEntry
{
  if(@sysvar::Engine::EngineStateSwitch) 
  {
    $EngineState::EngineSpeed = @this;
  }
}

2、CAPL程序编写完成后,点击上方的Compile进行编译,编译完成后,下方Output输出编译信息,如果有错误,按照提示修改程序后再编译,直到没有错误和警告。如下图所示:
在这里插入图片描述
在这里插入图片描述
3、使用上面的方法,实现Display.can和Light.can,并编译。
Display.can如下:

/*@!Encoding:936*/
variables 
{
  const long kOFF = 0;
  const long kON = 1;

  int gDebugCounter = 0;
  int geDebugCounter = 0;
}

//处理接收到报文EngineState事件
on message EngineState 
{  
  //如果为接收
  if (this.dir == RX)
  {
    @sysvar::Engine::EngineSpeedDspMeter = this.EngineSpeed;  //将转速赋值给变量EngineSpeedDspMeter
    geDebugCounter++;
    if(geDebugCounter == 10)
    {
      writeDbgLevel(1,"EngineState RX received by node %NODE_NAME%");
      geDebugCounter = 0;
    }  
  }
}

on start
{
  write("This is CANoe Demo!");
}

//处理接收到报文LightState事件
on message LightState 
{
  gDebugCounter++;

  //如果为接收
  if (this.dir == RX)
  {
    SetLightDsp(this.HeadLight,this.FlashLight);  //通过Control界面下的Head和Hazard按钮,控制车灯状态

    if(gDebugCounter == 10)
    {
      writeDbgLevel(1,"LightState RX received by node %NODE_NAME%");
      gDebugCounter = 0;
    }    
  }
  else  //如果为发送
  {
    if(gDebugCounter == 10)
    {
      writeDbgLevel(1,"Error: LightState TX send to node %NODE_NAME%"); 
      gDebugCounter = 0; 
    }
  }
}

SetLightDsp (long headLight, long hazardFlasher)
{
  write("headLight = %d",headLight);
  write("hazardFlasher = %d",hazardFlasher);
  if(headLight == kON) 
  {
    if(hazardFlasher == kON) 
    {
      @sysvar::Lights::LightDisplay = 7;
    } 
    else if(hazardFlasher == kOFF) 
    {
      @sysvar::Lights::LightDisplay = 4;
    }
  }
  else if(headLight == kOFF) 
  {
    if(hazardFlasher == kON)  
    {
      @sysvar::Lights::LightDisplay = 3;
    } 
    else if(hazardFlasher == kOFF) 
    {
      @sysvar::Lights::LightDisplay = 0; 
    }
  }
}

Light.can如下:

/*@!Encoding:936*/

variables 
{
  msTimer tFlashLightFrequency;
  const int gFlashLightFrequency = 500;
  int gHazardLightsStatus = 0;

  int gDebugCounterTX = 0;
  int gDebugCounterTXRQ = 0;
  int gDebugCounterRX = 0;
}

//处理发送报文LightState事件
on message LightState 
{
 
  if (this.dir == TX)
  {
    gDebugCounterTX++;
    if(gDebugCounterTX == 10)
    {
      writeDbgLevel(1,"LightState TX send by node %NODE_NAME%");
      gDebugCounterTX = 0;
    }     
  }
  if(this.dir == TXREQUEST)
  {
    gDebugCounterTXRQ++;
    if(gDebugCounterTXRQ == 10)
    {
      writeDbgLevel(1,"LightState TXREQUEST send by node %NODE_NAME%");
      gDebugCounterTXRQ = 0;
    } 
  }
  if (this.dir == RX)
  {
    gDebugCounterRX++;
    if(gDebugCounterRX == 10)
    {
      writeDbgLevel(1,"Error: LightState RX received by node %NODE_NAME%");
      gDebugCounterRX = 0;
    }
  }
}

//双闪灯闪烁频率
on timer tFlashLightFrequency
{
  gHazardLightsStatus = (gHazardLightsStatus == 1 ? 0 : 1);
  $LightState::FlashLight = gHazardLightsStatus;
  setTimer(this, gFlashLightFrequency);
}

//处理系统变量HazardLightsSwitch变化事件
on sysvar sysvar::Lights::HazardLightsSwitch
{
  if (@this)
  {
    gHazardLightsStatus = 1;
    setTimer(tFlashLightFrequency, gFlashLightFrequency);
  }
  else
  {
    cancelTimer(tFlashLightFrequency);
    gHazardLightsStatus = 0;
  }

  $LightState::FlashLight = gHazardLightsStatus;
}

至此,CAPL编程完成。

六、仿真测试

1、回到CANoe的Home界面,设置为仿真环境,
在这里插入图片描述

2、点击Panel→View下的All,在跳出的Windows下,选中Select all,如下图:
在这里插入图片描述
出现仿真面板Control和Display:
在这里插入图片描述
鼠标放在面板上,右键,设置为MDI Windows模式,并调整好位置。

3、点击上方Write,添加Write窗口,右键设置为MDI Windows模式。

4、由Home选项卡切换到Analysis选项卡,点击上方Trace,添加Trace窗口,右键设置为MDI Windows模式。调整好各界面布局如下图:
在这里插入图片描述

5、点击Home界面下的Start,开始仿真通过Control内的控件控制Display中的控件显示,仿真结果如下视频所示:

20230213_104650

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/343379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022年Q4业绩超预期,功能性饮料能成为百事下一增长极吗?

北京时间2月9日,美国食品饮料巨头百事公司发布2022财年年报,第四季度业绩再超预期。 据百事公司财报显示,其2022年Q4实现营收280亿美元,市场预期为268.8亿美元;核心每股收益为1.67美元,市场预期为1.64美元…

专业调度器JS版:BRYNTUM SCHEDULER PRO

BRYNTUM SCHEDULER PRO 5.2 专业的日程安排小部件,有大脑的专业调度UI组件。Scheduler Pro 可帮助您安排任务,同时将资源和任务的可用性考虑在内,POJIE VERSION 连接你的任务 让 Scheduler Pro 处理剩下的事情。它将根据您定义的链接安排您的任务并遵守任…

目标检测论文阅读:GraphFPN算法笔记

标题:GraphFPN: Graph Feature Pyramid Network for Object Detection 会议:ICCV2021 论文地址:https://ieeexplore.ieee.org/document/9710561/ Abstract 特征金字塔已经被证明在需要多尺度特征的图像理解任务中是强大的。SOTA的多尺度特征…

指派问题与匈牙利法讲解

指派问题概述:实际中,会遇到这样的问题,有n项不同的任务,需要n个人分别完成其中的1项,每个人完成任务的时间不一样。于是就有一个问题,如何分配任务使得花费时间最少。通俗来讲,就是n*n矩阵中&a…

Django框架之展示书籍列表案例

展示书籍列表 需求 实现步骤 1.创建视图2.创建模板3.配置URLconf 1.创建视图 查询数据库数据构造上下文 传递上下文到模板 # 定义视图:提供书籍列表信息 def bookList(request):# 查询数据库书籍列表数据books BookInfo.objects.all()# 构造上下文context {boo…

超详细的JAVA高级进阶基础知识04

目录 4. 面向对象高级 - 常用的API 4.1 Arrays 工具类 4.1.1 Arrays 类介绍 4.2 冒泡排序 4.3 选择排序 4.4 二分查找 4.5 正则表达式 4.5.1 String 类中与正则有关的常见方法 4.5.2 练习 4.5.3 今日学习目标 4. 面向对象高级 - 常用的API 4.1 Arrays 工具类 4.1.1…

Java面试——Spring Bean相关知识

目录 1.Bean的定义 2.Bean的生命周期 3.BeanFactory及Factory Bean 4.Bean的作用域 5.Bean的线程安全问题 1.Bean的定义 JavaBean是描述Java的软件组件模型。在Java模型中,通过JavaBean可以无限扩充Java程序的功能,通过JavaBean的组合可以快速的生…

Day887.MySQL写入binlog和redolog的流程机制 -MySQL实战

MySQL写入binlog和redolog的流程机制 Hi,我是阿昌,今天学习记录的是关于MySQL写入binlog和redolog的流程机制的内容。 只要 redo log 和 binlog 保证持久化到磁盘,就能确保 MySQL 异常重启后,数据可以恢复。 那redo log 的写入…

《第一行代码》 第四章:碎片的最佳实践

一&#xff0c;碎片的简单用法 在一个活动中添加两个碎片&#xff0c;并且让这两个碎片平分活动空间。 第一步&#xff1a;首先在layout中创建 left_fragment.xml&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"androi…

【LoRaWAN 时钟同步】

本文主要介绍了 LoRaWAN 自组网协议、设备工作模式、设备间的时间同步问题 LoRaWAN 时钟同步1. 前言2. 设备数据收发2.1 数据帧格式2.2 数据发送2.3 数据接收3. A类设备4. C类设备5. B类设备5.1 GPS5.3 网关时间同步5.4 节点时间同步5.4.1 首次时间同步5.4.2 节点接收Beacon5.5…

生成系列论文:文本控制的3d点云生成 TextCraft(一):论文概览

TextCraft: Zero-Shot Generation of High-Fidelity and Diverse Shapes from Text 论文原文&#xff1a; https://arxiv.org/abs/2211.01427 论文的研究动机 DALL2已经在文本控制的图像生成上取得很好的效果&#xff0c;但是基于文本控制的3d点云生成的研究还不太成熟&#…

软件架构知识2-系统复杂度

架构设计的真正目的&#xff1a;是为了解决软件系统复杂度带来的问题&#xff0c;一个解决方案。 系统复杂度&#xff0c;如何入手&#xff1a; 1、通过熟悉和理解需求&#xff0c;识别系统复杂性所在的地方&#xff0c;然后针对这些复杂点进行架构设计。 2、架构设计并不是要…

毕业3年不到选择跳槽,居然拿到20K的薪资,简直了···

本人本科就读于某普通院校&#xff0c;毕业后通过同学的原因加入软件测试这个行业&#xff0c;角色也从测试小白到了目前的资深工程师&#xff0c;从功能测试转变为测试开发&#xff0c;并顺利拿下了某二线城市互联网企业Offer&#xff0c;年薪 30W 选择和努力哪个重要&#xf…

Java Email 发HTML邮件工具 采用 freemarker模板引擎渲染

Java Email 发HTML邮件工具 采用 freemarker模板引擎 1.常用方式对比 Java发送邮件有很多的实现方式 第一种&#xff1a;Java 原生发邮件mail.jar和activation.jar <!-- https://mvnrepository.com/artifact/javax.mail/mail --> <dependency><groupId>jav…

使用VUE自定义组件封装部门选择功能

背景 照惯例&#xff0c;先交待下背景&#xff0c;从真实需求出发&#xff0c;讲述实现效果、设计思路和实现方式。 软件系统中&#xff0c;会有一些常见常用的选择功能&#xff0c;如部门选择、人员选择等&#xff0c;用于填报表单&#xff0c;使用频率很高。直接使用一方面会…

浅谈应用安全测试工具

正确的应用程序安全测试工具可以改善企业安全态势和开发工作流程。如今&#xff0c;应用程序安全从一开始就内置在整个软件生命周期中&#xff0c;即使是具有成熟开发实践的组织也需要自动化工具来在复杂、快速变化的环境中成功地保护他们的软件。以下比较了三个广泛使用的应用…

MAVEN打包这一篇就够了

Maven打包说明IDEA目录结构Java代码从编码到最后运行到两个核心步骤为"编译"和"执行"。"编译"会根据"源代码"产出对应的".class"文件&#xff0c;而"执行"就是让程序运行起来&#xff0c;运行的对象就是这些"…

【C语言学习笔记】:动态库

一、动态库 通过之前静态库那篇文章的介绍。发现静态库更容易使用和理解&#xff0c;也达到了代码复用的目的&#xff0c;那为什么还需要动态库呢&#xff1f; 1、为什么还需要动态库&#xff1f; 为什么需要动态库&#xff0c;其实也是静态库的特点导致。 ▶ 空间浪费是静…

怎么打造WhatsApp Team?SaleSmartly(ss客服)告诉你

关键词&#xff1a;WhatsApp Team SaleSmartly&#xff08;ss客服&#xff09; 您是否正在寻找一种让您的团队能够在 WhatsApp协作消息传递的解决方案?拥有了 WhatsApp Team&#xff0c;不仅效率提升&#xff0c;还可以在智能聊天工具中比如SaleSmartly&#xff08;ss客服&…

51单片机——中断系统,小白讲解,相互学习

中断介绍 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的&#xff0c;中断功能的存在&#xff0c;很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一&#xff0c;是我们学些单片机必须要掌握的。 为了更容易的理解中断概念&…