最好的学习方式是什么?模仿。有人会问,那不是山寨么?但是我认为,那是模仿的初级阶段,当把别人最好的设计已经融化到自己的血液里,变成自己的东西,而灵活运用的时候,才是真正高级阶段。正所谓画虎画皮难画骨。但初级阶段仍然是必须经历的过程,他会使你在达到高级阶段的过程中少走很多弯路,下面我们来迈出这一步。先研究一下别人的简单例子。

最好的例子莫过于Vector本身的Demo了,这个在安装完CANoe之后就会被自动安装。先看最简单的一个,名字叫Easy,但并不简单哦,比我们之前介绍的所有的东西都整合再一起了,很简单,但很全面。但是假如你说,这个我自己也可以完全自己写出来(并不是仅仅是看懂哦),那么我可以肯定的说,在工作中,你完全可以胜任一般的任务要求哦~,剩下的只是工作量的问题了。但我相信到现在为止,你们很多人,都无法写出这样的程序,所以我建议你们把这个程序好好的研究明白,这点很重要。废话不多说,上图,下面是打开运行后的界面。

通过面板可以控制,及显示很多动画效果,做的非常的漂亮。在其余的窗体也将主要的数据以图表等表现方式呈现出来。

我们先看一下DBC的内容吧

Signals:

EngineSpeed 车速信息

FlashLight 双跳灯

HeadLight 大灯

OnOff 引擎状态

Messages:

EngineState 引擎状态:包含的信号有OnOff,EngineSpeed

LightState 灯光状态:包含的信号有FlashLight,HeadLight

Network nodes:

Display 显示节点,接收所有消息

Engine 引擎节点,发送EngineState 消息

Light 灯光节点,发送LightState 消息

Environment variables: 环境变量,一般与界面的组件相关联,这样就实现了图形化界面的控制与显示,下面就是关联的界面组件

EnvEngineSpeedDspMeter 

EnvEngineSpeedDspText 

EnvEngineSpeedEntry 

EnvEngineStateDsp 

EnvEngineStateSwitch 

EnvHazardLightsSwitch 

EnvHeadLightSwitch 

EnvLightDsp 

注意一下信号的信息:

Definition页面的,Init.Val的输入框使能了,之前是灰色的状态,为什么呢?点击一下蓝色的带下划线的连接,弹出窗台如下:

意思是说这个值的设置,必须要定义的属性才能有效,之前一直没有提到信号的属性,这次还是第一次遇到哦。个人理解信号属性是表明信号的特点的一系列参数,当然消息和节点也都有对应的属性。为了更加详细的了解这个属性,我们求助于帮助。

哦,明白了,原来是用来初始化数据的哦。其实在Definition表示的是物理值,都要转换成Raw值保存到GenSigStartValue属性中。在属性的创建我们之前也没有提到过,这里讲一下,请在CANdb++ Editor菜单中,View->Attribute Definitions

右键,New,填写好信息即可。属性背后跟行为是密切相关的,甚至跟底层dll,其他的一些属性请参考Help文档,当然重要的属性我们也会跟大家在后面提到。

dbc还有一些细节,就是接受的消息的定义,之间也没介绍过,例如Display节点只接收消息,那么你就应该在节点的属性上进行配置,方法是右击节点然后点Edit Node,在Mapped Rx Sig.中就可以定义接收的信号了,Add…

其实不定义接收消息也是可以的,但会在File->Consistency check 的检查中中显示出无接收节点等的报警。例如前面第一讲例子的dbc的检查如下:

再看一下CAPL程序。

engine.can 程序如下:

variables 
{
}

on envvar EnvEngineStateSwitch //当拨动开关的时候,会更改发动机发出的信号
{
$EngineState::OnOff = @this; //注意信号和环境变量直接赋值时的符号,信号用$,环境变量用@
if(@this)
$EngineState::EngineSpeed = @EnvEngineSpeedEntry;
else
$EngineState::EngineSpeed = 0;
}

on envvar EnvEngineSpeedEntry //当移动车速滑条时,会更改发动机发出的信号
{
if(@EnvEngineStateSwitch) 
{
$EngineState::EngineSpeed = @this;
}
}

on start //程序开始运行的时候,将调用所有的环境变量的事件
{
CallAllOnEnvVar(); // call all envvar procedures of this model and
// thus consider the START VALUES of all environment
// variables for: 
// - initialization of all message variables
// - starting of any timers
// - sending messages (output) with start values
}

light.can 的程序如下:

variables 
{
msTimer tFlashLightFrequency; //定义闪灯定时器
const int gFlashLightFrequency = 500; //定义闪灯频率,初始化为500ms
int gHazardLightsStatus = 0; //定义危险灯信号

int gDebugCounterTX = 0; //用于调试,记录TX报文个数
int gDebugCounterTXRQ = 0; //用于调试,记录TXRQ报文个数
int gDebugCounterRX = 0; //用于调试,记录RX报文个数
}

on envvar EnvHeadLightSwitch //大灯开关状态更改时,更新灯光消息的信号
{
// assign EV value to the message signal
$LightState::HeadLight = @this;
}

on start
{
CallAllOnEnvVar(); // call all envvar procedures of this model and
// thus consider the START VALUES of all environment
// variables for: 
// - initialization of all message variables
// - starting of any timers
// - sending messages (output) with start values

setWriteDbgLevel(0); // set DbgLevel = 1 to get more information in Write-Window
}

on message LightState //调试用,打印相关信息
{
if (this.dir == TX)
{
gDebugCounterTX++;
if(gDebugCounterTX == 10)
{
writeDbgLevel(1,"LightState TX received by node %NODE_NAME%");
gDebugCounterTX = 0;

}
if(this.dir == TXREQUEST)
{
gDebugCounterTXRQ++;
if(gDebugCounterTXRQ == 10)
{
writeDbgLevel(1,"LightState TXREQUEST received 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 envVar EnvHazardLightsSwitch //危险警示灯开关变化时,更新灯光消息的闪灯信号
{
if (@this)
{
gHazardLightsStatus = 1;
setTimer(tFlashLightFrequency, gFlashLightFrequency);
}
else
{
cancelTimer(tFlashLightFrequency);
gHazardLightsStatus = 0;
}

$LightState::FlashLight = gHazardLightsStatus;
}

on timer tFlashLightFrequency //危险报警灯间隔闪烁的控制
{
gHazardLightsStatus = (gHazardLightsStatus == 1 ? 0 : 1);
$LightState::FlashLight = gHazardLightsStatus;
setTimer(this, gFlashLightFrequency);
}

on key '0' //按键事件,定义打印调试信息的等级
{
setwriteDbgLevel(0);
}

on key '1' //按键事件,定义打印调试信息的等级
{
setwriteDbgLevel(1); 
}

以上程序,有C语言基础的同学应该都可以看得懂,这里不用详细介绍了。

看完程序大家可能有个疑问,没有调用任何发送CAN消息的函数(只是更改其中的信号),但报文却真的发出去了,这是为什么呢?

这是因为周期发送消息的工作,已经在消息的属性中定义了,这样消息会自动周期的发送。如下:

这个在消息的属性查看中的界面,当然也可以在上面我们介绍的View->Attribute Definitions,进行修改和查看,但区别是,这个只是针对个别消息的,View->Attribute Definitions,是针对所有的情况。还有消息属性中,对此进行归类,以上归类到Interaction Layer这个是CAN通讯的交互层。上面的各个属性的具体含义,请参考帮助文档,都有详细的说明。

下面说一下界面。

选中一个界面组件,在状态栏中可显示他的类型,关联的对象等信息。右边为属性窗口,定义选中组件的属性

这个组件类型为:Switch/Indicator

属性栏中:

Image 表示该组件使用的图片,因为要表示几种状态,所以做成这样,尺寸105x34 pix

State Count 表示状态的个数

其他的属性不一一介绍了,自己试一下基本可以知道,实在不行求助帮助文档,这里不一 一介绍了。

到现在整个工程的剖析基本上结束了,但说过的这些不足以覆盖所有的细节,但基本脉络已经很清晰了,剩下的可以自己研究,都不难理解。个人建议,在实际工作中创建自己的工程,当遇到问题是,参考例子中的实现方式,这样更加帮助理解。进步也最快。

CANOE入门(三)的更多相关文章

  1. 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

    前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...

  2. Swift语法基础入门三(函数, 闭包)

    Swift语法基础入门三(函数, 闭包) 函数: 函数是用来完成特定任务的独立的代码块.你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被用于“调用”函数 格式: ...

  3. Thinkphp入门三—框架模板、变量(47)

    原文:Thinkphp入门三-框架模板.变量(47) [在控制器调用模板] display()   调用当前操作名称的模板 display(‘名字’)  调用指定名字的模板文件 控制器调用模板四种方式 ...

  4. DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表

    原文:DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用 ...

  5. 微服务(入门三):netcore ocelot api网关结合consul服务发现

    简介 api网关是提供给外部调用的统一入口,类似于dns,所有的请求统一先到api网关,由api网关进行指定内网链接. ocelot是基于netcore开发的开源API网关项目,功能强大,使用方便,它 ...

  6. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...

  7. 3.Python爬虫入门三之Urllib和Urllib2库的基本使用

    1.分分钟扒一个网页下来 怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它是一段HTML代码,加 JS.CSS ...

  8. C#基础入门 三

    C#基础入门 三 类 类使用class关键字进行声明,前面加一个访问修饰符,public class car{} 访问修饰符:修师傅可以用来修饰类和类成员等,控制它们的可见度 修饰符关键字分别为:pu ...

  9. git入门三(远程、标签)

    git 入门三 (远程.标签)     分布式版本控制管理系统本地仓库和中心服务器仓库数据是本地的镜像仓库,中心服务器数据仓库的是为了多用户数据合并和获取同步的中心,多人协作需要管理这些远程仓库,以便 ...

  10. 转 Python爬虫入门三之Urllib库的基本使用

    静觅 » Python爬虫入门三之Urllib库的基本使用 1.分分钟扒一个网页下来 怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器 ...

随机推荐

  1. python爬虫之Splash使用初体验

    Splash是什么: Splash是一个Javascript渲染服务.它是一个实现了HTTP API的轻量级浏览器,Splash是用Python实现的,同时使用Twisted和QT.Twisted(Q ...

  2. valgrind 检查内存泄露

    https://www.oschina.net/translate/valgrind-memcheck

  3. rsync: chgrp "/.hosts.NBCxBB" (in test) failed: Operation not permitted (1)

    #记一次rsync出现的错误(网上基本都是说权限问题) #这并不是权限的问题,应为实际的文件已经传过去了,但是rsync就是会报这个错误,(虽然使用是正常的,但是看着就是不爽) [root@local ...

  4. Object...与Object[]使用的一点区别和记录

    Object是所有类的基类 简述: Object ...objects(称为可变个数的形参)这种参数定义是在不确定方法参数的情况下的一种多态表现形式.Java可变参数,即这个方法可以传递多个参数,这个 ...

  5. github上传时出现error: src refspec master does not match any解决办法22

    1 error:src refspec master does not match any这个问题,我之前也遇到过,这次又遇到了只是时间间隔比较长了,为了防止以后再遇到类似问题,还是把这个方法简单记录 ...

  6. yolo算法解析

  7. Go For It ,一个灵活的待办事项列表程序

    导读 Go For It,是我们开源工具系列中的第十个工具,它将使你在 2019 年更高效,它在 Todo.txt 系统的基础上构建,以帮助你完成更多工作. 每年年初似乎都有疯狂的冲动想提高工作效率. ...

  8. pycharm中查看源码的快捷键

    将光标移动至要查看的方法处,按住ctrl  点击鼠标左键,即可查看该方法的源码

  9. Cent OS安装使用ffmpeg(完整版)

    Cent OS安装使用ffmpeg centos作为主流后台linux 系统,ffmpeg作为视频流解析的主力,尤其是ffmpeg配合opencv使用,则是视觉操作的基础 版本: ffmpeg3.1 ...

  10. RPM包定制

    概述 问题:当领导给你 100 台已经安装好系统的服务器,然后让优化,让你提出一个快速部署方案.解答: 1.tar 打包 先编译安装 打包-->分发-->解包(比如 mysql 打包后直接 ...