单片机编程经验

2024-07-23 版权声明 我要投稿

单片机编程经验(精选9篇)

单片机编程经验 篇1

贴子发表于:2008/11/3 21:38:05 经验之一:用“软件陷阱+程序口令”对付PC指针的弹飞

当CPU受到外界干扰,有时PC指针会飞到另一段程序中,或跳到空白段去。其实,如果PC指针飞到空白段去,倒也好处理。只要在空白段设立软件陷阱(拦截指令),将程序拦截到初始化段或程序错误处理段。但是,如果PC指针飞到另一段程序中去了,系统如何办?小匠在这里推荐一种方法——程序口令。思路如下:

1、首先,程序必须模块化。每个模块(子程序)执行一个功能。每个模块只有一个出口(RET)。

2、设立一个模块(子程序)ID寄存器。

3、为每个子程序配置一个唯一的ID号码。

4、每当子程序执行完毕,要返回(RET)之前,先将本子程序的ID号送入 ID寄存器。

5、返回到上级程序后,先判断ID寄存器中的ID号。

如果正确,则继续执行;如果不正确,则表示PC指针有可能已经跳错了,子程序没有按预计的出口返回,这时将程序拦截到初始化段或程序错误处理段。

这种方法,如同在程序中设立了若干个岗哨,每次调用子程序返回后,都要对口令(ID号),验明正身后再放行。再配合软件陷阱,基本上可以将大多数PC指针弹飞的现象检测到。到了程序错误处理段,要杀要剐(冷启动还是热启动)就由您了。

仅以一条代码来揭示程序飞跑的本质!750102H ;MOV 01H,#02H,如当前PC不是指向75H,而是指向01H或02H,那么51内的指令译码器将把她们忠实地翻译成AJMP X01H 或 LJMP XXXXH 而XX01H XXXXH又是什么呢?天知道!这样恶性飞跑下去那还不死定!改革一下:

CLR A ;0C4H INC A ;04H MOV R1,A ;0F9H INC A ;04H MOV @R1,A ;86H

每一字节代码都不能在生成跳转和循环,且都是单字节指令!往那跑去?跑出去了都要自己回来!“在家”千日好!“跳出”事事难嘛!这样只要平时习惯了用累加器和寄存器把数倒一倒,把那些危险代码都给倒掉,这样虽说给PC的“足”上多加了两字节的“包”可它不好“跑”啊!“足包”====跑!有朋友会问:要是PC抓做02H--LJMP 又有抓做了老鼻子远的XXH,再抓做隔壁的YYH不就没用了吗?提这样的问题只有ZENYIN这种钻牛角得才会提!PC那一位最活跃啊?PC0啊!要“扯拐”显然发生在她身上,至于那PC15同志啊,睡得更死猪一样,雷爆(强干扰)来了都打不醒?此外如果干扰都强到了PC高位都出错的地步!关电!关电!不干了!“不是我们不行而是敌人太强大”!反过来要是敌人在你的专政下,只是偶尔出来捣捣乱,但一出来就冲到屁西(PC)高层,就要问问是不是你的王国根基(硬件)有问题了?而非出在意识形态(软件)上!硬件为本!软件为标!标本兼治铸就坚强体魄,方能百毒不侵!

经验之

二、不要轻信软件狗

关于软件狗的讨论,论坛上多矣。匠人也曾经查阅过许多关于软件狗的文章。有些大师确实提出了一些比较有技巧性的方法。但是,匠人的忠告是:不要轻信软件狗!其实,软件狗相当于软件的一种自律行为。一般的思路都是通过设立一个计数器,在计时中断中对其+1,在主程序的适当地方对其清零。如果程序失控了,清零指令未被执行,但中断造常发生,则计数器溢出(狗狗叫了)。但是这里有个问题:万一干扰导致中断被屏蔽了,那软件狗就永远不会叫了!——针对这种可能,有人提出在主程序中反复刷新中断使能标志,保证不让中断被屏蔽。——但万一程序飞到某个死循环中去了,不再执行“刷新中断使能标志”这一功能了,还是有可能把狗狗活活饿死。。

所以,匠人的观点是:看门狗必须拥有独立的计数器。(即硬件看门狗)好在现在好多芯片都提供了内部WDT。这种狗都是自带计数器的。即使干扰导致程序失控,WDT还是会造常计数直到溢出。当然,匠人也没有要将软件狗一棍子全部打死的意思。毕竟不管是软狗还是硬狗,逮到耗子就是好狗嘛(狗拿耗子——多管闲事?)。如果哪位训狗专家确实养过一条能看门的好软件狗,请牵出来让大伙瞧瞧。

经验之

三、话说RAM冗余技术

所谓的RAM冗余,就是:

1、将重要的数据信息备份2份(或以上)并存放在RAM中不同的区域(指地址不相连)。

2、当平时对这些数据进行修改时,同时也更新备份。

3、当干扰发生并被拦截到“程序错误处理段”中时,将数据与备份做比较,采用表决方式(少数服从多数)选出正确(或可能正确?)的那个。

4、备份越多,效果越好。(当然,你得有足够的存储空间)。

5、只备份最最原始的数据。中间变量(指那些可以从原始数据重新推导出来的数据)不必备份,注:

1、这种思路的理论依据,据说是源于一种“概率论”,即一个人被老婆打肿脸的概率是很大的,但如果他捂着脸去上班却发现全公司每个已婚男人的脸都青了,这种概率是很小的。同理,一个RAM寄存器数据被冲毁的概率是很大的,但地址不相连的多个RAM同时被冲毁的概率是很小的。

2、前两年,小匠学徒时,用过一次这种方法,但效果不太理想。当时感觉可能是概率论在我这失效了?现在回想起来,可能是备份的时机选的不好。结果将已经冲毁的数据又备份进去了。这样以来,恢复出来的数据自然也就不对了。

经验之

四、话说指令冗余技术

前面有个朋友问到指令冗余,按匠人的理解,指令冗余,就是动作冗余。举个例子,你要在某个输出口上输出一个高电平去驱动一个外部器件,你如果只送一次“1”,那么,当干扰来临时,这个“1”就有可能变成“0”了。正确的处理方式是,你定期刷新这个“1”。那么,即使偶然受了干扰,它也能恢复回来。除了I/O口动作的冗余,匠人强烈建议大家在下面各方面也采用这种方法:

1、LCD的显示。有时,也许你会用一些LCD的专用驱动芯片(如HT1621),这种芯片有个好处,即你只要将显示数据传送给它,它就会不断的自动扫描LCD。但是,你千万不要以为这样就没你啥事了。正确的处理方式是,要记得定期刷新送显数据(即使显示内容没有改变)。对于CPU中自带LCD DRIVER 的,也要定期刷新LCD RAM。

2、中断使能标志的设置。不要以为你在程序初始化段将中断设置好就OK了。应该在主程序中适当的地方定期刷新一下,以免你的中断被挂起来。

3、其它一些标志字和参数寄存器(包括你自己定义的),也要记得常常刷新。

4、其它一些你认为有必要反复刷新的地方。

经验之

五、10种软件滤波方法

下面奉献——匠人呕心沥血搜肠刮肚冥思苦想东拼西凑整理出来的10种软件滤波方法:

1、限幅滤波法(又称程序判断滤波法)

A、方法:根据经验判断,确定两次采样允许的最大偏差值(设为A),每次检测到新值时判断:如果本次值与上次值之差<=A,则本次值有效。如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值

B、优点:能有效克服因偶然因素引起的脉冲干扰。

C、缺点:无法抑制那种周期性的干扰,平滑度差。

2、中位值滤波法

A、方法:连续采样N次(N取奇数),把N次采样值按大小排列,取中间值为本次有效值。

B、优点:能有效克服因偶然因素引起的波动干扰,对温度、液位的变化缓慢的被测参数有良好的滤波效果。

C、缺点:对流量、速度等快速变化的参数不宜。

3、算术平均滤波法

A、方法:连续取N个采样值进行算术平均运算。N值较大时:信号平滑度较高,但灵敏度较低;N值较小时:信号平滑度较低,但灵敏度较高。N值的选取:一般流量,N=12;压力:N=4

B、优点:适用于对一般具有随机干扰的信号进行滤波,这样信号的特点是有一个平均值,信号在某一数值范围附近上下波动。

C、缺点:对于测量速度较慢或要求数据计算速度较快的实时控制不适用,比较浪费RAM。

4、递推平均滤波法(又称滑动平均滤波法)

A、方法:把连续取N个采样值看成一个队列,队列的长度固定为N,每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据.(先进先出原则),把队列中的N个数据进行算术平均运算,就可获得新的滤波结果。N值的选取:流量,N=12;压力:N=4;液面,N=4~12;温度,N=1~4

B、优点:对周期性干扰有良好的抑制作用,平滑度高,适用于高频振荡的系统。

C、缺点:灵敏度低,对偶然出现的脉冲性干扰的抑制作用较差,不易消除由于脉冲干扰所引起的采样值偏差,不适用于脉冲干扰比较严重的场合,比较浪费RAM

5、中位值平均滤波法(又称防脉冲干扰平均滤波法)

A、方法:相当于“中位值滤波法”+“算术平均滤波法”。连续采样N个数据,去掉一个最大值和一个最小值,然后计算N-2个数据的算术平均值。N值的选取:3~14

B、优点:融合了两种滤波法的优点,对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差。

C、缺点:测量速度较慢,和算术平均滤波法一样,比较浪费RAM。

6、限幅平均滤波法

A、方法:相当于“限幅滤波法”+“递推平均滤波法”,每次采样到的新数据先进行限幅处理,再送入队列进行递推平均滤波处理。

B、优点:融合了两种滤波法的优点,对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差。

C、缺点:比较浪费RAM。

7、一阶滞后滤波法

A、方法:取a=0~1,本次滤波结果=(1-a)*本次采样值+a*上次滤波结果。

B、优点:对周期性干扰具有良好的抑制作用,适用于波动频率较高的场合。

C、缺点: 相位滞后,灵敏度低,滞后程度取决于a值大小,不能消除滤波频率高于采样频率的1/2的干扰信号。

8、加权递推平均滤波法

A、方法:是对递推平均滤波法的改进,即不同时刻的数据加以不同的权。通常是,越接近现时刻的数据,权取得越大。给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低。

B、优点:适用于有较大纯滞后时间常数的对象和采样周期较短的系统。

C、缺点:对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号不能迅速反应系统当前所受干扰的严重程度,滤波效果差。

9、消抖滤波法

A、方法:设置一个滤波计数器将每次采样值与当前有效值比较:如果采样值=当前有效值,则计数器清零如果采样值<>当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出),如果计数器溢出,则将本次值替换当前有效值,并清计数器。

B、优点:对于变化缓慢的被测参数有较好的滤波效果,可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动。

C、缺点:对于快速变化的参数不宜,如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统。

10、限幅消抖滤波法

A、方法:相当于“限幅滤波法”+“消抖滤波法” 先限幅,后消抖。

B、优点: 继承了“限幅”和“消抖”的优点改进了“消抖滤波法”中的某些缺陷,避免将干扰值导入系统。

C、缺点:对于快速变化的参数不宜。

IIR 数字滤波器

A.方法:确定信号带宽,滤之。Y(n)= a1*Y(n-1)+ a2*Y(n-2)+.+ ak*Y(n-k)+ b0*X(n)+ b1*X(n-1)+ b2*X(n-2)+.+ bk*X(n-k)。

B.优点:高通,低通,带通,带阻任意。设计简单(用matlab)

单片机编程经验 篇2

关键词:计数程序,设计修改

1 软件介绍与仿真教学

PROTEUS软件是英国Lab Center Electronics公司出版的EDA (电子设计自动化) 工具软件。 Keil C51 是美国Keil Software公司出品的51 系列兼容单片机C语言软件开发系统。两软件的联合调试是单片机仿真教学的基础。通过实验室仿真实验, 可以使学生深入学习单片机编程技术。起到单纯的理论教学无法企及的教学高度。本文通过0 ~ 59 计数器的基本编程和仿真的变化过程, 来探讨此类仿真教学的特点。

2 计数问题基本编程与创新设计

设计一个计数电路, 在7段数码管上显示。要求按一下按键, 计数器增加一个值。从0开始到59计数。首先在PROTEUS的设计区, 设计对应的电路图。见图1。然后, 使用KEIL C51程序设计对应的C语言程序。如图2所示。

在PROTEUS程序中调用KEIL C51 编译后的HEX十六进制程序, 开始联合调试软硬件程序。程序的调试结果见图3。这是基本程序的的设计与调试过程。当学生按照设计要求, 调试成功基本程序后, 将获得一种成功的喜悦。在基本程序基础上, 对学生提出再次修改的要求。要求学生修改按键的硬件接口电路。软件的相应口定义将随之改变。然后重新仿真整个过程;修改百位计数器的变量值, 使计数由0 ~ 59, 变为0 ~ 10、0 ~ 20、…0 ~ 100, 重复整个仿真过程;将秒脉冲发生器放到按键位置代替按键, 变成秒计数器。通过这些变化, 启发学生积极主动的创新思维, 使学生深入理解与自我单片机设计的精髓, 达到一通百通, 融会贯通的学习效果。实践证明, 使用PROTEUS和KEIL C51 仿真软件, 在基础编程的基础上, 扩展思路中变化设计方案, 可以极大地促进学生的学习积极性和主动性, 提高学生对获得知识的兴趣, 提高学生的自主创新能力。

参考文献

[1]《单片机C语言应用100例第二版》王东峰, 陈圆圆, 郭向阳编著电子工业出版社2013.5

[2]《8051单片机C程序设计完全手册》求是科技编著人民邮电出版社2006.04

单片机编程经验 篇3

【关键词】可编程控制器;单片机;串行通信

串行通信是一种广泛应用于各个领域的通信方式,西门子S7-226可编程控制器与AT89S51单片机的结合作为一种新的串行通信方式,它在工业领域有广泛的运用,无论是从实用性还是灵活度的角度分析,该设计的结构都相对比较简单,且制作成本也相对较低,具有较强的发展价值。

一、参与试验中的通信硬件综述

1、试验中的单片机通信功能概况

AT89S51单片机是一种低功耗,高性能的单片机,包括4k字节的网络服务提供商能够对Flash只读程序存储器反复擦写一千次,另外还有128字节的随机存储器和一个全双工串行通信端口,不仅可以进行网络间通讯,而且还可以实现串行的异步通讯,甚至可作为一个同步的移位寄存器进行使用。一般来说,这种单片机可通过串口的中断实现数据的传输,由于它的串行通信口输出为TTL电平,在外在端口变为RS232端口进行全双工通信时,可以通过相应可靠型号的芯片等进行电平转换。而与外设含有RS-485接口时,则必须选择与之相对应型号的配套芯片实现电平的转换来进行半双工通信。

2、试验中的可编程控制器通信功能概况

西门子S7-226可编程控制器具有13K字节程序的数据存储量,两个9针RS-485端口与24路输入和16路输出,共包含40个数字量的I/O点,支持点至点、多点接口,自由通信等协议。PPI协议作为主从协议中的主站必须按照所要求的指令向从站设备传输信息。而从站设备只有响应的职能却不能够提供有效的信息反馈给主站的一方。PPI协议广泛应用于可编程控制器同触摸屏之间的通讯中。这其中主站是触摸屏,从站是可编辑控制器,通过触摸屏来传输指令,可编程控制器进行响应,但是并不向触摸屏发送反馈信息。而相对于许多的端口来说,可编程控制器允许主站与主站,主站与从站之间的通讯,而如果控制器是相对较大的规模的话,并且这个控制系统具有大量的控制器和集成线路端口,完成通信过程则需要借助其他的协议才能实现。针对自由方式的通信,则可以依据用户的需求对通讯协议进行配置和编程,就可以达成像单片机、打印机和变频器等一系列类似设备之间的联通灵活通信了。

二、参与试验的项目设计

1、参与试验的项目硬件构成

AT89S51单片机同西门子S7-226可编程控制器之间实现信息传输与反馈需要遵守以下流程来实现。西门子S7-226控制器上只有唯一一个RS-485端口,通过此端口接受发送器来连接单片机。因此需要选择有效可靠的端口来达成,可编程控制器所发出的485电平信号就可以通过转换进而变为单片机可以接收的信号,并借助相应形式的串口联结线实现内部寄存器的输入。可编程控制器同单片机间无法同时进行接收和发送主要是由于端口处所使用的是半双工的方式。这样,它们在进行信息的实时发送过程中,需要一个来自外部的硬件握手信号来实现二者的联结。

此次试验项目里在可编程控制器端选用的是1个数字量的输入口I0.0和输出口Q0.0,而内部寄存器端口采用的是并口P1中的P1.0、P1.1以及P1.2。以下是二者實现联结的具体操作事宜:当单片机需要向可编程控制器反馈信息的时候,置位P1.2可通过光耦PC817进行24V高电平向I0.0的输出,当前可编程控制器便是处于接收端的状态,要中断并对接收信息进行相应地设置,微控制器置P1.0低电平时也可以实现与指定端口之间的传输。这样,信息便通过相应的端口向选定好的端口实现传输发送,并且又转换为可编程控制器端口可以接收到的信号。而可编程控制器需要向单片机进行信息的发送时,可编程控制器可借助输出口Q0.0向单片机的P1.1进行高平点的发送,微控制单元进行串口中断的设置,置P1.0作为高电平接收信息。

2、参与试验的项目通信协议的设计

可编程控制器和单片机二者实现串口通信需要借助RS-485来完成,RS-485作为一种标准协议必须规定并提供指定对应的七层网络协议模型中最底层的规定,双方还需要进行其他的一些协议规定,比如字符格式以及波特率等内容。依照参与试验中各个具体项目的实际特性,在传送过程中进行相应的规定,无奇偶校验,并选择相对应的波特率。同时,加入帧校验码或者对起始字符和结束字符进行相应的标准化规定以保障在发送数据时整个通信过程的稳定和可靠。在计算帧校验码的过程中,必须以字节为依据对所传输的数据通过异或运算方式得出最终的数据,将所得结果发送给接收方,后者再进行相同的运算。然后将后者得出的结果与前者相较,如果前后运算结果出现了偏差,那么就要对发送过来的错误信息予以放弃并要求重新发送,数据传输格式如下所示:

起始字符状态信息有效数据帧校验码(FCS)结束字符

实际上,无论什么样的可编程控制器都能够与单片机通过串口完成通信,关键是要掌握该可编程控制器的通讯协议,了解帧的传送格式,这样便可以达成两者之间的串行通信了。

结语

如今,单片机与可编程控制器的结合使用已被广泛应用于许多领域,掌握可编程控制器的通信协议,使其与单片机通过串口完成通信的设计具有重要的现实意义。

参考文献

[1]李生军,李少蒙.单片机与PLC之间的串行通信实现[J].化工自动化及仪表,2010,37(2):78-80.

[2]武德庆.单片机与PLC串行通信数据传输模式实现[J].民营科技,2010,(09).

[3]刘慧龙,陈高辉.单片机与PLC的串口通信设计[J].科技创新与应用,2012,(11).

单片机编程经验 篇4

信息学院(院、系)专业班组单片机原理及接口技术课实验三单片机串行口编程

一、实验目的1、掌握单片机串行口的工作方式;

2、掌握单片机串行口的编程方法。

二、实验内容

1、学习单片机串行口的工作方式、初始化以及应用等;

2、利用单片机串行口编写程序在超级终端输出输入相应信息并根据输入的信息驱动开发板上的蜂鸣器按一定规律工作。

三、实验设备

1、STC单片机开发板;

2、PC机以及串口线。

四、实验步骤

参考实验指导书。

编程经验 篇5

序和分组就是典型的例子。在应用层做性能提升总是要比在数据库层容易的多。就像对于MySQL,sqlite更容易掌控。

2.关于并行计算,如果能避免就尽量避免。如果无法避免,记住,能力越大,责任越大。

如果有可能,尽量避免直接对线程操作。尽可能在更高的抽象层上操作。例如,在iOS中,GCD,分发和队列操作是你的好朋友。人类的大脑没有被设计成用来分析那些无穷临时状态——这是我的惨痛教训所得。

3.尽可能简化状态,尽可能局部本地化,适用至上。

4.短小可组合的方法是你的好朋友。

5.代码注释是危险的,因为它们很容易更新不及时或给人误导,但这不能成为不写注释的理由。不要注释鸡毛蒜皮的事情,但如果需要,在某些特殊地方,战略性的长篇注释是需要的。你的记忆会背叛你,也许会在明天早上,也许会在一杯咖啡后。

6.如果你认为一个用例场景也许“不会有问题吧”,它也许就是一个月后让你在发布的产品

中遭受惨痛失败的地方。做一个怀疑主义者,测试,验证。

7.有疑问时,和团队中所有相关人交流。

8.做正确的事情——你通常会知道这指的是什么。

9.你的用户并不傻,他们只是没有耐心理解你的捷径。

10.如果一个开发人员没有被安排长期的维护你们开发的系统,对他保持警惕。80%的血、汗、泪水都是在软件发布后的时间里流的——那时你会变成一个厌世者,但也是更聪明的“行家”。

11.任务清单是你的好朋友。

12.主动让你的工作更有乐趣,有时这需要你付出努力。

13.悄无声息的崩溃,我仍然会为此从噩梦中惊醒。监控,日志,警报。清楚各种的假警报

和不可避免的感觉钝化。保持你的系统对故障的敏感和及时警报。

单片机编程经验 篇6

李红志

程序的可读性、可扩展性、可复用性、易维护性、语法是代码的入门,算法是代码的灵魂。

第1章 编程常见错误

1.1、语法错误

1、错用函数数据类型,比如abs(x),x可能为16bit的值,如果为16bit的值,给出32bit的值就会出错。

2、内存越界访问

内存越界访问有两种:一种是读越界,即读了不属于自己的数据,如果所读的内存地址是无效的,程度立刻就崩溃了。如果所读内存地址是有效的,在读的时 候不会出问题,但由于读到的数据是随机的,它会产生不可预料的后果。另外一种是写越界,又叫缓冲区溢出,所写入的数据对别人来说是随机的,它也会产生不可 预料的后果。

3、结构的成员顺序变化引发的错误

在初始化一个结构时,老手可能很少像新手那样老老实实的,一个成员一个成员的为结构初始化,而是采用快捷方式,如:

Struct s { int l;char* p;};int main(int argc, char* argv[]){ struct s s1 = {4, “abcd”};return 0;} 以上这种方式是非常危险的,原因在于你对结构的内存布局作了假设。如果这个结构是第三方提供的,他很可能调整结构中成员的相对位置。而这样的调整往 往不会在文档中说明,你自然很少去关注。如果调整的两个成员具有相同数据类型,编译时不会有任何警告,而程序的逻辑可能相距十万八千里了。

4、栈溢出。

我们在前面关于堆栈的一节讲过,在PC上,普通线程的栈空间也有十几M,通常够用了,定义大一点的临时变量不会有什么问题。

而在一些嵌入式中,线程的栈空间可能只5K大小,甚至小到只有256个字节。在这样的平台中,栈溢出是最常用的错误之一。

1.2、编译错误 1.3、链接错误

第2章 编程知识

关键字valotile的作用是告诉编译器,不要把变量优化到寄存器里。

第3章 编程规范

1.1 整体结构

1、必须包含的两个文件:

“#include “std_inc.h”” “#include “std_defs.h””

2、一个完整的project需要有程序说明文档

3、需要有变量宏定义函数说明文档,包含变量规则命名。

4、需要有程序流程图

5、需要有硬件测试报告

6、需要有程序修改记录

7、要有软件时间控制分析

1.2 编程规范

1、定义宏定义按照功能模块来区分;

2、枚举型定义当宏定义来处理;

3、程序和数据要分开;

4、格式上要对齐;

5、空行要规范;

6、中断中调用的变量,一定要分析在计算过程中别的地方赋值是不是有非本身意义的赋值;

7、变量的意义要清晰;

8、程序要分层设计; 9、1.3 注释规范

1、变量和宏定义都要在定义的时候注释一下,作用是什么,单位,放大倍数。

2、用“#”标记需要问别人、需要改进的地方。

3、用“$”标记如果硬件改变需要进行变化的地方。

4、用“// XX”。

5、每个函数上面都要写注释;

6、程序段内不要太多的注释,多的话影响程序的可读性;

1.4 变量命名

1、变量名用小写

2、宏定义用大写

1.5 不建议使用全局变量的原因:

(1)全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元;

(2)它使函数的通用性降低了,因为函数在执行时依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。但若该外部变量与其他文件 中的变量同名时,就会出现问题,降低了程序的可靠性和通用性。在程序设计中,在划分模块时就要求模块的“内聚性”强、与其他模块的“耦合性”弱。即模块的功能要单一(不要把许多互不相干的功能放到一个模块中),与其他模块的相互影响要尽量少,而使用全局变量是不符合这个原则的。一般要求把C程序中的函数做成一个封闭体,除了可以通过“实参——形参”的渠道与外界发生联系外,没有其他渠道。这样的程序移植性好,可读性强。

(3)使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时各个外部变量的值。在各个函数执行时都可能改变外部变量的值,程序容易出错。因此要限制使用全局变量。

(4)如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。

说明:使用全局变量的作用是增加了函数间的数据联系的渠道。由于函数的调用只能带回一个返回值,因此有时可以利用全局变量增加与函数联系的渠道,从而到到一个以上的返回值。

第4章 2011-4-22:程序的矩阵化设计思想

适用于嵌入式软件设计,无操作系统,软件结构较复杂的情况。

1.6 定义

最小时延原则:软件设计过程中,在不影响其他性能的情况下,应该让数据的产生过程和使用过程之间的时延最小。

需控变量:软件运行过程中,需要控制计算顺序的全局变量。

非需控变量:软件运行过程中,不需要控制计算顺序的全局变量,比如从总线引发的中断中获取的信号。

优化矩阵:在设计函数执行顺序时,用于记录函数和函数输出变量的矩阵。1.7 软件结构的矩阵化

程序上的分层设计。层与层之间有接口。矩阵化设计。全局变量的作用范围要有设定,不能从上到下都是一种变量。分层设计后,才比较容易处理指令冲突的问题,因为指令被执行之前会有对几种指令进行判断的操作。模块化是矩阵化设计的基础,模块作为矩阵的cell,同一个层面的作为一个row,程序执行一次,就是从顶层到底层一次,只不过每次可能走的trace不同。这个trace就是程序真正运行了哪些模块。

程序应该是从模块化、发展到分层、再到矩阵。

环境识别、驾驶意图识别、干预退出预估、1.8 函数执行顺序的矩阵化

适用情况:系统信号较多,全局变量较多,在一个控制周期内,相互之间有计算先后要求。同一层次的函数较多。全局变量只在一个函数中被赋值,在多处被调用。

全局变量分为需控变量和非需控变量。

该方法是对某一层的函数进行执行顺序的设计 1.对每一个函数进行编号;

2.建立需控变量集:将每一个函数的输入全局变量和输出全局变量中的需控变量放进需控变量集。3.对需控变量集中的每个元素编号;

4.建立每个函数的输入需控变量集和输出需控变量集,变量集用需控变量集中元素编号表示;

5.逐个将函数添加至优化矩阵,每添加一个函数,调整优化矩阵,直到所有函数添加完成。得到每个函数的可存放域。

6.根据最小时延原则,调整每个函数到最优位置。7.输出可行的函数序列。第5章 编程经验

1.9 程序设计思想 控制时序的设计思想: 程序分层的设计思想: 程序的矩阵式设计思想; 变量的集中处理思想; 变量自衰减的处理思想;

估算变量的自衰减。估算变量时,由于只有满足估算条件才能进行估算,而估算条件不是持续成立的,所以只能在某些点进行估算。没有进行计算的地方,该变量就要随时间衰减,并且要给出一个health指标,表明这个被估算值的可信度。

干预退出预估的处理思想;

1.10 【2010-12-5】

1、能从CAN上获取的信号要从CAN上获取,比如发动机转速、发动机输出转矩、加速踏板位置(不知道还有用没了)、节气门开度(不知道还有用没了)、传动比(或者说档位)。

2、我觉得用115200,10ms传出100个byte没什么问题。这样的话,B+S的采集主要作用就在于同步一下压力,方向盘、横摆等信号用更高的频率采集,确认一下单片机的处理是否达到精度。

3、变量命名的规范化。全局变量中的temp,写成s32temp1,局部变量的temp,写成temp1s32.感觉不怎么好,但是总要区别一下的。

4、abs(x);的函数原型是int abs(int x)

5、尽量避免一个变量在不同程序段被幅值;

6、中断中用到的量,要小心在程序外会不会有非本身含义的短时间赋值;

7、一段代码尽量不要超过100行;

8、全局附着比局部复杂要复杂;

9、任何一段代码,要做到能用1句话描述;

10、【2011-7-4】

代码变成各种意义明确的节的优点:

1、高可靠性:每段很小,就更容易做到确认代码不会出问题,更能确认该段指令是千锤百炼的,绝对可靠的;

2、可维护性强:由于每段很小,很容易看懂,调试及修改都更方便;

3、可扩展性强:如果某一种计算有问题了,只用替换或修改某一小段,而不用到处找需要改哪些地方;

4、可复用性强:对某些小段,可能多个地方都可以用到,不用在不同的地方写很多次;

5、结构清晰:每一小段意义明确,程序结构、层次、调用关系、数据流等都更清晰;

6、可读性强:由于结构清晰,增加了可读性,另外结构清晰了,就容易写清楚注释,也增加了可读性;

7、函数无条件执行的优点:

1、结构更清晰:不用考虑是否执行了;

2、数据流更清晰:一个新的计算量由哪些变量得到,传递关系更清晰;

3、函数的模块化更好:能让函数无条件执行,表示该函数具有更高的独立性,也就是模块更完整,与其他代码的耦合程度更低,迁移更方便;

4、程序清晰之后,程序结构简单,从而增加可靠性;

5、集中处理的优点:(集中处理是只,如果一个变量的计算,在不同条件下,算法不同,那么把条件汇总到一起,在一段代码处处理这个变量)

1、结构清晰:一个变量的计算只出现在一个位置;

2、分散处理会造成同一个值在一次运算周期重复计算,后面的计算结果覆盖前面的计算结果,从而难以控制数据流;

3、【2011-7-5】

1、ESP方式的减压和泄压:开关控制方式下,两者没什么区别;

2、ABS方式的减压:减压速率和ESP减压方式差别很大;远小于ESP泄压速率,近似1/2关系;

3、Bosch 8.1的HCU,保压时有个大约90Hz的噪声,和王伟玮讨论了一下,基本上可以理解为那就是当时电机转动频率;

【2011-7-6】

1、在举升机上,两前轮确实会有转速差,并且转速差可能越来越大;

2、阀的端口,烧程序时的状态确认;没有高电平的;

3、粗略来讲,泄压速率正比于轮缸压力?

4、轮缸制动液净进入量和轮缸压力什么关系?在常用的范围内,大概是正比关系;

5、制动轮缸制动液液量增大了,谁变形了?制动盘、摩擦块、制动钳,还有谁?那个变形大?是不是制动钳>摩擦块>制动盘(最大也就0.1mm),6、主动增压时,进油速率基本恒定。HCU中的柱塞泵效率大概50%,好点儿能到60%;轮缸压力大,效率可能稍微高一点儿;轮缸压力大,电机转速稍微低一点儿。

7、【2011-7-8】

1、大型的复杂的程序,用面向对象编程效率要高得多;单就变量的private和public设定而言,就会减少很多变量赋值的误操作,相当于自动添加了一种自检验机制;其他还有很多优点。

2、应该把每个函数都做一个更新记录。这种更新记录怎么能做到比较容易看到上次的状态呢?难道只能把不同状 态都记录下来看的时候再对比?

3、【2011-7-9】

1、轴距和FMVSS126的A值之间的关系,基本上只轴距减小10%,A值减小3%(尊驰在CarSim中的仿真结果)。2DOF理论上应该成比例改变的,实际上可能悬架、轮胎的柔性有影响。

2、尊驰和C118在CarSim中仿真的A值大概都是31deg。

3、.c中的函数,必须在.h中声明,不是为了能被调用,还是为了比较直观地看到在这个.c文件中定义了哪些函数;

4、单片机上,除0,会怎样?

经测试,初步结论:正值/0 = 0xF*F,负值/0 = 1

5、坡道TCS之所以困难,就在于压力估算的偏差影响对坡度的识别,压力的持续控制也比较困难;

6、坡道对前轴载荷几乎没影响。cos(15deg)= 0.985

【2011-7-13】

1、任何一个条件执行的函数,都涉及到不满足条件时不执行了,它计算的变量清零,还是怎么处理。条件选择,都是选取一种处理方法,那么必须对任何一种处理都有对应的方法。

2、条件运算的函数改变的变量,函数不运行时也需要对变量进行赋值;函数在程序中的作用,就是为了给那几个变量赋值,不运行了,就要用其他方式赋值;

3、先分好层次,定义清楚变量和函数,画好框图再写程序;

4、定义文件之间的接口,函数之间的接口;

【2011-7-29】

1、数据后处理中用数据组合成控制信号,是不靠谱的。组合生成一些信号比较靠谱。

【2011-8-12】

1、程序要写到什么样才算好?多一个字则太多,少一个字则太少,天衣无缝,完美无暇,千锤百炼,炉火纯青。

2、一群人,怎么才能做好一个程序?首先定义清晰,规则明确,不能越俎代庖,每个人有不同的权限去维护不同的代码。每个人都要遵守其中的规则,不守规则的那个人就是系统的bug。

3、虽然说程序是调出来的,但是还是应该尽量写的时候就写完善,不能写得一塌糊涂而等调试去解决问题。写的时候,关注的只是那么几十行,而找bug的时候,关注的可是几千行,这效率能一样么?

4、大程序设计首要原则,降低各部分耦合度。

5、如果每个人负责几个文件的话,就不要轻易定义全局变量了,要尽量使用静态全局变量(作用域为本文件)。定义全局变量要先看全局变量库,并建立并进行登记。

6、以前程序很大的一个问题就是层次没分清,从而耦合度高,混乱。

7、格式上,所有的一块儿逻辑前面要有空行,比如if之类的。

8、定义一个新变量前,先检查一下是否已存在这个变量名。

9、函数中间尽量不用return,结构混乱。

10、减少调用层次;

11、程序的本质是什么?数据流;

12、函数的作用是什么?计算数据;

13、写程序的本质是什么?用矩阵化方式决定数据流的运行;

14、为什么要分层?降低耦合度;

【2012-2-5】

1、把OBJ中的一段,ID中的一段儿留给调试。也是分层的概念。

单片机编程经验 篇7

引言

中断服务例程是单片机应用系统的重要模块。采集数据是中断程序的主要工作之一, 这个过程较为短暂, 因此要求中断能够及时采集数据, 而对于处理数据的时间是较为宽松的。但是当系统中待处理的中断较多, 会导致程序执行效率降低;如果并发中断较多, 那么系统的性能大大降低了。为了解决中断的实时响应和数据处理耗时之间的矛盾, 通常在整个系统中, 数据采集和标志位设置被放置在中断服务中, 而将数据处理放置在中断的外面;与此同时, 可以采用消息及其消息循环机制来提高系统的效率。将中断产生的标志位看做消息, 将数据处理过程放置于消息循环之外, 可以解决采集数据和处理数据之间的矛盾, 从而提高系统整体的性能。

基于消息循环的编程机制

1 消息驱动机制。在面向对象 (Object Oriented, OO) 的编程模式里面, 通常使用消息机制来实现对象之间的通信过程。程序也是通过消息机制请求对象并进行处理的, 而各个对象之间的通信也是通过消息机制来实现的;在消息结构中, 包含了消息发送者的请求信息, 消息接收对象在获取到消息之后, 可以根据一定的处理机制来处理或者继续分发传递消息。一旦对象产生并发出消息之后会进入消息队列, 也可能不会进入消息队列而被直接传递给对象, 而主程序的作用是负责组织消息队列, 然后分发给消息处理Object。

2消息循环在单片机编程中的应用。单片机是单任务系统, 和传统的WINDOWS操作系统相比, 它不能同时执行多个程序, 而且系统资源相当有限。WINDOWS系统采取消息循环机制, 而单片机系统无法使用庞大的消息循环因此可以采取简化的操作方式, 可以这样来定制消息循环机制:当某个中断 (事件) 产生时, 中断例程会设置标志位状态, 而不同的状态位表示不同类型的消息和内容;而主程序的工作是判别标志位, 从而决定启动消息处理例程 (方法) 。如果采取这样的消息循环机制, 可以有效利用系统的有限资源, 从而实现数据采集例程和数据处理例程的完美结合, 可以大大提高单片机应用系统的整体性能。

基于消息循环机制的单片机多任务系统软件设计

在单片机应用系统软件研发过程中, 通常会使用到各种各样的中断事件处理程序。如果中断程序较多或者中断处理程序内容较多、过程复杂时, 容易导致中断服务例程的性能降低, 处理时间较长;此时如果有额外的中断事件发生时, 单片机控制系统无法及时处理, 尤其是对于像MCS-51两级中断优先级的单片机, 很难实时、快速响应中断事件。而对于实时性较高的中断事件来说, 这种效率很难快速采集数据, 但是对于数据处理的程序例程是相对较为宽松的。

因此, 可以在中断服务例程中完成数据采集的处理以及标致标志位设置的过程, 并将处理数据的过程放置在中断服务例程之外;与此同时, 把中断事件产生的标志位看做是消息结构, 并将处理数据的程序例程放在消息循环程序中, 可以有效优化中断服务例程的结构, 从而提高主程序响应中断事件的速度。另一方面, 这样的程序结构不会影响到数据处理的总体效率。而且采取这样的消息循环机制, 可以有效避免代码重入带来的堆栈混乱、溢出等种种问题。采取基于消息循环驱动的程序结构, 一般都是在主程序中处理消息循环过程, 然后根据消息发送对象的信息来选择相应的处理函数, 接收消息结构的对象则调用响应消息的相关函数;一旦消息响应函数收到主程序发送的消息时, 消息响应函数取得程序的控制优先权, 等该响应函数完成相关的处理过程中, 再将程序控制权交还给主程序, 然后主程序继续执行下面的代码。采取这种消息循环处理机制, 不仅促使程序结构更加清晰、明了, 而且也能够提高单片机应用系统设计的效率, 精简并优化系统结构, 从而提高单片机系统的实际应用能力, 也能提高系统的适应性。

消息循环在单片机编程中的实例分析

1 系统方案设计

下面以一个单片机应用系统实例来分析消息循环机制的应用, 即8051单片机UART接口和PC主机RS232接口进行通信, 在此介绍基于消息循环的处理机制在系统中的应用。

UART接口, 8051序列单片机的UART接口主要用于串行通信过程, TXD端发送数据, 然后从RXD端输入;其中一个SBUF作为发送缓冲区, 另外一个SBUF作为缓冲接收器。UART接口主要用于全双工串行口, 它可以结合驱动芯片实现和PC主机的通信。

2 通信需求分析

(1) 串行口波特率要求

8051单片机UART接口在和RS232C进行通信时, 一般会选择11.06左右的震荡频率。

(2) 通信初始化处理过程

首先确定定时器1的工作模式:使用TMOD寄存器;计算并确定定时器1的初始值:装在TL1和TH1;启动定时器1:设置TCON中的TR1标志位;确定串行口的控制方式:SCON编程;在串行口在处于中断时, 必须开CPU中断, 这通过IE寄存器来实现。

3 编程方法对比分析

在一般情况下, 我们会把中断事件发生处理的工作全都放在中断服务例程中, 而主程序只需要负责初始化系统并且等待消息达到并处理消息。但是这种设计方案存在多方面的问题:

(1) 中断事件服务例程处理事件较长, 此外CPU不会在同一时刻处理同一级别的中断事件。

(2) 采取同样的消息结构可能会带来代码重入的问题, 这样会增加堆栈的内存开销, 从而产生难以预料的结果。

(3) 而使用基于消息循环的编程机制, 则使用中断事件服务程序向主程序的消息队列结构发送消息, 从而分离中断事件服务例程的处理程序, 可以大大提高单片机应用系统的整体性能。

4 消息循环机制的应用

将消息循环处理机制引入到8051单片机UART接口和RS232C接口通信程序中, 其主要的处理过程如下:将通信处理过程分成若干个中断服务例程, 一序列的中断服务例程会向主程序发送相应的消息, 当中断服务例程处理完毕会返回到主程序, 然后由主程序跳转到消息处理函数中;这样一来, 中断事件服务例程只需要添加生成消息, 然后由主程序分发消息到消息处理函数中;而且采取消息循环处理机制可以避免消息处理函数相互调用而产生的代码重入问题, 这样可以有效避免代码重入的弊端, 参考下述中断服务例程和主程序的代码:

结语

单片机编程经验 篇8

方案一:采用模拟开关实现程控增益放大器。如图1所示,模拟开关可由数字编码控制以选通电阻网络中的不同阻值。该方案实现简单,但其缺点是放大倍数级差变化较大,可调范围较小。

方案二:利用数字电位器与运算放大器构成程控增益放大器,如图2。其特点是,可实现量程多级变化而且线路简单,但由于数字电位器制造工艺等因素限制,其通频带受限。

方案三:利用D/A转换器实现程控增益放大器,如图3。D/A转换器内部有一组模拟开关控制的电阻网络,与运放一起可组成可控增益放大器。该方案能很好的实现数字控制。

综上所述,方案三中采用D/A转换器组成的可编程放大器,具有较好的微机接口功能,使得其实现电路简单、可靠且通频带能满足题目要求,故选择方案三。

2系统设计一硬件设计

2.1稳压电源模块

稳压电源电路采用三端固定式稳压器,220V交流信号经变压、整流、滤波,再通过7812、7912、7805产生稳定电压给系统供电。在电路中,芯片输入端和输出端与地之间除分别接大容量滤波电容外,另外我们还需在芯片引出脚根部接小容量电容到地,分别用于抑制芯片的自激振荡和压窄芯片的高频带宽,减小高频噪声。

2.2程控放大模块

为了易于实现最大60dB增益的调节,可以采用D/A芯片DAC0832的电阻权网络改变反馈电压进而控制电路增益。又考虑到DAC0832是一种廉价型的8位D/A转换芯片,其输出其中Dn为8位数字量输入的二进制值,可满足256挡增益调节,满足题目步进0.25db的精度要求。它由CMOS电流开关和梯形电阻网络构成,具有结构简单、精确度高、体积小、控制方便、外围布线简化等特点,故可以采用DAC0832来实现信号的程控衰减。但由于DAC0832对输入参考电压Vref有一定幅度要求,为使输入信号在mV~V每一数量级都有较精确的增益,最好使信号在到达DAC0832前经过一个适应性的幅度放大调整,再通过DAC0832衰减后进行相应的后级放大,并使前后级增益积为60dB,与DAC0832的衰减分母抵消,即可实现程控放大。

2.3功率放大模块

题目中要求,输出能够带50Ω电阻负载,而输出电压峰峰值最大可达20V,则其要求最大功率为:故要对其进行功率放大。为避免交越失真带来的信号失真,采用甲乙类双电源互补对称电路(图4)。

2.4极性变换模块

单极性信号是指输出信号大于0,双极性信号则是指输出既有大于0的部分也有小于0的部分。因此,采用加法电路的方式将双极性信号变为单极性信号。

2.5 AGC功能模块

根据题目要求,要实现自动增益控制,使信号输出峰峰值在2到3V之间。设计该模块时,用STC52单片机内自带的AD转换器对输出信号峰值实时采样并调节内部增益,从而控制输出信号峰值(图5)。

2.6键盘及显示模块

为满足,增益可设置、步进以及功能选择,本系统采用4×4矩阵式键盘以节省单片机IO资源;显示部分最高显示增益为1000,故采用4为一体的共阴极数码管。

3误差分析

造成误差的原因有:(1)运放零点漂移。由于运算放大器的零点漂移,温度漂移等带来的误差,可以通过温度补偿措施来解决此误差。(2)采样电阻自热效应引起的误差。由于电阻在温度上升时阻值会发生变化,因此会引起温度飘移,给系统带来测量的误差。(3)A/D,D/A转换误差。受AD转换器精度及基准源稳定程度的限制,不可避免地带来一定的误差,为了更精确的输出恒流电源,必须选用更多位数的AD、DA芯片。(4)因外界突发干扰或仪表显示值等引起的随机误差或粗大误差。(5)纹波对电流输出的影响。

减小误差方法:采用屏蔽的方法、远离容易产生势骚动或脉冲工作方式的器件、减少IC供电电源的纹波等可减少由IC外部干扰产生的纹波。对选择低噪声的运放是解决问题的一种方法,但不幸的是大多数产品目录中均未列出噪声指标。根据少数运放的该项指标知道,其低频噪声(0.1 Hz~10Hz)电压的峰一峰值为(0.1μV~20μV),因此,选择满足1×10-6稳定度要求的运放也不是很容易的。另外,在输出接近低频直流时,运放的失调电压和失调电流也是产生低频噪声的源泉,特别是失调电流,在选择运放时亦应注意。消除高频噪声可采用交流负反馈来提高运放的交流放大倍数和拓宽频带,但将造成增益降低。解决的办法是在运放前加一级晶体管或场效应管的差分级,由于分离元件便于精选,故可改变整个比较放大器的噪声指标。

4结语

数控可编程放大器可以实现以下功能:(1)输出增益范围:0.5~1000;(2)具有“+”、“-”步进调整功能,步进增益0.5或5;(3)显示输出信号增益与实测增益的测量误差的绝对值≤测量值的5%;(4)输出级功率放大可以带50欧负载。

本设计制作完成了题目要求的基本部分的全部要求和发挥部分的大部分要求,而且增加了部分功能。

目前,在电子仪器,设备中经常要用到信号增益变换电路,有时要求输出可预置,并当负载在一定范围内变化时应具有良好的稳定性,而且精度较高。该设计完全如果再经过结构优化,将具有良好的市场前景。

参考文献

[1]全国大学生电子设计设计竞赛组委员会.全国大学生电子设计竞赛训练教程[M].北京电子工业出版社,2005.

[2]全国大学生电子设计设计竞赛组委员会.全国大学生电子设计竞赛获奖作品汇编(第一届-第五届)[M].北京理工大学出版社,2004.

[3]李银祥.数控电流源[R].武汉:武汉理工大学测试中心,2001.

[4]秦迎春.利用AD7542实现程控电流源[J].国外电子元器件,2003,6:32-33.

[5]张智杰.AD574在数据采集中的应用[J].国外电子元器件,2003,6:55-56.

单片机编程经验 篇9

在C51中常用的数据类型有整型 (int) 、字符型 (char) 。其中, 整型数据就是人们常说的字 (16位) , 字符型数据就是字节 (8位) 。

通过图1和图2来说明这两种数据在汇编和C51中的存储方式。由图1和图2可知, 地址0001H和0002H中分别存储字符型数据12H和34H, 这两种编程语言对于字符型数据来说存储方式是相同的。但是对于整型数据就不同了, 一个是整型数据3412H, 另一个是整型数据1234H。在汇编语言中整型数据存储方式是:高字节存高地址中, 低字节存低地址中;而对于整型数据在C51中存储方式是:高字节存低地址中, 低字节存高地址中。下面通过Keil C软件调试来说明这一问题。

如图3所示, 在片外地址0008H中存储的数据为1234H。

2 C51中如何观察和修改变量

在程序调试的过程中, 我们经常需要观察程序运行过程中某些变量的值是否正确。如:

对于以上汇编程序, 可以通过寄存器r3和dptr来观察变量的值。但是在C51中没有这些寄存器可以使用, 那将如何观察变量的值呢?如:

若我们想观察a、b变量的变化情况, 则变量的观察方法如下:创建目标没有错误后 (图4) , 单击开始/停止调试按钮;然后单击view (视图) 菜单→watch&call stack window (监视和调用堆栈窗口) , 这样就可以发现在页面上出现了一个新的窗口 (图5) 。

我们可以通过按F2键来添加我们需要观察的变量名, 然后点击“运行”就可以查看变量的值 (图6) 。

如想修改以上变量的值, 只需双击变量名 (Name) 后面的数值区即可。

3 C51语言的位运算符 (位左移和位右移)

C51语言相比C语言增加了两种位运算符, 位左移和位右移, 符号分别为“<<”和“>>”。

(1) 位左移运算符 (<<) 的使用方法:如将无符号字符数据a和b分别左移2次和3次, 程序以及运行结果如图7所示;如将带符号字符数据a和b分别左移2次和3次, 程序以及运行结果如图8所示。对于无符号数和带符号数左移, 移位后空白位补0, 溢出位舍弃。

(2) 位右移运算符 (>>) 的使用方法:如将无符号字符数据a和b分别右移2次和3次, 程序及运行结果如图9所示:如将带符号字符数据a和b分别右移2次和3次, 程序及运行结果如图10所示。对于无符号数右移, 移位后空白位补0, 溢出位舍弃;对于带符号数右移, 移位后空白位补1, 溢出位舍弃。

4 C51中绝对地址访问

在C51中我们介绍两种绝对地址的访问方法:

(1) 在程序中用include即可使用其中声明的宏定义函数来访问绝对地址。各函数如表1所示, 表1中, BYTE表示对相应的区进行字节寻址, WORD表示对相应区进行字寻址。C表示对CODE区进行寻址, D表示对片内DATA区寻址, X表示对片外所有DATA区寻址, P表示对片外0~256字节DATA区寻址。

(2) 使用_at_关键字。可以使用关键字_at_对指定的存储器空间的绝对地址进行访问, 一般格式如下:【存储器类型】数据类型说明符变量名_at_地址常数;这种方法使用过程中大家一定要注意:使用_at_定义的变量必须为全局变量。

下面通过编写如下程序来说明两种方法的不同。

如将整型数据1234H存入片外RAM0008H单元中, 将片外0008H单元中整型数据存入变量a中。程序及运行结果如图11所示 (为了说明问题, 在程序运行前在片外RAM0010H和0011H中存入数据56H和78H) 。

由图12可知, 在片外RAM0008H单元中存入数据1234H, 但是并没有把片外RAM0008H单元中数据1234H取出存入变量a中, 而是将片外RAM0010H和0011H中数据取出存入变量a中, 这是什么原因呢?我们将上述程序改成如下形式, 修改后运行结果如图11所示 (同样在程序运行前在片外RAM0010H和0011H中存入数据56H和78H) 。

由图12可知, 把语句a=XWORD[0x0008]改成a=XWORD[0x0004]后运行结果正确。这是因为利用宏定义函数XWORD (DWORD) 来访问绝对地址时表示的字地址是字节地址的一半, 这样如果用宏定义函数XWORD (DWORD) 访问字地址时就需要用字节地址除2后得到正确地址。

摘要:现在的单片机仿真器普遍支持C语言程序的调试, 为单片机使用C语言提供了便利条件 (简称C51) 。C语言相对汇编语言来说, 能直接对单片机硬件进行操作, 既有高级语言的特点, 又有汇编语言的特点。讨论了C51编程中需要注意的事项, 并结合Keil C仿真软件给出相应说明。

关键词:单片机,C51,Keil C

参考文献

[1]姜志海.单片机的C语言程序设计及应用[M].北京:电子工业出版社, 2011.

[2]邹益民.单片机C语言教程[M].北京:中国石化出版社, 2011.

上一篇:永远的校园教案下一篇:记一次春游800字作文