快要蓝桥杯了,写个真题练练手---------------------------------------------------------------------------------
内容概要:通过学习单片机。
适合人群:学生,大学生,入门,学习爱好者
能学到什么:一些简单的程序,简单的数码管移位显示,普普通通的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个小时,运行无错误,
望改进。