|
想用過普中開發(fā)板來實(shí)現(xiàn)一個(gè)出租車計(jì)價(jià)器的方案,但是lcd1602無法正確顯示,代碼和開發(fā)板如下
1.jpg (137.84 KB, 下載次數(shù): 0)
下載附件
2025-7-9 12:10 上傳
單片機(jī)源程序如下:
- #include <reg52.h>
- // #include <stdio.h> // 不再需要,可以移除
- // -------------------- 類型定義 --------------------
- typedef unsigned char u8;
- typedef unsigned int u16;
- // -------------------- 引腳定義 --------------------
- // LCD1602
- sbit LCD_RS = P2^6;
- sbit LCD_RW = P2^5;
- sbit LCD_EN = P2^7;
- #define LCD_DataPort P0
- // 獨(dú)立按鍵
- sbit KEY_START_STOP = P3^1; // K1: 開始/停止
- sbit KEY_CLEAR = P3^0; // K2: 清零 / 設(shè)置值-
- sbit KEY_MILEAGE = P3^2; // K3: 里程+0.1 / 設(shè)置值+
- sbit KEY_SET = P3^3; // K4: 設(shè)置
- // -------------------- 全局變量 --------------------
- // 計(jì)價(jià)器狀態(tài): 0-停止, 1-計(jì)價(jià)中, 2-設(shè)置模式
- u8 status = 0;
- // 設(shè)置模式子狀態(tài): 0-未設(shè)置, 1-設(shè)置起步價(jià), 2-設(shè)置起步里程, 3-設(shè)置單價(jià)
- u8 setting_mode = 0;
- // --- 計(jì)價(jià)參數(shù) (默認(rèn)值) ---
- u16 base_price = 130; // 起步價(jià): 13.0 元
- u16 base_mileage = 30; // 起步里程: 3.0 公里
- u16 unit_price = 23; // 單價(jià): 2.3 元/公里
- // --- 實(shí)時(shí)數(shù)據(jù) ---
- u16 mileage = 0; // 行車?yán)锍?(x0.1 公里)
- u16 price = 0; // 總價(jià) (x0.1 元)
- u16 time_s = 0; // 行車時(shí)長 (秒)
- u16 time_m = 0; // 分
- u16 time_h = 0; // 時(shí)
- // 定時(shí)器中斷計(jì)數(shù)變量
- u16 timer_count = 0;
- // -------------------- 函數(shù)聲明 --------------------
- // 延時(shí)
- void DelayMs(u16 ms);
- // LCD驅(qū)動(dòng)
- void LcdWriteCmd(u8 cmd);
- void LcdWriteData(u8 dat);
- void LcdInit();
- void LcdSetCursor(u8 row, u8 col);
- void LcdShowString(u8 row, u8 col, u8 *str);
- void LcdShowNum(u8 row, u8 col, u16 num, u8 len); // 顯示數(shù)字
- void LcdShowTime(); // 單獨(dú)的時(shí)間顯示函數(shù)
- // 顯示界面
- void UpdateDisplay();
- void DisplaySettingMode();
- // 核心邏輯
- void CalculatePrice();
- void KeyAction();
- void ResetAll();
- void Timer0Init();
- // -------------------- 主函數(shù) --------------------
- void main() {
- Timer0Init();
- LcdInit();
- ResetAll();
-
- while(1) {
- KeyAction();
- if (status == 1) { // 只有在計(jì)時(shí)狀態(tài)才需要不斷刷新時(shí)間
- LcdShowTime();
- }
- }
- }
- // -------------------- 核心邏輯函數(shù) --------------------
- void CalculatePrice() {
- if (mileage <= base_mileage) {
- price = base_price;
- } else {
- unsigned long temp_price = (unsigned long)(mileage - base_mileage) * unit_price;
- price = base_price + temp_price / 10;
- }
- // 價(jià)格計(jì)算后立即更新顯示
- if (status != 2) {
- UpdateDisplay();
- }
- }
- void KeyAction() {
- if (KEY_START_STOP == 0) {
- DelayMs(20);
- if (KEY_START_STOP == 0) {
- if (status != 2) {
- status = !status;
- if(status == 1 && mileage == 0){
- CalculatePrice(); // 開始時(shí)就計(jì)算一次價(jià)格
- } else if (status == 0) {
- // 停止計(jì)時(shí),但顯示保持不變
- }
- UpdateDisplay(); // 更新顯示(特別是狀態(tài)字符)
- }
- }
- while(KEY_START_STOP == 0);
- }
-
- if (KEY_CLEAR == 0) {
- DelayMs(20);
- if (KEY_CLEAR == 0) {
- if (status == 0) {
- ResetAll();
- } else if (status == 2) {
- switch(setting_mode) {
- case 1: if(base_price > 50) base_price -= 10; break;
- case 2: if(base_mileage > 10) base_mileage -= 10; break;
- case 3: if(unit_price > 10) unit_price -= 1; break;
- }
- DisplaySettingMode();
- }
- }
- while(KEY_CLEAR == 0);
- }
-
- if (KEY_MILEAGE == 0) {
- DelayMs(20);
- if (KEY_MILEAGE == 0) {
- if (status == 1) {
- mileage++;
- CalculatePrice();
- } else if (status == 2) {
- switch(setting_mode) {
- case 1: base_price += 10; break;
- case 2: base_mileage += 10; break;
- case 3: unit_price += 1; break;
- }
- DisplaySettingMode();
- }
- }
- while(KEY_MILEAGE == 0);
- }
-
- if (KEY_SET == 0) {
- DelayMs(20);
- if (KEY_SET == 0) {
- if(status == 1) return;
- status = 2;
- setting_mode++;
- if (setting_mode > 3) {
- setting_mode = 0;
- status = 0;
- ResetAll();
- } else {
- DisplaySettingMode();
- }
- }
- while(KEY_SET == 0);
- }
- }
- void ResetAll() {
- status = 0; // 確保是停止?fàn)顟B(tài)
- mileage = 0;
- price = 0;
- time_s = 0;
- time_m = 0;
- time_h = 0;
- T0 = 0; // 如果有,也停止計(jì)時(shí)器
- UpdateDisplay(); // 更新整個(gè)顯示
- LcdShowTime();
- }
- // -------------------- 顯示相關(guān)函數(shù) (無sprintf) --------------------
- // 更新主顯示界面(里程和價(jià)格)
- void UpdateDisplay() {
- // 第一行: L:XXX.XKM P:XXXX.X
- LcdShowString(0, 0, "L: KM P: "); // 模板,用空格覆蓋舊數(shù)據(jù)
- LcdShowNum(0, 2, mileage / 10, 3); // 里程整數(shù)部分,最多3位
- LcdWriteData('.');
- LcdShowNum(0, 6, mileage % 10, 1); // 里程小數(shù)部分
-
- LcdShowNum(0, 11, price / 10, 4); // 價(jià)格整數(shù)部分,最多4位
- LcdWriteData('.');
- LcdShowNum(0, 16, price % 10, 1); // 價(jià)格小數(shù)部分
- // 在時(shí)間前面顯示狀態(tài)符號
- LcdSetCursor(1, 0);
- if(status == 1) LcdWriteData('T'); // Timing
- else if(status == 0) LcdWriteData('S'); // Stop
- else if(status == 2) LcdWriteData('C'); // Config
- }
- // 單獨(dú)更新時(shí)間顯示,減少LCD刷新
- void LcdShowTime() {
- // 第二行: T:HH:MM:SS
- LcdSetCursor(1, 1);
- LcdShowString(1, 1, ":");
- LcdShowNum(1, 2, time_h, 2);
- LcdShowString(1, 4, ":");
- LcdShowNum(1, 5, time_m, 2);
- LcdShowString(1, 7, ":");
- LcdShowNum(1, 8, time_s, 2);
- }
- // 顯示設(shè)置模式界面
- void DisplaySettingMode() {
- LcdWriteCmd(0x01); // 清屏
- UpdateDisplay(); // 顯示狀態(tài)'C'
- switch(setting_mode) {
- case 1:
- LcdShowString(0, 0, "Set Base Price ");
- LcdShowNum(1, 5, base_price/10, 3);
- LcdWriteData('.');
- LcdShowNum(1, 9, base_price%10, 1);
- LcdShowString(1, 10, " Yuan ");
- break;
- case 2:
- LcdShowString(0, 0, "Set Base Mile ");
- LcdShowNum(1, 5, base_mileage/10, 2);
- LcdWriteData('.');
- LcdShowNum(1, 8, base_mileage%10, 1);
- LcdShowString(1, 9, " KM ");
- break;
- case 3:
- LcdShowString(0, 0, "Set Unit Price ");
- LcdShowNum(1, 5, unit_price/10, 2);
- LcdWriteData('.');
- LcdShowNum(1, 8, unit_price%10, 1);
- LcdShowString(1, 9, " Y/KM ");
- break;
- }
- }
- // -------------------- 定時(shí)器和中斷 --------------------
- void Timer0Init() {
- TMOD &= 0xF0;
- TMOD |= 0x01;
- TH0 = (65536 - 1000) / 256;
- TL0 = (65536 - 1000) % 256;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- void timer0_isr() interrupt 1 {
- TH0 = (65536 - 1000) / 256;
- TL0 = (65536 - 1000) % 256;
- if (status == 1) {
- timer_count++;
- if (timer_count >= 1000) {
- timer_count = 0;
- time_s++;
- if (time_s >= 60) {
- time_s = 0;
- time_m++;
- if (time_m >= 60) {
- time_m = 0;
- time_h++;
- }
- }
- }
- }
- }
- // -------------------- LCD底層驅(qū)動(dòng) --------------------
- void DelayMs(u16 ms) {
- u16 i, j;
- for(i=ms; i>0; i--)
- for(j=120; j>0; j--);
- }
- void LcdWriteCmd(u8 cmd) {
- LCD_RS = 0;
- LCD_RW = 0;
- LCD_DataPort = cmd;
- DelayMs(1);
- LCD_EN = 1;
- DelayMs(1);
- LCD_EN = 0;
- }
- void LcdWriteData(u8 dat) {
- LCD_RS = 1;
- LCD_RW = 0;
- LCD_DataPort = dat;
- DelayMs(1);
- LCD_EN = 1;
- DelayMs(1);
- LCD_EN = 0;
- }
- void LcdInit() {
- LcdWriteCmd(0x38);
- LcdWriteCmd(0x0C);
- LcdWriteCmd(0x06);
- LcdWriteCmd(0x01);
- DelayMs(5);
- }
- void LcdSetCursor(u8 row, u8 col) {
- u8 addr;
- if (row == 0) {
- addr = 0x80 + col;
- } else {
- addr = 0x80 + 0x40 + col;
- }
- LcdWriteCmd(addr);
- }
- void LcdShowString(u8 row, u8 col, u8 *str) {
- LcdSetCursor(row, col);
- while(*str != '\0') {
- LcdWriteData(*str++);
- }
- }
- // *** 新增的顯示數(shù)字的函數(shù) ***
- // 在(row, col)顯示數(shù)字num,共顯示len位,不足則前面補(bǔ)空格
- void LcdShowNum(u8 row, u8 col, u16 num, u8 len) {
- u8 i;
- u8 buf[5]; // 假設(shè)數(shù)字最大5位
- for (i = 0; i < len; i++) {
- buf[len - 1 - i] = (num % 10) + '0';
- num /= 10;
- }
-
- // 如果數(shù)字本身位數(shù)小于len,前面補(bǔ)空格
- for (i = 0; i < len; i++) {
- if (num == 0 && buf[i] == '0' && i < len - 1) { // 找到最高位
- if(i < len - 1) buf[i] = ' '; // 將高位0轉(zhuǎn)換為空格, 但保留個(gè)位數(shù)0
- } else {
- break; // 找到第一個(gè)非零數(shù)字后停止
- }
- }
- // 處理num=0的情況
- if (len > 1 && buf[0] == ' ') {
- // 確保個(gè)位數(shù)如果是0,能正常顯示
- if(len > 1 && num == 0){
- // 此處確保至少有一個(gè)'0'顯示
- }
- }
- LcdSetCursor(row, col);
- for (i = 0; i < len; i++) {
- LcdWriteData(buf[i]);
- }
- }
復(fù)制代碼 |
|