35、车辆遥测平台开发详解

车辆遥测平台开发详解

1. LCD 功能实现

在开发中,LiquidCrystal 库对于驱动并行 LCD 模块很方便,但在内存紧张时,可能需要自定义功能。以下是相关要点:

1.1 光标定位函数 lcd_gotoXY()

该函数用于将光标移动到指定位置,其实现代码如下:

void lcd_gotoXY(byte x, byte y)
{
  byte dr = 0x80 + x;
  if (y&1) dr+= 0x40;
  if (y&2) dr+= 0x14;
  lcd_commandWrite( dr );
}
  • 原理
    • 首先,将显示寄存器的基地址 0x80 与 X 位置相加,得到初始的显示寄存器地址。
    • 然后,根据 Y 值使用位运算符添加行偏移量。例如,若 Y 为 1,则添加 0x40 ;若 Y 为 2,则添加 0x14 ;若 Y 为 3,则两者都添加。
    • 最后,将计算得到的地址发送给 LCD。
  • 局限性 :该函数仅适用于不超过 20 列的显示器。
1.2 LCD 初始化函数 lcd_init()

初始化 LCD 需要一系列步骤,包括设置模式、定义自定义字符等,代码如下:

void lcd_init()
{
  delay(16);
  for(byte i=0; i<3; i++)
  {
    lcd_pushNibble(B00110000);
    lcd_commandWriteSet();
    delay(5);
  }
  lcd_pushNibble(B00100000);
  lcd_commandWriteSet();
  delay(1);
  lcd_commandWrite(B00101000);
  lcd_commandWrite(B00001100);
  lcd_commandWrite(B00000110);
  #define NB_CHAR  7
  lcd_commandWrite(B01001000);
  static prog_uchar chars[] PROGMEM ={
    B110000,B00000,B110000,B000110,B001111,B111111,B000110,
    B110000,B00000,B1101100,B001100,B0011011,B11011011,B001100,
    B1110011,B00000,B111000,B011000,B001111,B11011011,B011000,
    B000110,B00000,B1101100,B110000,B00000,B00000,B110000,
    B001100,B00000,B00000,B001100,B00000,B001100,B001111,
    B0110011,B1110111,B111111,B001100,B00000,B00000,B001100,
    B000011,B1110111,B11011011,B001111,B00000,B001100,B0011011,
    B000011,B1110111,B11011011,B0011011,B00000,B001100,B001111,
  };
  for(byte x=0;x<NB_CHAR;x++)
    for(byte y=0;y<8;y++)
      lcd_dataWrite(pgm_read_byte(&chars[y*NB_CHAR+x]));
  lcd_cls();
  lcd_commandWrite(B10000000);
}
  • 步骤
    1. 延迟 16 毫秒,让 LCD 有时间启动。
    2. 多次发送 B0011 到 LCD 数据线 7 到 4,设置 LCD 为 4 位模式。
    3. 最后一次发送 B0010
    4. 设置 LCD 为 4 位模式,使用 5×8 字体。
    5. 打开显示控制,隐藏光标,无闪烁。
    6. 设置输入模式为自动位置递增,无显示移位。
    7. 定义自定义字符,如 L/100 km/h 等。
    8. 将字符数据写入 LCD 控制器的字符生成 RAM。
    9. 发送“清屏”命令,并将 RAM 地址设置为 0。
2. GPS 功能实现

GPS 功能主要由 TinyGPS 库处理,相关代码位于 GPS.pde 文件中。

2.1 GPS 初始化函数 initGps()

该函数用于初始化 GPS 模块,代码如下:

void initGps()
{
  hostPrint(" * Initialising GPS             ");
  GPS.begin(GPS_BAUD_RATE);
  hostPrintLn("[OK]");
}
  • 步骤
    1. 向连接的主机发送初始化 GPS 的消息。
    2. 设置 GPS 模块的波特率。
    3. 发送初始化成功的消息。
2.2 处理 GPS 缓冲区函数 processGpsBuffer()

该函数用于从 GPS 串口缓冲区提取数据并喂给 TinyGPS 对象,代码如下:

bool processGpsBuffer()
{
  while (GPS.available())
  {
    if (gps.encode(GPS.read()))
      return true;
  }
  return false;
}
  • 步骤
    1. 检查 GPS 串口缓冲区是否有数据。
    2. 若有数据,则读取并使用 gps.encode() 进行解码。
    3. 若解码成功,则返回 true ;否则返回 false
2.3 GPS 数据转储函数 gpsdump()

该函数主要来自 TinyGPS 的示例代码,在开发过程中可用于查看 GPS 数据,正常运行时一般不调用。

3. VDIP 功能实现

VDIP 模块提供了 USB 大容量存储功能,相关代码位于 VDIP.pde 文件中。

3.1 VDIP 初始化函数 initVdip()

初始化 VDIP 模块需要设置引脚、复位模块并设置通信模式,代码如下:

void initVdip()
{
  hostPrint(" * Initialising VDIP            ");
  pinMode(VDIP_STATUS_LED, OUTPUT);
  digitalWrite(VDIP_STATUS_LED, HIGH);
  pinMode(VDIP_WRITE_LED, OUTPUT);
  digitalWrite(VDIP_WRITE_LED, LOW);
  pinMode(VDIP_RTS_PIN, INPUT);
  pinMode(VDIP_RESET, OUTPUT);
  digitalWrite(VDIP_RESET, LOW);
  digitalWrite(VDIP_STATUS_LED, HIGH);
  digitalWrite(VDIP_WRITE_LED, HIGH);
  delay( 100 );
  digitalWrite(VDIP_RESET, HIGH);
  delay( 100 );
  VDIP.begin(VDIP_BAUD_RATE);
  VDIP.print("IPA\r");
  VDIP.print(13, BYTE);
  digitalWrite(VDIP_WRITE_LED, LOW);
  hostPrintLn("[OK]");
}
  • 步骤
    1. 向连接的主机发送初始化 VDIP 的消息。
    2. 设置 VDIP 状态 LED、写入 LED、RTS 引脚和复位引脚的模式。
    3. 复位 VDIP 模块,延迟 100 毫秒。
    4. 打开与 VDIP 模块的串口连接,设置波特率。
    5. 发送 IPA 命令,将 VDIP 设置为 ASCII 通信模式。
    6. 发送初始化成功的消息。
3.2 处理 VDIP 缓冲区函数 processVdipBuffer()

该函数用于将 VDIP 模块的串口缓冲区中的数据传递给主机,代码如下:

void processVdipBuffer()
{
  byte incomingByte;
  while( VDIP.available() > 0 )
  {
    incomingByte = VDIP.read();
    if( incomingByte == 13 ) {
      HOST.println();
    }
    HOST.print( incomingByte, BYTE );
  }
}
  • 步骤
    1. 检查 VDIP 串口缓冲区是否有数据。
    2. 若有数据,则读取并发送给主机。
    3. 若读取到换行符( 13 ),则主机换行。
3.3 模式按钮中断服务函数 modeButton()

该函数用于处理“日志开/关”按钮的中断,代码如下:

void modeButton()
{
  if((millis() - logButtonTimestamp) > 300)  // debounce
  {
    logButtonTimestamp = millis();
    digitalWrite(LOG_LED, !digitalRead(LOG_LED));
  }
}
  • 步骤
    1. 检查自上次中断以来的时间是否超过 300 毫秒,以进行消抖处理。
    2. 若超过 300 毫秒,则更新时间戳。
    3. 切换日志 LED 的状态。
4. 主机命令处理

Host.pde 文件中的 processHostCommands() 函数用于处理来自主机的命令,代码如下:

void processHostCommands()
{
  if(logActive && !digitalRead(LOG_LED))
  {
    logActive = 0;
    digitalWrite(VDIP_STATUS_LED, LOW);
    VDIP.print("CLF OBDUINO.CSV\r");
    HOST.println("Stop logging");
  }
  else if( !logActive && digitalRead(LOG_LED))
  {
    logActive = 1;
    digitalWrite(VDIP_STATUS_LED, HIGH);
    VDIP.print("OPW OBDUINO.CSV\r");
    HOST.println("Start logging");
  }
  if( HOST.available() > 0)
  {
    char readChar = HOST.read();
    if(readChar == '1')
    {
      HOST.println("Start logging");
      logActive = 1;
      digitalWrite(VDIP_STATUS_LED, HIGH);
      digitalWrite(LOG_LED, HIGH);
      VDIP.print("OPW OBDUINO.CSV\r");
      HOST.print("> ");
    }
    else if( readChar == '2') {
      HOST.println("Stop logging");
      while(digitalRead(VDIP_RTS_PIN) == HIGH)
      {
        HOST.println("VDIP BUFFER FULL");
      }
      logActive = 0;
      digitalWrite(VDIP_STATUS_LED, LOW);
      digitalWrite(LOG_LED, LOW);
      VDIP.print("CLF OBDUINO.CSV\r");
      HOST.print("> ");
    }
    else if (readChar == '3'){
      HOST.println("Reading file");
      VDIP.print("RD OBDUINO.CSV\r");
      processVdipBuffer();
      HOST.print("> ");
    }
    else if (readChar == '4'){
      logActive = 0;
      digitalWrite(VDIP_STATUS_LED, LOW);
      digitalWrite(LOG_LED, LOW);
      VDIP.print("CLF OBDUINO.CSV");
      HOST.println("Deleting file");
      VDIP.print("DLF OBDUINO.CSV\r");
      HOST.print("> ");
    }
    else if (readChar == '5'){
      HOST.println("Directory listing");
      VDIP.print("DIR\r");
      HOST.print("> ");
    }
    else if (readChar == '6'){
      HOST.print(" * Initializing flash storage   ");
      pinMode(VDIP_RESET, OUTPUT);
      digitalWrite(VDIP_RESET, LOW);
      delay( 100 );
      digitalWrite(VDIP_RESET, HIGH);
      delay( 100 );
      VDIP.print("IPA");
      VDIP.print(13, BYTE);
      HOST.println("[OK]");
      HOST.print("> ");
    }
    else {
      HOST.print("Unrecognized command '");
      HOST.print(readChar);
      HOST.println("'");
      HOST.println("1 - Start logging");
      HOST.println("2 - Stop logging");
      HOST.println("3 - Display logfile");
      HOST.println("4 - Delete logfile");
      HOST.println("5 - Directory listing");
      HOST.println("6 - Reset VDIP module");
      HOST.print("> ");
    }
  }
}
  • 步骤
    1. 检查日志状态 LED 的状态变化,若有变化则相应地启动或停止日志记录。
    2. 检查主机串口缓冲区是否有命令。
    3. 根据读取到的命令字符执行相应的操作:
      • 1 :启动日志记录,打开 CSV 文件。
      • 2 :停止日志记录,关闭 CSV 文件。
      • 3 :读取日志文件内容并显示。
      • 4 :删除日志文件。
      • 5 :显示目录列表。
      • 6 :复位 VDIP 模块。
      • 其他:显示帮助信息。

以下是相关功能的流程图:

graph TD;
    A[开始] --> B[LCD 初始化];
    B --> C[GPS 初始化];
    C --> D[VDIP 初始化];
    D --> E[主循环];
    E --> F{有主机命令?};
    F -- 是 --> G{处理命令};
    F -- 否 --> H{处理 GPS 缓冲区};
    H -- 是 --> I{更新 GPS 数据};
    H -- 否 --> J{处理 VDIP 缓冲区};
    G --> E;
    I --> E;
    J --> E;
5. 辅助函数

Host.pde 文件中还定义了两个辅助函数 hostPrint() hostPrintLn() ,用于向主机发送消息,代码如下:

void hostPrint( char* message )
{
  #ifdef MEGA
  HOST.print(message);
  #endif
}

void hostPrintLn( char* message )
{
  #ifdef MEGA
  HOST.println(message);
  #endif
}

这些函数通过 #ifdef MEGA 检查,确保只有在为 Mega 目标构建时才会执行实际的打印操作。

综上所述,通过上述各个模块的实现,可以构建一个完整的车辆遥测平台,实现 LCD 显示、GPS 数据处理、USB 存储等功能,并通过主机命令进行控制。在实际开发中,需要注意各个函数的调用频率和缓冲区的处理,以确保系统的稳定性和可靠性。

车辆遥测平台开发详解(续)

6. 各模块功能总结与对比

为了更清晰地了解各个模块的功能和特点,下面通过表格进行总结对比:
| 模块 | 主要功能 | 关键函数 | 注意事项 |
| — | — | — | — |
| LCD | 驱动并行 LCD 模块,实现光标定位、初始化、自定义字符显示等功能 | lcd_gotoXY() lcd_init() | 光标定位函数在超过 20 列显示器可能不适用;初始化步骤较多,需严格按顺序执行 |
| GPS | 与 GPS 模块通信,处理 GPS 数据 | initGps() processGpsBuffer() gpsdump() | processGpsBuffer() 需频繁调用,防止串口缓冲区溢出 |
| VDIP | 实现 USB 大容量存储功能,处理模块初始化、数据传输和模式切换 | initVdip() processVdipBuffer() modeButton() | 初始化时需正确设置通信模式;处理大文件读取时可能出现缓冲区溢出问题 |
| 主机命令处理 | 处理来自主机的命令,控制日志记录、文件操作等 | processHostCommands() | 注意命令字符的识别和执行顺序,以及 VDIP 缓冲区状态检查 |

7. 实际应用中的优化建议

在实际应用车辆遥测平台时,可以考虑以下优化建议:
- 内存优化
- 对于 LCD 功能,若内存紧张,可继续采用自定义函数代替完整库的方式,减少内存占用。
- 合理使用全局变量和局部变量,避免不必要的内存浪费。
- 性能优化
- 增加 processGpsBuffer() processVdipBuffer() 函数的调用频率,确保数据及时处理,防止缓冲区溢出。
- 对于 VDIP 模块处理大文件读取的问题,可以增加缓冲区检查和通信超时机制,避免程序阻塞。
- 用户体验优化
- 完善主机命令的反馈信息,让用户更清楚操作结果。
- 优化自定义字符的显示效果,提高显示的清晰度和可读性。

8. 操作步骤总结

下面以启动日志记录为例,总结具体的操作步骤:
1. 确保系统已完成 LCD、GPS 和 VDIP 模块的初始化。
2. 通过主机向系统发送命令字符 1
3. 系统执行 processHostCommands() 函数,检查到命令字符为 1 后:
- 将 logActive 标志设置为 1
- 点亮 VDIP 状态 LED。
- 点亮日志 LED。
- 向 VDIP 模块发送 OPW OBDUINO.CSV\r 命令,打开 CSV 文件。
- 向主机发送 Start logging 消息,并输出 > 提示符。

9. 未来扩展方向

可以根据实际需求对车辆遥测平台进行扩展,以下是一些可能的扩展方向:
- 传感器扩展 :增加更多类型的传感器,如加速度传感器、温度传感器等,获取更全面的车辆数据。
- 通信方式扩展 :支持更多的通信协议,如 Wi-Fi、蓝牙等,方便数据的远程传输和共享。
- 数据分析功能 :在本地或远程服务器上对采集到的数据进行分析,提供更有价值的信息,如车辆行驶习惯分析、故障预警等。

10. 总结

通过对车辆遥测平台各个模块的详细介绍,包括 LCD 功能实现、GPS 数据处理、VDIP 模块操作和主机命令处理等,我们了解了如何构建一个完整的车辆遥测系统。在开发过程中,需要注意各个模块的初始化步骤、函数调用频率和缓冲区处理,以确保系统的稳定性和可靠性。同时,通过优化建议和扩展方向的探讨,可以进一步提升平台的性能和功能,满足不同用户的需求。

以下是一个扩展功能的流程图,展示了添加新传感器后的系统流程:

graph TD;
    A[开始] --> B[LCD 初始化];
    B --> C[GPS 初始化];
    C --> D[VDIP 初始化];
    D --> E[新传感器初始化];
    E --> F[主循环];
    F --> G{有主机命令?};
    G -- 是 --> H{处理命令};
    G -- 否 --> I{处理 GPS 缓冲区};
    I -- 是 --> J{更新 GPS 数据};
    I -- 否 --> K{处理新传感器数据};
    K -- 是 --> L{更新传感器数据};
    K -- 否 --> M{处理 VDIP 缓冲区};
    H --> F;
    J --> F;
    L --> F;
    M --> F;

通过以上内容,我们对车辆遥测平台的开发有了更深入的理解,希望能为相关开发工作提供有价值的参考。

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 本项目是本人参加BAT等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。 除开知识点,一定要准备好以下套路: 个人介绍,需要准备一个1分钟的介绍,包括学习经历、工作经历、项目经历、个人优势、一句话总结。 一定要自己背得滚瓜烂熟,张口就来 抽象概念,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化、应用方面系统性地回答 项目强化,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳 压力练习,面试的时候难免紧张,可能会严重影响发挥,通过平时多找机会参与交流分享,或找人做压力面试来改善 表达练习,表达能力非常影响在面试中的表现,能否简练地将答案告诉面试官,可以通过给自己讲解的方式刻意练习 重点针对,面试官会针对简历提问,所以请针对简历上写的所有技术点进行重点准备 Java基础 JVM原理 集合 多线程 IO 问题排查 Web框架、数据库 Spring MySQL Redis 通用基础 操作系统 网络通信协议 排序算法 常用设计模式 从URL到看到网页的过程 分布式 CAP理论 锁 事务 消息队列 协调器 ID生成方式 一致性hash 限流 微服务 微服务介绍 服务发现 API网关 服务容错保护 服务配置中心 算法 数组-快速排序-第k大个数 数组-对撞指针-最大蓄水 数组-滑动窗口-最小连续子数组 数组-归并排序-合并有序数组 数组-顺时针打印矩形 数组-24点游戏 链表-链表反转-链表相加 链表-...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值