




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、本文由“常州蓝云电子”小店主编写,本人水平所限,文中必然会有各种疏漏,本意只是帮助各位初学者领会源程序。如果大神,大牛觉得无用或者胡说,欢迎拍砖。如果同学们认为本身基础过硬,只需要阅读第一段即可。以下正文: 目前单片机编程一般使用的都是C语言编写的。C51遵循C语法,所以要读懂源程序,至少需要系统学习过C程序设计才能有看懂程序的可能。这方面知识实在欠缺的,至少也应该懂理解C语言中的几个关键词:if,else,for,while,switch;能够知道#include(包含),#define(宏定义),sbit(位定义), sfr(寄存器定义)其实就本店能做的学生设计而言,程序基本只有长短之分,
2、没有难易之别(因为难的我们根本做不了)。以下就本店一个简单的计时器例程来简单来说明一个源程序,各个部分的作用。#include<reg51.h> 这里包含了单片机的寄存器名称与实际地址的对应关系,也称头文件,这个学生名单差不多,学校处理各项数据时,一般只管学生学号。但是班主任却要知道学个学号和学生姓名的对应关系,这份表对于一个确实的单片机而言,是固定的,所以封装成了一个H文件,使用时直接调用就可以了。有效缩短了代码长度和编程时间。如果非要好奇心发作,可以在keil中把这个文件点开,会发现都是以下这样的定义。/* BYTE Register */ 字节定义,定义每个一寄存器地址,这样
3、便于记忆sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;/* BIT Register */ 位定义,定义可以位寻址的内存单元/* PSW */sbit CY = 0xD7;sbit AC = 0xD6;sbit F0 = 0xD5;sbit RS1 = 0xD4;sbit RS0 = 0xD3;#define uchar unsigned char 宏定义,以下文档中 uchar 就表示unsigned char简单说一下,宏定义后面第一部分只能是一个代号,为了便于理解和记忆,一般用全称的简写形式;而宏定义的第二部分就灵活得多,
4、可以是代码的全称,也可以是一个定值,或者是变量,表示式等等。以下uint 类同。#define uint unsigned intuchar S=0,P_S=0; 全局变量定义,所谓全局变量,就是可能在这个子程序中用到,也可能在另一个子程序中用到。需要注意的是,全局变量最好不要使用i,j,k,a,b,c,d;因为这几个字母在子程序中经常用作局部变量,比如一个for循环中就经常用i,j等作为循环变量。如果全局变量使用这些相同的字母,在子程序中可能会因为局部变量的赋值而发生错误。比如我把一个表示时间秒数的变量命名为j;然后我又调用了一个延时子程序,这程序里正好也有个j;delay1ms(uint
5、t) 子函数uint i,j;for(i=0;i<t;i+) for(j=0;j<120;j+) ;事情到这一步,就难办了,不管我之前j是多少,也就是不管当前秒表跑到多少秒了,执行这个子程序之后,j肯定是120."高精度秒表" - 0 Error(s), 0 Warning(s).当我把全局变量S换成j之后。出现了这样的提示,一切正常嘛!可是显示的时候,秒数会一直不对.会让你怀疑编译器不对,怀疑书上教得都是错的,怀疑自己水平不行,其实都不是啦!换个变量名称什么都好了。其实想想也是,一个女生叫什么静如,心如;男生叫什么杰伦,彦祖;在班上大家都是知道这家伙是什么样一
6、个人,于时哪天周董真的来班上了。有人匆匆奔走相告曰杰伦找来了,你很可能不屑一顾,那家伙来说来呗,但是如果有人说唱<双截棍>的来了,那情况就不一样了,在这里大明星(全局变量)周董因为一个同名的局部变量,成为了一个名不见经传的小角色。这还只是小事,更大的事,比如你带一个团(8001200人)遇到敌人,对方一个集团军人数(这数据多重要),被你在无线通信中因为局部变量换成了120,然后总部(主程序)让你全歼之,偶滴亲娘嘞,这命令怎么执行!因此全局变量最好用有具体含义的名称来表示,比如时间time=xxx.实在英文不好,怕记不住,可以用拼音代替。另外定义变量时,变量名不能是TH0,TL0这类
7、代号。因为这类代号是单片机功能的寄存器。如果不熟悉各个寄存器,可以使用下划线来命名,uchar S_last=0,P_S_last=0;因为寄存器名称中没有下划线,这样可以确保不会重名,需要注意的是下划线要划在两个字符中间,不能作为变量的开头和结尾,比如_Slast,Slast_都是不好的。在编译时会出错。sfr TL0 = 0x8A;sfr TL1 = 0x8B;sfr TH0 = 0x8C;sfr TH1 = 0x8D;uchar code duanma=0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0xbf;/*字符1,2,
8、3,0,-. */定义数组,code表示这些数是固定不变的,sbit key1=P10; 位定义,确宝按键编号sbit key2=P11;sbit key3=P12;sbit Point=P07; 小数点bit KT=0;uchar S_last=0,P_S_last=0; 全局变量/*1毫秒延时子函数*/delay1ms(uint t) 子函数uint i,j;for(i=0;i<t;i+) for(j=0;j<120;j+) ;/*键盘程序*/void keyscan()if(key1=0)delay1ms(5); if(key1=0) while(key1=0); TR0=T
9、R0; if(key2=0)delay1ms(5); if(key2=0) while(key2=0); TR0=0; S_last=S;P_S_last=P_S;S=0; P_S=0; if(key3=0)delay1ms(5); if(key3=0) while(key3=0); KT=KT; /*定时中断*/void t0_(void) interrupt 1 /定时器0中断ET0=0;TR0=0; TH0=(65536-10000)/256; TL0=(65536-10000)%256; TR0=1; P_S+; if(P_S>=100) P_S=0; S+; if(S=99)
10、TR0=0; P_S=0; ET0=1;void display() /*显示程序*/ if(KT=0) P2 = 0xfe; /开始扫描 P0 = duanmaP_S%10; delay1ms(2);P2 = 0xff;P2 = 0xfd; /开始扫描 P0 = duanmaP_S/10; delay1ms(2);P2 = 0xff;P2 = 0xfb;P0 = duanmaS%10;if(P_S>50|TR0=0)Point=0;delay1ms(2); P2 = 0xff;P2 = 0xf7;P0 = duanmaS/10;delay1ms(2);P2 = 0xff;P2 = 0x
11、ef;elseP2 = 0xfe; /开始扫描 P0 = duanmaP_S_last%10; delay1ms(2);P2 = 0xff;P2 = 0xfd; /开始扫描 P0 = duanmaP_S_last/10; delay1ms(2);P2 = 0xff;P2 = 0xfb;P0 = duanmaS_last%10;Point=0;delay1ms(2); P2 = 0xff;P2 = 0xf7;P0 = duanmaS_last/10;delay1ms(2);P2 = 0xff;P2 = 0xef;/*主函数*/void main() uint i; 这里定义了一个局部变量,但是并
12、没有使用到,于时编译时出现了STOPWATCH.C(111): warning C280: 'i': unreferenced local variablewarning与error相对应,如果程序编译时出现error,那编译是不会成功的,但是出现warning则编译已经完成,但是不够优化。一般的warning,出现的情况主要用,调用了不存在的函数(此类问题非常严重),有函数或者变量定义了却没有调用。定义了却不调用,不会影响程序的执行,只能徒然增加代码长度,浪费寄存器空间。但是如果调用了一个不存在的函数,问题就非常严重了。当程序执行到这一步时,因为调用函数不存在,编译器会认为代
13、码已经结束。这样在仿真或者调试时反映为系统不停复位。这个可以理解为看书,看到中途忽然出现一片空白页,上面写着个已完结。当然没必要再看去。那怕这只是个恶作剧,编译器毕竟不是人,会去再翻翻后面是什么,因为每一步都是由程序指针确定的,对于芯片而言,相当于导航到此结束,再往前走,就存在回不来的风险,那样程序会乱套。一个函数没有调用,只会出现一个warning,如果调用了一个不存在的函数,则会出现三个warning.通过warning数量可以判断出问题所在。如果程序运行时出现十几个警告,也不要慌,可能只是调用了几个不存在的函数罢了。如果定义了一个函数,假设为keyscan();在调用时却写成了keyca
14、n,key_scan,等。那么该调的没调用算一个,调用不存在的算三个。一个字符出错,就会导致4个warning。 TMOD=0x01; TH0=(65536-10000)/256; TL0=(65536-10000)%256; ET0=1; 前文已经说过,TH0,TL0等是功能寄存器,这些表示对功能寄存器赋值,以启动定时器。 TR0=0; EA=1; while(1) /无限循环,除非按下复位或者断电 keyscan(); /调用按键子函数 display(); /调用显示子函数 从这一个简简单单的例子可以看出,一个程序包含了头文件,宏定义,变量定义,子函数定义,主程序等。在定义变量后面,我们
15、有时还会看到void keyscan();这样的情况,就一个函数头在这里,完整子函数却在正文里面。为什么要这样做呢?在C51程序中,主函数不可以被子函数调用(很多人到京城办事可以,不可能把整个京城搬过来给你办事,因为京城同时还要处理其他事务,如果出现每个人都可以调动整个京城,而京城又可以调动每个人的情况,逻辑上无法执行),自己也不可以调用自己(相当于蛇吞自己,肯定没什么好结果)。但是主程序可以调用子程序,所以我们一般把主程序放在其他子函数之后。为什么要这样,因为编译器规定要调用一个函数,必须先定义。不仅仅要定义,还要在调用之前就定义。这个很好理解呀,你要找一个人,先得知道这个人的名字。如果这个人连名字都还没有,你怎
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【正版授权】 ISO 19932-1:2025 EN Equipment for crop protection - Knapsack sprayers - Part 1: Safety and environmental requirements
- 公司烤肉策划方案
- 公司组织烤肉派对活动方案
- 公司组织暖心小活动方案
- 公司春游一日游策划方案
- 公司游园会年会策划方案
- 公司暖冬捐衣活动方案
- 公司职场妈妈活动方案
- 公司甜品活动方案
- 公司春节抽奖活动方案
- 2025译林版高中英语高考复习必背全七册单词表(精校打印)
- 撬装加油站承包合同协议书
- 国家开放大学行管本科《政府经济学》期末考试总题库2025春期考试版
- 《自发性腹膜炎》课件
- 2024年03月广东2024年珠海华润银行社会招考(33)笔试历年参考题库附带答案详解
- 14-2《变形记》(节选)公开课一等奖创新教学设计统编版高中语文必修下册
- 卸料平台培训课件
- 2025年阳光财产保限公司招聘笔试参考题库含答案解析
- 监理工作廉洁自律制度及措施
- 公司法知识竞赛考试题库100题(含答案)
- 物业管理项目主动撤场
评论
0/150
提交评论