车辆遥测平台开发详解
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);
}
-
步骤
:
- 延迟 16 毫秒,让 LCD 有时间启动。
-
多次发送
B0011到 LCD 数据线 7 到 4,设置 LCD 为 4 位模式。 -
最后一次发送
B0010。 - 设置 LCD 为 4 位模式,使用 5×8 字体。
- 打开显示控制,隐藏光标,无闪烁。
- 设置输入模式为自动位置递增,无显示移位。
-
定义自定义字符,如
L/100、km/h等。 - 将字符数据写入 LCD 控制器的字符生成 RAM。
- 发送“清屏”命令,并将 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]");
}
-
步骤
:
- 向连接的主机发送初始化 GPS 的消息。
- 设置 GPS 模块的波特率。
- 发送初始化成功的消息。
2.2 处理 GPS 缓冲区函数
processGpsBuffer()
该函数用于从 GPS 串口缓冲区提取数据并喂给 TinyGPS 对象,代码如下:
bool processGpsBuffer()
{
while (GPS.available())
{
if (gps.encode(GPS.read()))
return true;
}
return false;
}
-
步骤
:
- 检查 GPS 串口缓冲区是否有数据。
-
若有数据,则读取并使用
gps.encode()进行解码。 -
若解码成功,则返回
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]");
}
-
步骤
:
- 向连接的主机发送初始化 VDIP 的消息。
- 设置 VDIP 状态 LED、写入 LED、RTS 引脚和复位引脚的模式。
- 复位 VDIP 模块,延迟 100 毫秒。
- 打开与 VDIP 模块的串口连接,设置波特率。
-
发送
IPA命令,将 VDIP 设置为 ASCII 通信模式。 - 发送初始化成功的消息。
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 );
}
}
-
步骤
:
- 检查 VDIP 串口缓冲区是否有数据。
- 若有数据,则读取并发送给主机。
-
若读取到换行符(
13),则主机换行。
3.3 模式按钮中断服务函数
modeButton()
该函数用于处理“日志开/关”按钮的中断,代码如下:
void modeButton()
{
if((millis() - logButtonTimestamp) > 300) // debounce
{
logButtonTimestamp = millis();
digitalWrite(LOG_LED, !digitalRead(LOG_LED));
}
}
-
步骤
:
- 检查自上次中断以来的时间是否超过 300 毫秒,以进行消抖处理。
- 若超过 300 毫秒,则更新时间戳。
- 切换日志 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("> ");
}
}
}
-
步骤
:
- 检查日志状态 LED 的状态变化,若有变化则相应地启动或停止日志记录。
- 检查主机串口缓冲区是否有命令。
-
根据读取到的命令字符执行相应的操作:
-
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;
通过以上内容,我们对车辆遥测平台的开发有了更深入的理解,希望能为相关开发工作提供有价值的参考。
超级会员免费看
5946

被折叠的 条评论
为什么被折叠?



