📄 sy0406.c
字号:
nop;
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
nop;
nop;
SCL=1;
nop;
nop;
nop;
if(SDA==1)
acknow=0; /* 24c02无应答 */
else
acknow=1; /* 发送数据正常 */
SCL=0;
nop;
nop;
}
/*******************************************************************
2051从24c02读数据字节数据接收函数
函数原型: uchar RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数应答从机。
********************************************************************/
uchar RcvByte()
{
uchar retc=0;
uchar count;
SDA=1; /*置数据线为输入方式*/
for(count=0;count<8;count++)
{
nop;
SCL=0; /*置时钟线为低,准备接收数据位*/
nop;
nop; /*时钟低电平周期大于4.7us*/
nop;
nop;
nop;
SCL=1; /*置时钟线为高使数据线上数据有效*/
nop;
nop;
retc=retc<<1;
if(SDA==1)
retc=retc+1; /*读数据位,接收的数据位放入retc中 */
nop;
nop;
}
SCL=0;
nop;
nop;
return(retc);
}
/********************************************************************
主机2051应答子函数
函数原型: void Ack(bit a);
功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack(bit a)
{
if(a==0)
SDA=0; /*在此发出应答或非应答信号 */
else /* 应答 a=0 非应答 a=1 */
SDA=1;
nop;
nop;
nop;
SCL=1;
nop;
nop; /*时钟低电平周期大于4us*/
nop;
nop;
nop;
SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
nop;
nop;
}
/*******************************************************************
用户接口函数
*******************************************************************/
/* 有无子地址表示是否向芯片的特定地址写数据 */
/*******************************************************************
向有子地址器件写入6字节数据函数 对应数据资料中的写模式
函数原型: bit TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no);
功能: 从启动总线到发送从地址,子地址,数据,结束总线的全过程,从器件
地址slaaddress,子地址subaddress,发送内容是s指向的内容,no=字节数
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
bit TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no) /* 向有子地址器件写入6字节数据函数 */
{
uchar i;
Start(); /*启动总线*/
SendByte(slaaddress); /*发送器件地址*/
if(acknow==0)
return(0);
SendByte(subaddress); /*发送器件子地址*/
if(acknow==0)
return(0);
for(i=0;i<no;i++)
{
SendByte(s[i]); /*发送数据*/
if(acknow==0)
return(0);
// s++;
}
Stop(); /*结束总线*/
return(0);
}
/*******************************************************************
向有子地址器件读取4字节数据函数
函数原型: bit TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no);
功能: 从启动总线到发送从地址,子地址,读数据,结束总线的全过程,从器件
地址slaaddress,子地址subaddress,读出的内容放入s, no=字节数
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
bit TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no)
{
uchar i;
Start(); /*启动总线*/
SendByte(slaaddress); /*发送器件从地址*/
if(acknow==0)
return(0);
SendByte(subaddress); /*发送器件子地址*/
if(acknow==0)
return(0);
Stop(); /*结束总线*/
Start(); /*重新启动总线*/
SendByte(slaaddress+1);
if(acknow==0)
return(0);
for(i=0;i<no;i++)
{
* s=RcvByte(); /*接收数据*/
Ack(0); /*发送应答位*/
s++;
}
* s=RcvByte(); /*接收数据*/
Ack(1);
Stop(); /*结束总线*/
return(1);
}
/*--------------------------------------*/
void open(void) /*开门比较密码副程式*/
{
char c; /*宣告变数*/
FLAG1=1; /*设开门标号为1*/
for(c=0;c<6;c++) /*比较六个密码*/
{
if (disple[c]!=bufdata[c]) /*按键值disple[]与密码TAB[]比较是否相等*/
FLAG1=0;
if (FLAG1==0) /*FLAG1=0 表示不相等*/
break; /*跳出此循环*/
}
if(FLAG1==1) /*如FLAG1=1 表示密码相等,令电锁P2.0置0动作*/
{
P2_0=0; /*P2.0置1,使绿色指示灯亮(喇叭响)*/
delay(2000); /*延时*/
TMOD=0x11;
TR1=1;
IE=0x8a; /*8是允许中断,a是TIMER0,TIMER1中断致能位*/
clear(); /*清除屏幕*/
BCD(); /*呼叫BCD十进制转换副程式,转换起始内定时间*/
while (1)
{
do
scan (); /*呼叫键盘扫描副程式,有按时FLAG0会为1*/
while (FLAG0!=1); /*判断有按键输入否?无时返回scan()*/
delay(1000); /*按钮防抖动延时,抗机械反弹跳*/
while(m==P1); /*按钮放开否?*/
switch(tab[ptr]) /*是则测试ptr键盘扫描计数器指标至TAB[]取到的键盘码*/
{
case 0x0c: SEC++;
BCD(); /*是否按"A",是则呼叫BCD码转换副程式*/
break; /*跳出此循环*/
case 0x0d: MIN++;
BCD(); /*是否按"B",是则呼叫BCD码转换副程式*/
break; /*跳出此循环*/
case 0x0e: HOUR++;
BCD(); /*是否按"C",是则呼叫BCD码转换副程式*/
default:break; /*跳出此循环*/
} /*跳至WHILE(1)*/
}
}
}
void speekclose(void)
{
if(disple[0]==5)
P2_0=1; /*P2.0置1,使绿色指示灯灭(喇叭关闭)*/
}
/*--------------------------------------*/
void disp(void) /*显示密码副程式*/
{ char c; /*宣告变数*/
read24c02(); /*呼叫读取密码存放在DATE1[]副程式*/
ptr=0xff;
for(c=0;c<6;c++) /*将密码存放在阵列buft[]存入显示器存放阵列disple[]*/
{
disple[c]=bufdata[c];
}
while(m==P1); /*判断按钮放开否,没有则在此等待*/
clear(); /*有则呼叫清除显示器*/
}
/*--------------------------------------*/
void scan(void) /*扫描键盘副程式*/
{
char a1=0xf7,i; /*A1=0XF7列扫描初值,I行*/
speekclose();
FLAG0=0; /*设按键回应旗号为0,键盘扫描计数指标为0*/
ptr=0;
for(i=0;i<4;i++) /*键盘4个扫描列*/
{
P1=a1; /*列扫描输出,读入P1存入M,以便侦测行与侦测按键是否放开*/
m=P1;
switch(m&0xf0) /*取行的高4位元,侦测那一行被按*/
{
case 0x70: ptr=i*4; /*第一行被按否?是则扫描指标=列X4*/
FLAG0=1; /*是则设FLAG0=1表有按键输入*/
break; /*跳出此循环*/
case 0xb0: ptr=i*4+1; /*第二行被按否?是则扫描指标=列X4+1*/
FLAG0=1; /*是则设FLAG0=1表有按键输入*/
break; /*跳出此循环*/
case 0xd0: ptr=i*4+2; /*第三行被按否?是则扫描指标=列X4+2*/
FLAG0=1; /*是则设FLAG0=1表有按键输入*/
break; /*跳出此循环*/
case 0xe0: ptr=i*4+3; /*第四行被按否?是则扫描指标=列X4+3*/
FLAG0=1; /*是则设FLAG0=1表有按键输入*/
default: break; /*跳出此循环*/
}
if(FLAG0==1)break; /*不为1,则扫描列右移,扫描下一列*/
a1=a1>>1|0x80; /*高位补1,由于P1.7~P1.4未接+5V,而是由指令加载高电平*/
}
} /*返回主程式*/
/*--------------------------------------*/
void service_int0 () interrupt 1 using 2 /*设定每隔3000us中断扫描一次数码管*/
{
ptr1++; /*扫描指标加1*/
TH0=(65536-2000)/256; /*每隔4000US扫描一次*/
TL0=(65536-2000)%256;
while (ptr1>5) ptr1=0; /*ptr1>5表示6个数码管都已经扫描过*/
P0=(ptr1<<4)|disple[ptr1]; /*将扫描值左移至高4位元再加上资料码*/
} /*返回主程式*/
/********************************************************/
void service_int1 () interrupt 3 using 3 /*TIMER1中断副程式--秒计时器*/
{
TH1=(65536-9200)/256; /*重设TIMER1计数值*/
TL1=(65536-9200)%256;
b1--; /*中断次数减1*/
if (b1==0) /*中断次数完成否,是则表1秒到了*/
{
b1=200; /*重设中断次数*/
SEC++; /*秒SEC加1*/
tserial(); /*宣告串口serial发送副程式*/
BCD(); /*呼叫BCD码转换副程式*/
}
TF1=0;
} /*返回主程式*/
/********************************************************/
void uartcom1_in1 () interrupt 4 using 1 /*串行口中断副程式*/
{ uchar v,i=0;
while(RI!=1); /*接收完成否*/
{
RI=0;
v=SBUF; /*接收的数据存入C*/
disple[5]=disple[4];
disple[4]=disple[3];
disple[3]=disple[2];
disple[2]=disple[1];
disple[1]=disple[0];
disple[0]=SBUF;
}
} /*返回主程式*/
/********************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -