《利用单片机分时电价系统设计 精品.docx》由会员分享,可在线阅读,更多相关《利用单片机分时电价系统设计 精品.docx(32页珍藏版)》请在课桌文档上搜索。
1、一、课题说明随着经济的快速发展,电力需求的不断增长和能源价格的不断提升。用电紧张已经成为突出的问题摆在我们面前。而电力又不是可以储存的特殊商品,某些时段用电多,其他时段用电少。用电高峰时电力供不应求,用电低谷时又电力过剩。为了应对这样的难题,可以采用分时电价来缓解供需矛盾,提高电力利用效率。分时电价是指在不同时段采用不同电价,根据用电需求和电网负荷将每天的时间划分为用电高峰时段(6:OO22:00)和用电低谷时间段(22:00-6:00),高峰时段执行较高电价(0.8元/度),低谷时段执行较低电价(0.6元/度)。通过价格杠杆调节电力资源。从而提高电力利用效率。本设计利用单片机控制普通电能表,
2、实现分时计费的功能。本系统可以作为额外的模块安装到普通电能表,这样用户已安装的普通电能表不需要更换为新的电能表,仅仅另外安装了本系统后就可以作为一个标准的智能电能表使用。本系统实现以下功能:1、 记录高峰用电量2、 记录低谷用电量3、 记录总用电量4、 计算并记录高峰时段用电电费5、 计算并记录低谷时段用电电费6、 计算并记录总电费7、 显示高峰用电量8、 显示低谷用电量9、 显示总用电量10、 显示高峰时段用电电费11、 显示低谷时段用电电费12、 显示总用电电费13、 清除电量记录和电费记录记录和计算用电量、电费都由单片机编程完成,显示功能由单片机控制1.CD实现。相应的显示功能选项由键盘
3、按键选择。二、系统整体设计本系统的设计时将整个系统划分为多个模块,简化设计流程。同时便于团队协作,将多个任务分配给多人完成。本系统可以简单的划分为5个模块:1、光电转换模块,用于将普通电能表的转数通过光电器件转换为电脉冲,送入CPU的Tl端口。2、键盘模块,用于将按键转换为按键编码,并用中断的方式通知CPU有键被按下。3、1.CD显示模块,用于显示必要的提示信息和电量、电费的数值。4、时钟模块,为CPU模块提供精确的时刻计数5、核心控制模块,由SST公司的89C58单片机和必要的外围芯片构成,用于接受光电模块送来的电脉冲,对脉冲进行计数,将计数值转化为电量,根据由时钟模块中取得的小时,判断用电
4、的时段,计算相应时段的电量和电费,并记入总电量和电费;接受键盘的中断,根据不同的按键显示不同的功能;控制1.CD显示模块,将CPU内部的数据送到1.CD上显示,并显示必要的提示信息。各个模块的原理框图下图所示。三、各个分系统的设计原理(共7点)1、 光电转换模块用于获取普通电能表记录的用电量,在普通电能表的旋转铝盘上打一个很小的检测孔提取光脉冲。铝盘每旋转一圈,模块会检测到一个光脉冲,经光电耦合并加以整形放大后转换成电脉冲,送到CPU的Tl端用作计数触发脉冲。普通电能表的铭牌上标有每KWh多少转,其含义为电能表转数每达这一数值就是用了一度电(即IKWh).将从电能表上提取转换后的的脉冲信号送入
5、单片机的Tl端并进行计数,编程时将TI计数器的计数模值设为电能表的转数,当计数器计数溢出时就可以判断电能表已经用了一度电。测试时可以使用实验室普通的信号发生器送出脉冲信号代替电能表的转数脉冲,送入单片机的TI端。2、 键盘模块由普通的16键非编码键盘与Intel8279可编程键盘/显示接口芯片组成完整的编码键盘电路。当键盘上有键按下时Intel8279会将按键转换为键码存储在一个FIFo(FirstInFirstOut,先入先出)队列中,并向CPU申请中断。CPU得知中断以后,从Intel8279的存储区读出键码,判断相应的按键,决定执行相应的功能。3、1.CD显示模块通过8255外围接口扩展
6、芯片连接到CPUo1.CD显示模块规格为122x32像素,在显示时分为上下两行。每行占122x16个像素,设计显示8个16x16的字符。严格的说要显示8个16x16的字符,至少要128x16个像素,设计时第四个字符和的8个字符各少3个像素列,虽然少了3个像素列,但是由于像素大小极其微小,人的肉眼是很难分辨出来的。这样的设计简化了编程需要考虑的问题。上行一般显示标题、提示、出错信息等,下行一般显示数值。使用时只需要CPU通过8255芯片将显示用的字码存储在1.CD模块的内部存储区,1.CD就可以显示出相应的字符。4、 在本系统中要记录不同时段的用电量,并计算出不同时段的电费。这就需要一个比较精确
7、的时间标准,通常可以使用Motorola公司的MC146818可编程时钟芯片,将计费段的时间存储起来,在各时间段开始向单片机的INTO端口申请中断,在不同的时段使系统执行不同的计费程序。在本系统中采用课题1的电脑时钟代替,将课题1的电脑时钟附加额外功能,在整点向外部RAM区的一个存储单元写入当前的钟点。CPU在计数满一度电的时候执行中断程序,此时CPU读取外部RAM中存储的钟点,判断不同的时段。执行不同的任务。5、 功能设置智能识辨技术:本系统的编码键盘每按下一个键,就中断一次。假如设置某个功能时需要按功能键B和输入数字24,就需要按键3次,键盘模块会发出3次中断申请。这样就带来一个问题:由于
8、每次中断都是调用同一个中断函数,这样,在按下功能键B后,如何将接下来按下的2和4识别为一个整数24并放入相应变量中,而不是认为按下2键是显示总电量,按下4键是显示低谷时段电费?智能识别技术的原理是在B键别按下时系统将标记一个标志位,表明B键已经被按下,然后2键被按下时,系统首先查看标志位有没有被设置,当它发现标志位已经被标记为B时,它即了解到这是一个功能设置,将2放入一个输入缓冲区,而不是显示总电量。并等待下次按键。接着4键被按下后,系统发现标志位被标记为B,它将4放入2后面的缓冲区,等待下次按键C然后结束键(本系统中为E)被按下,系统发现标志位被标记为B,又发现E为结束键,系统利用算法将缓冲
9、区中的2和4转换为一个整数送入到相应的变量中完成设置。然后系统中的标志位被清除,以后的按键回归到正常状态。系统利用智能识别技术,接受键盘输入,对内部的计费标准,如高峰电费、电表转数KWh等进行设置。6、 功能设置超时自动复位技术:(侦探狗技术)此项技术解决一个实际应用中遇到的问题。设某人A按了键盘上的自定义设置功能键,此时系统功能键标志将被做上标记,系统处于等待设置数值状态。但此时A恰好有事离开,某人B,在不知情的情况下,按照系统的说明书按了09的数字键,以为是显示或者是相应的其他功能。但是系统认为此时输入的数值是对内部数据的设置。这样会产生两个问题:一方面,B因为按了某键而系统没有执行相应功
10、能而莫明其妙;另一方面,B可能在不知情的情况下修改了内部计费、时段等标准,导致系统工作出错。侦探狗技术能够使功能设置在6.5S后超时,然后清除系统内部的功能设置标志,使系统恢复到正常状态。7、 四大关键辅助性算法:这里要说明的几个算法都不参与硬件的驱动,完全是纯软件的算法。虽然很短小,但是简练的完成了其目的。在整个系统控制程序中的地位,不亚于其他与硬件接触的函数。是整个系统中介于外部硬件数据与CPU数据之间的核心。1)算法NUmSToAITay:这个算法的功能是,将作为第一参数传递的int型整数的各位分离,按照由高位到地位的顺序依次放入作为第二参数传递的数组中。方便其他函数使用数组中的数字,利
11、用字库得到相应的字型码。此算法中其实包含2个子算法。如传递一个整数54321到函数中,第一个子算法将54321的各位分离放入数组,但是此时得到的序列为倒序,即:数组下标0,1,2,3,4分别存放数字1,2,3,4,5。第二个子算法将数组中的元素进行倒序运算,得到需要的顺序,即:数组下标0,1,2,3,4分别存放5,4,3,2,I02)算法:ArrayToCharacters:此算法的功能是,将作为第一参数传递的,存放1位数字的数组,通过查字库,将得到的字型码按顺序放入作为第二参数传递的将要显示的字符库中。此算法运算后得到的字符库就可以送入1.CD的显示缓存区,显示出相应的图形了。此算法利用Nu
12、msToArray算法得到的数组,查找字库,产生字符库。这两个函数作为核心算法被显示电量电费等函数使用。3) 算法ArrayToDigitalI:此算法的功能是将作为第一参数传递的存放一位数字的数组,转化为一个整数返回。此算法一般用来将存放在键盘缓存区的一位数字序列转化为一个整数。其他函数利用返回的整数设置相应变量的值。此函数被设置高峰时段,电表转数等函数使用作为核心算法。4) 算法ArrayToDigitalF:此算法的功能是将作为第一参数传递的存放一位数字的小数序列数组转换为一个浮点数返回。此算法一般用来将存放在键盘缓冲区的一个小数序列转化为浮点数返回给调用函数。此算法实现时将序列以小数点
13、(系统中为D键)为轴心分成两半,每半都是一个一位整数序列,将两个序列传递给AITayTODigitall,ArrayToDigitalI返回两个整数。将小数点后面的整数转换成小数加到小数点前面的整数上完成到浮点数的转换。此函数被设置电费函数调用作为核心算法。整个系统的电路图五、系统软件设计本系统的软件编程同样是按照模块设计的。首先解释本系统软件的部分全局变量。软件的代码请参见1.S图片或者PDF。initset结构用于保存高峰时段电价、低谷时段电价、高峰起始时间、高峰结束时间、低谷起始时间、低谷结束时间和普通电能表每度电的转数。这些变量用作电量计费的标准。键盘模块有修改这些变量的功能,以使智能
14、电表系统可以适应不同环境。initset结构定义的全局变量为Set,Set将initset结构中的变量实例化。coulometer结构定义电能表在高峰时段使用的电量、低谷时段使用的电量和使用的总电量。COUlOmeter结构定义的全局变量为CoUIo。fee结构记录当前使用的电费,包括高峰时段使用电量的电费,低谷时段使用电量的电费和使用的总电费。fee结构定义的全局变量为Fee。在程序中由于要用到外部存储器或者IO端口的直接地址,所以利用KeilC51中绝对定址关键字_at_定义了各种外部端口和IO端口的地址。其中RAM6264定义为外部RAM中存储的时刻的地址。mandPortOf8279为
15、键盘控制芯片8279的命令地址,DataOf8279定义为8279数据口的地址。mandPortOf8255定义为1.CD接口芯片8255的控制口地址,APOrtof8255定义为8255的A口地址,CPortOf8255定义为8255的C地址,但是在程序中没有直接使用C地址,而是通过8255的命令口使C的各位分别置位来控制C口的。全局函数InijCPUO和Init_8255and1.CD()用来对CPU和液晶显示模块进行初始化。IniJCPUO用于开放必要的中断允许,将Tl配置为计数器,用来检测电脉冲信号。Init_8255and1.CD()将8255的A、B、C口配置成方式0输出模式。打开
16、1.CD显示并清屏。1、键盘模块程序的设计:键盘模块包含两个中断函数,KeyBoard和DogSniffer,KeyBoard函数用于处理键盘按键事件,每次键盘按键中断,KeyBOad函数会检查按键的键值,根据不同的键值调用不同的功能函数。DogSniffer函数为侦探狗技术的实现函数,当在键盘上按下功能键时KeyBoard函数调用WakeupDog函数,唤醒侦探狗,其实质是向TO定时器送入定时初值,并使TO开始计时。当TO每65ms定时中断一次。每次中断后系统调用中断处理函数DogSniffer,DogSniffer函数判断功能键标志是否被标记,如果功能键标志被标记,而且按键时间超过TO的1
17、00次计数,即6.5So则DogSniffer使功能键标志复位。如果功能键标志没有被标记,则DOgSniffer使TO中断计数复位。并且不在向TO送入定时初值。如果功能键标志被标记,但是TO中断计数未达100次,则将TO中断计数加1,并向TO送入定时初值,开始下次定时。以下是键盘模块程序中使用的函数列表,其中NumsToArray等四个辅助算法函数在第二部分,系统整体设计中已经详细描述,这里不在说明。键盘模块各函数间的调用关系图如图所示。voidDogSniffer(Void)interrupt1using0;voidKeyBoard(Void)interrupt2using0;voidSho
18、wHighCoulometer(Void);voidShow1.owCoulometer(Void);voidShowAllCoulometer(Void);voidShowHighFee(Void);voidShow1.owFee(Void);voidShowAllFee(Void);voidClear(void);voidWakeupDog(void);voidSetHighFee(ucharkey);voidSet1.owFee(ucharkey);voidSetRotateSeed(ucharkey);voidSetHighStart(ucharkey);voidSetHighEnd(
19、ucharkey);voidSet1.owStart(ucharkey);voidSet1.owEnd(ucharkey);ucharNumsToArray(intnumber,ucharArray8);voidArrayToCharacters(ucharmessage8,uchardisplay832,ucharlength);intArrayToDigitalI(ucharA11*ay8,ucharlength);floatArrayToDigitalF(ucharArray8,ucharlength);KeyBoard中断处理函数首先将按键的键码读入一个变量中,然后判断功能键标志Whi
20、chFunctionKey是否被作标记,如果已做标记,则进入一个SWitCh语句,根据不同的键码,调用不同设置函数。如果WhichFunctionKey未被标记,则进入标准状态的按键处理过程,此过程通过一个SWitCh语句决定不同的执行方式。按下05键时,为显示相关信息的操作,则直接调用相关函数。按下C键时为复位语句,直接调用CIear()函数。当按下功能键6D时,首先将功能键标志WhichFunctionKey设置为相同的键码,然后唤醒侦探狗,进行设置超时探测。当下次按下按键时,由于WhiChFUnCtiOnKey已被标记,会转到相应的设置函数执行。如果长时间未按下任何键,当超过侦探狗的超时
21、时间后,侦探狗会将WhichFunctionKey标志的标记取消。ShowHighCoulometer,Show1.owCou1ometer,ShowAllCoulometer和ShowIIighFee、Show1.owFee、ShowAllFee两组函数用于显示coulometer和fee结构的变量中保存的高峰用电量、低谷用电量、总用电量和高峰电费、低谷电费、总电费的数值。这两组函数将内存中保存的数值转化为一个只存放单个位数字的数组,然后通过查字库NumCharacters,将单个数字的字型码送到要显示的字符缓存区里。ShowHighFee一组函数在显示时,由于内部变量为float型,在1.
22、CD上显示时比较困难,而且在计算电费时按照整数结算也是比较容易接受的选择,所以在实现时首先利用标准库中的ceil()函数将float取整,然后再转化为整型数字显示SetHighFee、Set1.owFee、SetRotateSpeed、SetHighStart、和SetHighEndSet1.owStartSet1.owEnd函数用于设置initset结构定义的电价、转数、高峰时段、低谷时段等变量。这些函数被调用时一般将按键信息存储在一个输入缓冲区里面。输入小数点用按键D代替,输入结束用按键E代替。当这些函数检测到一个输入结束按键时,它们将输入缓冲区的数据传递给ArrayToDigitalI或
23、者时ArrayToDigitalF,由他们完成输入到数值的转化。然后将转化后的数值设为相应变量的当前值。做完这些工作后,这些函数将输入缓存区、缓存位置计数和WhiehFUnCtiOnKey标志复位。以备下一次设置。2、1.CD显示模块程序设计:1.CD模块部分包含下列几个函数:voidSendmandTo1.CD(ucharmand);voidDisplay_1.eft(ucharmdata);voidDisplay_Right(ucharmdata);voidDisplay_All(ucharmdata);voidDisplaySelected(ucharpagenum,ucharcolum
24、n,ucharmdata16);voidDisplayAtRow(ucharrow,ucharcolumn,ucharmdata32);voidDisplayA1.ine(ucharline,ucharmdata832);DiSPIay_All函数用于系统启动时清屏,不用作其他用途,其他任何函数都不应该调用。1.CD模块的设计思想是尽力提供一个较为容易使用的、与硬件隔离的接口给其他调用函数。这一部分的编程模型如下图所示:1.CD部分的实现与此模型相对应、SendmandTo1.CDDisplay_1.eft和DiSPlay_Right函数位于此模型中的“1.CD驱动层”中,这3个函数直接接触硬
25、件,所有有关显示的调用都是基于这3个函数之上。SendmandTo1.CD函数的功能是向1.CD的驱动芯片发送命令字。其参数为要发送的命令字。Display_1.eft函数的功能是向1.CD的第一块驱动芯片内写入一个字节的显示数据,其直接表现为在1.CD的左半部分上显示字符。Display.Right函数能向1.CD的第二块驱动芯片内写入一个字节的显示数据,表现为在1.CD的右半部分显示字符。这3个函数都是利用作为全局变量定义的mandPortOf8255和APortOfB255,命令或者数据端口直接读写的。本系统的1.CD显示时一个字符占用16x16个象素的显示单元,即其一个字符的显示数据为
26、32个字节。DiSPlaySeIeCted函数和DispIayAtRow函数位于此编程模型之“编程抽象层”,是对SendmandTo1.CDDiSPIayj1.eft、DisplayeRight函数的低层封装。它们使用低层的SendmandTo1.CD等3个函数完成显示数据的功能。DisplaySelected函数在指定的页和列开始送入16个字节的显示数据,即半个字符。1.CD显示屏共32行,分为4页,每页8行,由于一个字高为16个像素,所以这个性质限制了DisplaySelected函数只能显示半个字。此函数隐藏了一个列实现的细节,1.CD由两块显示芯片控制,每一块控制61歹1.即060列为
27、第一块芯片控制,要用Display_1.eft函数显示,第二块控制61121歹U,要用Display_Right函数显示,而此函数可以接受的列为。0x7F。在函数中会对输入的列参数进行判断,小于0x40的列,函数会调用DiSPIayJ1.eft函数显示,大于或者等于0x40的列,函数会调用Display.Right函数显示。这样就完成了列的平滑显示。DisplayAtRow函数是对DisplaySelected函数的进一步封装,此函数的意图是掩盖页的跨越,使之能够以一个函数在1.CD上显示一个完整的、共32字节数据表示的字符。由于DiSPIaySeIeeted函数已经掩盖了列的跨越,所以Dis
28、playAtRow的列参数就直接传递给了DisplaySelected函数。DisplayAtRow函数将整个1.CD分成了两个显示行,每个显示行包含2个页,16个像素行,可以显示一个完整的字符。其实现原理是对于位于第O显示行的字符,调用2次DiSPIaySeIeCted函数,将字符的上半数据送到第O页显示,将字符的下半数据送到第1页显示,这样就完成了整个字符的显示。对于位于第1显示行的字符,将字符的上半数据调用DisplaySelected函数送到第2页显示,将字符的下半数据调用DisplaySelected函数送到第3页显示。这样就完成了页跨越的掩盖。位于1.CD显示驱动最高层,即“显示服
29、务提供层”的函数只有一个,即DisplayA1.ine,此函数是基于DisplayAtRow函数的封装。由于DisplayAtRow函数可以在指定位置显示一个字符,基于这种能力派生的DisplayA1.ine函数的功能就是将一行字符显示在某一个显示行上。由于1.CD最多可以显示8个16x16的字符。所以DiSPIayA1.ine函数显示字符串的最大字符限制也为8个字符。DisplayA1.ine函数用来向其他需要显示的函数提供服务。一个需要进行显示的函数将它要进行显示的数据通过查表或者其他途径转换为1.CD显示的显示码,然后将显示码保存在一个832的数组中传递给DisplayA1.ine函数,
30、然后DisplayA1.ine函数将数组中的数据全部送入某行进行显示。两个提示函数ShowDefauIt和ShowError用于显示必要的提示信息。ShowDefault函数设计成一个死循环,用于显示系统的待机画面。此待机画面用于向用户提示键盘上各个按键的功能。ShowError函数在用户操作出错时向用户显示一个出错提示,以便防止用户误操作。六、总结这个系统是我所设计过的最为复杂的一个系统,虽然硬件部分比较简单,但是这个系统的软件完全是在我已经纯熟的C语言编程技巧的基础上开发的,除了为了了解某些硬件的命令字查看过示例程序外,其他的程序完全是自己开发的,没有参考、抄袭其他任何、报告。通过这个系统
31、的设计,我对KeilC51的语法,开发方法有了较深的认识,可以肯定的说,如果有第二次机会开发这样的系统,那么,在系统控制程序上所犯的错误,将会大大减少。在设计本系统之前,为单片机编写的程序都是较小的程序,一直用汇编语言写。本系统的复杂性使汇编语言程序不利于编写和阅读,所以采用C语言编写。由于我以前都是为Intel80586以上,安装windows操作系统的PC写C语言的应用程序。所以虽然程序完全符合标准C语言的要求,但是由于硬件平台的不同,还是出现了很多问题。现将各种问题一一描述:1、 中断函数寄存器组使用不当:程序中有3个中断函数,在最初每个中断函数使用的寄存器组都不相同,本意是为了提高寄存
32、器的利用效率。定义侦探狗中断TO使用寄存器组1,键盘中断使用寄存器组2,电量中断使用寄存器组3。但是在调试中发生了一个错误。main函数和KeyBoard函数中都调用了DisplayA1.ine函数显示一个字符串。main中的调用可以正常工作,将字符串显示在1.CD上,但是KeyBoard函数中则只能显示字符串的上半行,下半行的字总是显示在1.CD的最左边,从而造成这样一些乱码。这个问题对我们造成了相当的困扰,因为main和KeyBOard调用的是同一个函数。开始时以为是在传递参数时指针出错,后来使用断点调试时才发现,DisplayA1.ine在显示下半行调用DisplaySelected函数
33、时,列Column的实际值都为0,所以所有的字符的下半行都送到第一个字符下面去显示。其后分析认为,产生的错误中,最大的不同是调用DisplayA1.ine函数的位置不同,即一个在mian中,另一个在KeyBOard中,它们两个函数使用了不同的寄存器组。main使用的寄存器组为第0组,KeyBoard使用第2组。由于DisplayA1.ine函数的参数是通过寄存器组来传递的,所以推断使用其他的寄存器组会导致显示错误。将KeyBoard函数使用的寄存器组改为0组,错误消失。2、 数据段溢出错误:在最初的程序中,除了字库外,全局变量、静态变量都按照标准C语言方式默认定义,没有考虑到存储位置的问题。但
34、是链接时发生错误,提示data段溢出。最初不明所以,其后查看C51的帮助文档时看到,如果不显式说明变量的存储位置,则变量会根据系统模式的设置存放到默认的数据区。本系统中使用的是89C58最小系统方式,默认情况下变量会存放到系统的data段,由于data段只有128个字节,而且还有寄存器组和位寻址区,难以容纳所有的变量。了解到这些以后,将所有的全局变量和静态变量都显式声明到idata段,idata段为256字节,足以容纳这些变量,问题得意解决。3、 编译器汇编语言与C语言交叉编译不完善:在本系统程序设计中,在某些位置需要用到汇编中的一条nop指令,由于C语言中并无与此功能相近的语句,所以我们求助
35、于C51中的C语言与汇编语言的交叉编译。即在相应位置力口入#Pragmaasmnoppragmaendasm汇编指令,执行空指令。在编译器中设置好相关选项并进行编译。在我的电脑上安装有KeilC518.02试用版,利用此版本进行编译、链接通过,但是使用版有代码大小限制,无法生成执行文件。实验室安装的为KeilC516.0版,在链接时无法通过,提示大堆的符号未定义。由于编译器版本老旧的问题,为了生成执行文件,只能将相应位置的汇编指令去除或者用与之近似的C语句代替。4、 编译器对预编译指令未正确解释:本系统程序设计时,由于字库比较大,所以最初是将字库定义在一个头文件CharaCterlib.h中,
36、与主程序隔离。这样的话,修改和阅读都比较方便。但是链接时产生错误,连接器抱怨说字库公开变量被多次定义。推断应该是头文件被多个模块包含产生了错误。然后修改了代码,将CharaCterIib.h文件中所有的变量定义都包含在预处理指令#ifndefCHARACTER1.IB_H#defineCHARACTER1.IB_H.#endif,但是在KeilC516.0版本中仍然会产生错误。如果换用KeilC518.0版本,则在头文件中不加预编译指令也不会报错。因为实际上只有main.c包含了characterlib.ho最后,只能将字库定义全部从CharaCterlib.h中移到main.c中,问题解决。
37、我可以容忍设计中出任何问题,但是不能容忍实验室的仪器出一点点问题。这是第一次课程设计时留下的痛苦回忆,设计的完全正确,但是结果完全错误。最后发现仪器装作可以正常工作的样子欺骗我们,那时真想扑上去咬它。这次使用的是湖北众友的单片机开发实验箱,总算是正常工作(并不是每个人的都正常工作,汗)。但是问题并不是没有。由于设计的系统中要用到一个1.CD显示模块,而这个模块是国产的模块,除了厂家外,并没有标准使用说明书。只能参考实验箱的使用手册。在这个手册上提供了3个关于1.CD的信息,一个是Protel画的实验箱的1.CD部分电路图,一个是手册上的1.CD连线示例图,还有一个是1.CD模块引脚说明表。但是
38、,这3个资料中,任意两个对1.CD引脚连线方法的说明都不同。真是很无语,幸好这个问题只影响PCB电路图的绘制,对于编程没有影响,暂时将其忽略To众友开发箱附带的使用手册也令人很无语,居然只有薄薄的58页,还没有我的设计报告长,国产产品的通病。幸好上面的电路图和随机附带的程序源码都还实用,不然的话。关于这个开发板的硬件呢,CPU是SST的89C58,256B可用内存(喜欢),32KB的FlaShROM(喜欢),时钟为33MHzo此单片机带的32KB的FlaShRoM帮了大忙,我的设计中程序共2000多行,1000行为字库,一半存放于外部RAM,一半存放于RoM中。100o行为程序代码。这样加起来
39、,代码大小为15KB,要不是他的ROM足够大,还真的放不下。1.CD为FM12232A液晶显示模块,共122x32个像素。以16x16的像素显示一个字的话,这个模块可以勉强显示2行,每行8个字。但是比较郁闷的是,如果要完全以16x16像素显示8个字,那么至少128x16个像素,这个模块一行只有122个像素,哭。既然要显示汉字,为什么不用128x32的啊,用122显8个汉字就会少6个像素,无语。只能将第四个字和第8个字各少3个像素。虽然肉眼不仔细看的话是看不出来的,总觉得不爽之至。还用到一个键盘,由Intel8279和16键的键盘组成。这个8279,Intel官方出的使用手册共16页,赞,看人家
40、的资料就是详细。自认为英文阅读还不错的我,(平时编程都是直接查MSDN的英文文档练出来的,全英文的芯片手册也看过不少),看到Intel的这个手册后呆了,好多词认识,好多词不认识。结果16页的手册没有几句话是我能看懂的。是我太低了,还是Intel太了?这个设计的题目其实很普通,但是据可靠消息,以前很少有人做这个题目,不幸做了这个课题的中途又改做其他的了。由于我班人积极得拼抢自认为简单的设计课题,结果我们这种沉稳的、看是不够积极的人就落下了这个看似很难的设计课题。本来如果以课程设计的观点来看,这个题目也不是很难。但是恰恰遇到了我这样一个人,在编程上超越了绝大部分做过这种课程设计的人,用以现实世界为
41、依据的观点观察了这个课题,设想了一系列实用的、会在现实中遇到的功能。结果这个课题变得无比复杂了,以致于编写了I(XX)行程序代码才解决了这个问题。一天同学告诉我说他用汇编写的程序都200行了,我说:我昨天晚上就写200行了。如此长的程序以致于有人听到后取笑:听说XXX写的程序2000行。我无法反驳,只是想,对于任何一个实用的系统来说,其控制程序没有短于2000行的吧。对于汇编,虽然我也很了解汇编,但是以前从没有试图比较C与汇编之间的效率问题。但是在这次设计中亲切的了解到了。程序中产生了某些问题,需要断点调试,将程序代码反汇编后吃了一惊。以前听说一般一条C语言一般会被解释为3条汇编指令,但是我以
42、前从未想像到i=0;这样一条语句等于3条汇编指令,而i+;这样一条语句被解释为8条汇编指令。不由得脊背发冷,幸亏最初就决定用C写这个系统,不然的话,我这里共2000行的代码,有I(X)O行是程序语句。如果用汇编写的话,至少要写5000行吧。对于KeilC51,虽然是一个很有用的工具。但是现在不免存在着暇痣。程序中用到了汇编中的一条nop指令,所以使用了KeilC51的C与汇编交叉编译。#pragmaasmnop#pragmaendasm但是KeiIC516中,居然出现了大堆了名称未定义出错提示。而且对于预编译指令#ifndefCHARACTER1.IBHdefineCHARACTER1.IBH
43、#endif居然未正确的解释,无语ing。很高兴这两个问题在KeilC518.02版中已经解决了。关于这些,后面有详细的描述。正如我在题记中所说C51中的C语言,不是C语言。虽然C51中C语言的语法完全相同,但是编程方法和PC上编程有极大的不同。首先PC上面的内存海量,你不用考虑某个变量该放在data?idata?orxdata?当然,最好放在code段,只要你不准备修改这个变量,因为一般单片机的片内RoM比RAM要大很多,ROM以KB衡量,RAM以B衡量。data访问最快,但是最小,只有128B,只能放最最最常用的东西,比如你床头放的东西最方便,但是只能放很少的东西,不然你的床会变成猪窝。i
44、data次之,Xdata为外扩的存储器,容量最大,但是访问最慢。一般放极大但是不常用的东西。其次在安装操作系统的PC上编程,不用考虑USB的端口地址,硬盘的端口地址,显示器的中断之类的。但是在单片机上,控制程序本身就是一个操作系统。经常会用到各个外部芯片的端口地址,中断号之类的。这个时候C51的_at_关键字就帮上忙了。这个关键字我找了好长时间的说。没有这个关键字,整个程序的设计就进行不下去了。因为标准C中并没有提供直接定位内存地址的关键字或者功能。而程序中必须对某些端口进行直接的读写。写到这里,不仅想起了微软。微软的系统一向以兼容性好而出名。单片机编程与PC编程最大的不同大概就是,单片机系统
45、的软件本身就是一个操作系统,而PC编程是对操作系统公开的接口进行编程。简单的说就是,微软给我们很多积木,我们自己来设计其造型。微软为了让操作系统兼容各种硬件做了多少工作?付出了多少努力?创新了多少技术?这恐怕我们这些人难以了解的。但是我自己做这样一个简单的系统就必须加入许多的复杂的技术,完成许多复杂的转换。屏蔽许多硬件的特性,使之使用起来更加柔和,更加贴近硬件。实在难以想象像Windows这样的系统会怎样的复杂。其实我一直迷惑微软是如何将windows制造出来,一直想微软是如何做到的。峰谷分时电价的现状分析与发展趋势探讨电价是电力市场最有效的济调节杠杆。随着电力经济体制改革与电力市场化,运用电
46、价来调节电力经济运行,以优化电力资源配置,提高电力企业整体经济效益,已经势在必行。分时电价是在改革中逐步试点与推广的一种新型电价制度,它是根据不同时段发供电成本不同而制定的不同电价。它包括峰谷分时电价与丰枯分时电价。本文试图对峰谷分时电价的必要性、现状与发展趋势作些探讨。1实施峰谷分时电价的必要性峰谷分时电价是电力产品的瞬时性及供求平衡的客观要求。电能产品作为一种特殊商品,其最大的特点是瞬时性,即电能的产、供、销是同时完成的。电能没有半成品,也不能大量储存。这一特点决定了电能产品供给弹性小,对即时需求依赖性很强。电力产品的特点决定电力企业生产特点是不论发供电设备使用情况如何,设施每天满负荷或轻
47、负荷运行,设备都必须保持良好的状态。而且电力生产除保持电力供求平衡外,为保证安全供电,还必须留有足够的发电备用容量。因此电力企业的基本折旧费、大修理及维修费用、管理费用等固定费用,占电力企业总成本的50%至60%,使生产与供给较为稳定。而电力需求在一年四季与一天的不同时段呈现出波动频繁与波动幅度较大的特点。一年的用电高峰集中于最热与最冷的季节,其它季节为低谷用电;一天的用电高峰集中于18点至22点,低谷用电集中于23点至次日7点。电力生产的稳定性与需求波动性矛盾决定了实施分时电价成为最佳的选择。通过分时电价调节需求,实现供求平衡。峰谷分时电价以均衡价格为理论依据,有利于运用价格机制均衡电力负荷
48、,实现电力资源优化配置。就电力短期供给和需求而言,在某一时点,电力生产成本、物价指数、季节变化、政策变动等因素的影响视为既定,电价便成为调节负荷率、促进资源优化配置的唯一因素。如图所示:假设均衡价格为P2,均衡需求量为Q2,在高峰用电期,需求量为Qh且Q1Q2,此时若实行传统价格不变(假定为P3),则P3P2,一方面促使发电企业为追求超额利润而加大供电量,另一方面用户也将自觉避开电价高峰,调整负荷分布,从而降低高峰需求量,增加低谷用电量,自觉削峰填谷,均衡电力负荷。正是分时电价不同时段的价差在自动调节着电力供给与需求的均衡,从而实现电力资源的有效配置与优化组合。在结构失衡、自然力制约、峰谷差拉大的情况下,实施峰谷分时电价更有必要。长期以来,我国电网建设滞后于电源建设,造成低压配电网多,网架结构薄弱,输配电能力不足,有电送不出;而电源结构较为单一,火电与水电比重较大,其它电源比重小,或刚开始建设起步,调峰电源较少,现有火、水电调峰性能差,加之受自然力影响,如遇酷冷、酷热、洪旱天气的影响,峰谷差急剧拉大,即使某些电网电能较为富余,高峰时也要拉闸限电,低