基于STM32的出租车计价器实验例程

基于STM32的出租车计价器实验例程

一、实验概述

出租车计价器是嵌入式系统经典应用,核心功能是里程计量费用计算时间计费人机交互。本实验基于STM32F103C8T6,通过霍尔传感器测里程、定时器计时、LCD显示费用,实现“起步价+里程费+等候费”的计费逻辑,支持按键设置和参数存储。

二、系统架构

graph TD
    A[霍尔传感器] -->|里程脉冲| B(STM32外部中断)
    C[按键模块] -->|设置参数| B
    B -->|数据处理| D[计费算法]
    D -->|费用/里程| E[LCD1602显示]
    F[定时器] -->|计时/低速检测| D
    G[EEPROM] -->|存储参数| D

三、硬件设计

1. 核心组件选型

组件 型号/规格 功能说明
主控芯片 STM32F103C8T6 32位ARM Cortex-M3,72MHz
里程传感器 AH3144霍尔传感器 开关型,输出脉冲(5V TTL)
显示模块 LCD1602(并行) 16×2字符显示(里程、费用)
存储芯片 AT24C02(I2C) 256字节EEPROM,存储参数
按键 4×轻触开关 启动/停止、设置、加、减
电源 5V DC 供电(STM32+LCD+传感器)

2. 硬件连接

模块 引脚 STM32引脚 说明
霍尔传感器 OUT PA0(EXTI0) 外部中断0,上升沿触发
LCD1602 RS PB0 寄存器选择
  RW PB1 读写控制(接地=只写)
  EN PB2 使能信号
  D4-D7 PB4-PB7 4位数据线(简化驱动)
AT24C02 SDA PB10(I2C2_SDA) I2C数据线
  SCL PB11(I2C2_SCL) I2C时钟线
按键 启动/停止 PC0 低电平有效
  设置 PC1 低电平有效
  PC2 低电平有效
  PC3 低电平有效

四、STM32CubeMX配置

1. 时钟配置

2. 外设配置

(1)外部中断(霍尔传感器)

(2)定时器(计时/低速检测)

(3)I2C(AT24C02)

(4)GPIO(按键与LCD)

五、软件设计

1. 核心模块实现

(1)霍尔传感器脉冲计数(外部中断)

// 全局变量
volatile uint32_t pulse_count = 0; // 脉冲总数(1脉冲=2m)
volatile float total_distance = 0.0f; // 总里程(km)

// 外部中断0回调函数(PA0,霍尔传感器)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if (GPIO_Pin == GPIO_PIN_0) {
    pulse_count++; // 每脉冲计数+1
    total_distance = (pulse_count * 2.0f) / 1000.0f; // 2m/脉冲 → km
  }
}

(2)定时器计时(低速检测与等候费)

// 全局变量
uint32_t timer_count = 0; // 1ms计数
uint32_t wait_time = 0; // 等候时间(秒)
uint8_t is_moving = 0; // 行驶状态(1=行驶,0=等候)

// TIM2中断回调函数(1ms)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM2) {
    timer_count++;
    if (timer_count % 1000 == 0) { // 1秒
      if (is_moving) {
        // 行驶中:检测速度(假设车速<12km/h为低速)
        float speed = (pulse_count * 2.0f) / (timer_count * 0.001f) * 3.6f; // km/h
        if (speed < 12.0f) {
          wait_time++; // 低速→等候时间+1秒
        }
      } else {
        wait_time++; // 停车等候→时间+1秒
      }
      timer_count = 0;
    }
  }
}

(3)计费算法(核心逻辑)

// 计费参数(存储在EEPROM)
typedef struct {
  float start_price; // 起步价(3km内,元)
  float per_km;      // 超起步里程单价(元/km)
  float per_minute;  // 等候费(元/分钟)
  float start_km;    // 起步里程(km)
} PriceParam;

PriceParam price = {10.0f, 2.0f, 0.5f, 3.0f}; // 默认参数
float total_fee = 0.0f; // 总费用

// 计算费用
void CalculateFee(void) {
  if (total_distance <= price.start_km) {
    total_fee = price.start_price; // 未超起步里程
  } else {
    // 超起步里程费用 + 等候费
    float extra_km = total_distance - price.start_km;
    total_fee = price.start_price + extra_km * price.per_km;
  }
  // 等候费(每分钟0.5元)
  total_fee += (wait_time / 60.0f) * price.per_minute;
}

(4)LCD1602显示驱动

// LCD写命令/数据
void LCD_WriteCmd(uint8_t cmd) {
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // RS=0(命令)
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // RW=0(写)
  GPIOB->ODR = (GPIOB->ODR & 0x0F) | (cmd & 0xF0); // 高4位
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); // EN=1
  HAL_Delay(1);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET); // EN=0
  // 低4位
  GPIOB->ODR = (GPIOB->ODR & 0x0F) | ((cmd << 4) & 0xF0);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
  HAL_Delay(1);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
}

// 显示里程和费用
void LCD_ShowData(void) {
  char buf[16];
  // 第一行:里程
  sprintf(buf, "Dist:%.2fkm", total_distance);
  LCD_WriteCmd(0x80); // 第一行首地址
  for (uint8_t i=0; i<16; i++) LCD_WriteData(buf[i]);
  // 第二行:费用
  sprintf(buf, "Fee:%.2f Yuan", total_fee);
  LCD_WriteCmd(0xC0); // 第二行首地址
  for (uint8_t i=0; i<16; i++) LCD_WriteData(buf[i]);
}

(5)按键处理(设置参数)

// 按键扫描(消抖)
uint8_t Key_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin) {
  if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
    HAL_Delay(20); // 消抖
    if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
      while (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET); // 等待释放
      return 1;
    }
  }
  return 0;
}

// 主循环按键处理
void Key_Process(void) {
  if (Key_Scan(GPIOC, GPIO_PIN_0)) { // 启动/停止
    is_moving = !is_moving;
  }
  if (Key_Scan(GPIOC, GPIO_PIN_1)) { // 设置
    // 进入参数设置模式(略,可切换显示参数并调整)
  }
  if (Key_Scan(GPIOC, GPIO_PIN_2)) { // 加
    price.start_price += 1.0f;
  }
  if (Key_Scan(GPIOC, GPIO_PIN_3)) { // 减
    price.start_price -= 1.0f;
  }
}

参考代码 基于STM32出租车计价器实验例程 www.youwenfan.com/contentcss/180355.html

六、实验步骤

1. 硬件连接

2. STM32CubeMX配置

3. 代码烧录与调试

七、实验结果

八、扩展功能

  1. 语音播报:添加SYN6288语音模块,播报费用;
  2. GPS定位:通过NEO-6M模块获取位置,显示在LCD;
  3. 夜间模式:添加光敏电阻,夜间自动加收20%费用;
  4. 数据存储:用AT24C02存储历史行程记录。

九、注意事项

  1. 霍尔传感器安装:确保与车轮磁铁对齐,每转1圈输出1个脉冲;
  2. LCD对比度调节:通过10kΩ电位器调节V0引脚电压;
  3. 参数存储:修改参数后需写入AT24C02,避免掉电丢失;
  4. 低功耗设计:停车时STM32进入停止模式,通过按键唤醒。

十、总结

本实验基于STM32实现了出租车计价器核心功能,涵盖传感器数据采集定时器中断LCD显示按键交互计费算法,通过模块化设计可快速扩展功能

专注于matlab/simulink,电子电路,编程