欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
單片機計算器出現問題
[打印本頁]
作者:
星際漫游者
時間:
2017-8-16 13:49
標題:
單片機計算器出現問題
請各位大神看一下我的仿真電路應該沒問題吧 仿真的這個計算器按鍵不起作用 請各位大神幫我分析一下原因
E80TDANI[9QLKA(2G8EE.png
(27.88 KB, 下載次數: 61)
下載附件
2017-8-16 13:48 上傳
#include <reg51.h>
#define LCD1602_DB P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
void LcdWaitReady() //等待液晶準備好
{
unsigned char sta;
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
do
{
LCD1602_E = 1;
sta = LCD1602_DB; //讀取狀態字
LCD1602_E = 0;
} while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止
}
void LcdWriteCmd(unsigned char cmd) //寫入命令函數
{
LcdWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
void LcdWriteDat(unsigned char dat) //寫入數據函數
{
LcdWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str) //顯示字符串,屏幕起始坐標(x,y),字符串指針str
{
unsigned char addr;
//由輸入的顯示坐標計算顯示RAM的地址
if (y == 0)
addr = 0x00 + x; //第一行字符地址從0x00起始
else
addr = 0x40 + x; //第二行字符地址從0x40起始
//由起始顯示RAM地址連續寫入字符串
LcdWriteCmd(addr | 0x80); //寫入起始地址
while (*str != '\0') //連續寫入字符串數據,直到檢測到結束符
{
LcdWriteDat(*str);
str++;
}
}
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len) //區域清除,清除從(x,y)坐標起始的len個字符位
{
unsigned char addr;
//由輸入的顯示坐標計算顯示RAM的地址
if (y == 0)
addr = 0x00 + x; //第一行字符地址從0x00起始
else
addr = 0x40 + x; //第二行字符地址從0x40起始
//由起始顯示RAM地址連續寫入字符串
LcdWriteCmd(addr | 0x80); //寫入起始地址
while (len--) //連續寫入空格
{
LcdWriteDat(' ');
}
}
void LcdFullClear()
{
LcdWriteCmd(0x01); //清屏
}
void LcdInit() //液晶初始化函數
{
LcdWriteCmd(0x38); //16*2顯示,5*7點陣,8位數據接口
LcdWriteCmd(0x0C); //顯示器開,光標關閉
LcdWriteCmd(0x06); //文字不動,地址自動+1
LcdWriteCmd(0x01); //清屏
LcdShowStr(15, 1, "0");
}
/***********************keyboard.c文件程序源代碼************************/
#include <reg51.h>
sbit KEY_IN_1 = P2^4; //矩陣按鍵的掃描輸入引腳1
sbit KEY_IN_2 = P2^5; //矩陣按鍵的掃描輸入引腳2
sbit KEY_IN_3 = P2^6; //矩陣按鍵的掃描輸入引腳3
sbit KEY_IN_4 = P2^7; //矩陣按鍵的掃描輸入引腳4
sbit KEY_OUT_1 = P2^3; //矩陣按鍵的掃描輸出引腳1
sbit KEY_OUT_2 = P2^2; //矩陣按鍵的掃描輸出引腳2
sbit KEY_OUT_3 = P2^1; //矩陣按鍵的掃描輸出引腳3
sbit KEY_OUT_4 = P2^0; //矩陣按鍵的掃描輸出引腳4
const unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到PC標準鍵盤鍵碼的映射表
{ '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}
};
unsigned char step = 0; //操作步驟
unsigned char oprt = 0; //運算類型
signed long num1 = 0; //操作數1
signed long num2 = 0; //操作數2
signed long result = 0; //運算結果
extern void LcdFullClear();
extern void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str);
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
unsigned char NumToString(unsigned char *str, signed long num) //整型數轉換為字符串,字符串指針str,待轉換數num,返回值為字符串長度
{
unsigned char i, len;
unsigned char buf[12];
if (num < 0) //如果為負數,則首先輸出符號到指針上,并取其絕對值
{
*str = '-';
str++;
num = -num;
}
i = 0; //先轉換為低位在前的十進制數組
do {
buf[ i] = num % 10;
num /= 10;
i++;
} while (num > 0);
len = i; //i最后的值就是有效字符的個數
while (i > 0) //然后將數組值轉換為ASCII碼反向拷貝到接收指針上
{
i--;
*str = buf[ i] + '0';
str++;
}
return len; //返回轉換后的字符串長度
}
void ShowOprt(unsigned char y, unsigned char type) //顯示運算符,顯示位置y,運算符類型type
{
switch (type)
{
case 0: LcdShowStr(0, y, "+"); break;
case 1: LcdShowStr(0, y, "-"); break;
case 2: LcdShowStr(0, y, "*"); break;
case 3: LcdShowStr(0, y, "/"); break;
default: break;
}
}
void Reset() //計算器復位函數
{
num1 = 0;
num2 = 0;
step = 0;
LcdFullClear();
}
void NumKeyAction(unsigned char n) //數字鍵動作函數,按鍵輸入的數值n
{
unsigned char len;
unsigned char str[12];
if (step > 1) //如計算已完成,則重新開始新的計算
{
Reset();
}
if (step == 0) //輸入第一操作數
{
num1 = num1*10 + n; //輸入數值累加到原操作數上
len = NumToString(str, num1); //新數值轉換為字符串
LcdShowStr(16-len, 1, str); //顯示到液晶第二行上
}
else //輸入第二操作數
{
num2 = num2*10 + n;
len = NumToString(str, num2);
LcdShowStr(16-len, 1, str);
}
}
void OprtKeyAction(unsigned char type) //運算符按鍵動作函數,運算符類型type
{
unsigned char len;
unsigned char str[12];
if (step == 0) //第二操作數尚未輸入時響應,即不支持連續操作
{
len = NumToString(str, num1); //第一操作數轉換為字符串
LcdAreaClear(0, 0, 16-len); //清除第一行左邊的字符位
LcdShowStr(16-len, 0, str); //字符串靠右顯示在第一行
ShowOprt(1, type); //在第二行顯示操作符
LcdAreaClear(1, 1, 14); //清除第二行中間的字符位
LcdShowStr(15, 1, "0"); //在第二行最右端顯示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 = NumToString(str, num2); //原第二操作數和運算符顯示在第一行
ShowOprt(0, oprt);
LcdAreaClear(1, 0, 16-1-len);
LcdShowStr(16-len, 0, str);
len = NumToString(str, result); //計算結果和等號顯示在第二行
LcdShowStr(0, 1, "=");
LcdAreaClear(1, 1, 16-1-len);
LcdShowStr(16-len, 1, 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) //Esc鍵,清除
{
Reset();
LcdShowStr(15, 1, "0");
}
}
void KeyDrive() //按鍵動作驅動函數
{
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];
}
}
}
}
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,即16ms(4*4ms)內都只檢測到按下狀態時,可認為按鍵已按下
KeySta[keyout][ i] = 0;
}
else if ((keybuf[keyout][ i] & 0x0F) == 0x0F)
{ //連續4次掃描值為1,即16ms(4*4ms)內都只檢測到彈起狀態時,可認為按鍵已彈起
KeySta[keyout][ i] = 1;
}
}
//執行下一次的掃描輸出
keyout++;
keyout &= 0x03;
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 <reg51.h>
void ConfigTimer0(unsigned int ms);
extern void KeyScan();
extern void KeyDrive();
extern void LcdInit();
unsigned char T0RH = 0; //T0重載值的高字節
unsigned char T0RL = 0; //T0重載值的低字節
void main(void)
{
EA = 1; //開總中斷
ConfigTimer0(1); //配置T0定時1ms
LcdInit(); //初始化液晶
while(1)
{
KeyDrive();
}
}
void ConfigTimer0(unsigned int ms) //T0配置函數
{
unsigned long tmp;
tmp = 11059200 / 12; //定時器計數頻率
tmp = (tmp * ms) / 1000; //計算所需的計數值
tmp = 65536 - tmp; //計算定時器重載值
tmp = tmp + 18; //修正中斷響應延時造成的誤差
T0RH = (unsigned char)(tmp >> 8); //定時器重載值拆分為高低字節
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0為模式1
TH0 = T0RH; //加載T0重載值
TL0 = T0RL;
ET0 = 1; //使能T0中斷
TR0 = 1; //啟動T0
}
void InterruptTimer0() interrupt 1 //T0中斷服務函數
{
TH0 = T0RH; //定時器重新加載重載值
TL0 = T0RL;
KeyScan(); //按鍵掃描
}
復制代碼
作者:
cjjcjj1
時間:
2017-8-16 15:25
提示:
作者被禁止或刪除 內容自動屏蔽
歡迎光臨 (http://m.raoushi.com/bbs/)
Powered by Discuz! X3.1