基于51单片机的金沙滩12864的计算器
生活随笔
收集整理的這篇文章主要介紹了
基于51单片机的金沙滩12864的计算器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
很久以前就想把LCD1602的計算器換成LCD12864,
目前邏輯是弄出來了,顯示出了點小問題,往后再看看顯示的問題
第一個文件:config.h
第二個文件keyboard.c
#include <reg52.h>sbit KEY_IN_1 = P2^4; sbit KEY_IN_2 = P2^5; sbit KEY_IN_3 = P2^6; sbit KEY_IN_4 = P2^7; sbit KEY_OUT_1 = P2^3; sbit KEY_OUT_2 = P2^2; sbit KEY_OUT_3 = P2^1; sbit KEY_OUT_4 = P2^0;unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到標準鍵盤鍵碼的映射表{ '1', '2', '3', 0x26 }, //數字鍵1、數字鍵2、數字鍵3、向上鍵{ '4', '5', '6', 0x25 }, //數字鍵4、數字鍵5、數字鍵6、向左鍵{ '7', '8', '9', 0x28 }, //數字鍵7、數字鍵8、數字鍵9、向下鍵{ '0', 0x1B, 0x0D, 0x27 } //數字鍵0、ESC鍵、 回車鍵、 向右鍵 };unsigned char pdata KeySta[4][4] = { //全部矩陣按鍵的當前狀態{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; extern void Reset(); extern void GetResult(); extern void NumKeyAction(unsigned char n); extern void OprtKeyAction(unsigned char type); extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);void KeyAction(unsigned char keycode) {if((keycode >= '0') && (keycode <= '9')){NumKeyAction(keycode - '0'); }else if(keycode == 0x26){OprtKeyAction(0);}else if(keycode == 0x28){OprtKeyAction(1);}else if(keycode == 0x25){OprtKeyAction(2);}else if(keycode == 0x27){OprtKeyAction(3);}else if(keycode == 0x0D){GetResult();}else if(keycode == 0x1B){Reset();LcdShowStr(15, 1, "0");} } /* 按鍵驅動函數,檢測按鍵動作,調度相應動作函數,需在主循環中調用 */ void KeyDriver() {unsigned char i, j;static unsigned char pdata backup[4][4] = { //按鍵值備份,保存前一次的值{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};for (i=0; i<4; i++) //循環檢測4*4的矩陣按鍵{for (j=0; j<4; j++){if (backup[i][j] != KeySta[i][j]) //檢測按鍵動作{if (backup[i][j] != 0) //按鍵按下時執行動作{KeyAction(KeyCodeMap[i][j]); //調用按鍵動作函數}backup[i][j] = KeySta[i][j]; //刷新前一次的備份值}}} }/* 按鍵掃描函數,需在定時中斷中調用,推薦調用間隔1ms */ void KeyScan() {unsigned char i;static unsigned char keyout = 0; //矩陣按鍵掃描輸出索引static unsigned char keybuf[4][4] = { //矩陣按鍵掃描緩沖區{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};//將一行的4個按鍵值移入緩沖區keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;//消抖后更新按鍵狀態for (i=0; i<4; i++) //每行4個按鍵,所以循環4次{if ((keybuf[keyout][i] & 0x0F) == 0x00){ //連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的按下KeySta[keyout][i] = 0;}else if ((keybuf[keyout][i] & 0x0F) == 0x0F){ //連續4次掃描值為1,即4*4ms內都是彈起狀態時,可認為按鍵已穩定的彈起KeySta[keyout][i] = 1;}}//執行下一次的掃描輸出keyout++; //輸出索引遞增keyout &= 0x03; //索引值加到4即歸零switch (keyout) //根據索引,釋放當前輸出引腳,拉低下次的輸出引腳{case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;default: break;} }第三個文件LCD12864.c
/* ******************************************************************************* * 《手把手教你學51單片機(C語言版)》 * 配套 KST-51 單片機開發板 示例源代碼 * * (c) 版權所有 2014 金沙灘工作室/清華大學出版社 保留所有權利 * 獲取更多資料請訪問:http://www.kingst.org * * 文件名:Lcd12864.c * 描 述:12864點陣液晶驅動模塊 * 版本號:v1.0.0 * 備 注:適用于KST-51開發板配套的12864液晶模塊 ******************************************************************************* */#define _LCD_12864_C #include "config.h" #include "Lcd12864.h" /* 等待液晶準備好 */ void LcdWaitReady() {uint8 sta;LCD12864_DB = 0xFF;LCD12864_RS = 0;LCD12864_RW = 1;do {LCD12864_E = 1;sta = LCD12864_DB;LCD12864_E = 0;} while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止 }/* 向液晶寫入一字節命令,cmd-待寫入命令值 */ void LcdWriteCmd(uint8 cmd) {LcdWaitReady();LCD12864_RS = 0;LCD12864_RW = 0;LCD12864_DB = cmd;LCD12864_E = 1;LCD12864_E = 0; } /* 向液晶寫入一字節數據,dat-待寫入數據值 */ void LcdWriteDat(uint8 dat) {LcdWaitReady();LCD12864_RS = 1;LCD12864_RW = 0;LCD12864_DB = dat;LCD12864_E = 1;LCD12864_E = 0; }/* 設置顯示RAM起始地址,亦即光標位置,(x,y)-對應屏幕上的字符坐標 */ void LcdSetCursor(uint8 x, uint8 y) {unsigned char addr;if (y == 0) //由輸入的屏幕坐標計算顯示RAM的地址addr = 0x80 + x; //第一行字符地址從0x00起始else if (y == 1)addr = 0x90 + x; //第二行字符地址從0x40起始else if (y == 2)addr = 0x88 + x; //第二行字符地址從0x40起始else if (y == 3)addr = 0x98 + x; //第二行字符地址從0x40起始LcdWriteCmd(addr | 0x80); //設置RAM地址 }void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str) {LcdSetCursor(x, y); //設置起始地址while (*str != '\0') //連續寫入字符串數據,直到檢測到結束符{LcdWriteDat(*str++);} } /* * 函數名:LcdShowString * 描 述:在顯示屏上顯示一串字符串 * 輸 入:str - 待顯示字符串指針 * x - 屏幕顯示橫坐標(以像素為單位) * y - 屏幕顯示縱坐標(以像素為單位) * 輸 出:無 * 備 注:輸入的字符串必須符合C語言規范,即以'\0'-NULL為結束標識; * x、y坐標必須是16的整數倍,因DDRAM地址以全角字符(16*16pixel)為單位。 */ void LcdShowString(uint8 x, uint8 y, uint8 *str) {uint8 addr;//由輸入的顯示坐標計算DDRAM的地址x >>= 4;// y=48y >>= 4;// y=3if (y >= 2){//y = 3 - 2y -= 2;//x = 8 + 8x += 8;}//addr = 16+8//16+16addr = y*16 + x;//由起始DDRAM地址連續寫入字符串LcdWriteCmd(0x30); //啟動DDRAM操作LcdWriteCmd(0x80|addr);//1000 0000 | 0001 1000while (*str != '\0'){LcdWriteDat(*str);str++;} } /* * 函數名:LcdShowImage * 描 述:在顯示屏上顯示一幅圖像 * 輸 入:img - 待顯示圖像指針 * x - 屏幕顯示橫坐標(以像素為單位) * y - 屏幕顯示縱坐標(以像素為單位) * w - 圖像寬度(以像素為單位) * h - 圖像高度(以像素為單位) * 輸 出:無 * 備 注:x與w必須是16的整數倍,因CGRAM最小尋址單位為2字節;y與h可為0-63的任意值。 */ void LcdShowImage(uint8 x, uint8 y, uint8 w, uint8 h, uint8 *img) {int16 i;uint8 xi,yi;uint8 xt,yt;x >>= 4;w >>= 3;i = 0;LcdWriteCmd(0x36); //啟動CGRAM操作for (yi=0; yi<h; yi++){yt = y+yi;xt = x;if (yt >= 32){yt -= 32;xt += 8;}LcdWriteCmd(0x80|yt);LcdWriteCmd(0x80|xt);for (xi=0; xi<w; xi++){LcdWriteDat(img[i++]);}} }/* 區域清除,清除從(x,y)坐標起始的len個字符位 */ void LcdAreaClear(uint8 x, uint8 y, uint8 len) {LcdSetCursor(x, y); //設置起始地址while (len--) //連續寫入空格{LcdWriteDat(' ');} } void LcdFullClear() {LcdWriteCmd(0x01); } /* * 函數名:LcdClearArea * 描 述:清除屏幕上的一塊圖形顯示區域 * 輸 入:x - 區域起始橫坐標(以像素為單位) * y - 區域起始縱坐標(以像素為單位) * w - 區域寬度(以像素為單位) * h - 區域高度(以像素為單位) * 輸 出:無 * 備 注:x與w必須是16的整數倍,因CGRAM最小尋址單位為2字節;y與h可為0-63的任意值。 */ void LcdClearArea(uint8 x, uint8 y, uint8 w, uint8 h) {uint8 xi,yi;uint8 xt,yt;x >>= 4;w >>= 3;LcdWriteCmd(0x36); //啟動CGRAM操作for (yi=0; yi<h; yi++){yt = y+yi;xt = x;if (yt >= 32){yt -= 32;xt += 8;}LcdWriteCmd(0x80|yt);LcdWriteCmd(0x80|xt);for (xi=0; xi<w; xi++){LcdWriteDat(0x00); //寫入0x00以清除顯示}} }/* 12864液晶初始化函數 */ void InitLcd12864() {uint8 x, y;//字符模式初始化LcdWriteCmd(0x30); //基本指令集LcdWriteCmd(0x01); //清零字符顯示LcdWriteCmd(0x02); //地址歸位LcdWriteCmd(0x0C); //開顯示//圖形模式初始化LcdWriteCmd(0x34); //啟動擴展指令,關閉圖形顯示for (y=0; y<32; y++) //清零圖形顯示緩沖區{LcdWriteCmd(0x80|y);LcdWriteCmd(0x80|0);for (x=0; x<32; x++){LcdWriteDat(0x00);}}LcdWriteCmd(0x36); //開啟圖形模式顯示 }第四個文件LCD12864.H
/* ******************************************************************************* * 《手把手教你學51單片機(C語言版)》 * 配套 KST-51 單片機開發板 示例源代碼 * * (c) 版權所有 2014 金沙灘工作室/清華大學出版社 保留所有權利 * 獲取更多資料請訪問:http://www.kingst.org * * 文件名:Lcd12864.c * 描 述:12864點陣液晶驅動模塊的頭文件 * 版本號:v1.0.0 * 備 注: ******************************************************************************* */#ifndef _LCD_12864_H #define _LCD_12864_H #include <reg52.h> #include <intrins.h>//12864液晶口線與板載1602液晶相同 #define LCD12864_DB LCD1602_DB #define LCD12864_RS LCD1602_RS #define LCD12864_RW LCD1602_RW #define LCD12864_E LCD1602_E#ifndef _LCD_12864_C#endifvoid InitLcd12864(); void LcdWaitReady(); void LcdFullClear(); //void LcdWriteCmd(uint8 cmd);#endif主函數:main.c文件
#include <reg52.h> #include "Lcd12864.h" #include "config.h" unsigned char step = 0; unsigned char oprt = 0; signed long num1 = 0; signed long num2 = 0; signed long result = 0; unsigned char T0RH = 0; unsigned char T0RL = 0;void ConfigTimer0(unsigned int ms); extern void KeyScan(); extern void KeyDriver(); extern void InitLcd1602(); extern void LcdShowString(uint8 x, uint8 y, uint8 *str); extern void LcdFullClear(); extern void LcdAreaClear(uint8 x, uint8 y, uint8 len);//extern void LcdShowString(uint8 x, uint8 y, uint8 *str); extern void LcdShowImage(uint8 x, uint8 y, uint8 w, uint8 h, uint8 *img); extern void LcdClearArea(uint8 x, uint8 y, uint8 w, uint8 h); extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);void main() {EA = 1; //開總中斷ConfigTimer0(1); //配置T0定時1msInitLcd12864(); //初始化液晶//LcdShowString(0, 0, "111111111111111"); //初始顯示一個數字0//LcdShowString(0, 16, "1111111111111111");//LcdShowString(0, 32, "1111111111111111");LcdShowString(112, 48, "0"); //因為字符顯示只能占用一半while (1){KeyDriver(); //調用按鍵驅動} } unsigned char LongToString(unsigned char *str, signed long dat) {signed char i = 0;unsigned char len = 0;unsigned char buf[12];if(dat < 0){dat = -dat;*str++ = '-';len++;}do{buf[i++] = dat % 10;dat /= 10;}while(dat > 0);len += i;while(i-- > 0){*str++ = buf[i] + '0';}*str = '\0';return len;} void ShowOprt(unsigned char y, unsigned char type) {switch(type){case 0: LcdShowString(0, y, "+"); break;case 1: LcdShowString(0, y, "-"); break;case 2: LcdShowString(0, y, "*"); break;case 3: LcdShowString(0, y, "/"); break;default: break;} } void Reset() {num1 = 0;num2 = 0;step = 0;LcdFullClear(); } void NumKeyAction(unsigned char n) {unsigned char len = 0;unsigned char str[12];if(step > 1){Reset();}if(step == 0){num1 = num1*10 + n;len = LongToString(str, num1);LcdShowString(128 - len, 48, str);}else {num2 = num2*10 + n;len = LongToString(str, num2);LcdShowString(128 - len, 48, str);} } void OprtKeyAction(unsigned char type) { unsigned char len;unsigned char str[12];if(step == 0){len = LongToString(str, num1);LcdAreaClear(0, 48, 128-len);LcdShowString(128-len, 32, str);ShowOprt(48, type); LcdAreaClear(1, 48, 14);//待定 LcdShowString(112, 48, "0"); oprt = type; step = 1; } } void GetResult() {unsigned char len;unsigned char str[12];if(step == 1){step = 2;switch(oprt){case 0: result = num1 + num2; break;case 1: result = num1 - num2; break;case 2: result = num1 * num2; break;case 3: result = num1 / num2; break;default: break;}len = LongToString(str, num2); LcdAreaClear(1, 32, 128-1-len);ShowOprt(32, oprt);LcdShowString(128-len, 32, str);len = LongToString(str, result);LcdShowString(0, 48, "=");LcdAreaClear(1, 48, 16-1-len);LcdShowString(128-len, 48, str); } }/* 配置并啟動T0,ms-T0定時時間 */ void ConfigTimer0(unsigned int ms) {unsigned long tmp; //臨時變量tmp = 11059200 / 12; //定時器計數頻率tmp = (tmp * ms) / 1000; //計算所需的計數值tmp = 65536 - tmp; //計算定時器重載值tmp = tmp + 12; //補償中斷響應延時造成的誤差T0RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節T0RL = (unsigned char)tmp;TMOD &= 0xF0; //清零T0的控制位TMOD |= 0x01; //配置T0為模式1TH0 = T0RH; //加載T0重載值TL0 = T0RL;ET0 = 1; //使能T0中斷TR0 = 1; //啟動T0 } /* T0中斷服務函數,執行按鍵掃描 */ void InterruptTimer0() interrupt 1 {TH0 = T0RH; //重新加載重載值TL0 = T0RL;KeyScan(); //按鍵掃描 }遇到的問題:中文字符是1616,字符是816,數字屬于英文字符,所以只占了8*16,中文字符的一半,默認是左半邊對齊,右移是需要同時顯示一個英文空格和一個英文字符。目的:想讓字符0顯示在12864的右下角
更新:在LCD12864數字顯示在左邊解決了移位的問題,+號和=號顯示在右邊,和課程例子有點區別
LCD12864.c
#include <reg52.h>typedef signed char int8; // 8位有符號整型數 typedef signed int int16; //16位有符號整型數 typedef signed long int32; //32位有符號整型數 typedef unsigned char uint8; // 8位無符號整型數 typedef unsigned int uint16; //16位無符號整型數 typedef unsigned long uint32; //32位無符號整型數#define LCD1602_DB P0 //1602液晶數據端口 sbit LCD1602_RS = P1^0; //1602液晶指令/數據選擇引腳 sbit LCD1602_RW = P1^1; //1602液晶讀寫引腳 sbit LCD1602_E = P1^5; //1602液晶使能引腳#define LCD12864_DB LCD1602_DB #define LCD12864_RS LCD1602_RS #define LCD12864_RW LCD1602_RW #define LCD12864_E LCD1602_Evoid LcdShowString(uint8 x, uint8 y, uint8 *str); void InitLcd12864(); void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str); void LcdFullClear(); /* 等待液晶準備好 */ void LcdWaitReady() {uint8 sta;LCD12864_DB = 0xFF;LCD12864_RS = 0;LCD12864_RW = 1;do {LCD12864_E = 1;sta = LCD12864_DB;LCD12864_E = 0;} while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止 }/* 向液晶寫入一字節命令,cmd-待寫入命令值 */ void LcdWriteCmd(uint8 cmd) {LcdWaitReady();LCD12864_RS = 0;LCD12864_RW = 0;LCD12864_DB = cmd;LCD12864_E = 1;LCD12864_E = 0; }void LcdWriteDat(uint8 dat) {LcdWaitReady();LCD12864_RS = 1;LCD12864_RW = 0;LCD12864_DB = dat;LCD12864_E = 1;LCD12864_E = 0; }void LcdSetCursor(unsigned char x, unsigned char y) {uint8 addr;//由輸入的顯示坐標計算DDRAM的地址x >>= 4;y >>= 4;if (y >= 2){y -= 2;x += 8;}addr = y*16 + x;//由起始DDRAM地址連續寫入字符串LcdWriteCmd(0x30); //啟動DDRAM操作LcdWriteCmd(0x80|addr); }void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str) {LcdSetCursor(x, y);while (*str != '\0'){LcdWriteDat(*str);str++;} } /* 區域清除,清除從(x,y)坐標起始的len個字符位 */ void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len) {LcdSetCursor(x, y); //設置起始地址while (len--) //連續寫入空格{LcdWriteDat(' ');} }/* 整屏清除 */ void LcdFullClear() {LcdWriteCmd(0x01); }void InitLcd12864() {uint8 x, y;//字符模式初始化LcdWriteCmd(0x30); //基本指令集LcdWriteCmd(0x01); //清零字符顯示LcdWriteCmd(0x02); //地址歸位LcdWriteCmd(0x0C); //開顯示//圖形模式初始化LcdWriteCmd(0x34); //啟動擴展指令,關閉圖形顯示for (y=0; y<32; y++) //清零圖形顯示緩沖區{LcdWriteCmd(0x80|y);LcdWriteCmd(0x80|0);for (x=0; x<32; x++){LcdWriteDat(0x00);}}LcdWriteCmd(0x36); //開啟圖形模式顯示 }keyboard.c
#include <reg52.h>sbit KEY_IN_1 = P2^4; sbit KEY_IN_2 = P2^5; sbit KEY_IN_3 = P2^6; sbit KEY_IN_4 = P2^7; sbit KEY_OUT_1 = P2^3; sbit KEY_OUT_2 = P2^2; sbit KEY_OUT_3 = P2^1; sbit KEY_OUT_4 = P2^0;unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到標準鍵盤鍵碼的映射表{ '1', '2', '3', 0x26 }, //數字鍵1、數字鍵2、數字鍵3、向上鍵{ '4', '5', '6', 0x25 }, //數字鍵4、數字鍵5、數字鍵6、向左鍵{ '7', '8', '9', 0x28 }, //數字鍵7、數字鍵8、數字鍵9、向下鍵{ '0', 0x1B, 0x0D, 0x27 } //數字鍵0、ESC鍵、 回車鍵、 向右鍵 }; unsigned char pdata KeySta[4][4] = { //全部矩陣按鍵的當前狀態{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} };extern void KeyAction(unsigned char keycode);/* 按鍵驅動函數,檢測按鍵動作,調度相應動作函數,需在主循環中調用 */ void KeyDriver() {unsigned char i, j;static unsigned char pdata backup[4][4] = { //按鍵值備份,保存前一次的值{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};for (i=0; i<4; i++) //循環檢測4*4的矩陣按鍵{for (j=0; j<4; j++){if (backup[i][j] != KeySta[i][j]) //檢測按鍵動作{if (backup[i][j] != 0) //按鍵按下時執行動作{KeyAction(KeyCodeMap[i][j]); //調用按鍵動作函數}backup[i][j] = KeySta[i][j]; //刷新前一次的備份值}}} } /* 按鍵掃描函數,需在定時中斷中調用,推薦調用間隔1ms */ void KeyScan() {unsigned char i;static unsigned char keyout = 0; //矩陣按鍵掃描輸出索引static unsigned char keybuf[4][4] = { //矩陣按鍵掃描緩沖區{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};//將一行的4個按鍵值移入緩沖區keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;//消抖后更新按鍵狀態for (i=0; i<4; i++) //每行4個按鍵,所以循環4次{if ((keybuf[keyout][i] & 0x0F) == 0x00){ //連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的按下KeySta[keyout][i] = 0;}else if ((keybuf[keyout][i] & 0x0F) == 0x0F){ //連續4次掃描值為1,即4*4ms內都是彈起狀態時,可認為按鍵已穩定的彈起KeySta[keyout][i] = 1;}}//執行下一次的掃描輸出keyout++; //輸出索引遞增keyout &= 0x03; //索引值加到4即歸零switch (keyout) //根據索引,釋放當前輸出引腳,拉低下次的輸出引腳{case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;default: break;} }main.c
#include <reg52.h>unsigned char step = 0; //操作步驟 unsigned char oprt = 0; //運算類型 signed long num1 = 0; //操作數1 signed long num2 = 0; //操作數2 signed long result = 0; //運算結果 unsigned char T0RH = 0; //T0重載值的高字節 unsigned char T0RL = 0; //T0重載值的低字節void ConfigTimer0(unsigned int ms); extern void KeyScan(); extern void KeyDriver(); extern void InitLcd12864(); extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str); extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len); extern void LcdFullClear();void main() {EA = 1; //開總中斷ConfigTimer0(1); //配置T0定時1msInitLcd12864(); //初始化液晶LcdShowStr(0, 48, "0"); //初始顯示一個數字0while (1){KeyDriver(); //調用按鍵驅動} } /* 長整型數轉換為字符串,str-字符串指針,dat-待轉換數,返回值-字符串長度 */ unsigned char LongToString(unsigned char *str, signed long dat) {signed char i = 0;unsigned char len = 0;unsigned char buf[12];if (dat < 0) //如果為負數,首先取絕對值,并在指針上添加負號{dat = -dat;*str++ = '-';len++;}do { //先轉換為低位在前的十進制數組buf[i++] = dat % 10;dat /= 10;} while (dat > 0);len += i; //i最后的值就是有效字符的個數while (i-- > 0) //將數組值轉換為ASCII碼反向拷貝到接收指針上{*str++ = buf[i] + '0';}*str = '\0'; //添加字符串結束符return len; //返回字符串長度 }void ShowOprt(unsigned char y, unsigned char type) {switch(type){case 0: LcdShowStr(112, y, "+"); break;case 1: LcdShowStr(112, y, "-"); break;case 2: LcdShowStr(112, y, "*"); break;case 3: LcdShowStr(112, y, "/"); break;default: break;} }void Reset() {num1 = 0;num2 = 0;step = 0;LcdFullClear(); }/* 數字鍵動作函數,n-按鍵輸入的數值 */ void NumKeyAction(unsigned char n) {unsigned char len;unsigned char str[12];if (step > 1) //如計算已完成,則重新開始新的計算{Reset();}if (step == 0) //輸入第一操作數{num1 = num1*10 + n; //輸入數值累加到原操作數上len = LongToString(str, num1); //新數值轉換為字符串LcdShowStr(16 - len, 48, str); //顯示到液晶第二行上}else {num2 = num2*10 + n;len = LongToString(str, num2);LcdShowStr(16 - len, 48, str);} }void OprtKeyAction(unsigned char type) { unsigned char len;unsigned char str[12];if(step == 0){len = LongToString(str, num1);LcdAreaClear(0, 48, 16-len);LcdShowStr(16-len, 32, str);ShowOprt(32, type); LcdAreaClear(1, 48, 14); LcdShowStr(0, 48, "0");oprt = type; step = 1; } }void GetResult() {unsigned char len;unsigned char str[12];if(step == 1){step = 2;switch(oprt){case 0: result = num1 + num2; break;case 1: result = num1 - num2; break;case 2: result = num1 * num2; break;case 3: result = num1 / num2; break;default: break;}len = LongToString(str, num2); ShowOprt(32, oprt); //LcdAreaClear(1, 32, 16-1-len); //待定--發現LCD12864上刪除了沒有啥影響LcdShowStr(16-len, 32, str);len = LongToString(str, result);LcdShowStr(112, 48, "=");//LcdAreaClear(1, 48, 16-1-len); //待定--發現LCD12864上刪除了沒有啥影響LcdShowStr(16-len, 48, str); } }/* 按鍵動作函數,根據鍵碼執行相應的操作,keycode-按鍵鍵碼 */ void KeyAction(unsigned char keycode) {if ((keycode>='0') && (keycode<='9')) //輸入字符{NumKeyAction(keycode - '0');}else if(keycode == 0x26){OprtKeyAction(0);}else if(keycode == 0x28){OprtKeyAction(1);}else if(keycode == 0x25){OprtKeyAction(2);}else if(keycode == 0x27){OprtKeyAction(3);}else if(keycode == 0x0D){GetResult();}else if(keycode == 0x1B){Reset();LcdShowStr(0, 48, "0"); //初始顯示一個數字0} } /* 配置并啟動T0,ms-T0定時時間 */ void ConfigTimer0(unsigned int ms) {unsigned long tmp; //臨時變量tmp = 11059200 / 12; //定時器計數頻率tmp = (tmp * ms) / 1000; //計算所需的計數值tmp = 65536 - tmp; //計算定時器重載值tmp = tmp + 28; //補償中斷響應延時造成的誤差T0RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節T0RL = (unsigned char)tmp;TMOD &= 0xF0; //清零T0的控制位TMOD |= 0x01; //配置T0為模式1TH0 = T0RH; //加載T0重載值TL0 = T0RL;ET0 = 1; //使能T0中斷TR0 = 1; //啟動T0 } /* T0中斷服務函數,執行按鍵掃描 */ void InterruptTimer0() interrupt 1 {TH0 = T0RH; //重新加載重載值TL0 = T0RL;KeyScan(); //按鍵掃描 }總結
以上是生活随笔為你收集整理的基于51单片机的金沙滩12864的计算器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法导论习题C.2-7,C.2-8答案
- 下一篇: 基于snowflake的Id序列号生成器