Taxi-Abrechnungssystem basierend auf STM32-Design

1. Projekteinführung

Im Stadtverkehr sind Taxis ein weit verbreitetes Fortbewegungsmittel. Um Transaktionen zwischen Fahrgästen und Fahrern zu erleichtern, werden in der Taxibranche häufig Taxiabrechnungssysteme eingesetzt. Das System kann den Fahrpreis des Passagiers automatisch berechnen, genaue und bequeme Abrechnungsdienste bereitstellen und die Fahrdaten des Passagiers aufzeichnen, um spätere Abfragen und Verwaltung zu erleichtern.

Die traditionelle Abrechnungsmethode für Taxis basiert auf manuellen Berechnungen, und der Fahrer schätzt die Kosten und informiert die Passagiere anhand der zurückgelegten Strecke und der Zeit. Allerdings ist diese Abrechnungsmethode fehler- und streitanfällig und für Fahrer und Fahrgäste nicht komfortabel und transparent genug. Daher benötigt die Taxibranche dringend ein genaueres, effizienteres und zuverlässigeres Abrechnungssystem.

Vor diesem Hintergrund entwirft und entwickelt dieses Projekt ein Taxiabrechnungssystem auf Basis des STM32-Mikrocontrollers, das die traditionelle manuelle Abrechnungsmethode ersetzen soll. Das System nutzt die leistungsstarke Verarbeitungsfähigkeit und die umfangreichen Peripherieschnittstellen des STM32-Mikrocontrollers, um verschiedene Funktionsmodule zu integrieren und Funktionen wie die automatische Berechnung von Passagiertarifen und die Anzeige von Rechnungsinformationen zu realisieren.

Durch das Taxi-Abrechnungssystem müssen Fahrgäste beim Einsteigen in den Bus nur die entsprechende Taste drücken, das System beginnt automatisch mit der Abrechnung und zeigt die Fahrzeit, den Kilometerstand und die Kosteninformationen in Echtzeit auf dem Bildschirm an. Auch Sonderfälle wie Staus oder Nachtfahrten können Fahrgäste über die Tasten eingeben, sodass das System eine entsprechende Zusatzabrechnung durchführen kann. Wenn der Fahrgast aus dem Bus aussteigt, stoppt das System automatisch die Abrechnung und zeigt den endgültigen Fahrpreis an. Gleichzeitig erfasst das System auch die Fahrdaten der Fahrgäste zur Abfrage und Verwaltung.

Bild-20230625095240766

Bild-20230625095227080

Bild-20230625094541137

Um den Quellcode des Projekts herunterzuladen, können Sie sich hier darüber informieren:

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

2. Systemdesign-Ideen

2.1 Systemarchitektur

Zu den Hauptkomponenten des Taxi-Abrechnungssystems gehören: STM32-Mikrocontroller, LCD-Display, Tasten, Zeitschaltkreis, Mauteintreiber und externer Speicher. Die Architektur des gesamten Systems ist wie folgt:

  • STM32-Mikrocontroller: STM32F103RCT6 wird als Steuerkern des Systems verwendet, der für den Empfang und die Verarbeitung von Eingangssignalen von verschiedenen Modulen sowie für die Steuerung der Informationsanzeige auf dem LCD-Bildschirm und den Betrieb des Mautsammlers verantwortlich ist.
  • LCD-Display: Ein 1,44 Zoll großes LCD-Display dient zur Anzeige aktueller Abrechnungsinformationen, einschließlich Fahrzeit, Kilometerstand und Gebühren.
  • Tasten: Dienen zur Eingabe der Zeit, zu der Fahrgäste in den Bus ein- und aussteigen, sowie für andere Sondersituationen wie Staus, Nachtfahrten usw.
  • Zeitschaltkreis: Wird zur genauen Messung der Fahrzeit verwendet.
  • Mauteinnehmer: Verantwortlich für die Berechnung der Fahrgastgebühren auf der Grundlage von Abrechnungsregeln und Echtzeitdaten.
  • Externer Speicher: Wird zum Speichern von Fahrdaten und Abrechnungsregeln verwendet.

2.2 Systemfunktionen

Das Taxiabrechnungssystem hat folgende Hauptfunktionen:

  • Berechnen Sie Fahrzeit und Kilometerstand in Echtzeit.
  • Passagiertarife werden automatisch gemäß den Abrechnungsregeln berechnet.
  • Zeigen Sie aktuelle Rechnungsinformationen auf dem LCD-Display an.
  • Unterstützen Sie die zusätzliche Abrechnung für besondere Umstände wie Staus, Nachtfahrten usw.
  • Speichern Sie Fahrdaten und Abrechnungsregeln zur Abfrage und Aktualisierung.

3. Code-Design

3.1 LCD-Anzeigecode

#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 Timing-Codes

Die Lade-Timing-Funktion wird durch Timer 2 realisiert und die Echtzeit-Timing-Zeit wird über die serielle Schnittstelle ausgedruckt. Starten Sie den Timer, indem Sie die Taste „S“ drücken, und stoppen Sie den Timer, indem Sie die Taste „Q“ drücken. Drucken Sie alle 500 Millisekunden die Echtzeit über die serielle Schnittstelle aus.

#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);
    }
}

Guess you like

Origin blog.csdn.net/xiaolong1126626497/article/details/132145021