|
#include <reg52.h>
/* 系統(tǒng)時(shí)鐘 */
#define SYS_XTAL (11059200UL/12)
/* 定時(shí)器T0重載值 */
unsigned char thr0, tlr0;
unsigned char thr1, tlr1;
/* 跑表計(jì)數(shù) */
unsigned char timer[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; //分別表示跑表的各個(gè)位上的數(shù)字
bit flag10ms = 0;
extern bit stopflag;//跑表走停標(biāo)志位
extern void InitalLCD1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
extern void KeyDriver();
extern void KeyScan();
void DisplayTimer();
void ConfigTimer0(unsigned int xms);
void ConfigTimer1(unsigned int xms);
/* 主函數(shù)main() */
void main(void)
{
ConfigTimer0(10); //定時(shí)10ms
ConfigTimer1(1);
InitalLCD1602();
LcdShowStr(0, 0, "stopwatch");
LcdShowStr(2, 1, "0000000.00 s"); //液晶初始化顯示
LcdShowStr(10, 0, "stop!");
while (1)
{
KeyDriver();
DisplayTimer();
if ((flag10ms == 1) && (stopflag == 1))
{
flag10ms = 0;
timer[0]++;
if (timer[0] > 9)
{
timer[0] = 0;
timer[1]++;
if (timer[1] > 9)
{
timer[1] = 0;
timer[2]++;
if (timer[2] > 9)
{
timer[2] = 0;
timer[3]++;
if (timer[3] > 9)
{
timer[3] = 0;
timer[4]++;
if (timer[4] > 9)
{
timer[4] = 0;
timer[5]++;
if (timer[5] > 9)
{
timer[5] = 0;
timer[6]++;
if (timer[6] > 9)
{
timer[6] = 0;
timer[7]++;
if (timer[7] > 9)
{
timer[7] = 0;
timer[8]++;
if (timer[8] > 9)
{
timer[8] = 0;
}
}
}
}
}
}
}
}
}
}
}
}
/* 將跑表時(shí)間顯示到液晶上 */
void DisplayTimer()
{
unsigned char str[20];
/* 分解timer */
str[0] = timer[8] + '0';
str[1] = timer[7] + '0';
str[2] = timer[6] + '0';
str[3] = timer[5] + '0';
str[4] = timer[4] + '0';
str[5] = timer[3] + '0';
str[6] = timer[2] + '0';
str[7] = '.';
str[8] = timer[1] + '0';
str[9] = timer[0] + '0';
str[10] = '\0';
LcdShowStr(2, 1, str);
}
/* 定時(shí)器T0配置 */
void ConfigTimer0(unsigned int xms)
{
unsigned long tmp;
tmp = (SYS_XTAL * xms) / 1000;
tmp = 65536-tmp + 18;
thr0 = (unsigned char)(tmp >> 8) ;
tlr0 = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0控制位
TMOD |= 0x01; //定時(shí)器方式1
TH0 = thr0;
TL0 = tlr0;
TR0 = 1; //開啟timer0
ET0 = 1; //開啟T0中斷
EA = 1; //開啟總中斷
}
/* 配置定時(shí)器T1 */
void ConfigTimer1(unsigned int xms)
{
unsigned long tmp;
tmp = (SYS_XTAL * xms) / 1000;
tmp = 65536 - tmp + 18;
thr1 = (unsigned char)(tmp >> 8);
tlr1 = (unsigned char)tmp;
TMOD &= 0x0F;
TMOD |= 0x10;
TH1 = thr1;
TL1 = tlr1;
TR1 = 1;
ET1 = 1;
EA = 1;
}
/* 定時(shí)器T0中斷服務(wù) */
void Timer0_ISP() interrupt 1
{
TH0 = thr0;
TL0 = tlr0;
flag10ms = 1; //定時(shí)10ms
}
/* 定時(shí)器T1中斷服務(wù) */
void Timer1_ISP() interrupt 3
{
TH1 = thr1;
TL1 = tlr1; //定時(shí)1ms
KeyScan();
}
/**
***********************************************************************
* @file Lcd1602.c
* @author xr
* @date 2014年5月7日13:33:17
* @version V1.2.3
* @brief LCD1602液晶底層驅(qū)動(dòng)
***********************************************************************
*/
#include <reg52.h>
//LCD1602_IO
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_EN = P2^7;
#define LCD1602_DB P0
/* 液晶忙碌等待 */
void LCD1602Wait()
{
unsigned char sta;
LCD1602_DB = 0xFF;//總線拉高,檢測(cè)液晶狀態(tài)字
LCD1602_RS = 0;
LCD1602_RW = 1;
do
{
LCD1602_EN = 1;
sta = LCD1602_DB;
LCD1602_EN = 0;//避免液晶輸出數(shù)據(jù)
} while (sta & 0x80);//狀態(tài)字最高位STA7 == 0空閑,1忙碌
}
/* 液晶寫命令 */
void LCD1602WriteCmd(unsigned char cmd)
{
LCD1602Wait();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_EN = 0;
LCD1602_DB = cmd;
LCD1602_EN = 1;
LCD1602_EN = 0;
}
/* 液晶寫數(shù)據(jù) */
void LCD1602WriteData(unsigned char dat)
{
LCD1602Wait();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_EN = 0;
LCD1602_DB = dat;
LCD1602_EN = 1;
LCD1602_EN = 0;
}
/* 液晶初始化 */
void InitalLCD1602()
{
LCD1602WriteCmd(0x38);
LCD1602WriteCmd(0x0C);
LCD1602WriteCmd(0x06);
LCD1602WriteCmd(0x01);//清屏
}
/* 寫數(shù)據(jù)到液晶上,字符串str,坐標(biāo)(x, y),地址addr */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str)
{
unsigned char addr;
if (y == 0)
{
addr = 0x00 + x;
}
else
{
addr = 0x40 + x;
}
LCD1602WriteCmd(addr | 0x80);
while (*str != '\0')
{
LCD1602WriteData(*str++);
}
}
#include <reg52.h>
/* 按鍵輸出輸入端口定義 */
sbit KEY_IN1 = P1^0;
sbit KEY_IN2 = P1^1;
sbit KEY_IN3 = P1^2;
sbit KEY_IN4 = P1^3;
sbit KEY_OUT1 = P1^7;
sbit KEY_OUT2 = P1^6;
sbit KEY_OUT3 = P1^5;
sbit KEY_OUT4 = P1^4;
extern unsigned char timer[9]; //分別表示跑表的各個(gè)位上的數(shù)字
/* 按鍵當(dāng)前狀態(tài) */
unsigned char volatile keySta[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
/* 按鍵對(duì)應(yīng)標(biāo)準(zhǔn)PC鍵盤編碼 */
const unsigned char code keyCodeMap[4][4] = {
{'1', '2', '3', 0x26}, /* 數(shù)字鍵 1, 2, 3 和 向上鍵 */
{'4', '5', '6', 0x25}, /* 數(shù)字鍵 4, 5, 6 和 向左鍵 */
{'7', '8', '9', 0x28}, /* 數(shù)字鍵 7, 8, 9 和 向下鍵 */
{'0', 0x1B, 0x0D, 0x27} /* 數(shù)字鍵 0 和 向右鍵 */
};
bit stopflag = 0;//跑表走停標(biāo)志位 0 停止,1運(yùn)行
void KeyAction(unsigned char keycode);
void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
/* 按鍵驅(qū)動(dòng)函數(shù) */
void KeyDriver()
{
/* 上一次按鍵的備份值 */
static unsigned char keybackup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
unsigned char i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (keySta[i][j] != keybackup[i][j]) //當(dāng)前按鍵狀態(tài)和上一次的按鍵狀態(tài)不同
{ //按鍵有動(dòng)作
if (keybackup[i][j] != 0) //上一次按鍵是彈起
{
KeyAction(keyCodeMap[i][j]); //當(dāng)前按鍵是想、按下
}
keybackup[i][j] = keySta[i][j]; //備份當(dāng)前按鍵值
}
}
}
}
/* 按鍵掃描函數(shù) */
void KeyScan()
{
unsigned char i = 0;
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}
};
/* 按鍵消抖 */
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN4;
/* 更新按鍵的值 */
for (i = 0; i < 4; i++)
{
if ((keybuf[keyout][i] & 0x1F) == 0x1F)
{
//五次檢測(cè)按鍵的值都是1
keySta[keyout][i] = 1;
}
else if ((keybuf[keyout][i] & 0x1F) == 0x00)
{
//五次檢測(cè)的按鍵值都是0
keySta[keyout][i] = 0;
}
}
/* 按鍵行索引++ */
keyout++;
keyout &= 0x03;//到4歸零
/* 根據(jù)按鍵索引選擇行按鍵進(jìn)行掃描 */
switch (keyout)
{
case 0: KEY_OUT1 = 0; KEY_OUT4 = 1;//選擇第一行按鍵
case 1: KEY_OUT2 = 0; KEY_OUT1 = 1;
case 2: KEY_OUT3 = 0; KEY_OUT2 = 1;
case 3: KEY_OUT4 = 0; KEY_OUT3 = 1;
default: break;
}
}
/* 按鍵動(dòng)作函數(shù) */
void KeyAction(unsigned char keycode)
{
unsigned char i = 0;
if (keycode == 0x3c) //ESC
{
/* 跑表復(fù)位 */
stopflag = 0;
for (i = 0; i < 9; i++)
{
timer[i] = 0;
}
LcdShowStr(2, 1, "0000000.00 s");
LcdShowStr(10, 0, "reset!");
}
else if (keycode == 0x0D) //回車鍵 跑表走停
{
if (stopflag == 0)
{
stopflag = 1;
LcdShowStr(10, 0, "start!");
}
else
{
stopflag = 0;
LcdShowStr(10, 0, "stop! "); //多寫入一個(gè)空格
}
}
}
|
|