维修网

 找回密码
 注册

QQ登录

只需一步,快速开始

微信扫码 , 快速开始

搜索附件  
维修网 附件中心 电子技术与产品开发 单片机开发与学习 初学者过来看看:一个c51例子,有矩阵键盘,模拟时钟,I2C,数码: fed70fea.rar

热门下载

附件中心&附件聚合2.0
For Discuz! X2.5 © hgcad.com

初学者过来看看:一个c51例子,有矩阵键盘,模拟时钟,I2C,数码: fed70fea.rar

 

初学者过来看看:一个c51例子,有矩阵键盘,模拟时钟,I2C,数码:
程序不够精炼,仅供参考;
       
       
  


//2防区报警+门禁//#include"stdio.h"#include"reg51.h"

#define byte unsigned char#define HIGH 1#define LOW 0#define FALSE 0#define TRUE ~FALSE#define function#define end_if#define end_for#define WRITE 0xA0 /* 定义24C04的器件地址SLA和方向位W */#define READ 0xA1 /* 定义24C04的器件地址SLA和方向位R */#define Code_Size 16sbit Buz =P1^0; //响铃 sbit Num1=P1^4; //第一位sbit Num2=P1^2; //第二位sbit Num3=P1^3; //第三位sbit Num4=P1^1; //第四位sbit SDA =P1^7; //数据sbit SCL =P1^6; //时钟sbit PP =P1^5; //页选sbit Dog =P3^2; //狗sbit Rel =P3^3; //继电器sbit Zone1 =P3^4; //防区1sbit Zone2 =P3^5; //防区2sbit An =P3^6; //出门按钮sbit Mc =P3^7; //门磁开关

unsigned char code table[] = { 0x60,0xfc,0x52,0x58,0xcc,0x49,0x41,0x7c,0x40,0x48,0xbf,0x46}; //显示字符的编码(共阴数码管)unsigned char code ok_time[]={"Time ok"};unsigned char code ok_zon1[]={"Zone 1 code enter ok"};unsigned char code ok_zon2[]={"Zone 2 code enter ok"};unsigned char code ok_zon3[]={"Zone 3 code enter ok"};unsigned char code ok_pass[]={"ass ok"};unsigned char code ok_fort[]={"Zone fortify ok"};unsigned char data zon_tmp_buf[Code_Size];unsigned char idata buffer[4];unsigned char idata timebuf[4];unsigned char idata cipbuf[6];unsigned char idata passbuf[6] = {132,132,132,132,132,132}; //初始密码byte chh,ptr,count0,scan,ch,buz_time,medkey,p,dis_count,Amount,hour,min,sec,a_count,an_count,count8,key_num,kkeeyy;bit zon1_ok,zon2_ok,zon3_ok,pass_ok,scre_ok,fort_ok,time_ok,fpass_rd,fSec,fk,fc,fr,fh,fcip,fan,fz1,fz2,fz3,ffz,fmod,fall,fortify,fortify2,re_count,fa_count,fsec2,fmc,modify;unsigned int count1,count2,count3,count4,count5,count6,time,count7;

//***********************以下为IIC读写程序**********************/***************************************************************************** 函数原型: void function delay(void);* 功 能: 本函数实际上只有一条返回指令, 在具体应用中可视具体要求增加延时 * 指令。****************************************************************************/void function delay( void ) {;}

/***************************************************************************** 函数原型: void function I_start(void);* 功 能: 提供I2C总线工作时序中的起始位。 ****************************************************************************/void function I_start( void ) {SCL = HIGH ;delay() ;SDA = LOW ;delay() ;SCL = LOW ;delay() ;}

/***************************************************************************** 函数原型: void function I_stop(void);* 功 能: 提供I2C总线工作时序中的停止位。****************************************************************************/void function I_stop( void ) {SDA = LOW ;delay() ;SCL = HIGH ;delay() ;SDA = HIGH ;delay() ;SCL = LOW ;delay() ;}

/***************************************************************************** 函数原型: void function I_init(void);* 功 能: I2C总线初始化。在main()函数中应首先调用本函数, 然后再调用* 其它函数。 ****************************************************************************/void function I_init( void ) {SCL = LOW ;I_stop() ;}

/***************************************************************************** 函数原型: bit function I_clock(void);* 功 能: 提供I2C总线的时钟信号, 并返回在时钟电平为高期间SDA 信号线上状* 态。本函数可用于数据发送, 也可用于数据接收。 ****************************************************************************/bit function I_clock( void ) {bit sample ;SCL = HIGH ;delay() ;sample = SDA ;SCL = LOW ;delay() ;return ( sample ) ;}

/***************************************************************************** 函数原型: bit function I_send(byte I_data);* 功 能: 向I2C总线发送8位数据, 并请求一个应答信号ACK。如果收到ACK应答* 则返回1(TRUE), 否则返回0(FALSE)。 ****************************************************************************/bit function I_send( byte I_data ) {register byte i ;/* 发送8位数据 */for ( i=0 ; i<8 ; i++ ) { SDA = (bit)( I_data & 0x80 ) ; I_data = I_data << 1 ; I_clock() ;end_for}/* 请求应答信号ACK */SDA = HIGH ;return ( ~I_clock() ) ; }

/***************************************************************************** 函数原型: byte function I_receive(void);* 功 能: 从I2C总线上接收8位数据信号, 并将接收到8位数据作为一个字节* 返回, 不回送应答信号ACK。主函数在调用本函数之前应保证SDA信* 号线处于浮置状态, 即使8051的P1.7脚置1。 ****************************************************************************/byte function I_receive( void ) {byte I_data = 0 ;register byte i ;for ( i=0 ; i<8 ; i++ ) { I_data *= 2 ; if ( I_clock() ) I_data++ ; end_ifend_for }return ( I_data ) ;}

/***************************************************************************** 函数原型: void function I_Ack(void);* 功 能: 向I2C总线发送一个应答信号ACK, 一般用于连续数据读取时。*****************************************************************************/void function I_Ack( void ) {SDA = LOW ;I_clock() ;SDA = HIGH ;}/* =========================================================================* * 上面给出的是I2C总线基本操作函数, 下面给出的是几个对I2C总线接口器件* 24C04操作的函数。* =========================================================================*/

/***************************************************************************** 函数原型: bit function E_address(byte Address);* 功 能: 向24C04写入器件地址和一个指定的字节地址。*****************************************************************************/bit function E_address( byte Address ) {I_start() ;if ( I_send( WRITE ) ) return ( I_send( Address ) ) ;else return ( FALSE ) ;end_if}

/***************************************************************************** 函数原型: bit function E_read_block(void);* 功 能: 从24C04中读取BLOCK_SIZE个字节的数据并转存于外部RAM存储映象* 单元, 采用序列读操作方式从片内0地址开始连续读取数据。如果* 24C04不接受指定的地址则返回0(FALSE)。*****************************************************************************/bit function E_read_block(unsigned char re_type,unsigned char rd,unsigned char re_size) {register byte i ;/* 从地址rd开始读取数据 */ if ( E_address( rd ) ) { /* 发送重复启动信号 */ I_start() ; if ( I_send( READ ) ) { for ( i=0 ; i<=re_size ; i++ ) { switch(re_type){ case 1: passbuf = ( I_receive()); break; case 2: zon_tmp_buf = ( I_receive()); break; case 3: passbuf = ( I_receive()); break; } if ( i != re_size ) I_Ack() ; else { I_clock() ; I_stop() ; end_if } end_for } return ( TRUE ) ; } else { I_stop() ; return ( FALSE ) ; end_if } } else I_stop() ; return ( FALSE ) ; end_if}

/***************************************************************************** 函数原型: void function wait_5ms(void);* 功 能: 提供5ms延时(时钟频率为12MHz)。****************************************************************************/void function wait_5ms( void ) {register int i ;for ( i=0 ; i<1000 ; i++ ) ;end_for}

/***************************************************************************** 函数原型: bit function E_write_block(void);* 功 能: 将外部RAM存储映象单元中的数据写入到24C04的头BLOCK_SIZE个字节。* 采用字节写操作方式, 每次写入时都需要指定片内地址。如果24C04* 不接受指定的地址或某个传送的字节未收到应答信号ACK, 则返回0* (FALSE)。 *****************************************************************************/bit function E_write_block(unsigned char wr_buf[32],unsigned char wd,unsigned char wr_size) {register byte i ;for ( i=0 ; i<=wr_size; i++ ) { if ( E_address(wd+i) && I_send( wr_buf ) ) { I_stop() ; wait_5ms(); } else return ( FALSE ) ; end_ifend_for }

return ( TRUE ) ;}

/****************初始化函数*****************************************************/void init(void) { register byte i ; PP=0; fSec=fk=fc=fr=fh=fan=fsec2=fz1=fz2=fz3=ffz=fmod=fall=fk=fa_count=0;fpass_rd=1; Rel=0; Zone1=Zone2=An=Mc=1; count0=scan=ch=buz_time=medkey=p=dis_count=Amount=a_count=0; count1=count2=count3=count4=count5=count6=time=0; for(i=0;i<4;i++) buffer=0;

TCON = 0xff; //串行口初始化1200 8 N 1 和定时器1 TMOD = 0x21; SCON = 0x50; TH1 = TL1 = 0xe8; //波特率1200 TH0 = TL0 = 0; TR1 = 1; ES = 1; ET0 = 1; TR0 = 1; EA = 1;}/************时钟函数**********************************************/unsigned int clock(void){ if(fSec) { fSec=0; sec++; if(sec==60){ min++; sec=0; if(min==60){ hour++; min=0; if(hour==24){hour=0;} }} } return(hour*100+min);}

/**********键盘扫描函数**********************************P2^7---7--8--9 | | |P2^6---4--5--6 | | |P2^5---1--2--3 | | |P2^4---*--0--# | | | P P P 3 2 1**********************************************/unsigned char key(void){ byte sccode,recode; register unsigned int j ; P2=0x0f; if((P2&0x0f)!=0x0f){ for(j=500;j>0;j--){}if((P2&0x0f)!=0x0f){ sccode=0xef; while(sccode!=0xff){ P2=sccode; if((P2&0x0f)!=0x0f){ recode=(P2&0x0f)|0xf0; return((~sccode)+(~recode)); } else sccode=(sccode<<1)|0x01; } } } return(0);}/************发送函数*******函数名:void code_send(unsigned char codebuf[32])*功 能:从串口发送代码**************************************/void code_send(unsigned char codebuf[32]){ register byte ii ; EA=0; ii=0; while(codebuf[ii]!=0) { //发送代码 SBUF=codebuf[ii]; while(TI==0); TI=0; ii++; } EA=1;}/************显示函数*******函数名:void dis(unsigned int tmp)*功 能:将无符号长整形变量 unsingned in tmp 拆散并放入缓冲区 buffer[] 数组**************************************/void dis(unsigned int tmp){ register byte i ; EA=0; for(i=0;i<4;i++) { buffer[3-i]=(unsigned char) (tmp%10);tmp=tmp/10; } EA=1;}

后续;
/************显示函数*******函数名:void key_dis(unsigned char k_tmp)*功 能:转换键盘数值并显示**************************************/

void key_dis(unsigned char k_tmp){ switch(k_tmp){ case 20: fh=1;dis(0);break; case 34: fh=1;dis(1);break; case 36: fh=1;dis(2);break; case 40: fh=1;dis(3);break; case 66: fh=1;dis(4);break; case 68: fh=1;dis(5);break; case 72: fh=1;dis(6);break; case 130: fh=1;dis(7);break; case 132: fh=1;dis(8);break; case 136: fh=1;dis(9);break; default  fh=0;dis(time);break; }}/************执行函数*******函数名:void unlay(void)*功 能:密码输入正确后的动作**************************************/void unlay(void){ if(!ffz) fortify=0; init(); }/************门禁处理函数*******函数名:void janitor(void)*功 能:处理门磁开关和出门按钮**************************************/void janitor(void){ if(!fcip && fsec2){ //条件:0。5秒扫描一次 fsec2=0; if(!An) {fan=1; Buz=0; buz_time=1; an_count=0;} //按钮按下置标志 if(fan) { if(Mc && !fmc){ //30秒内开门 an_count=0; fmc=1; //置标志 } if(fmc){ an_count++; //开门记时 if(an_count==60) { //开门时间超过30秒触发报警3 an_count=0; fmc=0; fan=0; ffz=1; fz3=1; if(function E_read_block(2,200,6)) code_send(zon_tmp_buf); } else { //30秒内门被关上 if(!Mc){ fmc=0; //清以上标志 fan=0; an_count=0; } } } else { //按钮按下后无开门动作 an_count++; if(an_count==60) { //30秒后清标志 an_count=0; fan=0; } } } if(!fan && Mc) fa_count=1; //没有按钮按下而门打开 置标志 if(fa_count){ a_count++; if(a_count==30){ //15秒内未输入密码触发报警3 ffz=1; fz3=1; a_count=0; fa_count=0; if(function E_read_block(2,200,6)) code_send(zon_tmp_buf); } } if(modify) {count8++; if(count8==20) {count8=0; modify=0;}} }}/************防区检测与处理函数*******函数名:void zone(void)*功 能:检测防区并处理**************************************/void zone(void){ if( Zone1 && !fz1) {fz1=1; if(function E_read_block(2,100,6)) code_send(zon_tmp_buf);} if( Zone2 && !fz2) {fz2=1; if(function E_read_block(2,150,6)) code_send(zon_tmp_buf);} if(fz1 || fz2){ ffz=1; } //*****在多个报警同时出现时轮流显示**** if(fz1 && fz2 && fz3) Amount=3; if(fz1 && fz2 && !fz3) Amount=2; if(fz1 && !fz2 && fz3) Amount=2; if(!fz1 && fz2 && fz3) Amount=2; if(fz1 && !fz2 && !fz3) Amount=1; if(!fz1 && fz2 && !fz3) Amount=1; if(!fz1 && !fz2 && fz3) Amount=1;}

/************密码验证函数*******函数名:void cip(void)*功 能:录入密码/验证密码**************************************/void cip(void){ register byte i ; if(fcip){ //录入密码标志为真 if(medkey!=0 && medkey!=18 && medkey!=24){ //*#不录入 passbuf
=medkey; //将密码放入缓冲器 p++; if(p==6){ //密码录入完成,响铃0.5秒提示,清标志 function I_init(); if(function E_write_block(passbuf,23,6)){p=0;fcip=0;Buz=0;buz_time=5;} } } } else{ if(!fpass_rd){ function I_init(); if(function E_read_block(1,23,6)){fpass_rd=1;} } if(medkey==24){if(fortify!=1) fortify=1;} // # 为设防按钮 if(medkey==18){for(i=0;i<6;i++){cipbuf=0;Buz=0;buz_time=5;} } // *为清密码键 if(medkey!=0){ count7=0; if(modify){ switch(medkey){ case 20: kkeeyy=0; break; case 34: kkeeyy=1; break; case 36: kkeeyy=2; break; case 40: kkeeyy=3; break; case 66: kkeeyy=4; break; case 68: kkeeyy=5; break; case 72: kkeeyy=6; break; case 130: kkeeyy=7; break; case 132: kkeeyy=8; break; case 136: kkeeyy=9; break; } timebuf
=kkeeyy; p++; count8=0; if(timebuf[0]>2){ timebuf[1]=timebuf[0]; timebuf[0]=0; p++; } if(timebuf[0]==2 && timebuf[1]>4){ timebuf[2]=timebuf[1]; timebuf[1]=0; p++; } if(timebuf[2]>6){ timebuf[3]=timebuf[2]; timebuf[2]=0; p++; } if(p==4){ modify=0; min=timebuf[2]*10+timebuf[3]; hour=timebuf[0]*10+timebuf[1]; } } else { cipbuf
=medkey; p++; if(p==6) p=0; } } } if(cipbuf[0]==passbuf[0] && cipbuf[1]==passbuf[1] && cipbuf[2]==passbuf[2] && //校验密码 cipbuf[3]==passbuf[3] && cipbuf[4]==passbuf[4] && cipbuf[5]==passbuf[5] ){ //正确后响铃并执行相应动作 unlay(); for(i=0;i<6;i++){cipbuf=0;Buz=0;buz_time=5;} }}/************显示输出函数*******函数名:void show(void)*功 能:按键盘/报警/时钟级别顺序显示**************************************/void show(void){ if(ffz){ //如果有报警 if(!fk){ //如果没有按键按下 fr=0; fh=1; //显示相应防区号 if(dis_count==0) { if(fz1) dis(1); else{ if(fz2) dis(2); else{ if(fz3) dis(3); } } } if(dis_count==1) { if(fz2) dis(2); else{ if(fz3) dis(3); else{ if(fz1) dis(1); } } } if(dis_count==2) { if(fz3) dis(3); else{ if(fz2) dis(2); else{ if(fz1) dis(1); } } } } else key_dis(medkey); //如果有按键按下就显示键值 } else { //如果没有报警 if(modify){ fr=1; fh=0; dis(timebuf[0]*1000+timebuf[1]*100+timebuf[2]*10+timebuf[3]); } else { if(!fk) { //如果没有按键按下 fr=1; fh=0; //时钟标志 dis(time); //显示时间 } else key_dis(medkey); //如果有按键按下就显示键值 } }}/****************************************************************/timerint () interrupt 1{

TR0=0; TL0=0xa8; TH0=0xf8; // 0xf70c for 2.5ms TR0=1;

count1++;if(count1==400){count1=0; fSec=1; fc=~fc; fsec2=1;} //设置秒标志 if(count1==200){fc=~fc; fsec2=1;} //设置运行标志//****************蜂鸣器****************** if (!Buz){count0++; if(count0==40*buz_time) {count0=0; Buz=1;}} //40为 1/10 秒 if (fk) { count2++; if(count2==800) {fk=0; count2=0;}} //按健释放后再显示按键2秒 if (fcip) {count3++;
if(count3==6000) {fcip=0; Buz=0; buz_time=5;count3=0;}} if (fall) {count6++; if(count6==200) {count6=0; fall=0;}}//**************************************** if(!ffz && !fcip && key_num==20 && !modify) {count7++; if(count7==600) {modify=1; count7=0; p=0; count8=0;}} else count7=0;//****************防区和按钮判断************ if(ffz){modify=0; Rel=1; count4++; if(count4==200) Buz=~Buz; if(count4==400){ Buz=~Buz; count4=0; dis_count++; if(dis_count==Amount) dis_count=0;}}//****************显示扫描****************** P0=0xff; //清显示 switch(scan) { case 0: Num1=0;Num2=Num3=Num4=1;break; //最高位 case 1: Num2=0;Num1=Num3=Num4=1;break; //第二位 case 2: Num3=0;Num1=Num2=Num4=1;break; //第三位 case 3: Num4=0;Num1=Num2=Num3=1;break; //最低位 } ch=buffer[scan]; if(ch==0 && fh){ //fh为消影标志 if(scan!=3) P0=0xff; else P0=table[ch]; } else{ if(scan==1 && fc && fr) P0=table[ch]&table[10]; //fc为时钟运行标志,fr为显示时钟标志 else P0=table[ch]; } if((fortify||ffz) && scan==0 && fc) P0=table[11]; scan++; if(scan==4) {scan=0; Dog=~Dog;}}后续;
/**********键盘扫描函数**********************************P2^7---7--8--9 | | |P2^6---4--5--6 | | |P2^5---1--2--3 | | |P2^4---*--0--# | | | P P P 3 2 1**********************************************/unsigned char key(void){ byte sccode,recode; register unsigned int j ; P2=0x0f; if((P2&0x0f)!=0x0f){ for(j=500;j>0;j--){} if((P2&0x0f)!=0x0f){ sccode=0xef; while(sccode!=0xff){ P2=sccode; if((P2&0x0f)!=0x0f){ recode=(P2&0x0f)|0xf0; return((~sccode)+(~recode)); } else sccode=(sccode<<1)|0x01; } } } return(0);}/************发送函数*******函数名:void code_send(unsigned char codebuf[32])*功 能:从串口发送代码**************************************/void code_send(unsigned char codebuf[32]){ register byte ii ; EA=0; ii=0; while(codebuf[ii]!=0) { //发送代码 SBUF=codebuf[ii]; while(TI==0); TI=0; ii++; } EA=1;}/************显示函数*******函数名:void dis(unsigned int tmp)*功 能:将无符号长整形变量 unsingned in tmp 拆散并放入缓冲区 buffer[] 数组**************************************/void dis(unsigned int tmp){ register byte i ; EA=0; for(i=0;i<4;i++) { buffer[3-i]=(unsigned char) (tmp%10); tmp=tmp/10; } EA=1;}////////////////////////////////////////////////////

//************************串口中断****************************void SerInt() interrupt 4 {unsigned char cbuf[32];register byte i ; if(RI) { RI = 0; chh = SBUF; if(chh!='n'){ // 不是换行符则放入缓冲 if(ptr<32) { cbuf[ptr] = chh; ptr++; } } else { ptr=0; if(cbuf[0]=='P' && cbuf[1]=='C') { //判断是否为PC信息 if(cbuf[2]=='T' && cbuf[3]=='I' && cbuf[4]=='M' && cbuf[5]=='E'){ hour=(cbuf[6]-'0')*10+(cbuf[7]-'0'); min =(cbuf[8]-'0')*10+(cbuf[9]-'0'); time_ok=1; } if(cbuf[2]=='Z' && cbuf[3]=='O' && cbuf[4]=='N' && cbuf[5]=='E'){ for(i=0;i<Code_Size;i++){zon_tmp_buf=cbuf[7+i];} if(cbuf[6]=='1') zon1_ok=1; if(cbuf[6]=='2') zon2_ok=1; if(cbuf[6]=='3') zon3_ok=1; } if(cbuf[2]=='P' && cbuf[3]=='A' && cbuf[4]=='S' && cbuf[5]=='S'&& passbuf[0]==cbuf[6] && passbuf[1]==cbuf[7] && passbuf[2]==cbuf[8] && passbuf[3]==cbuf[9] && passbuf[4]==cbuf[10] && passbuf[5]==cbuf[11]){ passbuf[0]=cbuf[12]; passbuf[1]=cbuf[13]; passbuf[2]=cbuf[14]; passbuf[3]=cbuf[15]; passbuf[4]=cbuf[16]; passbuf[5]=cbuf[17]; pass_ok=1; } if(cbuf[2]=='F' && cbuf[3]=='O' && cbuf[4]=='R' && cbuf[5]=='T'){ fortify=1; fort_ok=1; } if(cbuf[2]=='S' && cbuf[3]=='C' && cbuf[4]=='R' && cbuf[5]=='E' && passbuf[0]==cbuf[6] && passbuf[1]==cbuf[7] && passbuf[2]==cbuf[8] && passbuf[3]==cbuf[9] && passbuf[4]==cbuf[10] && passbuf[5]==cbuf[11]){ fortify=0; scre_ok=1; } } } } }//***********主程序************/main(){ unsigned char oldkey; init(); //初始化 fortify=0;fcip=1; hour=10; min=12; sec=34; fpass_rd=0; while(1) { //进入循环 time=clock(); key_num=key(); if(!key_num) oldkey=0; //清空oldkey if(!fall && !oldkey && key_num) { //有健按下 count2=0; //清计数器 if(key_num!=oldkey){ medkey=oldkey=key_num; Buz=0;buz_time=1; //响铃 fk=1;fall=1; cip(); } } janitor(); if(fortify) zone(); show(); if(ffz && modify) modify=0; if(time_ok){time_ok=0; code_send(ok_time);} if(fort_ok){fort_ok=0; code_send(ok_fort);} if(scre_ok){scre_ok=0; unlay();} if(pass_ok){pass_ok=0; if(function E_write_block(passbuf,23,6) && function E_read_block(1,23,6)) code_send(ok_pass);} if(zon1_ok){zon1_ok=0; if(function E_write_block(zon_tmp_buf,100,Code_Size)) code_send(ok_zon1);} if(zon2_ok){zon2_ok=0; if(function E_write_block(zon_tmp_buf,150,Code_Size)) code_send(ok_zon2);} if(zon3_ok){zon3_ok=0; if(function E_write_block(zon_tmp_buf,200,Code_Size)) code_send(ok_zon3);} }}//***************程序结束*************/

QQ|申请友链|手机版|小黑屋|最新贴|维修网 ( 粤ICP备09047344号

GMT+8, 2024-4-30 02:29 , Processed in 0.853409 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

返回顶部