#include <STC89C5xRC.H>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_data P0 //数据口
sbit LCD_RS = P2^3; //寄存器选择输入
sbit LCD_RW = P2^4; //液晶读/写控制
sbit LCD_EN = P2^5; //液晶使能控制
sbit K1 = P2^7; //按钮1 开始
sbit K2 = P3^4; //按钮2 模式(选择上限、下限、历史)
sbit K3 = P3^6; //按钮3 加
sbit K4 = P3^7; //按钮4 减
sbit K5 = P3^5; //按钮5 确定
sbit fmq = P1^0; //蜂鸣器警告
//STC89C52RC内部EEPROM操作子函数
void cc(uint addr);
void xcx(uint addr,uchar dat);
uchar dcx(uint addr);
void Q0();
unsigned char code DIS1[16] = {"点击开始进入测量"};
unsigned char DIS2[6] = {"心率"};
unsigned char DIS30[6] = {"下限"};
unsigned char DIS31[6] = {"上限"};
unsigned char DIS32[6] = {"下改"};
unsigned char DIS33[6] = {"上改"};
unsigned char DISxx[2]; //下限显示数组
unsigned char DISsx[4]; //上限显示数组
unsigned char DISls[4]; //历史数据数组
unsigned char DISxl[6]; //当前心率显示数组
unsigned char send[3];
unsigned char DIS4[16] = {"上次结果: "};
unsigned char code DIS5[16] = {"测量中,请稍等 "};
unsigned char code DIS6[]={"健康"};
unsigned char code DIS7[]={"偏高"};
unsigned char code DIS8[]={"偏低"};
unsigned char code DIS9[]={" "};
unsigned char data1[3];
int hrmin,hrmax,hrtmp,hrt,ls,cnt5ms,cnthr,cnt5s,temp1;
unsigned int tstflag,keymflag,minflag,maxflag;
void Delay(unsigned int time)
{
unsigned int i,k ;
for(i=0;i<255;i++)
for(k=0;k<time;k++)
_nop_();
}
bit lcd_busy() //检查LCD忙状态 , lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
void lcd_wcmd(uchar cmd) //写指令数据到LCD , RS=L,RW=L,E=高脉冲,D0-D7=指令码。
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
LCD_EN = 1;
LCD_EN = 0;
}
void lcd_wdat(uchar dat) //写显示数据到LCD ,RS=H,RW=L,E=高脉冲,D0-D7=数据。
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
LCD_EN = 1;
LCD_EN = 0;
}
void lcd_init()// LCD初始化设定
{
lcd_wcmd(0x34); //扩充指令操作
Delay(5);
lcd_wcmd(0x30); //基本指令操作
Delay(5);
lcd_wcmd(0x0C); //显示开,关光标
Delay(5);
lcd_wcmd(0x01); //清除LCD的显示内容
Delay(5);
}
void lcd_pos(unsigned char X,unsigned char Y)//设定显示位置
{
unsigned char pos;
if (X==1)
{X=0x80;}
else if (X==2)
{X=0x90;}
else if (X==3)
{X=0x88;}
else if (X==4)
{X=0x98;}
pos = X+Y ;
lcd_wcmd(pos); //显示地址
}
void clr_screen()// 清屏函数
{
lcd_wcmd(0x34);//扩充指令操作
lcd_wcmd(0x30);//基本指令操作
lcd_wcmd(0x01);//清屏
}
void LCD12864()
{
unsigned char i,u;
lcd_pos(1,0); //设置显示位置为第1行
if(tstflag==0){for(u=0;u<16;u++){lcd_wdat(DIS1[u]);}}
if(tstflag==1){for(u=0;u<16;u++){lcd_wdat(DIS5[u]);}}
lcd_pos(2,0); //设置显示位置为第2行
for(i=0;i<4;i++)
{
lcd_wdat(DIS2[i]);
}
lcd_wcmd(0x92);
for(i=0;i<6;i++)
{
lcd_wdat(DISxl[i]);
}
lcd_wcmd(0x94);
for(i=0;i<4;i++)
{
lcd_wdat(DIS9[i]);
}
lcd_wcmd(0x96);
for(i=0;i<4;i++)
{
if(hrt<hrmin && hrt!=0){lcd_wdat(DIS8[i]);}
else if(hrt>hrmax){lcd_wdat(DIS7[i]);}
else if(hrt==0){lcd_wdat(DIS9[i]);}
else {lcd_wdat(DIS6[i]);}
}
lcd_pos(3,0); //设置显示位置为第3行
if(keymflag==0||keymflag==2)
{for(i=0;i<4;i++)
{
lcd_wdat(DIS30[i]);
}
}
else if (keymflag==1)
{for(i=0;i<4;i++)
{
lcd_wdat(DIS32[i]);
}
}
lcd_wcmd(0x8B);
for(i=0;i<2;i++)
{
lcd_wdat(DISxx[i]);
}
if(keymflag==0||keymflag==1)
{
lcd_wcmd(0x8C);
for(i=0;i<4;i++)
{
lcd_wdat(DIS31[i]);
}
}
else if(keymflag==2)
{
for(i=0;i<4;i++)
{
lcd_wdat(DIS33[i]);
}
}
lcd_wcmd(0x8E );
for(i=0;i<4;i++)
{
lcd_wdat(DISsx[i]);
}
lcd_pos(4,0); //设置显示位置为第4行
for(i=0;i<10;i++)
{
lcd_wdat(DIS4[i]);
}
lcd_wcmd(0x9D);
for(i=0;i<4;i++)
{
lcd_wdat(DISls[i]);
}
}
//从EEPROM中读取第1扇区2002h起的10个数据存入data1数组,data1前两个数据为心率下限和上限,后八个数据位历史心率记录
void readrom()
{
data1[0]=dcx(0x2002);
data1[1]=dcx(0x2004);
data1[2]=dcx(0x2006);
}
//第1扇区2002h起的10个数据地址清空后将data1数组写入(STC单片机eeprom无法直接覆写,必须先清空再写)
void writerom()
{
cc(0x2000);
xcx(0x2002,data1[0]);
xcx(0x2004,data1[1]);
xcx(0x2006,data1[2]);
}
void key()
{
if(K1==0){Delay(30);if(K1==0){tstflag=1;}} //开始/停止测量
if(K2==0){Delay(30);if(K2==0){keymflag=keymflag+1;if(keymflag>2){keymflag=0;}}} //选择操作对象
if(keymflag==1){if(K3==0){Delay(30);if(K3==0){hrmin=hrmin+1;}}
else if(K4==0){Delay(30);if(K4==0){hrmin=hrmin-1;}}
data1[0]=hrmin;} //keymflag为1时修改下限
if(keymflag==2){if(K3==0){Delay(30);if(K3==0){hrmax=hrmax+1;}}
else if(K4==0){Delay(30);if(K4==0){hrmax=hrmax-1;}}
data1[1]=hrmax;} //keymflag为2时修改上限
if(keymflag==0){;} //keymflag为0时不操作
if(K5==0){Delay(30);if(K5==0){writerom();}} //确定,将修改后的参数写入rom
}
void buzz()
{
fmq=1;
Delay(100);
fmq=0;
Delay(100);
fmq=1;
Delay(100);
fmq=0;
Delay(100);
}
void tsthr()
{if(tstflag==1)
{
if(cnt5s==1){hrt=temp1*12;}
else if(cnt5s==2){hrt=temp1*6;}
else if(cnt5s==3){hrt=temp1*4;}
else if(cnt5s==4){
hrt=temp1*3;
if(hrt>hrmax||hrt<hrmin){buzz();}
cnthr=0;
cnt5ms=0;
cnt5s=0;
tstflag=0;
data1[2]=hrt;
writerom();
}
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void main(void)
{
readrom();
lcd_init();
tstflag=0,keymflag=0,cnthr=0,cnt5s=0,cnt5ms=0,fmq=0,minflag=0,maxflag=0;
hrmin=data1[0];
hrmax=data1[1];
ls=data1[2];
EA=1;
TMOD=0x01; //定时器0工作方式1
TH0=0xEE; //初值,每次5ms
TL0=0x00;
ET0=1; //允许定时器0中断
EX0=1; //允许外部中断0
IT0=1; //1为负跳变触发 0为低电平触发
TR0=1;
while(1)
{
EA=1;
tsthr();
DISxx[0]=hrmin/10+0x30;
DISxx[1]=hrmin%10+0x30;
DISsx[0]=' ';
DISsx[1]=hrmax/100+0x30;
DISsx[2]=hrmax%100/10+0x30;
DISsx[3]=hrmax%10+0x30;
DISls[0]=' ';
DISls[1]=ls/100+0x30;
DISls[2]=ls%100/10+0x30;
DISls[3]=ls%10+0x30;
DISxl[0]=' ';
DISxl[1]=hrt/100+0x30;
DISxl[2]=hrt%100/10+0x30;
DISxl[3]=hrt%10+0x30;
DISxl[4]=' ';
DISxl[5]=' ';
key();
LCD12864();
}
}
void timer0(void) interrupt 1
{
TH0=0xEE; //初值,每次5ms
TL0=0x00; // 适当增加TL0可微调延时使之略低于5ms
cnt5ms++;
if(cnt5ms==1000){cnt5s++;temp1=cnthr;cnt5ms=0;}
}
void int0(void) interrupt 0
{
cnthr++;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:擦除某一扇区(每个扇区512字节)
入口:addr = 某一扇区首地址
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void cc(uint addr)
{
// 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
ISP_CONTR = 0x81; // 打开 IAP 功能(ISPEN(ISP_CONTR.7)=1:允许编程改变Flash, 设置 Flash 操作等待时间。
ISP_CMD = 0x03; // 用户可以对"