出租车计价器课程设计如何实现?

99ANYc3cd6 课程介绍 1

出租车计价器课程设计

项目概述

本项目旨在设计并制作一个基于单片机的出租车计价器,该计价器能够实时模拟出租车的计费过程,包括起步价、里程费、等待费,并能通过按键进行模拟启动、暂停/继续、复位等操作,最终将总费用、行驶里程和等待时间等信息显示在LCD1602液晶屏上。

通过本课程设计,学生可以综合运用单片机原理、C语言编程、传感器技术、人机接口设计等知识,完成一个从理论到实践的完整电子产品开发过程。

出租车计价器课程设计如何实现?-第1张图片-指南针培训网

设计目标与要求

  1. 基本功能:

    • 显示功能: 使用LCD1602液晶屏实时显示总费用、行驶里程(单位:公里)、等待时间(单位:分钟)。
    • 计费模式:
      • 起步价: 启动后,自动显示并开始计算起步价(前3公里内收费10元)。
      • 里程费: 超过起步里程后,按每公里单价收费(2元/公里)。
      • 等待费: 在车辆停止或低速行驶时,开始按时间计费(每分钟0.5元)。
    • 控制功能:
      • 启动键: 模拟乘客上车,计价器开始计费。
      • 暂停/继续键: 模拟等红灯或临时停靠,暂停里程计费,开始等待计时;再次按下,继续行驶计费。
      • 复位键: 模拟乘客下车,计价器清零所有数据,恢复初始状态。
  2. 技术指标:

    • 计费精度: 费用计算精确到0.1元。
    • 里程精度: 里程计算精确到0.01公里。
    • 响应时间: 按键响应迅速,显示数据更新及时。
  3. 扩展功能 (可选):

    • 夜间模式: 在特定时间段(如晚上11点后至早上5点前)自动切换为夜间计价标准(起步价和单价上浮20%)。
    • 发票打印功能: 模拟打印发票,显示本次行程的详细信息。
    • 语音播报: 使用语音模块播报“欢迎乘坐”、“请系好安全带”等提示音。

系统总体方案设计

系统采用“单片机最小系统 + 传感器模块 + 输入模块 + 显示模块”的结构。

出租车计价器课程设计如何实现?-第2张图片-指南针培训网

工作流程:

  1. 用户通过按键模块向单片机发送指令(启动、暂停、复位)。
  2. 单片机根据指令控制计费状态。
  3. 单片机通过传感器模块获取里程信息(如霍尔传感器脉冲)。
  4. 单片机内部根据预设的计价算法(起步价、里程费、等待费)进行实时计算。
  5. 单片机将计算结果(总费用、里程、时间)发送到LCD1602显示屏上进行实时更新。

系统框图:

+---------------------+
|    按键模块         |  -----> |                |
| (启动/暂停/复位)    |         |                |
+---------------------+         |                |
                                |   单片机       |
+---------------------+         |   (主控制器)    |
|   传感器模块        |  -----> |   (如STC89C52)  |
| (霍尔传感器/编码器) |         |                |
+---------------------+         |                |
                                |                |
+---------------------+         |                |
|   LCD1602 显示模块  | <-----  |                |
| (显示费用/里程/时间)|         |                |
+---------------------+         +----------------+

硬件选型与电路设计

  1. 主控制器:

    • 型号: STC89C52RC 或 STM32F103C8T6
    • 理由: STC89C52是经典的51单片机,资料丰富,成本低,非常适合教学,STM32性能更强,资源更多,适合有更高要求的项目,本设计以STC89C52为例。
  2. 显示模块:

    • 型号: LCD1602 (1602字符型液晶显示器)
    • 理由: 可以显示2行,每行16个字符,足以显示总费用、里程、等待时间等信息,接口简单,驱动成熟。
  3. 输入模块:

    • 型号: 独立按键 x 3
    • 理由: 用于实现启动、暂停/继续、复位功能,电路简单,只需连接到单片机的I/O口,并做必要的上拉或下拉。
  4. 里程检测模块:

    • 方案A (推荐): 霍尔传感器 + 小磁铁
      • 原理: 在车轮的转动部件上粘贴一小块磁铁,将霍尔传感器固定在附近,车轮每转一圈,磁铁经过一次,霍尔传感器就输出一个脉冲信号,单片机对脉冲进行计数,即可换算出里程。
      • 优点: 非接触式,寿命长,安装方便。
    • 方案B: 光电对管/红外对管
      • 原理: 在车轮上贴一个反光片,利用红外发射和接收管检测反光片的经过。
      • 缺点: 易受灰尘和光线影响,可靠性不如霍尔传感器。
    • 方案C: 旋转编码器
      • 原理: 可以输出正交脉冲,不仅能检测转动,还能检测方向。
      • 优点: 精度高,信息量大。
      • 缺点: 成本相对较高,电路稍复杂。
  5. 电路连接:

    • LCD1602:

      RS, RW, E, D4-D7 -> 连接到单片机的P0或P2口(需要上拉电阻)。

    • 按键:

      三个按键分别连接到P3.0, P3.1, P3.2,并使用10KΩ电阻上拉到VCC。

    • 霍尔传感器:
      • VCC -> 5V
      • GND -> GND
      • OUT -> 连接到外部中断0(INT0, P3.2)或普通I/O口(如P3.3),使用中断可以更精确地捕获脉冲。

软件设计与流程图

软件是项目的核心,主要包括初始化、按键处理、计费逻辑、数据显示四大模块。

  1. 主程序流程图:

    graph TD
    A[开始] --> B{系统初始化};
    B --> C{等待按键事件};
    C -- 启动键 --> D[启动计费];
    C -- 暂停/继续键 --> E[切换计费状态];
    C -- 复位键 --> F[系统复位];
    D --> G[读取传感器数据];
    G --> H[根据状态计算费用];
    H --> I[更新LCD显示];
    I --> C;
    E --> G;
    F --> C;
  2. 计费逻辑详解 (伪代码):

    
    // 定义常量
    float START_PRICE = 10.0;      // 起步价
    float START_MILEAGE = 3.0;     // 起步里程
    float PRICE_PER_KM = 2.0;      // 每公里单价
    float PRICE_PER_MINUTE = 0.5;  // 每分钟单价

// 定义变量 float total_price = 0.0; float mileage = 0.0; int wait_time = 0; bool is_running = false; // 是否在行驶 bool is_waiting = false; // 是否在等待 unsigned long last_pulse_time = 0; int pulse_count = 0; const float MILEAGE_PER_PULSE = 0.01; // 每个脉冲代表的里程数

// 中断服务函数 (霍尔传感器中断) void HALL_ISR() { if (is_running && !is_waiting) { mileage += MILEAGE_PER_PULSE; pulse_count++; } }

// 主循环中的计费逻辑 void calculate_fare() { if (is_running) { // 1. 计算里程费 if (mileage > START_MILEAGE) { total_price = START_PRICE + (mileage - START_MILEAGE) * PRICE_PER_KM; } else { total_price = START_PRICE; }

    // 2. 计算等待费
    if (is_waiting) {
        // 等待费计算,可以在定时器中断里增加wait_time
        total_price += wait_time * PRICE_PER_MINUTE;
    }
}

3.  **软件模块划分:**
    *   **`main.c`**: 主函数,负责调用其他模块,实现主循环。
    *   **`lcd1602.c / lcd1602.h`**: LCD1602驱动函数库,封装初始化、写字符、字符串等函数。
    *   **`key.c / key.h`**: 按键扫描和消抖函数。
    *   **`timer.c / timer.h`**: 定时器初始化和中断服务函数,用于产生系统时钟(如1秒定时)来计算等待时间。
    *   **`interrupt.c / interrupt.h`**: 外部中断(霍尔传感器)服务函数。
    *   **`fare.c / fare.h`**: 计费逻辑核心函数。
---
#### **六、 核心代码框架示例 (基于Keil C51)**
**`main.c`**
```c
#include <reg52.h>
#include "lcd1602.h"
#include "key.h"
#include "timer.h"
#include "fare.h"
sbit KEY_START = P3^0; // 启动按键
sbit KEY_PAUSE = P3^1; // 暂停/继续按键
sbit KEY_RESET = P3^2; // 复位按键
void main() {
    // 初始化模块
    Lcd_Init();
    Timer0_Init(); // 初始化定时器,用于计时
    Init_Interrupt(); // 初始化外部中断0
    Lcd_ShowString(0, 0, "Total Price: 0.0");
    Lcd_ShowString(1, 0, "Mileage: 0.00km");
    Lcd_ShowString(0, 9, "Time: 0min");
    while (1) {
        // 按键检测
        if (Key_Scan(KEY_START) == 0) {
            Start_Fare(); // 启动计费
        }
        if (Key_Scan(KEY_PAUSE) == 0) {
            Toggle_Fare_State(); // 切换状态
        }
        if (Key_Scan(KEY_RESET) == 0) {
            Reset_Fare(); // 复位
        }
        // 计费逻辑
        Calculate_Fare();
        // 更新显示
        Update_Display();
    }
}

timer0.h (用于计时)

#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init();
#endif

timer0.c

#include "timer0.h"
unsigned int seconds = 0;
void Timer0_Init() {
    TMOD &= 0xF0; // 清除T0设置
    TMOD |= 0x01; // 设置T0为16位定时器模式
    TH0 = 0xFC;   // 定时1ms
    TL0 = 0x18;
    ET0 = 1;      // 使能T0中断
    EA = 1;       // 开启总中断
    TR0 = 1;      // 启动T0
}
// 定时器0中断服务函数
void Timer0_ISR() interrupt 1 {
    TH0 = 0xFC;
    TL0 = 0x18;
    seconds++;
}

fare.h

#ifndef __FARE_H__
#define __FARE_H__
void Start_Fare();
void Toggle_Fare_State();
void Reset_Fare();
void Calculate_Fare();
void Update_Display();
#endif

fare.c (核心逻辑)

#include "fare.h"
#include "lcd1602.h"
// 全局变量
float total_price = 0.0;
float mileage = 0.0;
unsigned int wait_time = 0;
bit is_running = 0; // 0: 停止, 1: 行驶
bit is_waiting = 0; // 0: 行驶中, 1: 等待中
// 计费参数
#define START_PRICE 10.0
#define START_MILEAGE 3.0
#define PRICE_PER_KM 2.0
#define PRICE_PER_MINUTE 0.5
void Start_Fare() {
    if (!is_running) {
        is_running = 1;
        is_waiting = 0;
        // 可以在这里启动一个里程计数定时器
    }
}
void Toggle_Fare_State() {
    if (is_running) {
        is_waiting = !is_waiting;
    }
}
void Reset_Fare() {
    is_running = 0;
    is_waiting = 0;
    total_price = 0.0;
    mileage = 0.0;
    wait_time = 0;
}
// 在外部中断或定时器中断中调用此函数来增加里程
void Add_Mileage_Pulse() {
    if (is_running && !is_waiting) {
        mileage += 0.01; // 假设每脉冲0.01公里
    }
}
// 在定时器中断中调用此函数来增加等待时间
void Add_Second() {
    seconds++;
    if (is_running && is_waiting) {
        wait_time = seconds / 60; // 将秒转换为分钟
    }
}
void Calculate_Fare() {
    if (is_running) {
        // 计算里程费
        if (mileage > START_MILEAGE) {
            total_price = START_PRICE + (mileage - START_MILEAGE) * PRICE_PER_KM;
        } else {
            total_price = START_PRICE;
        }
        // 计算等待费
        if (is_waiting) {
            total_price += (seconds / 60) * PRICE_PER_MINUTE;
        }
    }
}
void Update_Display() {
    char buf[16];
    // 显示总费用
    sprintf(buf, "Total Price: %.1f", total_price);
    Lcd_ShowString(0, 0, buf);
    // 显示里程
    sprintf(buf, "Mileage: %.2fkm", mileage);
    Lcd_ShowString(1, 0, buf);
    // 显示等待时间
    sprintf(buf, "Time: %dmin", wait_time);
    Lcd_ShowString(0, 9, buf);
}

项目扩展与深化

  1. RTC (实时时钟) 模块:

    • 加入DS1302或DS3231实时时钟芯片,可以获取当前时间,从而实现白天/夜间模式的自动切换,DS3232精度更高,自带温度补偿。
  2. EEPROM 存储模块:

    • 利用单片机自带的EEPROM或外挂AT24C02芯片,存储上一次的计费总额,防止掉电后数据丢失,出租车需要打印发票,这个功能很有必要。
  3. 串口通信模块 (MAX232):

    将计费数据通过串口发送到PC,使用上位机软件进行更复杂的数据管理和图表绘制。

  4. 语音模块 (SYN6288):

    添加语音播报功能,在启动、暂停、复位时播放相应的语音提示,提升用户体验。

  5. OLED 显示屏:

    将LCD1602替换为OLED显示屏,显示效果更佳,更省电,并且可以显示图形。

总结与展望

本课程设计提供了一个完整的出租车计价器实现方案,从硬件选型、电路连接到软件编程的各个环节都进行了详细的阐述,学生可以在此基础上,根据自己的兴趣和能力,选择性地实现扩展功能,从而深化对单片机应用的理解。

这个项目不仅锻炼了动手能力,更重要的是培养了系统思维模块化编程的思想,是电子工程和自动化专业学生非常宝贵的实践经历。

标签: 单片机 C语言

抱歉,评论功能暂时关闭!