Sistema de facturación de taxis basado en el diseño STM32

1. Introducción del proyecto

En el tráfico urbano, los taxis son un medio de transporte habitual. Para facilitar las transacciones entre pasajeros y conductores, los sistemas de facturación de taxis se utilizan ampliamente en la industria de taxis. El sistema puede calcular automáticamente la tarifa del pasajero, proporcionar servicios de facturación precisos y convenientes, y puede registrar los datos de conducción del pasajero para facilitar la gestión y la consulta posterior.

El método tradicional de facturación de taxis se basa en cálculos manuales, y el conductor estima e informa a los pasajeros del costo en función del kilometraje y el tiempo. Sin embargo, este método de facturación es propenso a errores y disputas, y no es lo suficientemente conveniente y transparente para los conductores y pasajeros. Por lo tanto, la industria del taxi necesita urgentemente un sistema de facturación más preciso, eficiente y confiable.

En base a estos antecedentes, este proyecto diseña y desarrolla un sistema de facturación de taxis basado en el microcontrolador STM32 para reemplazar el método tradicional de facturación manual. El sistema utilizará la poderosa capacidad de procesamiento y las ricas interfaces periféricas del microcontrolador STM32 para integrar varios módulos funcionales para realizar funciones como el cálculo automático de tarifas de pasajeros y la visualización de información de facturación.

A través del sistema de facturación de taxis, los pasajeros solo necesitan presionar el botón correspondiente al subir al autobús, y el sistema comenzará a facturar automáticamente y mostrará el tiempo de conducción, el kilometraje y la información del costo en la pantalla en tiempo real. Los pasajeros también pueden ingresar condiciones especiales, como atascos o conducción nocturna, a través de los botones, para que el sistema realice la facturación adicional correspondiente. Cuando el pasajero se baja del autobús, el sistema dejará de facturar automáticamente y mostrará la tarifa final. Al mismo tiempo, el sistema también registrará los datos de conducción de los pasajeros para su consulta y gestión.

imagen-20230625095240766

imagen-20230625095227080

imagen-20230625094541137

Para descargar el código fuente del proyecto, puede obtener más información aquí:

https://blog.csdn.net/xiaolong1126626497/category_10192120.html

2. Ideas de diseño del sistema

2.1 Arquitectura del sistema

Los componentes principales del sistema de facturación de taxis incluyen: microcontrolador STM32, pantalla LCD, botones, circuito de tiempo, cobrador de peaje y memoria externa. La arquitectura de todo el sistema es la siguiente:

  • Microcontrolador STM32: STM32F103RCT6 se utiliza como núcleo de control del sistema, que es responsable de recibir y procesar las señales de entrada de varios módulos y controlar la visualización de información en la pantalla LCD y el funcionamiento del recaudador de peaje.
  • Pantalla LCD: se utiliza una pantalla LCD de 1,44 pulgadas para mostrar la información de facturación actual, incluido el tiempo de conducción, el kilometraje y las tarifas.
  • Botones: Se utilizan para ingresar la hora en que los pasajeros suben y bajan del autobús y otras situaciones especiales, como atascos, conducción nocturna, etc.
  • Circuito de tiempo: se utiliza para medir con precisión el tiempo de conducción.
  • Recaudador de peaje: responsable de calcular las tarifas de los pasajeros en función de las reglas de facturación y los datos en tiempo real.
  • Memoria externa: se utiliza para almacenar datos de conducción y reglas de facturación.

2.2 Funciones del sistema

El sistema de facturación de taxis tiene las siguientes funciones principales:

  • Calcule el tiempo de conducción y el kilometraje en tiempo real.
  • Las tarifas de los pasajeros se calculan automáticamente de acuerdo con las reglas de facturación.
  • Muestra la información de facturación actual en la pantalla LCD.
  • Admite facturación adicional para circunstancias especiales, como atascos de tráfico, conducción nocturna, etc.
  • Almacene datos de conducción y reglas de facturación para consulta y actualización.

3. Diseño de código

3.1 Código de pantalla LCD

#include "stm32f10x.h"

// 定义LCD引脚连接
#define LCD_RS_PIN  GPIO_Pin_0
#define LCD_RS_PORT GPIOA
#define LCD_RW_PIN  GPIO_Pin_1
#define LCD_RW_PORT GPIOA
#define LCD_E_PIN   GPIO_Pin_2
#define LCD_E_PORT  GPIOA
#define LCD_D4_PIN  GPIO_Pin_3
#define LCD_D4_PORT GPIOA
#define LCD_D5_PIN  GPIO_Pin_4
#define LCD_D5_PORT GPIOA
#define LCD_D6_PIN  GPIO_Pin_5
#define LCD_D6_PORT GPIOA
#define LCD_D7_PIN  GPIO_Pin_6
#define LCD_D7_PORT GPIOA

// 定义命令和数据的宏
#define LCD_COMMAND 0
#define LCD_DATA    1

// 延时函数,用于产生适当的延时
void Delay(uint32_t nCount) {
    
    
    for (; nCount != 0; --nCount) {
    
    
    }
}

// 发送命令或数据到LCD函数
void LCD_Send(uint8_t byte, uint8_t mode) {
    
    
    GPIO_WriteBit(LCD_RS_PORT, LCD_RS_PIN, (mode == LCD_DATA) ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_RW_PORT, LCD_RW_PIN, Bit_RESET);
    
    GPIO_WriteBit(LCD_D4_PORT, LCD_D4_PIN, (byte >> 4) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D5_PORT, LCD_D5_PIN, (byte >> 5) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D6_PORT, LCD_D6_PIN, (byte >> 6) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D7_PORT, LCD_D7_PIN, (byte >> 7) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_WriteBit(LCD_E_PORT, LCD_E_PIN, Bit_SET);
    Delay(1000);
    GPIO_WriteBit(LCD_E_PORT, LCD_E_PIN, Bit_RESET);
    
    GPIO_WriteBit(LCD_D4_PORT, LCD_D4_PIN, (byte >> 0) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D5_PORT, LCD_D5_PIN, (byte >> 1) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D6_PORT, LCD_D6_PIN, (byte >> 2) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_D7_PORT, LCD_D7_PIN, (byte >> 3) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_WriteBit(LCD_E_PORT, LCD_E_PIN, Bit_SET);
    Delay(1000);
    GPIO_WriteBit(LCD_E_PORT, LCD_E_PIN, Bit_RESET);
    
    Delay(1000);
}

// 初始化LCD函数
void LCD_Init(void) {
    
    
    Delay(45000);
    LCD_Send(0x30, LCD_COMMAND);
    Delay(4500);
    LCD_Send(0x30, LCD_COMMAND);
    Delay(150);
    LCD_Send(0x30, LCD_COMMAND);
    Delay(150);
    
    LCD_Send(0x20, LCD_COMMAND);
    Delay(150);
    
    LCD_Send(0x28, LCD_COMMAND);
    Delay(150);

    LCD_Send(0x08, LCD_COMMAND);
    Delay(150);
    
    LCD_Send(0x01, LCD_COMMAND);
    Delay(150);
    
    LCD_Send(0x06, LCD_COMMAND);
    Delay(150);
    
    LCD_Send(0x0C, LCD_COMMAND);
    Delay(150);
}

// 在指定位置显示数字函数
void LCD_DisplayNumber(uint8_t number, uint8_t x, uint8_t y) {
    
    
    uint8_t data = 0x30 + number;  // 转换数字为对应的ASCII码
    
    if (x >= 0 && x < 16 && y >= 0 && y < 2) {
    
    
        uint8_t addr = 0x80 + (y * 0x40) + x;
        
        LCD_Send(addr, LCD_COMMAND);
        LCD_Send(data, LCD_DATA);
    }
}

int main(void) {
    
    
    // 初始化GPIO和LCD
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = LCD_RS_PIN | LCD_RW_PIN | LCD_E_PIN | LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN | LCD_D7_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    LCD_Init();
    
    while (1) {
    
    
        // 在第一行第一列显示数字1
        LCD_DisplayNumber(1, 0, 0);
    }
}

3.2 Códigos de tiempo

La función de temporización de carga se realiza a través del temporizador 2, y el tiempo de temporización en tiempo real se imprime en el puerto serie. Inicie el temporizador presionando la tecla 'S' y deténgalo presionando la tecla 'Q'. Cada 500 milisegundos, imprime la hora real en el puerto serie.

#include "stm32f10x.h"
#include <stdio.h>

// 定义计时状态
typedef enum {
    
    
    TIMER_STOPPED,
    TIMER_RUNNING
} TimerState;

TimerState timerState = TIMER_STOPPED; // 计时器初始状态为停止
uint32_t startTime = 0; // 开始计时的时间

// 初始化定时器2
void Timer2_Init(void) {
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1; // 设置预分频值,产生1ms的时间基准
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1;  // 设置计数器的重载值,每1秒中断一次
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// 开始计时
void StartTimer(void) {
    
    
    if (timerState == TIMER_STOPPED) {
    
    
        startTime = TIM_GetCounter(TIM2); // 记录开始计时的时间
        timerState = TIMER_RUNNING;
    }
}

// 停止计时
void StopTimer(void) {
    
    
    if (timerState == TIMER_RUNNING) {
    
    
        timerState = TIMER_STOPPED;
    }
}

// 获取实时时间,返回单位为毫秒
uint32_t GetElapsedTime(void) {
    
    
    if (timerState == TIMER_RUNNING) {
    
    
        return TIM_GetCounter(TIM2) - startTime;
    } else {
    
    
        return 0;
    }
}

// 初始化串口1
void USART1_Init(void) {
    
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // TX引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);

    USART_Cmd(USART1, ENABLE);
}

// 重定向printf函数到串口输出
int fputc(int ch, FILE *f) {
    
    
    if (ch == '\n') {
    
    
        USART_SendData(USART1, '\r');
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }

    USART_SendData(USART1, ch);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    return ch;
}

int main(void) {
    
    
    // 初始化定时器和串口
    Timer2_Init();
    USART1_Init();

    printf("Press 'S' to start the timer.\r\n");
    printf("Press 'Q' to stop the timer.\r\n");

    while (1) {
    
    
        if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) {
    
    
            uint8_t rxData = (uint8_t)USART_ReceiveData(USART1);
            
            if (rxData == 'S' || rxData == 's') {
    
    
                StartTimer();
                printf("Timer started.\r\n");
            } else if (rxData == 'Q' || rxData == 'q') {
    
    
                StopTimer();
                printf("Timer stopped.\r\n");
            }
        }

        // 每隔500毫秒打印实时时间
        if (GetElapsedTime() >= 500) {
    
    
            printf("Elapsed time: %lu ms\r\n", GetElapsedTime());
            startTime = TIM_GetCounter(TIM2); // 更新开始计时的时间
        }
    }
}

// 定时器2中断处理函数
void TIM2_IRQHandler(void) {
    
    
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
    
    
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

Supongo que te gusta

Origin blog.csdn.net/xiaolong1126626497/article/details/132145021
Recomendado
Clasificación