用单片机C语言控制6位密码锁。要求有一个清除键和确认键,密码输错了会有报警音。请高手帮助了

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用单片机C语言控制6位密码锁。要求有一个清除键和确认键,密码输错了会有报警音。请高手帮助了相关的知识,希望对你有一定的参考价值。

程序简单易懂,能实现这些功能就行,我做个毕业设计

我找到了一个,来自《51单片机C语言应用技术开发大全》
SCH图正在绘制中。。。

#include <REGX51.H>//51单片机的头文件
typedef unsigned char uchar; //类型定义,定义uchar类型
typedef unsigned int uint; //类型定义,定义uint 类型
//键盘子程序相关说明。
#define BLANKCHAR 10 //定义空白常量
#define PCHAR 11 //定义字符P常量
#define OPENCHAR 12 //定义开锁字符常量
#define ALARMCHAR 13 //定义字符A常量
#define LINECHAR 14 //定义字符-常量
#define BACKKEY 0X0D //定义退格键常量
#define ENTERKEY 0X0F //定义确认键常量
#define LOCKKEY 0X0E //定义闭锁键常量
#define NO_KEY 20 //定义无按键返回值
#define KEYPORT P2 //定义键盘端口
//Delay1Ms
void Delay1Ms()

uint i;
for (i=0;i<1000;i++);

//定义按键扫描码表 按键扫描时,4位列线和4位行线组成字节数据表
uchar code KEYCODE[]=
0XEE,0XED,0XEB,0XE7,
0XDE,0XDD,0XDB,0XD7,
0XBE,0XBD,0XBB,0XB7,
0X7E,0X7D,0X7B,0X77;
uchar KeyPre; //保存上次扫描按键的键值
uchar KeyUp;
//用于控制按键去抖动操作。1:扫描时去抖动 2:等待释放 3:释放时去抖动。
#define LEDPORT P0 //定义显示器段码输出端口
#define LEDCON P1 //定义显示器位控制端口
uchar code SEGCODE[]=
0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,// 0~9的共阳极代码
0xff,//不显示的共阳极段码
0X8C,//字符P的共阳极段码
0X8F,//┝的共阳极段码
0X88,//字符A的共阳极段码
0XBF,//字符-的共阳极段码
;
//定义LED位码控制码
uchar code BITCODE[]=0Xfe,0Xfd,0Xfb,0Xf7,0Xef,0Xdf,0Xbf,0X7f;
uchar DispBuf[6]; //保存显示的字符
bit DispNormal; //控制显示时,是正常显示还是闪烁显示。
uchar DispCnt; //控制闪烁显示时的频率。
#define SHORT_TIME 10 //蜂鸣器响200ms
#define LONG_TIME 100 //蜂鸣器响2s
#define LONGER_TIME 9000 //蜂鸣器响3 minutes
sbit ALARMCON=P3^4; //定义报警控制引脚
bit AlarmEnable; //是否报警或声音提示
uint AlarmTime; //控制报警时间长度
sbit LOCKCON=P3^3; //定义电子锁控制引脚
uchar code PassWord[]=1,2,3,4,5; //定义初时密码表
uchar PassInBuf[6]; //保存输入的密码字符
uchar PassPosi; //用户输入密码字符存放在PassInBuf[]的位置。
bit TimerBit; //20ms定时时间到
uchar SysMode; //系统所处模式 0:输入密码模式 1:报警模式 2:开锁模式
uchar ErrorCnt; //用户连续输入密码出错次数。
/*
入口参数:
FillChar:写入缓冲区的字符
出口参数:无
*/
void Fill_Buf(uchar FillChar)

uchar i;
for(i=0;i<6;i++)

DispBuf[i]=FillChar;//用字符FillChar填充DispBuf[i]
PassInBuf[i]=FillChar; //用字符FillChar填充PassInBuf [i]


void Fill_Buf_P()

Fill_Buf(BLANKCHAR); // DispBuf[1..5]= ' '
DispBuf[0]=PCHAR;// DispBuf[0]='P'

void Fill_Buf_O()

Fill_Buf(BLANKCHAR); // DispBuf[1..5]= ' '
DispBuf[0]=OPENCHAR; // DispBuf[0]='┝'

void Fill_Buf_A()

Fill_Buf(LINECHAR); // DispBuf[1..5]= ' -----'
DispBuf[0]=ALARMCHAR; // DispBuf[0]='A'

/*
入口参数:
DispPosi:要显示数据的LED号。
DispChar:要显示的内容。
出口参数:无
*/
void Disp_Led_Sin(uchar DispChar,uchar DispPosi)

LEDPORT=SEGCODE[DispChar];//输出显示段码
LEDCON&=BITCODE[DispPosi];//输出显示位码
Delay1Ms(); //延时1MS
LEDCON|=0X3F;//关闭显示器

/*(2)关闭显示函数Disp_Led_OFF。
函数Disp_Led_OFF在显示器上显示空白字符,主要用在闪烁显示。函数通过6次调用Disp_Led_Sin实现所需功能。代码如下:*/
void Disp_Led_OFF()

uchar i;
LEDCON|=0X3F;// 关闭显示器
for(i=0;i<6;i++)

Disp_Led_Sin(BLANKCHAR,i);//逐个显示空白字符


void Disp_Led_All()

uchar i;
LEDCON|=0X3F; // 关闭显示器
for(i=0;i<6;i++)

Disp_Led_Sin(DispBuf[i],i); //显示DispBuf[]中的数值


void Disp_LED()

DispCnt++;
DispCnt%=10;
if(DispCnt==0)

DispNormal=~DispNormal;//200ms将闪烁显示控制位取反

if(SysMode==1)
//报警模式,闪烁显示
if(!DispNormal)

Disp_Led_OFF();//显示空白字符
return;


Disp_Led_All();//显示DispBuf[]中的数值

/*
入口参数:
stime:蜂鸣器鸣叫时间。
出口参数:无
*/
void Sys_Speaker(uint stime)

AlarmEnable=1;//允许报警
AlarmTime=stime;//报警时间长短

void Sys_Alarm()

if(AlarmEnable==1)
//允许报警
ALARMCON=0;//报警
AlarmTime--;
if(AlarmTime==0)
//停止报警时间到
AlarmEnable=0;
ALARMCON=1;//禁止报警
if(SysMode==1)
//报警发生在模式1时,要返回模式0
SysMode=0;
Fill_Buf_P();//显示P




/*
入口参数:无
出口参数:按键值或无按键
*/
uchar Find_Key()

uchar KeyTemp,i;
KEYPORT=0xf0;//行线输出0,列线输出全1
KeyTemp=KEYPORT;//读按键端口值
if(KeyTemp==0xf0)
return NO_KEY;//无键按下,返回
KEYPORT=KeyTemp|0x0f;//列线输出,行线输入
KeyTemp=KEYPORT;//读取按键端口值
for(i=0;i<16;i++)

if(KeyTemp==KEYCODE[i])//根据按键端口扫描值,查找按键值
return i;//返回按键值

return NO_KEY;

/*
入口参数:无
出口参数:按键值或无按键
*/
uchar Scan_Key()

uchar KeyTemp;
KeyTemp=Find_Key();//扫描键盘,获得按键值
if(KeyTemp==NO_KEY)

if(KeyUp<2)
//无按键按下,返回
KeyUp=0;
return NO_KEY;

if(KeyUp==2)
//按键要释放,延时去抖动
KeyUp=3;
return NO_KEY;

if(KeyUp==3)
//按键释放,返回键值
KeyUp=0;
return KeyPre;


else

if(KeyUp==0)
//有键按下,保存键值
KeyUp=1;
KeyPre=KeyTemp;

else if(KeyUp==1)
//去抖动后,再次测到有按键按下
if( KeyPre==KeyTemp)
KeyUp=2;
else
KeyPre=KeyTemp;
else if(KeyUp==3)
//等待按键释放
KeyUp=2;


return NO_KEY;

/*
入口参数:
Key:按键值
出口参数:无
*/
void Key_Process(uchar Key)

uchar i;
if(Key==NO_KEY)
return ;//无按键,不处理
switch(SysMode)

case 0://输入密码
switch(Key)

case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
DispBuf[PassPosi]=LINECHAR;//显示'-'
PassInBuf[PassPosi]=Key;//保存用户输入的密码
if(PassPosi<5)
PassPosi++;//调整密码输入位置
Sys_Speaker(SHORT_TIME);//发按键提示音
break;
case BACKKEY://退格键
DispBuf[PassPosi]=BLANKCHAR;//显示' '
PassInBuf[PassPosi]=BLANKCHAR;//清除当前位置的密码
if(PassPosi>1)
PassPosi--;//调整显示位置
Sys_Speaker(SHORT_TIME);//发按键提示音
break;
case ENTERKEY://确定按键
for(i=0;i<5;i++)
//比较用户输入密码与系统预设密码是否一致
if(PassInBuf[i+1]!=PassWord[i])
break;

if(i>=5)
//输入密码正确
Fill_Buf_O();//显示开锁状态
PassPosi=1;
LOCKCON=1;//开锁
ErrorCnt=0;
Sys_Speaker(LONG_TIME);//发长提示音
SysMode=2;//转模式2

else

ErrorCnt++;//出错次数加一
if(ErrorCnt>2)
//次数超过3次
ErrorCnt=0;
Fill_Buf_A();//显示报警状态
PassPosi=1;
Sys_Speaker(LONGER_TIME);//发报警音
SysMode=1;

else
//出错次数少于3次,用户重新输入
Fill_Buf_P();
PassPosi=1;
Sys_Speaker(LONG_TIME);


break;
case LOCKKEY://闭锁键
Fill_Buf_P();//显示P
PassPosi=1;
Sys_Speaker(SHORT_TIME);
break;

break;
case 2://开锁状态
if(Key==LOCKKEY)
//用户按动闭锁按键
Fill_Buf_P();
SysMode=0;
LOCKCON=0;//闭锁
Sys_Speaker(SHORT_TIME);

break;


void Ini_Timer0()

TMOD&=0XF0;
TMOD|=0X01;// 初始化T0,模式1
TR0=0;
TH0=(65536-20000)/256;//T0 赋计数初值
TL0=(65536-20000)%256;
TR0=1;//启动T0
ET0=1;//允许T0中断

void Timer0() interrupt 1

TR0=0;
TH0=(65536-20000)/256; //T0 赋计数初值
TL0=(65536-20000)%256;
TR0=1;
TimerBit=1;//定时时间到

void Ini_System()

PassPosi=1;
LOCKCON=0;//闭锁
Ini_Timer0();//初始化T0
Fill_Buf_P();
EA=1;//允许系统中断

void main()

uchar KeyTemp;
Ini_System();
while(1)

if (TimerBit==1)
//定时时间到
Disp_LED();//刷新显示器
Sys_Alarm();//报警处理
KeyTemp=Scan_Key();//扫描按键
Key_Process(KeyTemp);//按键处理
TimerBit=0;


参考技术A 我博客有相关程序,包含两个单片机的通信,一个为呼叫,另一单片机为应答,当然,如果知道密码也不需要呼叫的密码锁。

说明:

1.基本部分为单片机的串口通信,包含串口通信,键盘扫描

2.程序部分有详细的注释。
/*-------------------------------------------
Project: mimasuo program (V0.1)
Filename: mimasuo.c

Prozessor: 80C51 family
Compiler: Keil Version 6.14

Autor: ********
Copyrigth: 041151**
date: 2008.3.17
------------------------------------------ */

#include<reg51.h>
#define uchar unsigned char
sbit ADCS =P3^6;
sbit ADC =P3^7;
sbit AD =P1^0;
int fafu=0;
uchar key,key1,i,count1=1,yidong=256;
uchar jgh[9]=0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00;//输出指示
uchar jgh1[9]; //输入键盘缓存
uchar mima[9]=0,1,2,3,4,5,6,7,8;//初始8位密码 : 12345678 第0位未用
uchar fangjian[4]=0,2,5,2; //初始门牌号 252 第0位未用
char count=0;

void init_serialcomm(void) //串口波特率设置

SCON=0x50;
TMOD=0x20;
PCON=0x80;
TH1=0x40;
TL1=0x40;//300
TR1=1;
EA=1;
TI=0;
RI=0;

void delay10ms(void) //10毫秒延时程序


unsigned char i,j,k;
for(i=5;i>0;i--)
for(j=4;j>0;j--)
for(k=248;k>0;k--);

uchar kbscan(void) // 键盘扫描程序

uchar sccode,recode;
P1=0xf0; //置所有行为低电平,行扫描,列线输入(此时)
if((P1&0xf0)!=0xf0) //判断是否有有键按下(读取列的真实状态,若第4列有键按下则P1的值会变成0111 0000),有往下执行

delays(); //延时去抖动(10ms)
if((P1&0xf0)!=0xf0) //再次判断列中是否是干扰信号,不是则向下执行

sccode=0xFE; //逐行扫描初值(即先扫描第1行)
while((sccode&0x10)!=0)//行扫描完成时(即4行已经全部扫描完成)sccode为1110 1111 停止while程序

P1=sccode; //输出行扫描码
if ((P1&0xf0)!=0xf0) //本行有键按下(即P1(真实的状态)的高四位不全为1)

recode=(P1&0xf0)|0x0f; //列
return(sccode&recode); //返回行和列

else //所扫描的行没有键按下,则扫描下一行,直到4行都扫描

sccode=(sccode<<1)|0x01;//行扫描码左移一位




else

return 0; //无键按下,返回0



uchar readnumber(uchar tmp) //按键扫描的结果,转换为数字,便于程序对按键数据处理

switch(tmp)

case 0x28:return 0 ;break;
case 0x14:return 1 ;break;
case 0x24:return 2 ;break;
case 0x44:return 3 ;break;
case 0x12:return 4 ;break;
case 0x22:return 5 ;break;
case 0x42:return 6 ;break;
case 0x11:return 7 ;break;
case 0x21:return 8 ;break;
case 0x41:return 9 ;break;
case 0x88:return 10 ;break;
case 0x82:return 11 ;break;
default:break;



void main(void) //主程序

P2=0xff;
init_serialcomm();
while(1)

key=kbscan();
// P2=key;
fafu++;
if(fafu==10000)
fafu=0;
ADCS = 1;
ADC = 1;

if(RI) //呼叫应答

RI=0;
ADCS = 0;
// P2=~P2;


if(key!=0)
do
key1=kbscan();
AD = 0;
while(key1!=0);//等待按键释放
AD = 1;

if(readnumber(key)==10) // 密码比较
count1=1;
for(i=1;i<=8;i++)

if(mima[i]==jgh1[i])
count1++;

if(count1==9)

// P2=~P2;
ADCS = 0;

else ADC=0;


if(readnumber(key)==11) // 呼叫房间
count1=1;
for(i=1;i<=3;i++)

if(fangjian[i]==jgh1[i])
count1++;

if(count1==4) //发送传送码

SBUF=0xf0;
while(TI==0);
TI=0;
P2=~P2;



if((key!=0x88)&&(key!=0x84)&&(key!=0x82)) //数字键输入,并把输入的数据存到数组中
count++;
P2=jgh[count];
jgh1[count]=readnumber(key);
if(count==8)
count=0;

if(key==0x84)
//取消功能键
count--;
if(count<=0)count=0;
P2=jgh[count];





详细代码可以到我博客下载:
http://www.shenzhenwangzhanyouhua.com/seo/danpianji-key-machine.html

参考资料:http://www.shenzhenwangzhanyouhua.com/seo/danpianji-key-machine.html

本回答被提问者采纳
参考技术B 6位密码锁?用矩阵键盘,程序应该还是比较容易实现的。 参考技术C 前段时间帮朋友写了一个,
我在实验板上模拟出来了,
你留个邮箱,
我连那块实验板的原理图一起发给你~

单片机Keil C51 C语言多文件如何使用全局位变量?跪拜!!

建立工程,有3个。c文件, 如1.c 2.c 3.c 。 现要定义一个bdata m变量,要单独操作某一位,特定义sbit x=m^1,要求可以在1.c 2.c 3.c 三个文件中都可以使用或操作m,该如何定义呢?请用过的帮个忙,也许我表达有些问题,就是我要在多个文件都能操作同一个自己定义的可寻址变量中的某一位,从而改变这个可寻址变量。316591813.明早9点后 我会在线,可以在线帮忙,解决后还可再加分,拜托拜托。。。

extern就可以。在一个文件里定义:
bdata m;
sbit x=m^1;
然后在另一个文件里声明:
extern bdata m;(如果不使用m可以不声明。)

extern bit x;
这样就可以使用了。如果变量较多,建议楼上的方法,用全局头文件。
参考技术A 不管你引用再多的文件
main函数只有一个吧!!

如果引用的c文件需要使用全局变量。就把变量写在引用文件前面
比如
int i; //全局变量
#include "1.h"
#include "2.h"
#include "3.h"

不知道能不能帮到你 反正我是这么理解的
参考技术B 新件一个头文件 GLOAB.h
在里面定义好,bata m;
在定义需要的全局变量
最好加上不重复包含头文件的定义
然后1.c,2.c,3.c写上一句
#include“GLOAB.h”就可以用了追问

感谢您的热心帮助,但您回答的不太详细,好像没说“位”的问题,也许是我基础不够没听懂,还是谢谢!

以上是关于用单片机C语言控制6位密码锁。要求有一个清除键和确认键,密码输错了会有报警音。请高手帮助了的主要内容,如果未能解决你的问题,请参考以下文章

《单片机C语言程序设计实训100例——基于8051+Proteus仿真》 第03篇源代码

单片机Keil C51 C语言多文件如何使用全局位变量?跪拜!!

H264录像机密码忘记了,今天超级密码是多少

如何用C语言控制计算机串口

单片机 用汇编语言编写交通红绿灯 只要求红灯30秒,黄灯5秒,绿灯30秒,黄灯5秒,其他不限

单片机 C语言 从AD得到一个8位二进制数 0x00~0xff 想把它换算成小数显示 0.00~1.00