CANOpen紧急报文
/* 紧急报文初始化 */
void emergencyInit(CO_Data *d)
{/* 按索引号0x1003和子索引号0x00注册字典入口的回调函数 */RegisterSetODentryCallBack(d, 0x1003, 0x00, &OnNumberOfErrorsUpdate);/* 错误个数 */*d->error_number = 0;
}/* 紧急报文停止 */
void emergencyStop(CO_Data* d)
{}/* 发送紧急报文 */
UNS8 sendEMCY(CO_Data *d, UNS16 errCode, UNS8 errRegister, const void *Specific, UNS8 SpecificLength)
{Message m;MSG_WAR(0x3051, "sendEMCY", 0);/* cob_id */m.cob_id = (UNS16)(*(UNS32*)d->error_cobid);/* 数据帧 */m.rtr = NOT_A_REQUEST;/* 错误码 */m.Data[0] = errCode & 0xFF;m.Data[1] = (errCode >> 8) & 0xFF;/* 错误掩码 */m.Data[2] = errRegister;/* 集体字段 */if(Specific == NULL){m.Data[3] = 0;m.Data[4] = 0;m.Data[5] = 0;m.Data[6] = 0;m.Data[7] = 0;SpecificLength = 5;}else{if(SpecificLength > 5) SpecificLength = 5;memcpy(&m.Data[3], Specific, SpecificLength); }/* 数据包长度 */m.len = SpecificLength + 3;return canSend(d->canHandle,&m);
}/* 错误发生 */
UNS8 EMCY_setError(CO_Data *d, UNS16 errCode, UNS8 errRegMask, UNS16 addInfo)
{UNS8 index;UNS8 errRegister_tmp;/* 遍历错误数据列表 */for(index = 0; index < EMCY_MAX_ERRORS; ++index){/* 如果该错误码已经出现在错误列表中 */if(d->error_data[index].errCode == errCode){/* 该错误已经存在,则无需重复发送 */if(d->error_data[index].active){MSG_WAR(0x3052, "EMCY message already sent", 0);return 0;}/* 如果该错误不存在,则需要上报 */elsed->error_data[index].active = 1;break;}}/* 如果该错误在列表中不存在 */if(index == EMCY_MAX_ERRORS){/* 则遍历列表,看看有没有错误列表项未被错误占用 */for(index = 0; index < EMCY_MAX_ERRORS; ++index) {if(d->error_data[index].active == 0) break;}}/* 错误列表已经满了,直接退出 */if(index == EMCY_MAX_ERRORS){MSG_ERR(0x3053, "error_data full", 0);return 1;}/* 将错误码、错误掩码、错误发生标志位重新赋值 */d->error_data[index].errCode = errCode;d->error_data[index].errRegMask = errRegMask;d->error_data[index].active = 1;/* 该节点已经存在错误 */d->error_state = Error_occurred;/* 遍历整个错误列表 */for(index = 0, errRegister_tmp = 0; index < EMCY_MAX_ERRORS; ++index){/* 如果该错误已经发生 */if(d->error_data[index].active == 1){/* 则将错误掩码记录下来 */errRegister_tmp |= d->error_data[index].errRegMask;}}/* 将错误掩码记录下来 */*d->error_register = errRegister_tmp;/* 将错误历史记录向后偏移一个 */for(index = d->error_history_size - 1; index > 0; --index){*(d->error_first_element + index) = *(d->error_first_element + index - 1);}*(d->error_first_element) = errCode | ((UNS32)addInfo << 16);/* 已经发生的错误种数 */if(*d->error_number < d->error_history_size) {++(*d->error_number);}/* 发送紧急报文 */if(d->CurrentCommunicationState.csEmergency)return sendEMCY(d, errCode, *d->error_register, NULL, 0);else return 1;
}/* 错误恢复 */
void EMCY_errorRecovered(CO_Data* d, UNS16 errCode)
{UNS8 index;UNS8 errRegister_tmp;UNS8 anyActiveError = 0;/* 遍历错误列表,找到该错误项 */for(index = 0; index < EMCY_MAX_ERRORS; ++index){if(d->error_data[index].errCode == errCode){ break;}}/* 如果找到该错误项并且未被解决 */if((index != EMCY_MAX_ERRORS) && (d->error_data[index].active == 1)){/* 首先将该错误置为已经解决 */d->error_data[index].active = 0;/* 遍历错误列表,重新计算错误掩码 */for(index = 0, errRegister_tmp = 0; index < EMCY_MAX_ERRORS; ++index){/* 如果该错误未被解决 */if(d->error_data[index].active == 1){/* 依然存在未解决错误 */anyActiveError = 1;/* 更新错误掩码 */errRegister_tmp |= d->error_data[index].errRegMask;}}/* 如果不存在错误 */if(anyActiveError == 0){/* 将错误状态设置为无错误 */d->error_state = Error_free;/* 发送紧急报文,通知主站所有错误已经解决 */if(d->CurrentCommunicationState.csEmergency)sendEMCY(d, 0x0000, 0x00, NULL, 0);}/* 记录错误掩码 */*d->error_register = errRegister_tmp;}elseMSG_WAR(0x3054, "recovered error was not active", 0);
}/* 紧急报文处理 */
void proceedEMCY(CO_Data* d, Message* m)
{UNS8 nodeID;UNS16 errCode;UNS8 errReg;MSG_WAR(0x3055, "EMCY received. Proceed. ", 0);/* 紧急报文数据长度始终8字节 */if(m->len != 8) {MSG_ERR(0x1056, "Error size EMCY. CobId : ", m->cob_id);return;}nodeID = m->cob_id & 0x7F;errCode = m->Data[0] | ((UNS16)m->Data[1] << 8);errReg = m->Data[2];/* 从节点上报错误回调函数 */(*d->post_emcy)(d, nodeID, errCode, errReg);
}
CANOpen紧急报文相关推荐
- Emergency 紧急报文的实施
Emergency 紧急报文的实施 紧急报文的概念 1.紧急时间由设备内部的错误事件触发,将诊断信息发送给主站.当诊断事件消失之后,从站应该将诊断事件和错误复位吗再发送一次.下图紧急事件数据帧格式
- CANOpen网络管理报文
网络管理报文用于监视和设置节点的运行状态,心跳机制和寿命保护机制都基于该报文. /* 改变节点状态 */ UNS8 masterSendNMTstateChange(CO_Data *d, UNS8 ...
- CANOpen同步报文
同步(SYNC),该报文对象基于生产者/消费者模式,由SYNC生产者周期性的广播,作为网络基本时钟,实现整个网络的同步传输,每个节点都以该同步报文作为同步PDO触发参数,因此该同步报文的COB-ID具 ...
- CANopen通讯基础
文章目录 CANopen通讯基础 CAN概述 CAN的基本原理 CANopen概述 CANopen对象词典 CANopen通讯标识符 CANopen协议概述 CANopen管理报文 CANopen紧急 ...
- CANOpen报文类型
CANOpen应用层协议细化了CAN总线协议中关于标识符的定义.定义标准报文的11比特标识符中高4比特为功能码,后7比特为节点号,重命名为通讯对象标识符(COB-ID). 功能码将所有的报文分为7个优 ...
- canopen服务器协议,CANopen
CAN應用層和CANopen CANopen 概述 CANopen是附加了一套设备子协议的高层(第7层)CAN通信协议.作为一种标准化.高度可配置的嵌入式网络解决方案,它广泛应用于实时工业应用.机器人 ...
- CANOpen状态机
CANopen 的每一个节点都维护了一个状态机.该状态机的状态决定了该节点当前支持的通讯方式以及节点行为. 节点在不同的状态下支持不同的报文通讯 初始化:bootup报文(lifeguard的一种) ...
- CANopen协议及应用
文章目录 CANopen协议 CAN总线 CAN报文 CANopen概述 对象字典(Object Dictionary) 概述 通讯对象子协议区 制造商特定子协议 CANopen报文 NMT网络管理 ...
- CANopen协议解读
CANopen协议解读 一.协议标准 二.CANopen报文说明 三.CANopen协议内容 1. ID的理解 2. NMT (1) 节点状态 (2) 节点状态控制 (3) 节点心跳报文 一.协议标准 ...
最新文章
- ​《头号玩家》中的“绿洲”,用 VR 可以找到
- 智慧电梯物联网 未来电梯将更智能
- BZOJ2298 [HAOI2011]problem a
- 自定义ChannelHandler 的添加过程
- mysql 交集_MYSQL交集函数
- TCP三次握手,握的是啥?
- 造轮子是什么意思_聊聊在阿里工作一年的收获,什么是真正的技术能力?
- Flowmill :为分布式应用程序世界构建的网络可观察性解决方案
- 无法获取计算机名,Spring Cloud常见问题之:无法注册主机名
- 获取所有汉字与 Unicode 的对照表
- Pascal之父、编程祖师爷尼古拉斯•威茨痛批:教授成了项目经理,大学过于“重论文轻教学“...
- .net平台调用(P/Invoking)查询网站
- php 请求 响应,发送http响应后继续处理php
- mac检测是否安装mysql_mac安装mysql
- Java工具类,随机生成(姓名,年龄,性别,密码,邮箱,地址,)
- distill_basic_teacher
- 【nestjs】Nest can‘t resolve dependencies of xxx无法解析xxx的依赖关系
- css中字母数字自动换行
- 线程调度策略SCHED_RR(轮转法)和SCHED_FIFO(先进先出)之对比
- springboot+mybatis-plus在log控制台输出sql语句
热门文章
- Qt学习笔记-OpenGL做正方体并旋转
- Qt creator5.7 OpenCV249之图片灰度处理(含源码下载)
- HTML期末学生大作业-乒乓球网页作业html+css+javascript
- c语言中用于获取字符串长度的函数是,C语言中求字符串长度的函数的几种实现方法...
- 如何创建一个特定版本的python虚拟环境
- 鼠标在滑块上滚轮控制_高速直线运动导轨—滚轮直线导轨
- Process com.xxxxxxxx has died
- (数据库系统概论|王珊)第七章数据库设计-第四节:逻辑结构设计
- 面试题55 - I. 二叉树的深度
- Redis持久化RDB