#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned long startTime = 0; // 记录按钮按下的起始时间
unsigned long elapsedTime = 0; // 记录按钮按下的持续时间
const int pinToDetect = 4; // 检测 D2 引脚
const int pinToDetect1 = 7; // 检测 D7 引脚
int button; //按键0当前状态
int button1; //按键1当前状态
const unsigned long TIMER_INTERVAL = 50; // 按键检测定时周期
LiquidCrystal_I2C lcd(0x27, 16, 2); // 设置LCD1602设备地址
float unit_price = 3.00; //每公里单价
float kilometers = 0.00; //初始里程
float price;//总价
String timeString;
// 定义全局变量来存储时间
unsigned long lastTime = 0;
int seconds = 0;
int minutes = 0;
void setup() {
pinMode(pinToDetect, INPUT); // 将引脚设置为输入模式
pinMode(pinToDetect1, INPUT); // 将引脚设置为输入模式
//定时器初始化
cli(); // 关闭中断
// 设置定时器1的模式和预分频系数,选择CTC模式,设置预分频系数为64
TCCR1A = 0; // 设置定时器1为CTC模式
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // 设置预分频系数为64,开启比较匹配中断
OCR1A = (F_CPU / 64 / 1000) * TIMER_INTERVAL - 1; // 计算比较寄存器的值
TIMSK1 |= (1 << OCIE1A); // 启用定时器1的比较匹配中断
sei(); // 启用全局中断
lcd.init(); // 初始化LCD
delay(100); // 添加延迟
lcd.backlight(); // 设置LCD背景亮
Serial.begin(9600);
}
int Keystatus() { //读取按键状态
int pinState = digitalRead(pinToDetect); // 读取引脚状态
int pinState1 = digitalRead(pinToDetect1); // 读取引脚状态
if (pinState == HIGH) {
button = 0;
} else {
button = 1;
}
int buttonState = digitalRead(pinToDetect1);
// 当按钮按下时
if (buttonState == 0) {
// 如果起始时间为0,说明按钮刚刚按下
if (startTime == 0) {
startTime = millis(); // 记录按钮按下的起始时间
}
elapsedTime = millis() - startTime; // 计算按钮按下的持续时间
} else {
// 当按钮释放时,重置起始时间和持续时间
startTime = 0;
elapsedTime = 0;
}
// 输出按钮按下的持续时间
if(elapsedTime<=700&&elapsedTime!=0){
button1=1;
}
else if(elapsedTime>700&&elapsedTime<=2500){
button1=2;
}
else if(elapsedTime>2500){
button1=0;
}
delay(100); // 延迟一段时间以稳定检测
}
//模拟时间增加
void updateTime() {
unsigned long currentTime = millis(); // 获取当前时间
if (currentTime - lastTime >= 1000) { // 每秒执行一次
lastTime = currentTime; // 更新上次执行时间
seconds++; // 秒数加1
if (seconds >= 60) { // 如果秒数超过60,重置为0,分钟加1
seconds = 0;
minutes++;
if (minutes >= 60) { // 如果分钟超过60,重置为0
minutes = 0;
}
}
// 整合分钟和秒数为字符串
String timeString1 = "";
if (minutes < 10) {
timeString1 += "0"; // 如果分钟小于10,补0
}
timeString1 += minutes;
timeString1 += ":";
if (seconds < 10) {
timeString1 += "0"; // 如果秒数小于10,补0
}
timeString1 += seconds;
timeString=timeString1;
Serial.print(timeString);
Serial.print(" ");
Serial.print(kilometers);
Serial.print(" ");
Serial.print(unit_price);
Serial.print(" ");
Serial.print(price);
Serial.println(" ");
//displayInformation(unit_price,price,kilometers,timeString);
}
}
// 模拟公里数增加的函数
float increaseKilometers() {
// 每次增加10公里
if (button == 1) {
float randomNumber = random(1, 11) / 500.0; //生成随机加速器
for (int i = 0; i <= random(3, 7); i++) { //总里程
kilometers = kilometers + randomNumber;
}
}
}
// 计算价格的函数
float calculatePrice() {
// 假设价格与公里数成正比
float distance = 1.00; //起步里程
//displayInformation(unit_price, 7.00, kilometers);
price=7.00;
if (kilometers >= distance) {
price = unit_price * (kilometers - distance) + 7.00;
//displayInformation(unit_price, price, kilometers);
}
}
// 显示信息的函数
void displayInformation(float unit_price, float price, float kilometers , String timeString) {
lcd.clear(); // 清除LCD显示屏上的内容
// 在LCD上显示单价和公里数
lcd.setCursor(0, 0);
lcd.print("U:$");
lcd.print(unit_price, 2); // 显示单价,小数点后保留2位
lcd.print(" K:");
lcd.print(kilometers);
// 在LCD上显示价格
lcd.setCursor(0, 1);
lcd.print("P:$");
lcd.print(price, 2); // 显示价格,小数点后保留2位
lcd.print( " T:");
lcd.print(timeString); // 显示价格,小数点后保留2位
}
void loop() {
if(button1==0){
increaseKilometers();
calculatePrice();
}
else if(button1==2){
price=0;kilometers=0;timeString="00:00";lastTime = 0;seconds = 0;minutes = 0;
}
// 调用显示信息的函数
displayInformation(unit_price,price,kilometers,timeString);
delay(1000); // 延迟2秒,然后重新显示信息
}
// 定时器1的比较匹配中断服务程序
ISR(TIMER1_COMPA_vect) {
// 在这里调用你想要重复执行的函数
Keystatus();
if(button1==0){
updateTime();
}
}