单片机开发工程案例分析与解析

2018-10-30 17:49

主程序开始初始化变量设置定时器T1的参数扫描键盘N按键弹起或按下?Y将当前的键值暂存(Key_val_old)按键是按下?Y启动键启动定时器1取消键关闭定时器1清除变量转换键白天/晚上切换NN定时器1启动且脉冲产生中断?Y清零的30秒计时值清除INT0中断标志N脉冲个数<100(1千米)Y脉冲个数增1距离值增加1千米总价格计算清零的脉冲个数数码管动态扫描显示图3-12 出租车计价器的主程序流程图

中断服务程序主要实现计时功能,当启动键按下之后,定时器开始工作,用一个变量对定时器溢出中断的次数进行计数,达到计时功能,该变量在每次脉冲到来时被清零(在主程序中清零),当脉冲长时间没有来,则当该变量计数超过30秒时,总金额按照途中等待计费标准进行计价。中断程序的流程图如图3-13所示。

中断服务程序开始中断次数+1N计时1秒中断次数>4000Y中断次数=0达到30秒的计时?N30秒的计时++Y途中等待超30秒计价30秒的计时=0结束中断3-13 出租车计价器的中断服务程序流程图

(4)设计系统软件调试方案、硬件调试方案及软硬件联合调试方案

软件调试方案:伟福软件中,在“文件\\新建文件”中,新建C语言源程序文件,编写相应的程序。在“文件\\新建项目”的菜单中,新建项目并将C语言源程序文件包括在项目文件中。

在 “项目\\编译”菜单中将C源文件编译,检查语法错误及逻辑错误。在编译成功后,产生以 “*.hex”和“*.bin” 后缀的目标文件。

硬件调试方案:在设计平台中,将单片机的P1.0-P1.2分别与3个独立式键盘通过插线连接起来,将P3.2与脉冲信号源连接起来。

在伟福中将程序文件编译成目标文件后,将下载线安装在实验平台上,运行“MCU下载程序”,选择相应的flash 数据文件,点击“编程”按钮,将程序文件下载到单片机的Flash中。

然后,上电重新启动单片机,检查所编写的程序是否达到题目的要求,是否全面完整地完成试题的内容。

3.4.2 程序设计

/*晶振:11.0592M T1-250微秒溢出中断一次;P3.2(int0)-中断100次,查询IE0置位,

P1^0为启动键;P1^1为清除键;P1^2为白天/晚上的切换键 变量的定义:

key_val: 返回按键的值 255-无键 T1_cnt: 定时器溢出数计数 cnt_30: 30秒钟的计时 cnt_distance: 计算路程 cnt_cost: 总金额

state_val: 状态:0-白天 1 夜晚

cost_val[3]: 收费标准:白天单价cost_val[0]=1元/公里;晚上单价cost_val[1]=2元/公里;

等待单价cost_val[2]=1元/30s

led_seg_code:数码管7段码 */ //------------------- #include \

unsigned char data cnt_30,cnt_distance,cnt_cost; unsigned int data T1_cnt,D_cnt;

unsigned char data key_val,key_val_old; unsigned char data state_val; char code cost_val[3]={1,2,1}; char

code

led_seg_code[10]={0x3f,0x06,0x05b,0x04f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//led_seg_code[0-9]代表0-9 //-------延时----------------- void delay(unsigned int i)//延时 { while(--i); }

//-------初始化变量------------------ void init_variant() //初始化一些变量的内容 {unsigned char i;

cnt_30=0; //30秒的计时 D_cnt=0; //脉冲的个数 cnt_distance=0; //距离的计数 cnt_cost=0; //保存总价格 }

//-------扫描键盘----------------- unsigned char scan_key() { unsigned char i,k; i=P1;

if (i==0xff)

{ k=255; } //无键按下 else //有键按下 { delay(10); //延时去抖动 if(i!=P1) {k=255;} else

{ switch (i)

{ case 0xfe: k=0; break; //P1.0按下,启动键 case 0xfd: k=1; break; //P1.1按下,清除键 case 0xfb: k=2; break; //P1.2按下,切换键 } } }

return k; }

//-------数码管动态扫描------------- void led_show() {unsigned char i,k; //-----显示单价---- k=cost_val[state_val]; i=k; //暂存个位

3 单片机开发工程案例分析与解析

3.1 定时报警器

设计一个单片机控制的简易定时报警器。要求根据设定的初始值(1-59秒)进行倒计时,当计时到0时数码管闪烁“00”(以1Hz闪烁),按键功能如下:

(1)设定键:在倒计时模式时,按下此键后停止倒计时,进入设置状态;如果已经处于设置状态则此键无效。

(2)增一键:在设置状态时,每按一次递增键,初始值的数字增1。

(3)递一键:在设置状态时,每按一次递减键,初始值的数字减1。

(4)确认键:在设置状态时,按下此键后,单片机按照新的初始值进行倒计时及显示倒计时的数字。如果已经处于计时状态则此键无效。

3.1.2 模块1:系统设计

(1)任务分析与整体设计思路

根据题目的要求,需要实现如下几个方面的功能。

计时功能:要实现计时功能则需要使用定时器来计时,通过设置定时器的初始值来控制溢出中断的时间间隔,再利用一个变量记录定时器溢出的次数,达到定时1秒中的功能。然后,当计时每到1秒钟后,倒计时的计数器减1。当倒计时计数器到0时,触发另一个标志变量,进入闪烁状态。

显示功能:显示倒计时的数字要采用动态扫描的方式将数字拆成“十位”和“个位”动态扫描显示。如果处于闪烁状态,则可以不需要动态扫描显示,只需要控制共阴极数码管的位控线,实现数码管的灭和亮。

键盘扫描和运行模式的切换:主程序在初始化一些变量和寄存器之后,需要不断循环地读取键盘的状态和动态扫描数码管显示相应的数字。根据键盘的按键值实现设置状态、计时状态的切换。

(2)单片机型号及所需外围器件型号,单片机硬件电路原理图 选用MCS-51系列AT89S51单片机作为微控制器,选择两个四联的共阴极数码管组成8位显示模块,由于AT89S51单片机驱动能力有限,采用两片74HC244实现总线的驱动,一个74HC244完成位控线的控制和驱动,另一个74HC244完成数码管的7段码输出,在输出口上各串联一个100欧姆的电阻对7段数码管限流。

由于键盘数量不多,选择独立式按键与P1口连接作为四个按键输入。没有键按下时P1.0-P1.3为高电平,当有键按下时,P1.0-P1.3相应管脚为低电平。电路原理图如图3-1所示。

U5 KEY3KEY4 VCCR5 10KR1210K R1310KR1410K C1 CAP11.0592 C2 CAP KEY1KEY2U21234567813121514VCC311918RST91716P10/TP11/TP12P13P14P15P16P17INT1INT0T1T0EA/VPX1X2RESETRDWR89S52RXDTXDALE/PPSEN10113029P00P01P02P03P04P05P06P07P20P21P22P23P24P25P26P2739383736353433322122232425262728LED_ALED_BLED_CLED_DLED_ELED_FLED_GLED_HLED_J0LED_J1LED_J2LED_J3LED_J4LED_J5LED_J6LED_J7LED_ALED_BLED_CLED_DLED_ELED_FLED_GLED_H246811131517119U31A11A21A31A42A12A22A32A41G2GHC244U4LED_J0LED_J1LED_J2LED_J3VCCC3S1RESETR110022URSTLED_J4LED_J5LED_J6LED_J71113151711924681A11A21A31A42A12A22A32A41G2GHC2441Y11Y21Y31Y42Y12Y22Y32Y4181614129753L_COM1L_COM2L_COM3L_COM4L_COM5L_COM6L_COM7L_COM8LED_H1LED_G1LED_F1LED_E1LED_D1LED_C1LED_B1LED_A110831211962HGFEDCBALED4SCHCOM1COM2COM3COM47L_COM55L_COM64L_COM71L_COM81Y11Y21Y31Y42Y12Y22Y32Y4181614129753R2R3R4R6R7R8R9R10100100100100100100100100LED_A1LED_B1LED_C1LED_D1LED_E1LED_F1LED_G1LED_H1LED_H1LED_G1LED_F1LED_E1LED_D1LED_C1LED_B1LED_A110831211962HGFEDCBALED4SCHU6COM1COM2COM3COM47L_COM15L_COM24L_COM31L_COM4Y110KR11

图3-1 定时报警器电路原理图 (3)程序设计思路,单片机资源分配以及程序流程 ①单片机资源分配

采用单片机的P3口作为按键的输入,使用独立式按键与P3.0-P3.3连接,构成四个功能按键。

在计时功能中,需要三个变量分别暂存定时器溢出的次数(T1_cnt)、倒计时的初始值(init_val)以及当前倒计时的秒数(cnt_val)。

按键扫描功能中,需要两个变量,一个变量(key_val_new)用来存储当前扫描的键值(若无按键按下则为255),另一个变量(key_val_old)用来存储上一次扫描的键值。只有这两个变量值不一样时,才能说明是一次新的按键按下或弹起了,同时将新的键值赋给key_val_old变量。

在显示功能中,需要定义一组数组(code类型),值为0-9数字对应的数码管7段码。还需要定义一个变量(show_val)暂存要显示的数据,用于动态扫描显示中。

在整个程序中,定义了一个状态变量(state_val)用来存储当前单片机工作在哪种状态。 ②程序设计思路

鉴于题目要求,存在三种工作模式:初始值设置模式、倒计时模式、计时到0时的闪烁模式。变量state_val为0时,处于倒计时模式。

变量state_val为1时,处于初始值设置模式。变量state_val为2时,处于闪烁模式。这些状态的切换取决于按下哪一个键以及是否计时到0。状态的切换图如图3-2

State_val=0 计数按下

按下设置键 确认键 按下确认键

按下

递增键倒计数减到0 State_val=1 State_val=2 设置闪烁

按下按下递减键 设置键

图3-2 状态的切换

单片机复位之后,默认处于倒计时模式,启动定时器,定时器每隔250us溢出一次,根据定时器溢出次数来计时,到1秒时将时间的计数器减1。当“设置键”按下时,变量state_val由0变为1,切换到设置模式。可以使用“递增键”“递减键”对计时初始值进行修改。按下“确认键”时,回到计时模式开始以新的初始值进行倒计时。当倒计时到0时,变量state_val由1变为2,处于闪烁状态,在这种状态下,根据按键的情况分别又切换到计时和设置状态。 ③程序流程

主程序首先需要初始化定时器的参数和一些变量,然后进入一个循环结构,在循环中始终只做两件事,一是键盘的扫描,二是数码管的动态扫描。

在扫描键盘后,根据前一次按键的结果是否与本次键值相同。如果

不同,表示有键按下或弹起,同时用本次按键值更新上一次的按键值。这样设计旨在避免一个按键长时间按下时被重复判为有新键按下,使得当前按下的键只有松开后,下一次按下时才算为一次新的按键。 根据按键的值分别改变变量(state_val)的值或者在设置状态时的倒计时初始值。完整的主程序图如图3-3所示。

主程序Mian()初始化变量

和定时器

扫描按键

NKey_new==Key_old

Key_old=Key_newY保存键值

Key_new==1?N NKey_new==2?Y

设置模式YKey_new==3?

关定时器 YKey_new==4?设置模式 初始值-1Y设置模式 计数模式初始值+1 开定时器

动态扫描

图3-3 主程序的流程图

在定时器的参数中,选择定时器

T1的8位自动装载模式,每250us

产生一次溢出中断,中断服务程序如图3-4所示。

audio_out=1; //-----------

init_variant();//清除所有输入,等待下一次输入 }

else //输入错误次数超过3次 { alarm_out=0; //报警灯亮

pw_error=0; //密码错误指示灯亮 error_num=0; //密码输入错误次数清零 //----------

audio_out=0; //长鸣声报警 delay(60000); delay(60000); delay(60000); delay(60000); delay(60000); delay(60000); delay(60000); delay(60000); delay(60000); audio_out=1; //-------------

TR1=1; //打开定时器计时

cnt_state=2; //下一状态处于15秒计时的状态 } } break; case 7://取消键 init_variant(); break; } } }

led_show(); } }

//-----程序结束-----------------

3.4 出租车计价器

设计并制作一台出租车计价器。调试时采用10Hz方波信号模拟,每个方波代表10m。基本要求: (1)不同情况具有不同的收费标准

白天 1元/公里 晚上 2元/ 公里 途中等待(30s)1元/30s

(2)数据输出(6位LED数码管显示)

单价输出2位 路途输出2位 总金额输出2位 (3)按键(3个)

启动计价开关 数据复位(清零) 白天/晚上转换

3.4.1模块1:系统设计

(1)分析任务要求,写出系统整体设计思路

通过分析,需要实现四个主要的功能模块,分别为脉冲计数模块、定时器计时模块、按键的处理以及数码管动态扫描等功能。 定时器计时模块主要完成途中等待(即没有脉冲来时)30秒的计时。在启动键按下后,定时器就不停的计时,只要有脉冲来就将计时的值清除为零。如果没有脉冲来,当计时超过30秒时,相应的总金额要按照收费标准计价。

中断的管理:尽管中断有嵌套以及优先级的功能,但是由于定时器已经使用一个了中断资源,脉冲检测不宜再采用中断方式,而是采用查询方式。由于需要不停的要清除30秒的计时,因此,脉冲的计数

不采用定时器的计数方式。

启动键触发定时器开始工作,而定时器的运行可以作为脉冲计数的标志,只要定时器计时在运行,每来一个中断都应该计数。 主程序完成键盘的扫描和按键的处理,查询脉冲产生的中断,并完成脉冲的计数。每个脉冲代表10米,则当计数到100时表示1千米的距离,相应的总金额要按照收费标准计价

(2)选择单片机型号和所需外围器件型号,设计单片机硬件电路原理图

采用MCS51系列单片机At89S51作为主控制器,外围电路器件包括数码管驱动、独立式键盘、复位电路等。硬件电路原理图如图3-9所示。

U5 P10KEY2 P11KEY3P12 VCCR 510KR1210K R1310K 脉冲输入 C1 CAPY1 11.0592C2 CAP KEY1U21234567813121514VCC311918RST91716P10/TP11/TP12P13P14P15P16P17INT1INT0T1T0EA/VPX1X2RESETRDWR89S52RXDTXDALE/PPSEN10113029P00P01P02P03P04P05P06P07P20P21P22P23P24P25P26P2739383736353433322122232425262728LED_ALED_BLED_CLED_DLED_ELED_FLED_GLED_HLED_J0LED_J1LED_J2LED_J3LED_J4LED_J5LED_J6LED_J7LED_ALED_BLED_CLED_DLED_ELED_FLED_GLED_H246811131517119U31A11A21A31A42A12A22A32A41G2GHC244U4LED_J0LED_J1LED_J2LED_J324681A11A21A31A42A12A22A32A41G2GHC2441Y11Y21Y31Y42Y12Y22Y32Y4181614129753L_COM1L_COM2L_COM3L_COM4L_COM5L_COM6L_COM7L_COM8LED_H1LED_G1LED_F1LED_E1LED_D1LED_C1LED_B1LED_A110831211962HGFEDCBALED4SCHCOM1COM2COM3COM47L_COM55L_COM64L_COM71L_COM81Y11Y21Y31Y42Y12Y22Y32Y4181614129753R2R3R4R6R7R8R9R10100100100100100100100100LED_A1LED_B1LED_C1LED_D1LED_E1LED_F1LED_G1LED_H1LED_H1LED_G1LED_F1LED_E1LED_D1LED_C1LED_B1LED_A110831211962HGFEDCBALED4SCHU6COM1COM2COM3COM47L_COM15L_COM24L_COM31L_COM4VCC复位电路S1RESETR1100C322URSTLED_J411LED_J513LED_J615LED_J71711910KR11图3-11 出租车计价器的硬件电路原理图

数码管驱动采用2个四联共阴极数码管显示,由于单片机驱动能力有限,采用74HC244作为数码管的驱动。在74HC244的7段码输

出线上串联100欧姆电阻起限流作用。

独立式按键使用上提拉电路连接,在没有键按下时,输出高电平。P0口用于输出7段LED共阴极显示代码,P2口用于输出低电平有效的位选码。0~9的7段LED共阴极显示代码:3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH。

(3)分析软件任务要求,写出程序设计思路,分配单片机内部资源,画出程序流程图

软件的任务要求包括定时器的设置、按键的扫描、按键的功能处理、脉冲的计数、路途等待超30秒的计时以及总金额的计算等。

程序设计的思路:使用中断方式对定时器的溢出进行计数实现30秒的计时。主程序采用查询外部中断标志实现脉冲的计数,由于每个脉冲代表10m,因此,当脉冲计数超过100时,计价器按照收费标准计价。主程序在初始化变量和定时器参数设置之后,进入一个循环结构,循环扫描键盘、查询脉冲的中断、数码管的动态扫描等功能,当脉冲的中断标志被查询到,若路途等待时间未超30秒时,要及时将路途等待时间的值清除为零。主程序的流程图如图3-12所示。

show_val[6]: 显示的值 init_val[6]: 密码初始值

key_val: 返回按键的值 255-表示无按键按下 key_index: 当前按键是哪一位密码 T1_cnt: 定时器计数溢出数

cnt_val_15s: 报警计时的数值

cnt_val_5s: 待机时间计时

cnt_val_4s: 输入正确,等待4秒清除开锁信号 cnt_state: 计时状态 error_num: 错误次数 led_seg_code:数码管7段码 */

#include \/*

key0=P1^0;

key1=P1^1;key2=P1^2;

key3=P1^3;key4=P1^4;key5=P1^5;enter=P1^6;esc=P1^7;*/

sbit relay_open=P3^0; //电磁锁开锁驱动 sbit pw_error=P3^1; //密码错误信号 sbit alarm_out=P3^2; //报警输出 sbit open_lock=P3^3; //已开锁指示信号 sbit audio_out=P3^4; //有源蜂鸣器

unsigned char data cnt_val_15s,cnt_val_5s,cnt_val_4s,cnt_state; unsigned int data T1_cnt;

unsigned char data key_val,key_index,key_val_old; unsigned char data state_val,error_num; unsigned char data show_val[6]; char code init_val[6]={1,2,3,4,5,0}; char

code

led_seg_code[11]={0x3f,0x06,0x05b,0x04f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};

//led_seg_code[0-9]代表0-9 led_seg_code[10]=0x00数

码管不显示任何内容

//--------延时程序---------------- void delay(unsigned int i)//延时 { while(--i); }

//--------清除输入内容---------- void init_variant() {unsigned char i; for(i=0;i<6;i++)

show_val[i]=10; //led_seg_code[10]=0x00表示数码管不显示任何内容

key_index=0; //没有任何输入或清除所有输入时,保存当前键的位置

}

//---------按键扫描---------------

unsigned char scan_key() { unsigned char i,k; i=P1;

if (i==0xff && cnt_state!=2) { k=255; } //无键按下 else //有键按下 { delay(500); //延时去抖动 if(i!=P1) {k=255;} else

{ TR1=1; //有键按下则开定时器,启动待机计时 cnt_val_5s=0; switch (i)

{ case 0xfe: k=0; break; case 0xfd: k=1; break; case 0xfb: k=2; break; case 0xf7: k=3; break; case 0xef: k=4; break; case 0xdf: k=5; break; case 0xbf: k=6; break; case 0x7f: k=7; break; }

} } return k; }

//---------数码管显示--------------- void led_show()

{P0=led_seg_code[show_val[0]]; P2=0xdf; delay(500);

P0=led_seg_code[show_val[1]]; P2=0xef; delay(500);

P0=led_seg_code[show_val[2]]; P2=0xf7; delay(500);

P0=led_seg_code[show_val[3]]; P2=0xfb; delay(500);

P0=led_seg_code[show_val[4]]; P2=0xfd; delay(500);

P0=led_seg_code[show_val[5]];

P2=0xfe;

delay(500);

}

//--------定时器T1中断服务程序----------------- void timer1() interrupt 3 //T1中断 { T1_cnt++;

if(T1_cnt>3999) //如果计数>3999, 计时1s { T1_cnt=0; switch (cnt_state)

{ case 0: //待机,需要计时5s if(cnt_val_5s<5) { cnt_val_5s++;} else

{ cnt_val_5s=0;

init_variant();//待机计时到5秒时,清除输入的

TR1=0; //停止计时 } break;

case 1://密码输入正确,需要计时4s if(cnt_val_4s<4) { cnt_val_4s++;}

内容

else

{ cnt_val_4s=0;

init_variant();//密码输入正确,计时到4秒时,清除输入的内容

open_lock=1; //已开锁信号清零 relay_open=1; //开锁信号清零 cnt_state=0;

TR1=0; //停止计时 } break;

case 2: //密码输入错误3次,计时15s if(cnt_val_15s<15) { cnt_val_15s++;} else

{ cnt_val_15s=0;

init_variant();//三次密码错误时,计时15秒,清除输入的内容

open_lock=1; // 清除所有指示和报警 relay_open=1; alarm_out=1; pw_error=1; cnt_state=0;

TR1=0; //停止计时 } break; } } }

//--------判断键盘输入内容与密码是否一致------ unsigned char check_input_pw() { unsigned char i,k; k=1;

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

{ k=k && (show_val[i]==init_val[i]); } return k; }

//---------主程序---------------- main()

{ //初始化各变量 audio_out=1; P3=0xff; cnt_val_15s=0; cnt_val_5s=0; cnt_val_4s=0;

cnt_state=0;

//0-待机计时5s状态;1-密码正确,计时4s状态 ;2-三次密码错误,处于计时15秒状态。

T1_cnt=0; error_num=0; key_val_old=255; init_variant(); //初始化51的寄存器

TMOD=0x20; //用T1计时 8位自动装载定时模式

TH1=0x19; //500微秒溢出一次; 250=(256-x)*12/11.0592 -> x=19

TL1=0x19;

EA=1; //开中断 ET1=1;

TR1=0; //开定时器T1 while(1)

{ key_val=scan_key(); //按键输入,有键按下key_val为0-7,无键按下key_val为255。

if (key_val!=key_val_old) { key_val_old=key_val;

if (key_val!=255&& cnt_state!=2) { audio_out=0;

delay(100); //延时去抖动 audio_out=1; switch (key_val) { case 0: case 1:

case 2:

case 3: case 4: case 5:

if(key_index<6) //密码为6位,超过6位视为输入无效

{ show_val[key_index]=key_val; key_index++; } break; case 6: //确认键

if(check_input_pw()) {//密码正确

error_num=0; //密码输入错误次数清零 //---------

pw_error=1; //密码错误指示灯灭 relay_open=0; //开锁驱动信号灯亮 open_lock=0; //已开锁信号灯亮

//---------

delay(50000); //两声短“滴”声 audio_out=0; delay(50000); audio_out=1; delay(50000); audio_out=0; delay(50000); audio_out=1; //---------

cnt_state=1; //下一状态处于4秒计时的状态 TR0=1; //启动定时 } else

{ if (error_num<2)

{error_num++; //输入错误次数小于3次时,没错一次error_num增一

pw_error=0; //密码错误指示灯亮 //-----------

delay(20000);//一声长“滴”声,提示错误 audio_out=0; delay(60000);


单片机开发工程案例分析与解析.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:第3单元 运动图象 追及和相遇问题知能检测

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: