学习计划——蓝桥杯单片机组省赛,第十一届真题,智能门锁

快要蓝桥杯了,写个真题练练手---------------------------------------------------------------------------------

内容概要:通过学习单片机。
适合人群:学生,大学生,入门,学习爱好者
能学到什么:一些简单的程序,简单的数码管移位显示,普普通通的e2prom存储使用
阅读建议:此资源以学习计划——蓝桥杯单片机组省赛,第十一届真题,智能门锁为例子,希望可以共同进步,本人一大一学生,望大佬多给指导

先看题目要求

 

 

 

 题目还是比较简单的,东西比较少;

拿到手,先把iic.文件都添加了(毕竟要e2prom),

自然,头文件加起来

#ifndef __ALL_H__
#define __ALL_H__

#include "STC15F2K60S2.H"
#include "INTRINS.H"
#include "stdio.h"
typedef unsigned char u8 ;
typedef unsigned int u16 ;

#include "delay.h"
#include "port.h"
#include "time.h"
#include "led.h"
#include "led8.h"
#include "key.h"

#include "ad.h"
#include "ds18b20.h"
#include "ds1302.h"
#include "eeprom.h"
#include "iic.h"
#include "onewire.h"
#include "rtc.h"

#include "control.h"
#endif

第一反应先写led8(数码管)

led8.h如下

#include "led8.h"
u8 disp_buf[8]={0,0,0,0,0,0,0,0};
const u8 duan[17] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xc1,0x8c,0x86,0xc8,0xc6};
					 //显示字符   0    1    2    3    4    5    6    7    8    9    灭  -    U	   P	E   N     c
                     //数组下标   0    1    2    3    4    5    6    7    8    9    10  11   12	   13	14	15	 16	
const u8 wei[9] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00};//0100_0000 
//****************************************************
void led8wei_lock(void)
{
	P2 |= 0xc0;//1100_0000  110--Y6 为1 
	P2&=0x1F; // 0001_1111
}
//****************************************************
void led8duan_lock(void)
{
	P2 |= 0xe0;//1110_0000  111--Y7 为1 
	P2&=0x1F; // 000
}
//****************************************************
void DisplayScan(void)
{
	static u8 display_index=0;  //显示位索引

	//先关显示(关位选) 再送段码 送位选
	LED_PORT=wei[8];
	led8wei_lock();
	
	//送段码
	LED_PORT=duan[disp_buf[display_index]];
	led8duan_lock();

	//送位选
	LED_PORT=wei[display_index];
	led8wei_lock();
	
	if(++display_index >= 8)	display_index = 0;	//8位结束回0
}

数码管写好后,可以再把按键程序完成,

key.h如下,

#include "key.h"

u8 GetKey44(void)
{
	u8 key=10;// 10为空值
	
	P33=0;P32=1;P31=1;P30=1;
	P44=1;P42=1;P35=1;P34=1;
	if(!P42)key=11;//清除
	if(!P35)key=22;//修改
	if(!P34)key=33;//输入
	
	P33=1;P32=0;P31=1;P30=1;//下面是输入值
	P44=1;P42=1;P35=1;P34=1;
	if(!P44)key=8;
	if(!P42)key=9;	

	P33=1;P32=1;P31=0;P30=1;
	P44=1;P42=1;P35=1;P34=1;
	if(!P44)key=4;
	if(!P42)key=5;
	if(!P35)key=6;
	if(!P34)key=7;		
	
	P33=1;P32=1;P31=1;P30=0;
	P44=1;P42=1;P35=1;P34=1;
	if(!P44)key=0;
	if(!P42)key=1;
	if(!P35)key=2;
	if(!P34)key=3;	
	
	return key;
}

再把其他杂七杂八的外设和模块写完;

#include"port.h"

//*********************************	
void port_init(void)
{
	P0M0=0;
	P0M1=0;
	P1M0=0;
	P1M1=0;
	P2M0=0;
	P2M1=0;
	P3M0=0;
	P3M1=0;	
}
//********************************
#include "eeprom.h"

#define W2402 0xa0
#define R2402 0xa1

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

void write_eeprom(u8 adr,u8 val)
{
    IIC_Start();
	IIC_SendByte(W2402);
    IIC_WaitAck();
    IIC_SendByte(adr);
    IIC_WaitAck();
    IIC_SendByte(val);
    IIC_WaitAck();
    IIC_Stop();
}

u8 read_eeprom(u8 adr)
{
	unsigned char dat;
  
	IIC_Start();
	IIC_SendByte(W2402);
	IIC_WaitAck();
	IIC_SendByte(adr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(R2402);
	IIC_WaitAck();
	dat = IIC_RecByte();
	IIC_SendAck(0); 
	IIC_Stop();
	
	return dat;
}
//************************
#include"time.h"
bit f_1ms=0;
void Timer0Init(void)		//1001微秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xC2;		//设置定时初始值
	TH0 = 0xD4;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void tim_isr0(void) interrupt 1 //0-INT0  1--T0  2--INT1 3--T1
{
	f_1ms=1;
	DisplayScan();
}
//***********************
#include "all.h"
#define FMQ 	6
#define JDQ		4
u8 ctrl_dat=0x00;

void ctrl_lock(void);
//void fmq_on(void);
void fmq_off(void);
void jdq_on(void);
void jdq_off(void);
//********************************************
void fmq_off(void)//0
{
	if(ctrl_dat&0x40==0)return;//已经off   0100_0000 
	ctrl_dat &= ~(1<<FMQ);
	P0 = ctrl_dat;
	ctrl_lock();	
}
//********************************************
void jdq_off(void)//0
{
	if(ctrl_dat&0x10==0)return;//已经off   0001_0000 
	ctrl_dat &= ~(1<<JDQ);
	P0 = ctrl_dat;
	ctrl_lock();	
}
//********************************************
void jdq_on(void)//1
{
	if(ctrl_dat&0x10 != 0)return;//已经on   0001_0000  	
	ctrl_dat |= 1<<JDQ;
	P0 = ctrl_dat;
	ctrl_lock();	
}

//********************************************
void ctrl_lock(void)
{
	P2 |= 0xa0;
	P2 &= 0x1f;
}
//************************************
#include"led.h"
u8 led_dat=0;
//****************************************************	
void led_lock(void)
{
	P2 |= 0x80;//1000_0000  100-Y4 
	P2&=0x1F; // 000
}
//********************************
void led_out(u8 dat)
{
	LED_PORT = ~dat;
	led_lock();
}
//************************************************
void led_xout(u8 dat)
{
	led_dat ^= dat;
	LED_PORT = ~led_dat;
	led_lock();
}
//****************************************************
void led_on(u8 dat)
{
	u8 temp=0;
	
	if (dat==0)return; 
		dat--;
	
	temp = 1<<dat;
	if(led_dat & temp==0)return;
	led_dat |= temp;
	led_out(led_dat);
}
//****************************************************
void led_off(u8 dat)
{
	u8 temp=0;
	
	if (dat==0)return; 
		dat--;
	
	temp = 1<<dat;
	if(led_dat & temp==0)return;
	led_dat &= ~temp;
	led_out(led_dat);
}
//****************************************************

最后一部,可以写主函数了(万事俱备只欠东风)

主函数部分————

void main(void)
{
	init();
	ET0=1;EA=1;
	while(1)
	{
		tim_mainloop();
		keypd_mainloop();
		state_mainloop();
	}
}

变量设置部分

#include "all.h"

bit f_20ms=0;
bit f_5ms =0;
bit wrong = 0;//错误标志位
bit modify = 0;//清除标志位

u16 led_5s;//led5秒标志位
u16 open_5s;//门开5秒标志位
u8 code_count=0;//密码组合标志
u8 key_code;
u8 password[6];//初始密码
u8 input[6];//输入密码

void init(void);
void code_in(void);//写入
void code_out(void);//读取

void keypd_mainloop(void);
void tim_mainloop(void);
void state_mainloop(void);

void disp_temp(void);
void disp_on(void);
void disp_set(u16 dat);

初始化函数

void init(void)
{
	port_init();
	//e2prom写入
	code_in();
	
	//e2prom读取	
	code_out();
	
	//fmq,jdq 灭
	fmq_off();jdq_off();
	
	//led  灭
	led_out(0);
	
	//数码管 灭
	disp_temp();
	
	//定时器
	Timer0Init();
}

按键判断

void keypd_mainloop(void)
{
	static u8 _state = 0;
	u8 key_temp = 10;

	if (!f_20ms)return;
	f_20ms = 0;

	key_temp = GetKey44();

	switch (_state)
	{
		case 0: if (key_temp != 10)_state = 1;
			break;
		case 1:
			if (key_temp != 10)
			{
				key_code = key_temp;
				_state = 2;
			}
			else
			{
				_state = 0;
			}
			break;
		case 2:
			if (!(key_temp != 10)) _state = 0;
			break;
			
		default:break;
	}
}

计数器函数

void tim_mainloop(void)
{
	static u8 cnt_20ms = 0;
	static u8 cnt_5ms = 0;
	
	if (!f_1ms)return;
	f_1ms = 0;
	
	if (++cnt_5ms >= 5)
	{
		f_5ms = 1; cnt_5ms = 0;
	}
	
	if (++cnt_20ms >= 20)
	{
		f_20ms = 1; cnt_20ms = 0;
	}
	open_5s++;
	led_5s++;
}

led8显示函数

void disp_temp(void)//初始化显示
{
	int i;
	if(!modify)
	{
		for(i=0;i<8;i++)
		{
			disp_buf[i]=10;
		}	
	}
	else
	{
		disp_buf[0] = 11;//GANG
		for(i=1;i<8;i++)
		{
			disp_buf[i]=10;
		}	
	}

}
//********************
void disp_on(void)//开门显示
{
	disp_buf[0] = 0;
	disp_buf[1] = 10 ;//灭
	disp_buf[2] = 10 ;//灭
	disp_buf[3] = 10 ;//灭
	disp_buf[4] = 0;
	disp_buf[5] = 13;//P
	disp_buf[6] = 14;//E
	disp_buf[7] = 15;//N
}

密码的读取与写入

void code_in(void)//写入
{
	u8 i;
	u8 new_ = 0;//e2prom标志位
	new_ = read_eeprom(0x06);//读取读写标志位,防止初始密码不变
	
	if(new_ != 1) //初始密码写入//8888 8888
	{
		new_ = 1;
		write_eeprom(0x06,1);//存入读写标志位
		for (i = 0; i < 6; i++) 
		{
			write_eeprom(0x00 + i, 8);
			Delay10ms();
		}
	}
	else
	{
		for (i = 0; i < 6; i++) //非第一次通电状态
		{
			write_eeprom(0x00 + i, password[i]); 
			Delay10ms();
		}	
	
	}
}
//**************************
void code_out(void)//读取
{
	int i;
	for (i = 0; i < 6; i++) 
	{
		password[i] = read_eeprom(0x00 +i);
		Delay10ms();
	}
}

主体控制程序

void state_mainloop(void)
{
	static u8 state = 0;
	int i;
	
	if(!f_5ms)return; //消去led虚影
	f_5ms = 0;
	
	switch(state)
	{
		case 0://初始态
			if(key_code == 33) 
			{
				state = 1;//输入开启
			}break;
			
		case 1://输入态 				
			disp_buf[0] = 11;//GANG
			led_on(7);
		
			if((key_code >= 0) && (key_code < 10))//数字判断
			{
				modify = 0;
				input[code_count]=key_code;
				
				for(i=7-code_count;i<8;i++)//密码移位
				{
					disp_buf[i-1]=disp_buf[i];
				}
				disp_buf[7]=key_code;
				code_count++;
				
				if(code_count==6)
				{
					code_count = 0;
					state = 2;
					led_off(7);
				}
			}
			
			if(key_code == 11)   //清除输入
			{	
				disp_temp();
				code_count = 0;
				modify = 1;
			}
			break;
			
		case 2://判断态//
			for(i=0;i<6;i++)
			{
				if(input[i] == password[i])           //if正确
				{
					state = 3;open_5s = 0;
				}
				else 
				{
					wrong = 1;					
					led_5s = 0;	
					state = 20;
				}
			}
			break;
		case 20://错误态//
			if(wrong)                                 //错误
			{	
				led_on(1);
				if(led_5s == 5000) //初始化
				{
					led_off(1);
					state = 0;
					wrong = 0;
					disp_temp();
				}
			}else state = 0;
			break;
			
		case 3://正确态//s_12
			jdq_on();disp_on();
		
			if(open_5s == 5000 && key_code == 10)
			{
				jdq_off();state=0;disp_temp();
			}
			
			if(key_code == 22)
			{		
				state = 4;jdq_off();disp_temp();open_5s = 0;
			}
			break;
			
		case 4://修改密码
			jdq_on();
			disp_buf[0] = 11;//GANG
			led_on(8);
			if((key_code >= 0) && (key_code < 10))
			{
				modify = 0;
				password[code_count]=key_code;
				
				for(i=7-code_count;i<8;i++)//密码移位
				{
					disp_buf[i-1]=disp_buf[i];
				}
				disp_buf[7]=key_code;
				code_count++;
				
				if(code_count==6)
				{
					code_in();
					code_count = 0;
					state = 3;
					led_off(8);
					open_5s=0;
				}
			}
			
			if(key_code == 11)//清除密码修改
			{
				disp_temp();
				modify = 1;
				code_count = 0;	
				code_out();
			}
			
			if(open_5s == 5000 && key_code == 10)
			{
				jdq_off();state=0;disp_temp();led_off(8);
			}
			break;
	}
	key_code = 10;
}

当然,头文件就不发了,简简单单加名字就行;

整体程序完成花了2个小时,运行无错误,

望改进。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

D77happyday

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值