9 应用实例
在本章中,将前几章所学的内容进一步扩展,设计并完成几个完整的应用实例,巩固所学的知识,提高程序设计和调试能力。
9.1 直流电动机的应用
直流电动机的基本知识如下。
1)直流电动机工作原理
直流电动机就是将直流电能转换为机械能的转动装置。直流电动机具有良好的调速性能、较大的启动转矩和过载能力强等诸多优点,因此在许多行业应用广泛。在全国大学生电子设计竞赛中,微型直流电动机、电动小车多次作为控制类题目的主要控制对象。
微型直流电动机(包括玩具直流电动机、小型直流减速电动机等)一般为永磁式直流电动机。永磁式直流电动机由定子磁极、转子、换向器、电刷、机壳、轴承等构成。定子磁极采用永磁体(永久磁钢),定子的作用是产生主磁场。转子是进行能量转换的电枢,在磁场中产生感应电动势和电磁转矩。直流电动机的定子上固定有环状永磁体,电流通过转子上的线圈产生安培力,当转子上的线圈与磁场平行时,旋转的转子受到的磁场方向将改变,此时转子末端的电刷跟换向片交替接触,从而线圈上的电流方向也随之改变,但产生的洛仑兹力方向不变,所以电动机能保持一个方向转动。要改变直流电动机旋转方向,只需要改变转子线圈的电压极性即可。
直流电动机转速公式:
式中:U d为电动机外加直流电压,R a为电枢绕组电阻,C eΦ为电动机常数,I为电动机电流,电动机电流的大小与负载大小有关。从直流电动机转速公式可见,只要改变电枢电压就能实现直流电动机的无级调速。
2)直流电动机驱动电路
小功率直流电动机驱动电路可以采用如图9.1所示的H桥开关电路。这种驱动电路可以很方便地实现直流电动机的四象限运行,即正转、正转制动、反转和反转制动。U A和U B是互补的TTL驱动信号。由于大功率PNP晶体管价格高,难实现,所以这个电路只在小功率电动机驱动中使用。当4个功率开关全用NPN晶体管时,需要解决两个上桥臂晶体管(BG1和BG3)的基极电平偏移问题。图9.1(b)中H桥开关电路利用两个晶体管实现了上桥臂晶体管的电平偏移。但电阻上的损耗较大,所以也只能在小功率电动机驱动中使用。
图9.1 H桥开关电路
对于H桥驱动电路,上下桥臂功率晶体管施加互补信号。由于带载情况下,晶体管的关断时间通常比开通时间长,例如当下桥臂晶体管未及时关断,而上桥臂抢先开通时就出现所谓“桥臂直通”故障——桥臂直通时电流迅速变大造成功率开关损坏,所以设置导通延时是必不可少的。
在实际制作中,可以采用大功率达林顿管或场效应管等分离元件进行驱动电路设计。为了简化电路设计,建议使用H桥电动机驱动L298N等专用芯片,其性能稳定可靠、电路简单。对于大功率驱动系统,希望将主回路与控制回路之间实行电气隔离,此时常采用光电耦合电路来实现。
L298N是ST公司生产的一种高电压、大电流电动机驱动芯片。该芯片主要特点是工作电压高,最高工作电压可达46V;输出电流大,瞬间峰值电流可达3A,持续工作电流为2A;额定功率25W。L298N内含两个H桥的高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机、继电器线圈等感性负载;采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作;有一个逻辑电源输入端,使内部逻辑电路部分在低电压下工作;可以外接检测电阻,将变化量反馈给控制电路。L298N内部结构如图9.2所示。该芯片可以驱动一台两相步进电动机或四相步进电动机,也可以驱动两台直流电动机。
若使用一个L298N驱动器驱动两台直流电动机,则引脚ENA、ENB可用于输入PWM脉宽调制信号对电动机进行调速控制。如果无须调速可将两引脚接5V,使电动机工作在最高速状态,实现电动机正反转就更容易了。如果输入信号端IN1接高电平,输入端IN2接低电平,电动机M1正转;如果信号端IN1接低电平,IN2接高电平,电动机M1反转。控制另一台电动机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电动机M2正转;反之则反转。
对于电动机的调速,我们采用PWM调速的方法。其原理就是开关管在一个周期内的导通时间是t,PWM周期为T,则电动机两端的平均电压为U d=V s*t/T=a*V s。其中,占空比a=t/T,V s为驱动电源电压。电动机的转速与电动机两端的电压成正比,而电动机两端的电压与控制波形的占空比也成正比,因此电动机的速度与占空比成正比。占空比越大,电动机转得越快。
图9.2 L298N内部结构示意图
实例9.1 直流电动机的单片机控制
任务要求:设计一个能控制直流电动机正反转的调速电路,采用PWM方式调速,有加减速按键、启动停止按键和方向选择键。
分析说明:在选择控制直流电动机的PWM周期时,要考虑的因素主要是电枢电感、驱动器能承受的频率、散热条件、对噪声的要求,等等。在驱动器能承受的范围内,周期短一点好(也就是PWM频率高一点)。这样转矩更平稳,噪声小,电流纹波小,但是驱动器发热会严重一些。直流电动机用PWM实现调速的PWM波周期通常在毫秒以下量级,电动机功率越大,可以允许周期也大一些。不考虑开关频率的限制,周期越短越好。但实际上电流越大、电压越高,开关的频率上限越低,或者说周期的下限越高。PWM周期较大时,电动机高转速时由于惯性大不会有瞬间停顿问题,但让电动机运转在很低的转速时,确实会出现类似蠕动的瞬间停顿的问题。一般选取PWM周期为2.5 ms。
1)硬件电路设计
为了保证电路简单、可靠性高,直流电动机驱动电路采用电动机专用驱动芯片L298N。4个二极管起保护驱动芯片L298N的作用,当加到电动机上的直流电压关断时,电动机电枢线圈将产生很高的感应电压,此感应电压可以通过二极管提供的回路泄放,从而保护驱动芯片。硬件电路如图9.3所示。
2)程序设计
3)仿真结果与分析
仿真结果如图9.3所示。注意:电路仿真与实物运行有所不同,仿真时电动机加减速过程较慢,启动后要多等待一会儿,等电动机加速结束,运行稳定后,再进行加速或减速控制。可以通过示波器观察PWM信号周期和占空比。
图9.3 实例9.1仿真结果
9.2 舵机的单片机控制
舵机的工作原理如下。
舵机是伺服马达的俗称,它是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具、航模和遥控机器人中已经使用得比较普遍。
舵机常用的控制信号是一个周期为20 ms,宽度为0.5 ms~2.5 ms的脉冲信号。当舵机收到该信号后,会马上激发出一个与之相同的、宽度为1.5 ms的负向标准的中位脉冲。之后两个脉冲在一个加法器中进行相加得到所谓的差值脉冲。输入信号脉冲如果宽于负向的标准脉冲,得到的就是正的差值脉冲。如果输入脉冲比标准脉冲窄,相加后得到的肯定是负的脉冲。此差值脉冲放大后就是驱动舵机正反转动的动力信号。舵机电动机的转动,通过齿轮组减速后,同时驱动转盘和标准脉冲宽度调节电位器转动,直到标准脉冲与输入脉冲宽度完全相同、差值脉冲消失时才会停止转动。这就是舵机的工作原理。
小型舵机的工作电压一般为4.8 V或6 V,转速也不是很快,一般为0.22 s/60°或0.18 s/60°。假如你更改角度控制脉冲的宽度变化太快,舵机可能反应不过来。如果需要更快速的反应,就需要更高的转速。舵机的控制一般需要一个20 ms左右的时基脉冲,该脉冲的高电平部分一般为0.5 ms~2.5 ms范围内的角度控制脉冲部分。以180°角度伺服为例,那么对应的控制关系是:
0.5 ms→0°;1.0 ms→45°;1.5 ms→90°;2.0 ms→135°;2.5 ms→180°。
这只是一种参考数值,具体的参数,请参见舵机的技术参数。
标准的舵机有3条导线,分别是电源线、地线、控制线,如图9.4所示。PWM脉冲宽度与舵机输出转角的关系如图9.5所示。
图9.4 标准舵机引脚图
图9.5 PWM脉冲宽度与舵机输出转角的关系
实例9.2 舵机的单片机控制
任务要求:设计一个舵机控制电路,能够启动、停止、增加或减少转角和回零。
1)硬件电路设计
要精确控制PWM脉冲宽度,单片机选用XT2片外晶振8MHz。设置5个按键分别为启动、停止、增加、减少和回零。硬件电路如图9.6所示。
2)程序设计
图9.6 实例9.2仿真结果
3)仿真结果与分析
实例9.2的仿真结果如图9.6所示。
9.3 LED点阵汉字显示屏应用实例
汉字LED点阵屏简介如下。
按性能和用途分类,LED显示屏分为条屏、图文屏、视屏以及数码屏四种。
条屏系列一般为单基色显示屏,主要用于显示标准16×16汉字。这类屏幕多做成条形,故称为条屏。可用USB输入、RS-232输入或GPRS无线输入。图文屏系列一般为双基色显示屏,主要用于显示文字和图形,一般无灰度控制;它通过与计算机通信输入信息。与条屏相比,图文屏的优点是显示的字体字形丰富,并可显示图形;与视屏相比,图文屏最大的优点是一台计算机可以控制多块屏,而且可以脱机显示。
视屏系列一般为全彩色显示屏,与计算机VGA信号点对点同步显示。视屏开放性好,对操作系统没有限制,能实时反映计算机监视器的显示。
数码屏的显示器件为7段码数码管,适于制作时钟屏、利率屏等,广泛用于证券交易所股票行情显示,银行汇率、利率显示,各种价目表等。多数情况下,在数码屏上加装条屏来显示欢迎词、通知、广告等。
像素是LED显示屏的最小成像单元,俗称“点”或“像素点”。为便于组装和显示,出厂的半成品通常是以显示模组形式提供的,一个显示模组将多个显示单元加显示驱动做在一起。模组也称单元板,单元板通常有64×32(64列32行)、64×16(64列16行)。将单元板按一定方式拼接在一起,加上控制卡/控制系统、电源和框架等就构成为LED显示屏。
扫描方式决定了模组之间连接的形式,扫描方式有1/16、1/8、1/4、1/2、静态这几种。因为LED显示屏是逐行刷新显示的,扫描方式也就决定了显示刷新的方式,如1/16就是每次刷新1行,16行为一个扫描周期,需ABCD四个信号控制;1/8就是每次刷新1行,8行为一个扫描周期,需ABC三个信号控制;其他依次类推。如果采用相同的LED灯,1/16扫的亮度要比1/8低,静态的亮度是最高的。户内的屏一般采用1/16,户外和半户外的一般采用1/16或者1/8。对于显示屏经常受到阳光猛烈照射的环境,最好用1/4扫描。
实例9.3 LED点阵汉字移动显示
任务要求:使用16×16点阵显示4个汉字“汉字显示”,并且实现汉字向左移动显示。
分析说明:为了在LED点阵上显示汉字,通常采用字模软件生成汉字点阵字模。我们采用字模Ⅲ增强版,如图9.7所示。该软件为单色液晶显示生成字模,同样适用于为点阵LED汉字显示生成字模。该软件不需要安装,在程序包中双击ZimoIII.exe即可使用。首先,进行参数设置,字模格式为横向取模,字节正序,汉字大小16×16;第二,字符输入;第三,生成字模,字模代码可以直接复制或者导出到文件,供编程使用。
图9.7 字模生成软件的使用
1)硬件电路设计
为了显示4个汉字,采用8片74HC595、1片74HC154,扫描方式采用1/16。4个汉字为128×16点阵,16行由74HC154逐行扫描;128列分为8字节,由74HC595提供8个字的段码。硬件电路如图9.8所示。
2)程序设计
显示采用扫描方式为1/16,即每次刷新1行,每行显示1.5ms,16行为一个扫描周期,共24ms。由于人眼的视觉暂留现象,将感觉到16行LED显示屏是同时亮的。若显示的时间太短,则亮度不够,若显示的时间太长,将会感觉到闪烁。
图9.8 实例9.3仿真结果
3)仿真结果及分析
实例9.3仿真结果如图9.8所示,汉字的移动效果如图9.9所示。
图9.9 汉字移动效果图
9.4 简易流量计
流量计的定义:指示被测流量和(或)在选定的时间间隔内流体总量的仪表,简单来说就是用于测量管道或明渠中流体流量的一种仪表,工程上常用单位m3/h。它可分为瞬时流量(Flow Rate)和累计流量(Total Flow),瞬时流量即单位时间内流体流过封闭管道或明渠有效截面的量;累计流量为在某一段时间间隔内(一天、一周、一月、一年)流体流过封闭管道或明渠有效截面的累计量。流体即流过的物质,可以是气体、液体、固体。通过瞬时流量对时间积分亦可求得累计流量,所以瞬时流量计和累计流量计之间也是可以相互转化的。流量计可分为转子流量计、节流式流量计、细缝流量计、容积流量计、电磁流量计、超声波流量计等,还可分为液体流量计和气体流量计。
在工业现场,测量流体流量的仪表统称为流量计或流量表,它是工业测量中最重要的仪表之一。随着工业的发展,对流量测量的准确度和范围要求越来越高,为了适应多种用途,各种类型的流量计相继问世,广泛应用于石油天然气、石油化工、水处理、食品饮料、制药、能源、冶金、纸浆造纸和建筑材料等行业。
实际应用中要求流量计具备的功能较多,以脉冲输出转子流量计为例,主要特点如下所示。
(1)可显示管道内流体的瞬时流量、累计流量和单班累计流量。(www.xing528.com)
(2)内部可置入高精度修正曲线,确保流量检测的准确性。
(3)表头采用MSP430芯片,液晶显示,超低功耗。
(4)高精度D/A转换芯片,保证4 m A~20 m A电流稳定输出。
(5)具有二线制4 m A~20 m A电流输出功能和脉冲输出功能。
(6)采用铁电数据存储器,具有高可靠数据掉电保护功能(存储速度快,无数次上电冲击数据不丢失)。
(7)具有RS485通信输出功能,标准Modbus/RTU协议,DC24V或DC12V供电。
(8)表头采用电池供电,可供电两年;或者采用外部DC24V、DC12V供电。
限于本书的篇幅,仅重点介绍设计显示总流量和瞬时流量等主要功能的简易流量计。
实例9.4 简易流量计的设计
任务要求:设计一个脉冲输出转子流量计,管道流量经转子检测变换为脉冲输出,一个脉冲对应一个脉冲当量。要求显示总流量和瞬时流量。
1)硬件电路设计
选用MSP430F249低功耗单片机,液晶显示选用1602字符型LCD,硬件电路如图9.10所示。
2)程序设计
图9.10 实例9.4仿真结果
3)仿真结果与分析
实例9.4的仿真效果如图9.10所示。
9.5 简易计算器
简易计算器包括矩阵式按键输入、输入数据的处理(数字键的处理、功能键的处理)、字符液晶显示和一定难度的单片机程序设计。如果读者能够独立完成该例程序的设计与仿真,说明读者已经达到单片机入门学习的基本要求了。
实例9.5 简易计算器的设计
任务要求:以MSP430F149单片机为核心实现一个简单计算器。其中,输入设备用矩阵键盘,共有“0~9”“+”“-”“*”“/”“=”“ON/C”16个按钮;输出设备采用LCD1602显示器。该计算器的功能是通过键盘输入一行有两个正数和一个运算符组成的字符串,字符串在LCD1602液晶的第一行显示,当输入“=”时,计算并在液晶上显示表达式运算结果。如果数据超过了16个字符长度,或者在除法运算中除数为0,则显示ERROR。按下“ON/C”键时,计算器重新开始输入。
1)硬件电路设计
计算器系统原理如图9.11所示。其中,单片机采用MSP430F149单片机,键盘为4×4矩阵键盘,通过单片机的I/O端口实现键盘扫描处理,显示器采用LCD1602液晶,电源部分为5V外部电源输入,供给液晶显示器,5V电源经过低压差稳压芯片产生3.3V作为单片机的供电电源。硬件电路设计如图9.12所示。
图9.11 简易计算器原理框图
图9.12 简易计算器硬件电路设计图
图9.12中,单片机的P1.0~P1.3端口作为矩阵键盘输出端口,P1.4~P1.7端口作为键盘输入端口,并用10 kΩ电阻上拉到电源。时钟源采用外部32.768 k Hz时钟晶振。
2)程序设计
系统的软件主要由键盘扫描模块、液晶驱动模块、计算器处理模块组成。根据项目定义的需求,软件设计的关键在计算器处理模块,计算器的输入是键盘编码,需要按照输入的数字和运算符的次序将键盘编码序列转换成十进制数字,同时要对输入的键盘编码进行合法性校验。下面介绍各具体模块。
(1)液晶显示模块程序设计。
根据前面的章节所述的LCD1602液晶显示器的驱动程序,为进一步提高程序的可移植性,程序设计中对端口的控制采用了多个宏定义如下。
这种编程的方式可以适应不同的端口配置和单片机类型,液晶模块驱动程序设计如下。
(2)键盘扫描模块程序设计。
在之前介绍的键盘扫描程序中,是利用单片机软件延迟完成去抖处理,即在主程序中扫描键盘输入端口,一旦检测到按键输入端口为低电平时,便调用软件延时程序延时一段时间,一般为10 ms左右;然后再次检测按键输入端口,如果还是低电平则表示按键按下,转入执行按键处理程序。如果第二次检测按键输入端口为高电平,则放弃本次按键的检测,重新开始一次按键检测过程。这种方式实现的按键输入接口,作为基础学习和在一些简单的系统中可以采用,但在多数实际产品设计中,这种按键输入软件的实现方法有很大的缺陷和不足。
这种简单的按键检测处理方法,由于采用了软件延时,浪费了大量宝贵的单片机计算时间,使得单片机的运行效率降低。另外,在用户按键时间超过一定的范围时,这种程序设计会导致扫描到重复的键盘编码。如果在程序中要判断键盘弹起而用户按键时间较长时,会造成单片机长时间等待键盘弹起,使得单片机不能处理其他的事件。这种软件的设计思想实际上是一种轮询机制,通过单片机周而复始的对外部设备的状态进行查询,不容易同系统中其他功能模块协调工作。用于处理时间要求比较高的系统时,经常会导致处理的时间不确定。还有,由于不同的产品系统对按键功能的定义和使用方式要求不同,加上在测试和处理按键的同时,单片机还要同时处理其他的任务(如显示、计算、计时等),因此,编写键盘和按键接口的处理程序需要掌握有效的分析方法,具备一定的软件设计能力和程序编写技巧。
这里介绍一种软件设计中很重要的设计方法,即有限状态机。有限状态机由有限的状态和相互之间的转移构成,系统在任何时候只能处于给定数目的状态中的一个。当接收到一个输入事件时,状态机产生一个输出,同时也可能伴随着状态的转移。状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:
①现态是指当前所处的状态;
②条件又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移;
③动作是条件满足后执行的动作,动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态;动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态;
④次态是条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
通常有两种方法来建立有限状态机,一种是“状态转移图”,另一种是“状态转移表”,分别用图形方式和表格方式建立有限状态机。实时系统经常会应用在比较大型的系统中,这时采用图形或表格方式对理解复杂的系统具有很大的帮助。下面利用状态机来实现键盘的接口程序,并和前面章节中的键盘接口程序进行对比。
在单片机系统中,用户对按键的操作是随机进行的,不能预设用户对按键的操作时间和顺序,因此程序必须对按键需要一直循环查询。由于按键的检测过程需要进行去抖处理,因此在10 ms左右时间调用一次键盘处理状态机程序,这样可以避免采用软件延迟消除按键抖动的影响,同时也远小于按键0.3 s~0.5 s的稳定闭合期,不会将按键操作过程丢失。
图9.13所示的是一个简单按键状态机的状态转换图。在图中,将一次完整的按键操作过程分解为三个状态,每隔10 ms检测一次按键的输入信号,并输出一次按键的确认信号,同时按键的状态也发生一次转换,程序每10 ms完成一次状态机的转换处理。下面对该专题图做进一步的分析和说明,并根据状态图给出软件的实现方法。
图9.13 键盘状态机转换图
图中S0为按键的初始状态,当按键无输入时,下一状态依旧为S0。当按键有输入时,由于还没有经过去抖处理,不能确认按键是否真正按下,下一状态进入S1。S1为按键闭合确认状态,它表示在10 ms前按键为闭合的,因此当再次检测到按键输入时,可以确认经过10 ms的去抖按键被按下了,下一状态进入S2。而当再次检测到按键无输入时,表示按键可能处在抖动干扰状态,下一状态返回到“S0”。这样,利用S1,实现了按键的去抖处理。S2为等待按键释放状态,因为只有等按键释放了,一次完整的按键操作过程才算完成。将状态机从S2转移到S0,开始新的键盘扫描过程。分析中可以知道,一次按键操作的整个过程,按键的状态是从S0→S1→S2,最后返回到S0的。并且在整个过程中,按键的输出信号仅在S2时给出了唯一的一次确认有效按键产生信号,其他状态均输出无效键值。所以上面状态机所表示的按键系统,不仅克服了按键抖动的问题,同时也确保在一次按键的整个过程中,系统只输出一次按键闭合信号。换句话讲,不管按键被按下的时间保持多长,在整个按键过程中都只给出了一次确认的输出,它是一个最简单和基本的按键。当有了正确的状态转换图,就可以根据状态转换图编写软件了。下面是利用状态图基于状态机方式编写的矩阵按键接口函数read_key()。
该矩阵按键接口函数read_key()在整个系统程序中应每隔10ms调用执行一次,每次执行时,先将行线输出全为0,然后进入用switch结构构成的状态机。switch结构中的case语句分别实现了三个不同状态的处理判别过程,在每个状态中将根据状态的不同,以及读取与按键连接的I/O的电平确定按键输出值key和下一次按键的状态值(key_state)。函数read_key()的返回参数提供上层程序使用。返回值为0x FF时,表示无有效按键;而返回其他值表示有一次按键闭合动作,需要进入按键处理程序进行相应的键处理。在函数read_key()中定义了两个局部变量,其中key为局部变量,每次函数执行时key为函数的返回值,总是先初始化为0,只有在状态1中重新设置为键盘编码,作为表示按键确认的标志返回。变量key_state非常重要,它保存着按键的状态值,该变量的值在函数调用结束后不能消失,必须保留原值,因此在程序中定义为“局部静态变量”,用static声明。
(3)定时器程序。
定时器采用单片机内部的定时器A,工作在定时/计数模式,按照前面章节的说明,定时器A初始化和中断服务程序如下。
定时器时钟采用慢速时钟,工作频率为1 MHz,周期为1μs,如果要得到10 ms定时中断,TAR的初始值应该为65536-10 ms/1μs=55536。其中key_val为一个全局变量,当通过定时器中断读取按键的键值时会修改key_val的值,这个值用在后面的计算器处理程序中。
(4)计算器模块程序。
按照计算器的需求,通过键盘输入一组字符串,其中包含两个参与运算的数据和一个运算符,当键盘输入字符串时,显示器要实时显示当前输入的字符。当键盘输入“=”时,将结果计算出并显示在液晶的第二行。计算器程序包括几个问题要处理,首先,要将参与运算的操作数从字符串中提取出来,并将字符串转换为对应的十进制数据;其次,在键盘输入时,要根据前面输入的字符,避免错误表达式的产生,比如输入的第一个字符和最后一个字符不能是操作数,当输入了一个运算符后,不能再次输入一个运算符等;最后,运算结果为十进制数字,还需要考虑其正负号,并转化为字符串供液晶驱动程序处理。图9.14所示的是一个基本的计算器程序的流程图,按照这个流程图介绍程序的实现过程。
图9.14 计算器流程图
计算器核心程序如下。
程序首先将输入表达式缓冲区expression和数字缓冲区str1、str2清零,这三个缓冲区大小定义为MAX_DISPLAY_CHAR,这个宏定义为16,其大小是按照LCD1602液晶每行最多显示为16个英文字符确定的。随后程序进入无限循环读取从键盘输入的字符。
首先判断字符是否为“=”或者“C”,在前面部分已经说明,当输入字符为“=”时,计算表达式结果;如果为“C”,清除显示重新输入。当不是这两个字符时,输入的字符必定为数字或者运算符。程序调用is_operator()函数判断是否为运算符,如果是运算符,则还要判断运算符的位置是否是表达式的第一个或者最后一个字符,并判断表达式中是否已经出现过运算符,以上条件不满足则丢弃这个键盘输入。当运算符输入是首次出现并且其位置合法时,读入表达式缓冲区并更新显示。如果是数字,则直接读入到表达式缓冲区中并更新显示。
当输入字符为“=”,则进行表达式计算。第一步将参与运算的数字字符串解析出来,通过调用字符串复制函数strncpy将数字字符串分别复制到str1和str2中,字符的个数和位置通过变量operator_pos和char_pos计算出来,这两个变量分别是运算符在表达式中的位置和当前字符的位置。第二步是调用string_to_long()函数将字符串转换为数字。函数如下:
在计算器程序开始时已经将str1和str2清零,因此在复制数字字符后,这两个缓冲区都必然有“0”结尾的字符。string_to_long函数通过循环读取字符并判断是否为零,如果为“0”则转换程序结束返回,否则就将每个数字字符ASCII编码减去字符“0”得到当前字符的数字,并通过将之前的数字乘10和当前数字相加得到所需的十进制数。
当获取参与运算的数字后,程序调用calc_operation()来完成整数的加减乘除运算,程序如下。
该程序对运算结果做了限制,结果大小在-9999999和9999999之间,如果是除法运算,还需要限制除数不能为零,否则结果无效。最后调用显示程序calc_disp()完成结果的显示,程序如下。
其中num_to_string()函数将整数转换为字符串,如果为负数,还需要在字符串前面增加一个‘-’,num_to_string()程序如下。
程序首先判断数字是否为0,如果是零直接返回;然后判断是否为负数,如果是在显示缓冲区增加一个“-”,并变换成正整数。正整数变换成字符串的方式是通过对正整数取10的余数,以整数255为例,255% 10=5,将数字5加上字符“0”得到字符“5”,再对正整数取10的商255/10=25,继续循环直至商为0结束转换,并将显示缓冲区中的字符向前移位,即可利用LCD1602液晶的显示代码实现结果的显示。
(5)主程序。
最后介绍主程序,主程序对硬件进行所需的初始化,并调用calculator(),主程序如下。
以上程序还只能完成正整数的四则运算,程序结构也不够简洁,如果需要实现浮点数的输入和运算处理,应该采用状态机的方式来控制程序的流程,并进一步提高程序容错能力。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。