久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 51單片機實驗板lcd1602無法正確顯示 [打印本頁]

作者: Acrux    時間: 2025-7-9 11:18
標題: 51單片機實驗板lcd1602無法正確顯示
想用過普中開發板來實現一個出租車計價器的方案,但是lcd1602無法正確顯示,代碼和開發板如下


單片機源程序如下:
  1. #include <reg52.h>
  2. // #include <stdio.h> // 不再需要,可以移除

  3. // -------------------- 類型定義 --------------------
  4. typedef unsigned char u8;
  5. typedef unsigned int u16;

  6. // -------------------- 引腳定義 --------------------
  7. // LCD1602
  8. sbit LCD_RS = P2^6;
  9. sbit LCD_RW = P2^5;
  10. sbit LCD_EN = P2^7;
  11. #define LCD_DataPort P0

  12. // 獨立按鍵
  13. sbit KEY_START_STOP = P3^1; // K1: 開始/停止
  14. sbit KEY_CLEAR = P3^0;      // K2: 清零 / 設置值-
  15. sbit KEY_MILEAGE = P3^2;    // K3: 里程+0.1 / 設置值+
  16. sbit KEY_SET = P3^3;        // K4: 設置

  17. // -------------------- 全局變量 --------------------
  18. // 計價器狀態: 0-停止, 1-計價中, 2-設置模式
  19. u8 status = 0;
  20. // 設置模式子狀態: 0-未設置, 1-設置起步價, 2-設置起步里程, 3-設置單價
  21. u8 setting_mode = 0;

  22. // --- 計價參數 (默認值) ---
  23. u16 base_price = 130;  // 起步價: 13.0 元
  24. u16 base_mileage = 30; // 起步里程: 3.0 公里
  25. u16 unit_price = 23;   // 單價: 2.3 元/公里

  26. // --- 實時數據 ---
  27. u16 mileage = 0;    // 行車里程 (x0.1 公里)
  28. u16 price = 0;      // 總價 (x0.1 元)
  29. u16 time_s = 0;     // 行車時長 (秒)
  30. u16 time_m = 0;     // 分
  31. u16 time_h = 0;     // 時

  32. // 定時器中斷計數變量
  33. u16 timer_count = 0;

  34. // -------------------- 函數聲明 --------------------
  35. // 延時
  36. void DelayMs(u16 ms);

  37. // LCD驅動
  38. void LcdWriteCmd(u8 cmd);
  39. void LcdWriteData(u8 dat);
  40. void LcdInit();
  41. void LcdSetCursor(u8 row, u8 col);
  42. void LcdShowString(u8 row, u8 col, u8 *str);
  43. void LcdShowNum(u8 row, u8 col, u16 num, u8 len); // 顯示數字
  44. void LcdShowTime(); // 單獨的時間顯示函數

  45. // 顯示界面
  46. void UpdateDisplay();
  47. void DisplaySettingMode();

  48. // 核心邏輯
  49. void CalculatePrice();
  50. void KeyAction();
  51. void ResetAll();
  52. void Timer0Init();


  53. // -------------------- 主函數 --------------------
  54. void main() {
  55.     Timer0Init();
  56.     LcdInit();
  57.     ResetAll();
  58.    
  59.     while(1) {
  60.         KeyAction();
  61.         if (status == 1) { // 只有在計時狀態才需要不斷刷新時間
  62.             LcdShowTime();
  63.         }
  64.     }
  65. }

  66. // -------------------- 核心邏輯函數 --------------------
  67. void CalculatePrice() {
  68.     if (mileage <= base_mileage) {
  69.         price = base_price;
  70.     } else {
  71.         unsigned long temp_price = (unsigned long)(mileage - base_mileage) * unit_price;
  72.         price = base_price + temp_price / 10;
  73.     }
  74.     // 價格計算后立即更新顯示
  75.     if (status != 2) {
  76.         UpdateDisplay();
  77.     }
  78. }

  79. void KeyAction() {
  80.     if (KEY_START_STOP == 0) {
  81.         DelayMs(20);
  82.         if (KEY_START_STOP == 0) {
  83.             if (status != 2) {
  84.                 status = !status;
  85.                 if(status == 1 && mileage == 0){
  86.                     CalculatePrice(); // 開始時就計算一次價格
  87.                 } else if (status == 0) {
  88.                     // 停止計時,但顯示保持不變
  89.                 }
  90.                  UpdateDisplay(); // 更新顯示(特別是狀態字符)
  91.             }
  92.         }
  93.         while(KEY_START_STOP == 0);
  94.     }
  95.    
  96.     if (KEY_CLEAR == 0) {
  97.         DelayMs(20);
  98.         if (KEY_CLEAR == 0) {
  99.             if (status == 0) {
  100.                 ResetAll();
  101.             } else if (status == 2) {
  102.                 switch(setting_mode) {
  103.                     case 1: if(base_price > 50) base_price -= 10; break;
  104.                     case 2: if(base_mileage > 10) base_mileage -= 10; break;
  105.                     case 3: if(unit_price > 10) unit_price -= 1; break;
  106.                 }
  107.                 DisplaySettingMode();
  108.             }
  109.         }
  110.         while(KEY_CLEAR == 0);
  111.     }
  112.    
  113.     if (KEY_MILEAGE == 0) {
  114.         DelayMs(20);
  115.         if (KEY_MILEAGE == 0) {
  116.             if (status == 1) {
  117.                 mileage++;
  118.                 CalculatePrice();
  119.             } else if (status == 2) {
  120.                 switch(setting_mode) {
  121.                     case 1: base_price += 10; break;
  122.                     case 2: base_mileage += 10; break;
  123.                     case 3: unit_price += 1; break;
  124.                 }
  125.                 DisplaySettingMode();
  126.             }
  127.         }
  128.         while(KEY_MILEAGE == 0);
  129.     }
  130.    
  131.     if (KEY_SET == 0) {
  132.         DelayMs(20);
  133.         if (KEY_SET == 0) {
  134.             if(status == 1) return;

  135.             status = 2;
  136.             setting_mode++;
  137.             if (setting_mode > 3) {
  138.                 setting_mode = 0;
  139.                 status = 0;
  140.                 ResetAll();
  141.             } else {
  142.                 DisplaySettingMode();
  143.             }
  144.         }
  145.         while(KEY_SET == 0);
  146.     }
  147. }

  148. void ResetAll() {
  149.     status = 0; // 確保是停止狀態
  150.     mileage = 0;
  151.     price = 0;
  152.     time_s = 0;
  153.     time_m = 0;
  154.     time_h = 0;
  155.     T0 = 0; // 如果有,也停止計時器
  156.     UpdateDisplay(); // 更新整個顯示
  157.     LcdShowTime();
  158. }

  159. // -------------------- 顯示相關函數 (無sprintf) --------------------
  160. // 更新主顯示界面(里程和價格)
  161. void UpdateDisplay() {
  162.     // 第一行: L:XXX.XKM P:XXXX.X
  163.     LcdShowString(0, 0, "L:    KM P:     "); // 模板,用空格覆蓋舊數據
  164.     LcdShowNum(0, 2, mileage / 10, 3); // 里程整數部分,最多3位
  165.     LcdWriteData('.');
  166.     LcdShowNum(0, 6, mileage % 10, 1); // 里程小數部分
  167.    
  168.     LcdShowNum(0, 11, price / 10, 4); // 價格整數部分,最多4位
  169.     LcdWriteData('.');
  170.     LcdShowNum(0, 16, price % 10, 1); // 價格小數部分

  171.     // 在時間前面顯示狀態符號
  172.     LcdSetCursor(1, 0);
  173.     if(status == 1) LcdWriteData('T'); // Timing
  174.     else if(status == 0) LcdWriteData('S'); // Stop
  175.     else if(status == 2) LcdWriteData('C'); // Config
  176. }

  177. // 單獨更新時間顯示,減少LCD刷新
  178. void LcdShowTime() {
  179.     // 第二行: T:HH:MM:SS
  180.     LcdSetCursor(1, 1);
  181.     LcdShowString(1, 1, ":");
  182.     LcdShowNum(1, 2, time_h, 2);
  183.     LcdShowString(1, 4, ":");
  184.     LcdShowNum(1, 5, time_m, 2);
  185.     LcdShowString(1, 7, ":");
  186.     LcdShowNum(1, 8, time_s, 2);
  187. }

  188. // 顯示設置模式界面
  189. void DisplaySettingMode() {
  190.     LcdWriteCmd(0x01); // 清屏
  191.     UpdateDisplay();   // 顯示狀態'C'
  192.     switch(setting_mode) {
  193.         case 1:
  194.             LcdShowString(0, 0, "Set Base Price  ");
  195.             LcdShowNum(1, 5, base_price/10, 3);
  196.             LcdWriteData('.');
  197.             LcdShowNum(1, 9, base_price%10, 1);
  198.             LcdShowString(1, 10, " Yuan ");
  199.             break;
  200.         case 2:
  201.             LcdShowString(0, 0, "Set Base Mile   ");
  202.             LcdShowNum(1, 5, base_mileage/10, 2);
  203.             LcdWriteData('.');
  204.             LcdShowNum(1, 8, base_mileage%10, 1);
  205.             LcdShowString(1, 9, " KM   ");
  206.             break;
  207.         case 3:
  208.             LcdShowString(0, 0, "Set Unit Price  ");
  209.             LcdShowNum(1, 5, unit_price/10, 2);
  210.             LcdWriteData('.');
  211.             LcdShowNum(1, 8, unit_price%10, 1);
  212.             LcdShowString(1, 9, " Y/KM ");
  213.             break;
  214.     }
  215. }

  216. // -------------------- 定時器和中斷 --------------------
  217. void Timer0Init() {
  218.     TMOD &= 0xF0;
  219.     TMOD |= 0x01;
  220.     TH0 = (65536 - 1000) / 256;
  221.     TL0 = (65536 - 1000) % 256;
  222.     EA = 1;
  223.     ET0 = 1;
  224.     TR0 = 1;
  225. }

  226. void timer0_isr() interrupt 1 {
  227.     TH0 = (65536 - 1000) / 256;
  228.     TL0 = (65536 - 1000) % 256;

  229.     if (status == 1) {
  230.         timer_count++;
  231.         if (timer_count >= 1000) {
  232.             timer_count = 0;
  233.             time_s++;
  234.             if (time_s >= 60) {
  235.                 time_s = 0;
  236.                 time_m++;
  237.                 if (time_m >= 60) {
  238.                     time_m = 0;
  239.                     time_h++;
  240.                 }
  241.             }
  242.         }
  243.     }
  244. }

  245. // -------------------- LCD底層驅動 --------------------
  246. void DelayMs(u16 ms) {
  247.     u16 i, j;
  248.     for(i=ms; i>0; i--)
  249.         for(j=120; j>0; j--);
  250. }

  251. void LcdWriteCmd(u8 cmd) {
  252.     LCD_RS = 0;
  253.     LCD_RW = 0;
  254.     LCD_DataPort = cmd;
  255.     DelayMs(1);
  256.     LCD_EN = 1;
  257.     DelayMs(1);
  258.     LCD_EN = 0;
  259. }

  260. void LcdWriteData(u8 dat) {
  261.     LCD_RS = 1;
  262.     LCD_RW = 0;
  263.     LCD_DataPort = dat;
  264.     DelayMs(1);
  265.     LCD_EN = 1;
  266.     DelayMs(1);
  267.     LCD_EN = 0;
  268. }

  269. void LcdInit() {
  270.     LcdWriteCmd(0x38);
  271.     LcdWriteCmd(0x0C);
  272.     LcdWriteCmd(0x06);
  273.     LcdWriteCmd(0x01);
  274.     DelayMs(5);
  275. }

  276. void LcdSetCursor(u8 row, u8 col) {
  277.     u8 addr;
  278.     if (row == 0) {
  279.         addr = 0x80 + col;
  280.     } else {
  281.         addr = 0x80 + 0x40 + col;
  282.     }
  283.     LcdWriteCmd(addr);
  284. }

  285. void LcdShowString(u8 row, u8 col, u8 *str) {
  286.     LcdSetCursor(row, col);
  287.     while(*str != '\0') {
  288.         LcdWriteData(*str++);
  289.     }
  290. }

  291. // *** 新增的顯示數字的函數 ***
  292. // 在(row, col)顯示數字num,共顯示len位,不足則前面補空格
  293. void LcdShowNum(u8 row, u8 col, u16 num, u8 len) {
  294.     u8 i;
  295.     u8 buf[5]; // 假設數字最大5位
  296.     for (i = 0; i < len; i++) {
  297.         buf[len - 1 - i] = (num % 10) + '0';
  298.         num /= 10;
  299.     }
  300.    
  301.     // 如果數字本身位數小于len,前面補空格
  302.     for (i = 0; i < len; i++) {
  303.         if (num == 0 && buf[i] == '0' && i < len - 1) { // 找到最高位
  304.              if(i < len - 1) buf[i] = ' '; // 將高位0轉換為空格, 但保留個位數0
  305.         } else {
  306.             break; // 找到第一個非零數字后停止
  307.         }
  308.     }
  309.     // 處理num=0的情況
  310.     if (len > 1 && buf[0] == ' ') {
  311.          // 確保個位數如果是0,能正常顯示
  312.          if(len > 1 && num == 0){
  313.              // 此處確保至少有一個'0'顯示
  314.          }
  315.     }


  316.     LcdSetCursor(row, col);
  317.     for (i = 0; i < len; i++) {
  318.         LcdWriteData(buf[i]);
  319.     }
  320. }
復制代碼

作者: IdeaMing    時間: 2025-7-9 13:39
1,檢查pin腳定義,
2,檢查端口是否有輸出正確的數據,
3,檢查數據的LSB還是MSB.
作者: man1234567    時間: 2025-7-9 15:46
學習板自帶的1602例程移植就好。
作者: 單片機重購    時間: 2025-7-9 16:28
首先你使用LCD1602的液晶屏應該是有自帶的驅動程序。從你需要實現的目的開始求我們現在,你的要是沒有看到的。不知道你的具體要求是什莫。你是不是覺得LCD1602比較簡單,我給你說我之前用普中科技的板子寫代碼用來寫字符的時候時,我也出錯了。所以我大概率判斷是你的LCD1602的驅動程序有問題,是需要去查看LCD1602驅動程序的問題。也有可能是你的端口輸出數據的問題,數據到底是LSB還是MSB呢,你是不是把數據的類型搞錯了哦。是不是輸出的數據類型不對等的呢。
作者: hhdsdy    時間: 2025-7-9 18:07
這個程序是從這塊開發板的1602移植的嗎?看照片各個模塊的引腳是固定死無法自己定義的,所以軟件得服從硬件,先把各個引腳定義為硬件的實際連接才行。
作者: 轉角遇見劫匪    時間: 2025-7-9 18:30
首先你使用LCD1602的液晶屏應該是有自帶的驅動程序。從你需要實現的目的開始求我們現在,你的要是沒有看到的。不知道你的具體要求是什莫。你是不是覺得LCD1602比較簡單,我給你說我之前用普中科技的板子寫代碼用來寫字符的時候時,我也出錯了。所以我大概率判斷是你的LCD1602的驅動程序有問題,是需要去查看LCD1602驅動程序的問題。也有可能是你的端口輸出數據的問題,數據到底是LSB還是MSB呢.
作者: hhdsdy    時間: 2025-7-9 22:47
地板樓的“單片機重購”和6樓的“ID:1156151”帖子怎么一模一樣?是同一個人嗎?
作者: 人中狼    時間: 2025-7-10 16:43
沒查忙
作者: joyb    時間: 2025-7-11 08:49
單獨實驗1602




歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 亚洲 欧美 综合 | 亚洲高清免费视频 | 久久久久国产精品视频 | 亚洲视频免费 | 激情久久久 | 精品黄色片 | 成人做爰www看视频软件 | 国产美女自拍视频 | 欧美亚洲国产精品 | 91视频免费观看 | av网站在线免费观看 | 久久精品国产一区二区 | 欧美自拍视频 | a视频在线观看 | 国产1级片 | 久草视频免费看 | 亚洲欧美日韩一区二区 | 诱人的大乳奶3做爰 | 国产成人亚洲精品自产在线 | 香蕉综合网 | 欧美亚洲国产精品 | 天天爽夜夜操 | 天天综合色| 欧美日韩在线一区二区 | 国产在线黄色 | 日韩视频网 | 欧美一级一级 | 亚洲激情一区 | 日韩午夜在线观看 | www中文字幕 | 国产亚洲区| 特一级黄色片 | 日韩成人精品视频 | 波多野结衣一级片 | 一级黄色片免费观看 | 免费网站黄色 | 黄色在线小视频 | 一级片在线观看视频 | 国产午夜在线观看 | 日韩精品视频在线免费观看 | 九九九久久久 |