蓝桥杯备赛笔记.docx

上传人:b****8 文档编号:27939930 上传时间:2023-07-06 格式:DOCX 页数:97 大小:3.84MB
下载 相关 举报
蓝桥杯备赛笔记.docx_第1页
第1页 / 共97页
蓝桥杯备赛笔记.docx_第2页
第2页 / 共97页
蓝桥杯备赛笔记.docx_第3页
第3页 / 共97页
蓝桥杯备赛笔记.docx_第4页
第4页 / 共97页
蓝桥杯备赛笔记.docx_第5页
第5页 / 共97页
点击查看更多>>
下载资源
资源描述

蓝桥杯备赛笔记.docx

《蓝桥杯备赛笔记.docx》由会员分享,可在线阅读,更多相关《蓝桥杯备赛笔记.docx(97页珍藏版)》请在冰豆网上搜索。

蓝桥杯备赛笔记.docx

蓝桥杯备赛笔记

1、P0口的复用

P2口高3位的值

38译码器低电平端口

功能

备注

000(0x00)

Y0

001(0x20)

Y1

010(0x40)

Y2

011(0x60)

Y3

8255的CE引脚

0:

使能8255

1:

禁用8255

100(0x80)

Y4

LED灯锁存信号

0:

点亮LED灯

1:

熄灭LED灯

101(0xA0)

Y5

UNL2003输出锁存信号

0:

断开继电器、禁用直流电机、关闭蜂鸣器

1:

闭合继电器、转动直流电机、开启蜂鸣器

110(0xC0)

Y6

数码管位选锁存信号

0:

禁用该位

1:

使能该位

111(0xE0)

Y7

数码管段选锁存信号

0:

点亮该段

1:

熄灭该段

PS1:

上电后需给所有锁存器初始化(Y5,Y6初始化为0x00,其余初始化为0xFF)

PS2:

使用P0口时,按如下方式:

禁用所有寄存器——P0口赋值——打开目标寄存器——禁用所用寄存器

PS3:

锁存器高电平选通,低电平关闭

/**********************************************

*@brief初始化开发板

*@paramnone

*@returnnone

************************************************/

voidinitial_board(void)

{

P0_BUS_COMcom;

P2&=0x1F;//禁用所有锁存器

for(com=3;com<8;com++){

if(com==UNL2003||com==DIGITAL_BIT)

P0=0x00;

else

P0=0xFF;

P2|=com<<5;

_nop_();

P2&=0x1F;

}

}

/**********************************************

*@brief通过P0总线传输数据

*@paramcom:

总线占用的端口;databuf:

传输的数据

*@returnnone

************************************************/

voidP0_BUS(unsignedcharcom,unsignedchardatabuf)

{

P2&=0x1F;//禁用所有锁存器

P0=databuf;

P2|=com<<5;

_nop_();

P2&=0x1f;

}

PS4:

数码管段码

unsignedcharcodeNUM[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};

2、按键

一、单按键

单按键按如下流程图获取按键值:

分层思想在按键上的应用:

1、硬件层

从I/0口获取按键信息映射到keybuf(按键寄存器)上

2、驱动层

根据keybuf的值,分析按键是否有效(是否有抖动产生的),并返回按键编码

3、应用层

对不同按键的响应

分层的好处:

如果按键连接的I/O变化,或者按键所在的I/O口不连续,只需修改硬件层的程序,驱动层和应用层则不受影响。

/**********************************************

*@brief初始化键盘

*@paramnone

*@returnnone

************************************************/

voidinitial_key(void)

{

KEY0=1;

KEY1=1;

KEY2=1;

KEY3=1;

}

/**********************************************

*@brief读键值(硬件层)

*@paramnone

*@return读取的键值

************************************************/

staticuint8get_keybuf(void)

{

uint8keybuf;

keybuf=P3&0x0F;

returnkeybuf;

}

/**********************************************

*@brief获取按键编码值(驱动层)

*@paramnone

*@return按键的编码值

************************************************/

uint8readkey(void)

{

staticuint8lastkey=NOKEY;//上一次获取的键值

staticuint16keycount=0;//获取同一键值的次数

staticuint16keyovertime=KEY_OVER_TIME;//进入连击延时

staticuint16upspeed=0;//加速相应(长按越久连击延时越短)

uint8keytemp=NOKEY;//保存当前获取的键值

keytemp=get_keybuf();

if(keytemp==NOKEY){//是否有按键按下

keycount=0;

upspeed=0;

keyovertime=KEY_OVER_TIME;//退出连击模式

returnNOKEY;

}else{

if(keytemp==lastkey){//是否和上一次键值相同

if(++keycount==KEY_WOBBLE_TIME){//是否到达有效按键次数

returnkeytemp;

}else{

if(keycount>keyovertime){//是否长按进入连击模式

keycount=0;

if(upspeed

upspeed+=50;

keyovertime=KEY_QUICK_TIME-upspeed;//进入连击模式

}

returnNOKEY;

}//else

}else{

lastkey=keytemp;//保留上一次按键值

keycount=0;

upspeed=0;

keyovertime=KEY_OVER_TIME;

returnNOKEY;

}//else

}//else

}

二、矩阵键盘

矩阵键盘原理介绍:

如图,当按下S7时P30和P37将相连。

这个时候有四种情况:

按下S7前P30的状态

按下S7前P37的状态

按下S7后

0

0

都为0

0

1

都为0(I/O口特性,P37会被P30拉低)

1

0

都为0

1

1

都为1

由上表可知,在S7按下前,只有在P30和P37处于不同状态下,S7才能使P30或P37状态产生变化,这样单片机才能检测到按键。

因此,矩阵键盘不能像单按键一样,把I/O全部拉高就可以(如果全部拉高,即P30与P37都为1,这样不管按键怎么按,两个I/O的状态始终不变,单片机当然无法检测到)。

其他按键同理可得,既然状态设为不同按键才能产生响应,那么要初始化为0xF0H还是0x0FH呢?

如果初始化为0x0FH,同一行按键按下时(例如S7,S11,S15,S19)都会使P30变为低电平,无法分别是同一行中哪一个按键产生反应。

若初始化为0XF0H,则会无法分辨同列的按键。

怎么办?

通常有以下两种方法:

1、扫描法

1)初始化为0xFFH

2)拉低P30(即先扫描第一行)

3)检测P34~P37中有无被拉低的引脚

4)若检测到P34~P37中有引脚被拉低,即可以确定按键,若无引脚被拉低,初始化为0xFFH后扫描下一行。

charget_num(void)

{

unsignedchari,j,m,n;

for(i=1,m=0x01;i<=4;i++,m=m<<1)

{

P3=0xFF&~m;

for(j=1,n=0x10;j<=4;j++,n=n<<1)

if((P3&n)==0)

returni*4-(4-j)-1;

}

return16;

}

2、线翻转法

1)令P3=0x0F;

2)获取P3口的值,获取行按键,保存到KEY_ROW里

3)令P3=0xF0;

4)获取P3口的值,获取列按键,保存到KEY_COL里

5)结合KEY_ROW和KEY_COL(KEY_COL|KEY_ROW),即可获取按键值。

假设按下的按键为S4,按以上步骤,则,KEY_ROW的值为0x07H,KEY_COL的值为0x70H。

KEY_COL|KEY_ROW=0x77。

其他按键同理,可以获得不同编码。

结合单按键的算法,对矩阵键盘进行消抖(把行按键当成单按键看待,当行按键消抖完成后,再获取一次列按键,生成按键编码返回)。

/**********************************************

*@brief初始化键盘

*@paramnone

*@returnnone

************************************************/

voidinitial_key(void)

{

KEYBOARD=0xFF;

}

/**********************************************

*@brief读键值(硬件层)

*@paramRowOrCol:

0为读取行键值,1为读取列键值

*@return读取的键值

************************************************/

staticuint8get_keybuf(BOOLRowOrCol)

{

uint8keybuf;

if(RowOrCol){

KEYBOARD=0xF0;

keybuf=KEYBOARD&0xF0;

}else{

KEYBOARD=0x0F;

keybuf=KEYBOARD&0x0F;

}

returnkeybuf;

}

/**********************************************

*@brief获取按键编码值(驱动层)

*@paramnone

*@return按键的编码值

************************************************/

uint8readkey(void)

{

staticuint8lastkey=NOKEY;//上一次获取的键值

staticuint16keycount=0;//获取同一键值的次数

staticuint16keyovertime=KEY_OVER_TIME;//进入连击延时

staticuint16upspeed=0;//加速相应(长按越久连击延时越短)

uint8keytemp_row=NOKEY;//保存当前获取的行键值

uint8keytemp_col=NOKEY;//保存当前获取的列键值

uint8keyvalue=NOKEY;

keytemp_row=get_keybuf(0);

if(keytemp_row==(NOKEY&0x0F)){//是否有按键按下

keycount=0;

upspeed=0;

keyovertime=KEY_OVER_TIME;//退出连击模式

returnNOKEY;

}else{

if(keytemp_row==lastkey){//是否和上一次键值相同

if(++keycount==KEY_WOBBLE_TIME){//是否到达有效按键次数

keytemp_col=get_keybuf

(1);

switch(keytemp_row|keytemp_col){

case0x77:

keyvalue=0;break;

case0xB7:

keyvalue=1;break;

case0xD7:

keyvalue=2;break;

case0xE7:

keyvalue=3;break;

case0x7B:

keyvalue=4;break;

case0xBB:

keyvalue=5;break;

case0xDB:

keyvalue=6;break;

case0xEB:

keyvalue=7;break;

case0x7D:

keyvalue=8;break;

case0xBD:

keyvalue=9;break;

case0xDD:

keyvalue=10;break;

case0xED:

keyvalue=11;break;

case0x7E:

keyvalue=12;break;

case0xBE:

keyvalue=13;break;

case0xDE:

keyvalue=14;break;

case0xEE:

keyvalue=15;break;

default:

break;

}

returnkeyvalue;

}else{

if(keycount>keyovertime){//是否长按进入连击模式

keycount=0;

if(upspeed

upspeed+=25;//增加连击响应的速度

keyovertime=KEY_QUICK_TIME-upspeed;//进入连击模式

}

returnNOKEY;

}//else

}else{

lastkey=keytemp_row;//保留上一次按键值

keycount=0;

upspeed=0;

keyovertime=KEY_OVER_TIME;

returnNOKEY;

}//else

}//else

}

如果相对多键同时按也产生响应时(视为不同与单按键),只需在switch添加响应的键值即可。

例如同时按下S4,S5,添加的键值应为:

0x73H

PS:

以上程序若使用IAP15F2K61S2-89C52转换板,着会发现,按下键值键盘第一列与第二列时没有反应(从左往右),这是应为,IAP15F2K61S2-89C52转换板默认用P42和P44代替P36和P37。

按照分层思想,只需更改硬件层的代码,即可解决问题。

/**********************************************

*@brief读键值

*@paramRowOrCol:

0为读取行键值,1为读取列键值

*@return读取的键值

************************************************/

staticuint8get_keybuf(BOOLRowOrCol)

{

uint8keybuf;

if(RowOrCol){

KEYBOARD=0x30;

P4|=0x14;//由于转接板问题,键盘列3、列4分别接在P42、P44上

keybuf=KEYBOARD&0x30;

if(P4&0x04)

keybuf|=0x40;

if(P4&0x10)

keybuf|=0x80;

}else{

KEYBOARD=0x0F;

P4&=0xEB;

keybuf=KEYBOARD&0x0F;

}

returnkeybuf;

}

三、外部中断

IAP15有5个外部中断,分别为

中断类型

占用引脚

中断号

相关寄存器

INT0

P3.2

0

IE(B0):

是否开启中断

TCON(B0,B1):

中断的触发类型、

中断标志位

INT1

P3.3

2

IE(B2):

是否开启中断

TCON(B2,B3):

中断的触发类型、

中断标志位

INT2

P3.6

10

INT_CLKO(B3):

是否开启中断

INT3

P3.7

11

INT_CLKO(B4):

是否开启中断

INT4

P3.0

16

INT_CLKO(B6):

是否开启中断

在CT107D89训练板上,可以直接使用有INT0,INT1,INT4三个外部中断,其中INT0和INT1可以通过配置TCON寄存器中的IT0,IT1位选择下降沿触发

(1)或上升沿与下降沿触发(0),INT4仅能使用下降沿触发

使用外部中断通常需要以下两步:

①:

初始化所需中断(配置相关寄存器)

②:

编写中断服务程序

①初始化中断

开启相关中断位即总中断,选择合适的中断模式。

以上是初始化需要做的。

INT0和INT1中断允许位在IE寄存器

EX0:

0:

关闭INT0;1:

开启INT0;

EX1:

0:

关闭INT1;1:

开启INT1;

IE寄存器可以按位寻址,以开启INT0为例,

可以用IE|=0x01H;来开启INT0。

或者可以使用EX0=1;来开启INT0。

不管使用哪种方式,最后都不要忘记打开总中断开关EA。

INT4中断允许位在INT_CLKO寄存器

EX4:

0:

关闭INT4;1:

开启INT4;

该寄存器不能按位寻址,因此只能用INT_CLKO|=0x40H;来开启INT4。

允许中断中后,可以在TCON寄存器配置外部中断类型

IT0:

0:

INT0仅下降沿触发;1:

INT0可以由上升沿和下降沿触发

IE0:

INT0中断标志位,产生INT0中断后置‘1’,响应中断后硬件自动清0

IT1:

0:

INT1仅下降沿触发;1:

INT1可以由上升沿和下降沿触发

IE1:

INT1中断标志位,产生INT1中断后置‘1’,响应中断后硬件自动清0

仅INT0和INT1支持中断类型的选择,INT4只能使用下降沿触发中断。

当IT0=0时,INT0上升沿与下降沿触发中断;当IT0=1时,INT0下降沿触发中断。

INT1与IT1的关系同上

若上电后开启INT0和INT1中断,不配置IT0与IT1,默认为上升沿与下降沿触发中断。

当产生INT0中断时,IE0会被置1,(INT1中断置位IE1),然后进入中断服务程序,完成中断服务后,硬件自动清零。

INT4的中断标志隐藏,用户不可见。

(INT2,INT3的中断标志位对用户也是隐藏的)。

②编写中断服务程序

中断服务程序就是个特殊的函数。

通常函数要程序要主动在主函数或其他函数内调用,中断函数不能直接调用,只有在相应的中断触发后,CPU会自动进入中断函数。

voidINT0_Routine(void)interrupt0

{

/*dosomething*/

}

以上是INT0的中断函数。

中断函数一般有以下几个特点:

①返回值和参数都为空

②函数名后跟随“interrupt+中断号”

中断函数名可以任意命名,只要名称符合C语言的规范即可,没有特殊的要求。

以下是使用INT0的例子:

voidinitial_exinterrupt(void)

{

INT0=1;

IT0=1;//0:

上升沿和下降沿触发;1:

仅下降沿触发

EX0=1;//使能外部中断1

EA=1;

}

voidINT0_Routine(void)interrupt0

{

COUNT++;

}

四、定时器

IAP15拥有3个定时器:

定时器0,定时器1,定时器2

定时器

溢出中断号

拥有模式

相关寄存器

定时器0

1

模式0 :

16位自动重装模式

模式1:

16位不可重装模式

模式2 :

8位自动重装模式

模式3 :

16位自动重装模式(产生不可屏蔽中断)

AUXR(B7):

配置1T或12T

INT_CLKO(B0) :

是否输出时钟

TMOD(B0~3) :

选择定时器模式

TL0,TH0 

IE(B1):

是否开启中断

TCON(B4,B5) :

是否启动定时器、

定时器中断标志位

定时器1

3

模式0 :

16位自动重装模式

模式1:

16位不可重装模式

模式2 :

8位自动重装模式

AUXR(B6):

配置1T或12T

INT_CLKO(B1) :

是否输出时钟

TMOD(B4~7) :

选择定时器模式

TL1,TH1 

IE(B3):

是否开启中断

TCON(B6,B7) :

是否启动定时器、

定时器中断标志位

定时器2

12

模式0 :

16位自动重装模式

AUXR(B2,B3,B4):

配置1T或12T、

定时还是计数、

是否启动定时器

INT_CLKO(B2) :

是否输出时钟

IE2(B2) :

是否开启中断

T2L,T2H

使用定时器时,一般需要以下几个步骤:

①选择1T模式或者12T模式(配置AUXR寄存器);

②是否输出时钟(配置INT_CLKO寄存器);

③设置定时器模式(配置TMOD、AUXR寄存器);

④设置初值(TL0,TH0,TL1,TH1,T2L,T2H);

⑤是否开启中断(配置IE、IE2寄存器);

⑥开始运行定时器(配置TCON、AUXR寄存器)

⑦编写相应的中断服务函数(开启定时器中断的情况下)。

下面详细介绍上面步骤:

①选择1T模式或者12T模式(配置AUXR寄存器);

T0x12:

0:

定时器0以12T模式运行;1:

定时器0以1T模式运行

T1x12:

0:

定时器1以12T模式运行;1:

定时器1以1T模式运行

T2x12:

0:

定时器2以12T模式运行;1:

定时器2以1T模式运行

当对计时的精度较高,时间较短(微妙级)时,应选用1T模式;当对计时的精度要求较低,时间较长(毫秒级),最

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1