LIN 仿真
LIN仿真工程概述
随着汽车电子电气架构的持续演进与智能化水平的提升,车载网络呈现出分层化与多样化特点。在车身控制、舒适性模块等对带宽和实时性要求相对较低的领域,LIN总线凭借其低成本、高可靠性的优势,得到了广泛应用。各类ECU,特别是作为LIN从节点的传感器、执行器控制器,其功能逻辑与主从节点间的交互时序日益精细,对仿真测试的依赖度不断提高。利用ETStudio等工具建立LIN总线仿真环境,可以有效地模拟LIN网络通信、主节点调度及从节点响应行为,从而在零部件开发早期验证其协议一致性、功能逻辑正确性以及网络管理合规性。基于仿真环境,开发者能够提前介入集成测试,加速自身产品的功能开发与缺陷排查,显著提升开发效率与产品质量。
LIN仿真工程在ECU,尤其是LIN从节点模块的开发周期中扮演着关键角色,需要与需求分析、底层软件配置、应用层软件开发、集成测试、硬件在环测试乃至售后诊断等环节紧密结合。对于涉及复杂唤醒/睡眠管理、帧调度或诊断服务的LIN节点,一个高保真的仿真环境能极大降低实车或实件测试的复杂度与成本,缩短开发验证周期。
LIN仿真工程开发流程与策略
在LIN节点模块开发初期,需结合具体的OEM LIN规范及产品需求说明书,对LIN通信矩阵(LDF文件)进行透彻分析。需明确主节点的调度表、从节点的信号发布/订阅关系、诊断帧安排、网络管理策略等。由软件测试团队或专门的网络仿真团队负责仿真工程的初步搭建与后续维护,确保仿真模型与真实网络行为的高度一致。
LIN仿真工程开发策略
鉴于不同主机厂和不同车型平台的LIN规范存在差异,开发者需针对性地制定仿真策略,以满足项目特定需求。以下是在LIN仿真工程构建过程中需注意的一系列要点,有助于打造高质量仿真项目:
- 优先采用官方LDF文件:尽可能使用OEM提供的LIN描述文件(LDF),确保波特率、帧ID、信号定义、调度表等信息的绝对准确,避免因自建数据库错误导致的通信异常排查。
- 深入分析并记录需求:在仿真准备阶段,明确需要模拟的LIN帧类型(无条件帧、事件触发帧、零星帧等)、信号交互逻辑、诊断服务(如读取数据标识符)及网络管理(唤醒/睡眠)行为,为仿真工程的架构设计奠定合理基础。
- 积极参与各阶段评审:主动参与需求评审、LDF文件评审、测试用例评审等,通过集思广益,避免遗漏关键LIN通信需求、错误理解调度逻辑或覆盖不全测试场景。
- 及时同步LDF变更:密切跟踪项目进展,确保在LDF文件更新后,能及时获取最新版本并同步调整仿真模型中的帧结构、信号或调度参数。
- 规划实物替代节点:在样品可用后,制定计划将仿真中的部分节点逐步替换为真实ECU,进行半实物仿真,以获取更精确的集成测试结果。
- 合理构建仿真工程结构:
a. 主从节点模块化分离:将LIN主节点仿真与各个从节点仿真设计为独立模块,可在测试过程中灵活启停,便于故障隔离与测试组合。
b. 公用逻辑抽象封装:将LIN协议处理(如校验和计算)、通用信号转换等与具体节点功能关联度低的代码封装为可重用模块,减少重复开发。
c. 预留扩展接口:为可能新增的LIN节点或信号预留配置接口或数据通道,增强工程的可扩展性。 - 做好工程与工具的版本管理:在ETStudio等仿真软件升级前后,做好工程配置的备份与兼容性测试,确保仿真工程在不同软件版本间的可用性。
- 实施严格的代码与文档管理:对仿真工程的源代码进行版本控制(如Git),任何修改需提交记录。项目发布时,需同步更新版本说明、配置文档及使用指南。
仿真工程示例
实现功能
以一个简单的车窗控制LIN网络为例,需要实现的仿真功能主要包括:
- 控制操作:提供仿真操作面板,模拟驾驶员对车窗开关(主节点发送控制命令)的操作,以及LIN主节点的唤醒、睡眠指令发送。
- 通信模拟:仿真LIN主节点按照LDF定义的调度表,周期性地发送包含控制信号的主帧;仿真车窗电机控制器(从节点)在接收到有效帧后,发送包含状态信号(如位置、堵转)的响应帧。
- 逻辑响应与显示:仿真模型根据LIN报文交互,动态更新车窗状态(如上升、下降、停止、当前位置百分比),并在图形化界面进行直观显示。
- 协议与数据分析:利用工具的报文跟踪窗口,实时监控LIN总线上的帧序列、信号值;利用图形窗口绘制关键信号(如电机电流、位置反馈)随时间的变化曲线,用于分析时序逻辑与性能。
项目实现
新增 LIN 总线支持
可通过主菜单 Device → Channel Assignment → Channel Config 添加 LIN 通道并将其映射到可用硬件。添加完成后,在 Simulation Setup 窗口右侧的系统视图中对 Lin Network 位置右键,可快速添加名为 LIN 的网络,此时会显示一个独立的 LIN 网络(初始状态下尚无节点)。

导入 LDF 数据库文件
与 CAN 总线类似,LIN 也使用数据库文件(LDF)来管理相关报文与信号,ETStudio 可以借助这些数据库快速且清晰地解析 LIN 总线上的数据信息。
添加环境(系统)变量
与 CAN 相同,可手动添加系统变量以用于绑定仪表盘、信号或其它对象。本示例中添加了如下系统变量:

仪表盘设计
在 LDF 数据库中查看车内灯条相关的 LIN 信号时,可发现存在多种模式(例如 IDEL、LOAD、EXE、RUN、GLOBAL、CONFIGBRT),通过控件交互可以实现流水灯、呼吸灯等动态效果。

C 小程序实现
为提高代码可读性与可移植性,建议在开发时将功能模块以 .h / .cpp方式拆分,降低模块间耦合,避免重复定义、函数冲突或数据安全问题。
// All_Light_Control.h 包含所有关于Light_Control的功能函数声明
#ifndef __ALL_LIGT_CONTROL__H__
#define __ALL_LIGT_CONTROL__H__
void On_SysVar_All_Light_IDEL_Mode();
void On_SysVar_All_Light_LOAD_Mode();
void On_SysVar_All_Light_EXE_Mode();
void On_SysVar_All_Light_RUN_Mode();
void On_SysVar_All_Light_GLOBAL_Mode();
void On_SysVar_All_Light_CONFIGBRT_Mode();
void On_SysVar_All_Light_Mode_Confirm();
void On_SysVar_Light_Mode_Start();
void On_SysVar_Light_Mode_Pause();
void On_SysVar_Light_Mode_Resume();
void On_SysVar_Light_Mode_Stop();
void On_SysVar_Breath_Mode_Start();
void On_SysVar_Breath_Mode_Pause();
void On_SysVar_Breath_Mode_Resume();
void On_SysVar_Breath_Mode_Stop();
void On_running_light_timer(void *timer);
void On_running_light_control_timer(void *timer);
void On_running_light_global_timer(void *timer);
void On_breath_light_timer(void *timer);
void On_breath_light_control_timer(void *timer);
void On_breath_light_global_timer(void *timer);
void On_idle_mode_timer(void *timer);
void On_close_all_light_timer(void *timer);
void reset_current_radio_state(int var);
#endif
//common.h 包含所有需要用到的定义.h文件/枚举值/静态全局对象等
#ifndef __COMMON__H__
#define __COMMON__H__
#include "BaseMiniProgram.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include "SystemVariableDefine.h"
#include "MainPanel.h"
#include "AutoAddress.h"
#include "Identfication.h"
#include "Temperature_Control.h"
#include "All_Light_Control.h"
typedef void* msTimer;
typedef struct message
{
int ID;
int DLC;
byte byte[8];
}message_t;
enum Setp_State{
WAIT_FOR_NEXT_STEPS = 0,
OPEN_EXTENDED_SESSION = 1,
RESET_LIGHT_BRIGHTNESS = 2,
CONFIGURE_LAMP_BOARD = 3,
CONTROL_ECU_POSITION = 4,
END_PROCESS = 5,
OPEN_EXTENDED_SESSION_FAILED = 6,
RESET_LIGHT_BRIGHTNESS_FAILED = 7,
CONFIGURE_LAMP_BOARD_FAILED = 8,
CONTROL_ECU_POSITION_FAILED = 9,
END_PROCESS_FAILED = 10,
CURRENT_STEP_PASSED = 11,
CURRENT_STEP_TIMEOUT = 12,
UDS_RESPONSE_SUCCESSED= 254,
UDS_RESPONSE_FAILED = 255,
};
enum T_For_Timer{
T_UDS_CMD_OUTPUT = 200,
T_Response_TIMEOUT = 10,
T_KT_TIMEOUT = 20,
T_AUTO_STEP = 100,
T_SEND_UDS = 20,
T_OUTPUT_MSG = 10,
T_TEMP_CONTROL_TIMEOUT = 100,
T_COMMON_CONTROL_TIMEOUT = 100,
T_LIGHT_CONTROL = 40,
T_BREATH_GLOBAL = 3000,
T_BREATH_GLOBAL_NEXT = 1000,
};
enum Light_Mode
{
IDEL = 0,
LOAD = 1,
EXE = 2,
RUN = 3,
GLOBAL = 4,
CONFIGBRT = 5
};
static int uds_cmd_send_flag,send_page,page,common_cmd_send_flag,out_put_line[13];
static byte temp[255];
static message linMsg,linMsgResp;
static int NodeSel_Rq = 0;
static int response_header_flag = 0,step_result = WAIT_FOR_NEXT_STEPS,data_len,data_len_temp=0,only_load_flag = 0;
static byte uds_cmd_list[13][8],common_cmd_list[12][8];
static char cmd_result_code[255];
static byte lin_send_message[15][8];
static int light_set_flag = 0;
static LIN::AILC_LIG_Rq_LIN_ST3 light_sts;
// diagRequest LIG_MBEAM.Temperature_LM_1_10_Read temp_all_read;
// diagRequest LIG_MBEAM.Temperature_LIG_ECU_Read temp_lig_ecu_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_1_Read temp_lm_1_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_2_Read temp_lm_2_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_3_Read temp_lm_3_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_4_Read temp_lm_4_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_5_Read temp_lm_5_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_6_Read temp_lm_6_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_7_Read temp_lm_7_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_8_Read temp_lm_8_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_9_Read temp_lm_9_read;
// diagRequest LIG_MBEAM.GA_Temperature_LM_10_Read temp_lm_10_read;
// diagRequest LIG_MBEAM.GA_Temperature_per_channel_Read temp_per_channel_read;
// diagResponse LIG_MBEAM.Temperature_LM_1_10_Read temp_all_read_resp;
void reset_autoaddress_execute_setps();
void set_Progress_Bar();
void reset_output_line_for_temperature_uds_cmd();
void reset_output_line_for_common_uds_cmd();
void init_common_cmd_list();
void get_temperature_value(int data);
#endif
#include "../Config/common.h"
int color_iter,color_first,color_end;
msTimer running_light_timer;
msTimer running_light_control_timer;
msTimer running_light_global_timer;
msTimer breath_light_timer;
msTimer breath_light_control_timer;
msTimer breath_light_global_timer;
msTimer idle_mode_timer;
msTimer close_all_light_timer;
int interval_ts;
int interval_br,br_flag=0,down_up_flag = 0;
//diagRequest LIG_MBEAM.LIG_Variant_Coding_Read lig_varoding_read;
int NodeSel_Count = 0;
int mode_flag = 0; // 0 running light 1 breath light
int running_light_output_flag = 0;
int idel_flag = 0;
int LIG_TmToChg = 50;
int array_for_light_control_mode[6] = {1,0,0,0,0,0};
void On_SysVar_All_Light_IDEL_Mode()
{
if (Light_Control:: All_Light_IDEL == 1)
{
reset_current_radio_state(0);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_LOAD_Mode()
{
if (Light_Control::All_Light_LOAD == 1)
{
reset_current_radio_state(1);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_EXE_Mode()
{
if (Light_Control::All_Light_EXE == 1)
{
reset_current_radio_state(2);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_RUN_Mode()
{
if (Light_Control::All_Light_RUN == 1)
{
reset_current_radio_state(3);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_GLOBAL_Mode()
{
if (Light_Control::All_Light_GLOBAL == 1)
{
reset_current_radio_state(4);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_CONFIGBRT_Mode()
{
if (Light_Control::All_Light_CONFIGBRT == 1)
{
reset_current_radio_state(5);
Light_Control::All_Light_EXECUTED = 1;
Light_Control::All_Light_COMPLETED = 0;
}
}
void On_SysVar_All_Light_Mode_Confirm()
{
if (Light_Control::All_Light_Mode_Confirm == 1)
{
if (array_for_light_control_mode[0] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
light_sts.Transmit();
}
else if (array_for_light_control_mode[1] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
only_load_flag = 1;
light_set_flag = 1;
NodeSel_Rq = 1;
start_timer(T_KT_TIMEOUT,true,On_light_setting_timer);
}
else if (array_for_light_control_mode[2] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = EXE;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
light_set_flag = 1;
NodeSel_Rq = 1;
start_timer(T_KT_TIMEOUT,true,On_light_setting_timer);
}
else if (array_for_light_control_mode[3] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = RUN;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
light_set_flag = 1;
NodeSel_Rq = 1;
start_timer(T_KT_TIMEOUT,true,On_light_setting_timer);
}
else if (array_for_light_control_mode[4] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = GLOBAL;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
light_sts.Transmit();
}
else if (array_for_light_control_mode[5] == 1){
light_sts.AILC_LIG_Color_Rq_ST3 = Light_Control::All_Light_Color_ID;
light_sts.AILC_LIG_Brt_Rq_ST3 = Light_Control::All_Light_Brightness;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = CONFIGBRT;
light_sts.AILC_LIG_NodeSel_Rq = 1;
if (Light_Control::All_Light_Chgmd_Rq < 4){
light_sts.AILC_LIG_ChgMd_Rq_ST3 = Light_Control::All_Light_Chgmd_Rq;
}
else{
light_sts.AILC_LIG_ChgMd_Rq_ST3 = 0;
}
light_sts.AILC_LIG_TmToChg_Rq_ST3 = Light_Control::All_Light_TmToChg_Rq;
light_set_flag = 1;
NodeSel_Rq = 1;
start_timer(T_KT_TIMEOUT,true,On_light_setting_timer);
}
Light_Control::All_Light_EXECUTED = 0;
Light_Control::All_Light_COMPLETED = 1;
}
}
// //running light
// on diagResponse LIG_MBEAM.LIG_Variant_Coding_Read
// {
// if (!this.IsPositiveResponse())
// {
// NodeSel_Count = 16;
// }
// else{
// NodeSel_Count = this.GetParameter("PLIG_vMAM_amount");
// color_iter = getSignal(AILC_LIG_Color_Rq_ST3_LIG);
// //cancelTimer(running_light_timer);
// //cancelTimer(running_light_control_timer);
// //cancelTimer(running_light_global_timer);
// //cancelTimer(breath_light_timer);
// //cancelTimer(breath_light_control_timer);
// //cancelTimer(breath_light_global_timer);
// //灭灯
// NodeSel_Rq = 1;
// color_iter = 1;
// light_sts.AILC_LIG_Oprtn_Rq_ST3 = VtSig_AILC_LIG_Oprtn_Rq_ST3_LIG::LOAD;
// light_sts.AILC_LIG_TmToChg_Rq_ST3 = 0;
// light_sts.AILC_LIG_Brt_Rq_ST3 = 0;
// light_sts.AILC_LIG_Oprtn_Rq_ST3 = 1;
// light_sts.AILC_LIG_NodeSel_Rq = 1;
// light_set_flag = 1;
// start_timer(,true,On_close_all_light_timer,T_KT_TIMEOUT);
// if(mode_flag == 0){
// color_end = Light_Control::Color_Num_Frist);
// start_timer(,true,On_running_light_timer,500);
// }
// else{
// light_sts.AILC_LIG_TmToChg_Rq_ST3 = LIG_TmToChg;
// color_end = Light_Control::Color_Num_End);
// start_timer(,true,On_breath_light_timer,500);
// }
// }
// }
void On_SysVar_Light_Mode_Start()
{
if(Light_Control::All_Light_Mode_Confirm == 1){
mode_flag = 0;
// lig_varoding_read.SendRequest();
}
}
void On_SysVar_Light_Mode_Pause()
{
if(Light_Control::Running_Light_Pause)
{
//cancelTimer(running_light_timer);
//cancelTimer(running_light_control_timer);
//cancelTimer(running_light_global_timer);
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.Transmit();
}
}
void On_SysVar_Light_Mode_Resume()
{
if(Light_Control::Running_Light_Resume)
{
if(NodeSel_Rq == 1)
start_timer(T_LIGHT_CONTROL,true,On_running_light_timer);
else
start_timer(T_LIGHT_CONTROL,true,On_running_light_control_timer);
}
}
void On_SysVar_Light_Mode_Stop()
{
if (Light_Control::Running_Light_Stop == 1){
color_iter = 0;
//cancelTimer(running_light_timer);
//cancelTimer(running_light_control_timer);
//cancelTimer(running_light_global_timer);
NodeSel_Rq = 0;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.Transmit();
}
}
void On_SysVar_Breath_Mode_Start()
{
if(Light_Control::Breathing_Light_Start == 1){
mode_flag = 1;
// lig_varoding_read.SendRequest();
br_flag = 0;
}
}
void On_SysVar_Breath_Mode_Pause()
{
if(Light_Control::Running_Light_Pause == 1){
//cancelTimer(breath_light_timer);
//cancelTimer(breath_light_control_timer);
//cancelTimer(breath_light_global_timer);
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.Transmit();
}
}
void On_SysVar_Breath_Mode_Resume()
{
if(Light_Control::Breathing_Light_Resume == 1){
if(NodeSel_Rq == 1)
start_timer(T_KT_TIMEOUT,true,On_breath_light_timer);
else
start_timer(T_KT_TIMEOUT,true,On_breath_light_control_timer);
}
}
void On_SysVar_Breath_Mode_Stop()
{
if(Light_Control::Breathing_Light_Stop == 1){
color_iter = 0;
//cancelTimer(breath_light_timer);
//cancelTimer(breath_light_control_timer);
//cancelTimer(breath_light_global_timer);
NodeSel_Rq = 0;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.Transmit();
}
}
void On_running_light_timer(void *timer)
{
//if(color_iter >= 1 && color_iter <= color_end)
//{
//light_sts.AILC_LIG_Color_Rq_ST3 = color_iter;
light_sts.AILC_LIG_Color_Rq_ST3 = color_end;
light_sts.AILC_LIG_NodeSel_Rq = 1;
NodeSel_Rq = 1;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
start_timer(T_KT_TIMEOUT*2,true,On_running_light_control_timer);
//color_iter++;
//}
//else
//{
// color_iter = 1;
//start_timer(T_KT_TIMEOUT,true,On_running_light_timer);
//}
}
void On_running_light_control_timer(void *timer)
{
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
if (NodeSel_Rq <= NodeSel_Count){
if(running_light_output_flag)
{
if(NodeSel_Rq == 1){
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Count;
}
else{
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq - 1;
}
light_sts.AILC_LIG_Brt_Rq_ST3 = 0;
light_sts.Transmit();
start_timer(T_LIGHT_CONTROL,true,On_running_light_control_timer);
running_light_output_flag = 0;
}
else{
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq;
light_sts.AILC_LIG_Brt_Rq_ST3 = 50;
light_sts.Transmit();
running_light_output_flag = 1;
if(NodeSel_Rq == NodeSel_Count)
{
NodeSel_Rq = 1;
start_timer(T_KT_TIMEOUT*2,true,On_running_light_timer);
}
else{
NodeSel_Rq ++;
}
start_timer(T_LIGHT_CONTROL,true,On_running_light_global_timer);
}
}
}
void On_running_light_global_timer(void *timer){
if(idel_flag == 0){
light_sts.AILC_LIG_Oprtn_Rq_ST3 = GLOBAL;
light_sts.Transmit();
idel_flag = 1;
start_timer(T_LIGHT_CONTROL,true,On_running_light_global_timer);
}
else{
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
light_sts.Transmit();
idel_flag = 0;
start_timer(T_LIGHT_CONTROL,true,On_running_light_control_timer);
}
}
// breathing light
void On_breath_light_timer(void *timer){
//cancelTimer(breath_light_timer);
light_sts.AILC_LIG_Color_Rq_ST3 = color_end;
light_sts.AILC_LIG_NodeSel_Rq = 1;
NodeSel_Rq = 1;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
start_timer(T_KT_TIMEOUT*3,true,On_breath_light_control_timer);
//global帧
start_timer(T_BREATH_GLOBAL,true,On_breath_light_global_timer);
/*if(color_iter >= 1 && color_iter <= color_end)
{
light_sts.AILC_LIG_Color_Rq_ST3 = color_iter;
light_sts.AILC_LIG_NodeSel_Rq = 1;
NodeSel_Rq = 0;
light_sts.AILC_LIG_Oprtn_Rq_ST3 = VtSig_AILC_LIG_Oprtn_Rq_ST3_LIG::LOAD;
start_timer(,true,On_breath_light_control_timer,T_KT_TIMEOUT);
if(color_iter == color_end)
{
color_iter = 1;
}
else
{
if(br_flag)
color_iter++;
}
}
else
color_iter = 1;
start_timer(,true,On_breath_light_control_timer,T_KT_TIMEOUT*3);
//global帧
start_timer(,true,On_ breath_light_global_timer,T_BREATH_GLOBAL);*/
}
void On_breath_light_control_timer(void *timer){
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
if (NodeSel_Rq <= NodeSel_Count){
if(br_flag) //brt -> 0
{
light_sts.AILC_LIG_Brt_Rq_ST3 = 0;
}
else{ // brt -> 100
light_sts.AILC_LIG_Brt_Rq_ST3 = 100;
}
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq;
light_sts.Transmit();
if(NodeSel_Rq == NodeSel_Count)
{
if (br_flag){
br_flag = 0;
//cancelTimer(breath_light_control_timer);
start_timer(T_KT_TIMEOUT,true,On_breath_light_control_timer);
}
else{
br_flag = 1;
//cancelTimer(breath_light_control_timer);
start_timer(T_KT_TIMEOUT,true,On_breath_light_global_timer);
}
NodeSel_Rq = 1;
}
else{
//cancelTimer(breath_light_control_timer);
start_timer(T_KT_TIMEOUT*3,true,On_breath_light_control_timer);
NodeSel_Rq ++;
}
}
}
void On_breath_light_global_timer(void *timer){
light_sts.AILC_LIG_Oprtn_Rq_ST3 = GLOBAL;
light_sts.Transmit();
idel_flag = 1;
//cancelTimer(breath_light_global_timer);
start_timer(T_KT_TIMEOUT*3,true,On_idle_mode_timer);
}
void On_idle_mode_timer(void *timer){
light_sts.AILC_LIG_Oprtn_Rq_ST3 = IDEL;
if(NodeSel_Rq<=NodeSel_Count){
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq;
light_sts.Transmit();
if(NodeSel_Rq == NodeSel_Count){
//cancelTimer(idle_mode_timer);
NodeSel_Rq = 1;
//cancelTimer(idle_mode_timer);
start_timer(T_BREATH_GLOBAL_NEXT,true,On_breath_light_timer);
}
else{
start_timer(T_KT_TIMEOUT,true,On_idle_mode_timer);
NodeSel_Rq++;
}
}
}
void On_close_all_light_timer(void *timer){
light_sts.AILC_LIG_Oprtn_Rq_ST3 = LOAD;
if(NodeSel_Rq<=16){
light_sts.Transmit();
if(NodeSel_Rq == 16){
//cancelTimer(close_all_light_timer);
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq;
light_sts.Transmit();
//cancelTimer(close_all_light_timer);
light_sts.AILC_LIG_Oprtn_Rq_ST3 = GLOBAL;
light_sts.Transmit();
NodeSel_Rq = 1;
}
else{
light_sts.AILC_LIG_NodeSel_Rq = NodeSel_Rq;
light_sts.Transmit();
start_timer(T_KT_TIMEOUT,true,On_close_all_light_timer);
NodeSel_Rq++;
}
}
else
{
NodeSel_Rq = 1;
light_sts.Transmit();
}
}
void reset_current_radio_state(int var)
{
for (int iter=0;iter<6;iter++){
array_for_light_control_mode[iter] = 0;
}
array_for_light_control_mode[var] = 1;
Light_Control::All_Light_IDEL = array_for_light_control_mode[0];
Light_Control::All_Light_LOAD = array_for_light_control_mode[1];
Light_Control::All_Light_EXE = array_for_light_control_mode[2];
Light_Control::All_Light_RUN = array_for_light_control_mode[3];
Light_Control::All_Light_GLOBAL = array_for_light_control_mode[4];
Light_Control::All_Light_CONFIGBRT = array_for_light_control_mode[5];
}
Trace 窗口与日志
与 CAN 仿真类似,跟踪窗口与日志记录是 LIN 仿真流程的重要组成部分。具体操作与前一节相同。
工程操作测试
完成上述配置后,读者可以连接相应设备,在 ETStudio 中运行工程,并根据需要切换车内灯条的控制模式以观察对应的功能效果。也可以通过预设的跑马灯与呼吸灯控制按钮来展示功能效果。
扩展话题 — 关于网络管理
为了适应汽车系统的持续更新与扩展、保证越来越多 ECU 单元的正常运行并降低电池的功耗,引入了网络管理(Network Management, NM)机制。尤其是仪表/主机/座椅调节单元等在车辆熄火后灯仍不立即熄灭的 ECU,需要合理的网络管理策略。通过网络管理,这些 ECU 可以实现系统性的休眠、唤醒与挂起机制,以确保可靠的车载通信并减少系统的静默功耗。
常见的网络管理模式包括 OSEK(Open Systems and their Interfaces for the Electronics in Motor Vehicles)网络管理和 AUTOSAR(AUTomotive Open System ARchitecture)网络管理。
OSEK 的网络管理可分为直接管理与间接管理两类:直接管理要求网络中的每个节点具有唯一身份和专用的网络管理报文,并通过协商机制控制网络中所有节点同时进入休眠;间接管理则通过被动检测节点的周期性应用报文,如果在一段时间内未收到相关报文,则认为该节点已离线或进入休眠状态。
AUTOSAR 的网络管理要求参与管理的节点具有唯一标识号并使用特定的网络管理报文,同时对网络的工作状态进行规范,从而保证车载 ECU 能够协同地唤醒与进入睡眠。