单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12911|回复: 1
收起左侧

单片机点亮第一盏灯实验详细教程

[复制链接]
51黑电子迷 发表于 2017-5-20 17:30 | 显示全部楼层 |阅读模式
第一个实验:keil软件使用与点亮人生的第一只发光二极管

本实验教程的 pdf完整版下载及配套的的仿真工程文件和源码下载地址:http://www.51hei.com/bbs/dpj-85401-1.html
1.001.jpg




本章详细介绍单片机程序常用编译软件 Keil 的用法,用一个完整的 C51 程序来操作发光二极管的点亮与熄灭,然后调用 C51 库函数来方 便地实现流水灯,从这一章开始我们将手把手地讲解单片机 C 语言编 程。认真学好本章,对于初学者来说将会是一个非常好的开头。


用实操点亮一只灯程序来学会使用编程软件 keil 的基本功能。

最终目标:点亮下图 D8 发光二极管。

1 电路走线如下:

1.002.jpg



2 元件特性 发光二极管的原理

1.003.jpg


正极这边为高电平,负极为低电平,发光二极管就行,两边为高电平, 发光二极管就不亮。


3 程序流程:把 P1.1~P1.7 置高电平,P1.0 置低电平即可。

4 程序的书写与调试。 我们要书写程序,需要一个 keil 软件。


Keil 的操作步骤。 详细操作步骤:

1.004.jpg



从图片中不难看出,我们写的程序(子项目)都是围绕总项目转的, 然后从总项目输出我们想要的单片机程序。



第一步:新建总项目(打开软件跟着做,熟悉一下)



当我们安装好 Keil Uvision 3 编程软件后,就点 projec(t
项目)——new



prouect(新项目)来新建项目。

1.005.jpg


点击完 new project 后,会有如下对话框。

1.006.jpg

从上面不难看出,我们新建的单片机程序项目后缀名字是 uv2,而且

当 uv2 项目产生的时候,会自动附带很多其它 uv2 需要的文件,为了 防止我们产生浏览混乱,这个时候我们就需要“新建一个文件夹”, 把 uv2 存在里面,那么附带的文件也会自己存进去这个文件夹里面去 方便我们浏览和操作了。



1.007.jpg


我命名字为“点亮一只灯”,并且双击进入这个文件夹里面。

1.008.jpg




1.009.jpg







CPU 选择是找到 Atmel 并点击其它+号。



1.010.jpg










往下拉,找到 AT89C52(选择 51 类型的单片机)

1.011.jpg





选择后,点确定按钮。








1.012.jpg




是否复制 51 标准代码,这个暂时没有什么用,点否就可以。

1.013.jpg


这个时候,我们才创建好总项目,从一开始的图片我们看到,还需要

为总项目“添加子项目”。




下面图片指针头指的是,点亮一盏灯的总项目,通过上面的操作,已 经创建完成。


1.014.jpg








第二步:为总项目添加子项目




为总项目添加子项目之前,我们需要新建一个文件(程序编辑窗口), 点击软件 file 下面那个文本图标 create a newfile(创建一个新的文件)




1.015.jpg








得到如下图的程序编辑窗口,在这里面编写单片机的程序。

1.016.jpg




现在我们需要的是点亮一只灯的程序。


1.017.jpg




#include Main()

{ P1=0xfe;

} 写好后,我们还不知道子项目里的程序有没有错,现在我们需要把这 个子项目添加到“点亮一只灯.uv2”的总项目里,去让软件查错,方 便我们修正,输出我们想要的单片机代码去让单片机工作,那需要如 何做呢?



很显然,当我们新建一个子项目编辑窗口时(子项目),软件是没有

把这个子项目存到总项目当中的,而是需要我们人手添加进去。










操作方法是:先保存,然后再把这个子项目添加到总项目去。







先保存。

需要点击如下图的图标 save the active document(保存活动文档),就 是保存当前编辑中的程序编辑窗口(子项目)。





1.018.jpg


或许有些朋友很聪明,看到窗口上的*号就知道还没有保存的文件。
















默认保存在我们创建的“点亮一只灯”文件夹当中,还有重要的一点

是,记得文件名后缀必须是“.c”,第二次:文件名后缀必须是“.c” 第三次:文件名后缀必须是“.c”,重要是事情说三遍,这样后面的 操作就会万无一失了。





1.019.jpg







保存后,某些字母是有颜色的,这个就是保存好的象征,如下图所示:


1.020.jpg








保存后,现在我们需要把子项目添加到总项目当中。



1.021.jpg







鼠标右击“source              group1”选择”add file to group ’source group1 ’”(添

加文件到组,根源组 1)


1.022.jpg







默认打开的就是“点亮一只灯”文件夹下面的“点亮一点灯”的 C 语

言程序(就是我们刚刚保存的.c 文件) 然后点窗口上的 add(添加),




1.023.jpg




Source group1 下有了“点亮一只灯”的 C 语言程序

1.024.jpg



添加成功后,就退出上面那个添加窗口。





添加子项目到总项目后,我们还不知道我们写的程序有没有错,现在

1.025.jpg 要做的是,让软件查错,那要如何做呢? 如下图所示。






































如果总项目只有一个子项目的时候(就像点亮一只灯.c),我们就点 built target,如果有二个或以上的子项目,就点 built all target files, 就两个按钮就是这样用,这就为什么叫总项目和子项目的原因,因为 总项目中可以包含多个子项目的。



来看看点击后的效果。







这里只有一个子项目,只点 build target 就行。

1.026.jpg



1.027.jpg




从上图可以看到,build 完后,我们看到是 0 error (0 错误),0 warning

(0 警告)。




如果我们把 P1=0xff;,后面这个“;”分号去掉,看看是怎么样。



1.028.jpg






很明显,它出来了一句,syntax error near (}
语法错误在花括号附近),



target not created(目标没创建)。








双击 syntax error near }这条语句时,光标就会出来在附近,让你改错。




1.029.jpg


现在我们把分号加上后,它编译没有错误,证明程序可以运用,但是

软件还没有输出单片机运行需要的代码。

1.030.jpg










第三步:输出单片机运行需要的代码

鼠标右击“target”点“options for target ‘target 1’”(选项对于目标 1)



1.031.jpg








点第三列的 output “输出”按钮,然后把 create hex file“创建 16 进

制文件”勾上后,点确定。



1.032.jpg




再点 built target

1.033.jpg




这样在编译没有错误成功后,它就会产生一个 hex 文件(单片机需要 的代码),我们就可以用这个 hex 文件让我们的单片机工作啦!






它在什么位置?就在我们新建的“点亮一只灯”的文件夹里面。


1.034.jpg

需要用的时候,我们需要到这个文件夹找出来,这样我们 P1.0 口的 发光二极管就可以点亮了。


1.035.jpg


查找方法:

如果你是用仿真软件。 先双击 89C52

1.036.jpg







再点击 program file 到点亮一盏灯文件夹里面,把点亮一只灯.hex 文 件,找出来就行。(如下图)



1.037.jpg




找出来后,再点右上角的 OK 就可以了。




你可以复制下面程序去编程软件,熟悉上面的功能,如果想要靠自己 记忆去写,也可以尝试一下。


#include

main()

{ P1=0xff;

}




程序讲解:


#include     包含这个头文件,头文件上面我们讲解,就是为

单片机里面的地址命名字,方便我们直接用名字使用(每个程序的开 头肯定有头文件的)





main()

{

}

Main()这个是主函数入口,程序在花括号{ }里面执行,之于 main 旁边 的括号是什么东西,我们以后用到再讲解,现在明白它是固定格式 main(),mian 括号就行。





P1=0xfe;

P1=1111 1110,把 P1.0 位置低电平,点亮 D8 发光二极管。




需要注意的是,这里的 P1 不可随意写,P 是大写,若写成 p,编译程 序时将报错,因为编译器并不认识 p1,它只认识 P1,这是因为我们 在头文件中定义的是“sfr P1= 0x90;”。

P1=0xfe 后面的分号“;”也不要漏掉,不然程序会报错, 这些也是大多初学者编写第一个程序时常犯的错误,希望大家留意一
下。

















注释问题。




知识点:C 语言中注释的写法

在 C 语言中,注释有两种写法:

(1)// 两个斜扛后面跟着的为注释语句。这种写法只能注释一行, 当换行时,又必须在新行上重新写两个斜扛。


(2)/*…*/ 斜扛与星号结合使用,这种写法可以注释任意行,即斜 扛星号与星号斜扛之间的所有文字都作为注释。





下图是第二种。



1.038.jpg







所有注释都不参与程序编译,编译器在编译过程会自动删去注释,注

释的目的是为了我们读程序方便,一般在编写较大的程序时,分段加 入注释,这样当我们回过头来再次读程序时,因为有了注释,其代码 的意义便一目了然了。若无注释,我们不得不特别费力地将程序 重新阅读一遍方可知道代码含义。养成良好的书写代码格式的习惯, 经常为自己编写的代码加入注释,以后定能方便许多。



练习:

把 P1.1~P1.7 口逐个点亮。

把 P1.0~P1.3 点亮,其它四个不亮。













while语句 通过上面一节的学习,想必大家已经对点亮实验板上的任意发光二极 管非常熟悉了,但是,先不要高兴得太早,上面的程序并不完善,任 何一个程序都要有头有尾才对,而上面我们写的程序似乎只有头而无 尾。我们分析一下看,当程序运行时,首先进入主函数,顺序执行里 面的所有语句,因为主函数中只有一条语句,当执行完这条语句后,

该执行什么了?




因为我们没有给单片机明确指示下一步该做什么,所以单片机在运行 时就很有可能会出错。




根据经验,当 Keil 编译器遇到这种情况时,它会自动从主函数开始处 重新执行语句,所以单片机在运行上面两个程序时,实际上是在不断 地重复点亮发光二极管的操作,而我们的意图是让单片机点亮二极管 后就结束,也就是让程序停止在某处,这样一个有头有尾的程序才完



整。



那么如何让程序停止在某处呢?我们用 while 语句就可以实现。 知识点:while()语句的应用

格式:

while(表达式)

{

内部语句(内部可为空)


}

特点:先判断表达式是真还是假,再执行或者不执行内部语句。 在 C 语言的判断条件中,1 或以上为真,0 为假。 判断原则:若表达式不是 0,即不是 while(0)这样的形式。这样说就

是 while(1),while(2),while(3 或以上),即为真,那么执行 while 花括 号的内部语句,如果是 while(0)即为假,跳过while,不执行 while 花 括号的内部语句。



while 有两种形式:

1 如果语句只有一条。 直接用表达式+执行语句+分号结束就行。 如:


While(1)              表达式。

P1=0xfe;              执行语句+分号。




While(1)是表达式,用来判断是真是假。 因为这里是真,所以语句就无限循环于 P1=0xfe,后面再加上一个分 号表示这是一条结束。





1.039.jpg










2 如果有两条以上表达式。 如:


While(1) P1=0xfe; P1=0xfa;






它也只是无限循环于 P1=0xfe 这条语句,而不往下执行 P1=0xfa,这

样的程序格式显然是满足不了多少功能,没有什么意义的,那我们要 怎么写才能让 while 执行多些语句呢?




从上面可以观察到,我们还有花括号可用。 是的,


while(1)

{

}




“While(1)+花括号”就可以实现我们想要的功能。





While(1)

{ P1=0xfe; P1=0xfa;

}




这样就可以执行完 P1=0xfe,又继续执行 P1=0xfa,如果后面还有语句

就会接着一条条继续执行,直到 } 的这个结尾,继续又重新开始到

{ 这个开始继续执行,无限循环。





1.040.jpg







现在我们可以了解到,while 有无限循环执行它内部语句的用法,如

果只有一条语句,直接在这条语句加分号就行,如果有两条语句或以 上就需要加{}花括号。







如果 while(0) P1=0xfe; P1=0xfa;




因为现在 while 为假,所以它不会执行 P1=0xfe,而往下执行 P1=0xfa, 因为 P1=0xfa;是不属于 while 的内部语句。



花括号原理也是一样。


while(0)

{ P1=0xfe; P1=0xfa;

} P1=0x0f;




不执行 while 花括号里面的语句,执行 P1=0x0f;










通过这些认识 我们来编写一个完整的点亮第一个发光二极管的程序。

#include               //52 系列单片机头文件

void main()              //主函数

(

P1=0xfe;

while(1);

)




这里的 main 前面多了一个 void,void 有空的意思,在 main 前面加上


void 这个东西,实际意义并不大,只是让程序具体点,你直接用 main()

也可以。




然后到 P1=0xfe,再停止在 while(1);这里,while 里面,如果有一条语 句就执行完这个语句,停止到分号,如果没有语句就直接在分号这里 无限循环,相当于停止标记,所以以后一看到 while(1);,就知道是停 止标记了。











知识点:for语句 格式:


for(表达式 1;表达式 2;表达式 3)

{

内部语句


}




例子:


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

{ P1=0xfe;

}





语句解说:

1.041.jpg







执行过程:

1.042.jpg








上图文字说明:

1 判断:判断 i 是否少于 3。

2 执行:执行 for 内部语句。

3              i++:i 自加 1。







从上面图片可以看到 第一轮:

第 1 步:初始化 i=0(i 赋值等于 0)。 第 2 步:判断 i 是否少于 3。

第 3 步:现在 i=0 是少于 3,就执行 for 花括号的内部语句一次。

第 4 步:当执行完一次内部语句后,i++(i++的意思就是 i 自己加 1)。




第二轮:

第 5 步:因为上面 i 从 0 加了一次,现在 i=1。 第 6 步:判断 i 是否少于 3。

第 7 步:现在 i=1 是少于 3,就执行 for 花括号的内部语句一次。

第 8 步:当执行完一次内部语句后,i++(i++的意思就是 i 自己加 1)。


第三轮:

第 9 步:因为上面 i 从 1 加了一次,现在 i=2。 第 10 步:判断 i 是否少于 3。

第 11 步:现在 i=1 是少于 3,就执行 for 花括号的内部语句一次。 第 12 步:当执行完一次内部语句后,i++(i++的意思就是 i 自己加 1)。




第四轮:

第 13 步:因为上面 i 从 2 加了一次,现在 i=3。 第 14 步:判断 i 是否少于 3。

第 15 步:现在 i=3 不少于 3,就不执行 for 内部语句了,退出 for 语 句继续往下面执行。





1.043.jpg


要点:

1 当 for 初始化完一次后,就没有它的事了。

2 因为 i 初始化是 0,从第 0 次开始执行,就算 i<3 也是执行 3 次(第

0 次,第 1 次,第 2 次,共三次)

3              i++是 i 自加 1 的意思。













如果上面的理解。 那么


for(i=3;i>0;i--)

{ P1=0xfe;

}

也是一样的原理,这里是 i 首先等于 3,如果 i>0,就执行内部语句, 然后 i--,这里是 i 自减 1 次。这个也是共执行 3 次,执行完后就退出 for 语句







通过以上步骤,这个 for 语句就执行完了,单片机在执行这个 for

语句的时候是需要时间的,上面 i 的初值较小,所以执行的步数就少,


当我们给 i 赋的初值越大,它执行所需的时间就越长,因此我们就可

以利用单片机执行这个 for 语句的时间来作为一个简单延时语句。







很多初学者容易犯的错误是,想用 for 语句写一个延时比较长的语句, 那么他可能会这样写:





unsigned char i;(unsigned char 无符号字符型,这是是定义 i 为无 符号字符型,数值范围是 0~255)








for(i=0;i<3000;i--)

{

;

}




但是结果却发现这样写并不能达到延长时间的效果,因为在这里 i 是 一个字符型变量,它的最大值为 255,当你给它赋一个比最大值都大 的数时,这里 i 赋值是 3000,程序自然就出错误了。




因此我们尤其要注意,每次给变量赋初值时,都要首先考虑变量类型, 然后根据变量类型赋一个合理的值,我们所指的变量类型,就是字符



型(8 位),和整型(16 位),等,而且这两个在 51 单片机最常用,

理解这两个,其它的都已收入囊中。




如果我们想用 for 语句做一个秒的延时,我们该怎么写呢? 秒是我们日常用的时间单位,如果单片机也用秒的时间来一句句执行 程序语句,这样就非常没有效率,还不如直接用人手操作,我们创造 出单片机代替人手的根本原因,就是让它自动化,而且快速。





那单片机到底有多快?

我们用 s(秒),单片机用的时间是 us(微秒) 而且


1s=1000ms=1000000us

1 秒=1000 毫秒=1 百万微秒。 很明显,单片机用的时间是我们的时间的 1 百万倍。


如果我们知道单片机执行一条语句需要多少时间,就可以用 for 语句 编写出一个一秒的延时程序了。





我们来看看执行一个分号需要多少时间。因为晶振是决定时间的,我 们单片机常用的是 11.0592M,想计算准确的时间,先在软件里面设 置一下。



1.044.jpg

右击 target,点 option for target ,点 target,在 xtal 窗口输入“11.0592”,

后点确定。







然后通过 keil 软件——start/stop debug 可以监测到程序执行流程,进 入 debug(调试)后(看下图),按键盘F10 或者 F11 一步步执行, F10 是跨越式执行,F11 是细节语句执行,说的多不如动手试一试, 就会明白很多了。





1.045.jpg














来看看执行分号之前的时间。

1.046.jpg




从上图可以看到,执行一个分号之前的时间是,0.00044162 s(左边 的 sec 那里看到),0.00044162 s=0.00044162s*100 万=441.62us(小数 点向右移六位就行)








执行一次分号后的时间。



1.047.jpg




从 上 图 可 以 看 到, 执 行 完 一 次 分号 之 后 的 时 间 是: 0.00044596

s=445.96us







分号之前的时间=441.62us 分号之后的时间=445.96us 分号用的时间=445.96us - 441.62us=4.34us。 所以执行一次分号的时间是 4.34 微秒。




从我们上面图片程序可以看到。


For(j=0;j<230;j++)

{

;

}


为什么是执行 230 次分号呢?

因为 230*4.34us(一次分号的时间)= 998.2us=0.9982ms 约等于 1ms,

(因为 1s=1000ms,1ms=1000us,牢记这个时间关系)




现在我们知道。


For(j=0;j<230;j++)

{

;

}




这个 for 语法是执行了 1ms(1 毫秒)的时间,但是这还没有达到我 们想要的 1S 的时间,或许有些朋友很聪明可以想出,把这个 1ms 执 行多 1000 次不就是 1S 的时间了?




好家伙,现在动手。





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

{

For(j=0;j<230;j++)

{

;

}


}




1.048.jpg




很明显,C 语言是可以用于内嵌语句执行的,从上面图片不难看到, 执行完 230 次分号后(花 1ms),还要重复执行 1000 次 1ms 就是 1s 了。



一盏灯的一秒亮与灭

目标:一盏灯的一秒亮与灭

1 电路流程图:




2 元件特性 发光二极管的原理





正极这边为高电平,负极为低电平,发光二极管就行,两边为高电平, 发光二极管就不亮。






3 程序流程的概括

1.049.jpg




从上面图片可以看到,让一只灯亮灭的原理还是比如容易的,首先是 点亮一只灯,然后一秒延时,再灭灯,再一秒延时,再回到点亮一只 灯这样无限循环的重复。




来看看程序。

#include                     //头文件

#define uchar unsigned char   //把 unsigned char 命名字为 uchar


#define uint unsigned int              //把 unsigned int 命名字为 uchar

uint i;              //整型 i 变量

uchar j;              //字符型 j 变量

sbit led=P1^0;              //把 P1 的第 0 个位命名字为 led







main()              //主函数入口

{




while(1)              //无限循环入口

{

led=0;              //点亮 P1.0




for(i=0;i<1000;i++)              //延时 1 秒

{

for(j=0;j<230;j++)

{

;

}

}


led=1;              灭灯




for(i=0;i<1000;i++)              延时一秒

{

for(j=0;j<230;j++)

{

;

}

}

}











}







看看这前面部分是什么东西

#include              //头文件

#define uchar unsigned char              //把 unsigned char 命名字为 uchar

#define uint unsigned int              //把 unsigned int 命名字为 uchar uint i;              //整型 i 变量

uchar j;              //字符型 j 变量


sbit led=P1^0;                          //把 P1 的第 0 个位命名字为 led







#include              //头文件 头文件每个程序开头肯定有的。





#define 也很好理解的,也是作命名字用,因为当引入头文件 reg52

后,单片机也只是知道什么是 unsigned char,unsigned int 等。




而我们觉得太长不好写,就有了#define uchar unsigned char ,把 unsigned char(无符号字符型)命名字为uchar,#define uint unsigned int 也是同样的道理,uint(无符号整型)




1.050.jpg




还记得我们上面学过的 8 位,16 位吗?8 个位的二进制最大的数是十 进制 255,当超过 255 后,它就又会回归到 0重新开始,而我们的 uchar 就是用于表明是 8 个位的水杯(最大十进制数是 255)。



而 uint 是 16 位的水杯,最大的十进制数可以表达到 65535,6 万多。




那么现在 uint i,和 uchar j 现在明白了麽?

uint i,声明一个 16 位的变量 i,方便程序内用。I 的数值范围在 0~65535

内都可以。

uchar j,声明一个 8 位的变量 j,方便程序内用。J 的数值范围在 0~255

内都可以。




声明完后,I, j 这些变量位置哪里来?当你定义好,单片机 RAM(动 态存储器)自动分配的,这不用你操心。


从上面程序你可以看到 I, j 在哪里用吗? 延时程序
for(i=0;i<1000;i++)              延时一秒

{

for(j=0;j<230;j++)              延时 1 毫秒

{

;

}

}


很明显,j 少于 255,所以用 uchar 就行,i>255<6 万用 uint




sbit led=P1^0;              也很好理解的,声名特殊功能寄存器的位,把 P1.0 这 个位命名字为 led,现在看到^这个符号了吧?很常用。




命名字方式,我们学过四种。 特殊功能寄存器的位命名:sbit 特殊功能寄存器 8 位地址命名:sfr P1=0x90;

特殊功能寄存器 16 位地址命名:sfr16 TC=0x91;(连续用 0x91,0x92 这两个地址,只声名第一个地址就可以)Define:把什么名字命什么名字(多数用于英文字母的定义,方便我 们记忆运用)





再看看我们程序编写时常用的四种(牢记)。

1 特殊功能寄存器位命名:sbit

2 Define:把什么名字命什么名字(多数用于英文字母的定义,方便 我们记忆运用)


3 Uchar 字符型。

4 Uint 整型。




如何区分特殊功能寄存器和普通寄存器?原理很简单的,当你这个寄 存器是特殊功能的,比如 P1(厂家告诉你这个寄存器有什么用,就



是特殊功能),如果定义它的位来运用,就用 sbit(特殊功能寄存器

位命名)。




如果厂家没有告诉你这个寄存器具体有什么用,就是普通寄存器,比 如 uchar i, uint j,等等,当你声明好后,单片机会自动分配寄存器的, 如果你想用普通的位,直接用 bit 就行,如 bit flag,为 flag 这个名字 定义为位功能,这个时候 flag 也是只能在 0~1,这两个数内变化,现 在稍微了解就行,以后用就的时候你就明白了。








再来看看程序,和我们的流程图是一模一样。



1.051.jpg







从上面图片我们发现,延时程序是一模一样的,那我们有没有方法把

同样的代码放在别处,需要的时候才调用出来,这样就可以减少很多 代码重写,不用浪费那么多单片机内部资源。




有两种方式: 第一种是在主程序(main)上面书写。 第二种是在主程序(main)下面书写。






来看看第一种,在主程序上面书写。

1.052.jpg




从上面图片可以看到,当定义好头文件后和其它相应的名字后,子程 序就可以开始书写了。












延时子程序讲解

void del_ms(uint k)                            // 延时子程序

{

for(i=0;i<k;i++)[ size][="" align]
{

for(j=0;j<230;j++)

{

;

}

}

}




Void 是空的意思,相当于从这个子程序中,没有东西(数值)返回的 意思吧,现在不理解,你可以暂时忽略它,直接书写就行,以后你见 到有东西(数值)返回的,对比一下,就一目了然了。

del_ms(uint k)

del_ms 是子程序名字, del 是我们把英文单词 delay(延时)的缩写, 加_符号,再加 ms(毫秒),这样从字面上就可以直接理解到是延时 1


毫秒的子程序,其实这个子程序名字你可以自己定义的,以后慢慢你

就懂。

叫做 ms 的原因是现在我们没有像上面那样直接赋值 1000 次的一毫 秒延时,而是把这个 1000 变成可变的数字,如下图所示的 uint k:


1.053.jpg

可以看到,现在我们上面的 1000 改变成可变的变量整型 k,uint(无符 号整型)可在 0~65535 之间随意赋值,定义完后,k 就可以在 0~65535 随意赋值。


如果是少于 255 的话,用无符号字符型(uchar)就行,这里大于 255, 就用了整型,而且这个 k,只能在延时子程序花括号范围内使用,就 是


del_ms(uint k)

{

K 在这里随意使用,在这范围外使用是无效的。


}


你在主程序(main)内定义,就是主程序(main)花括号内可以使用,其 它范围无效,如果你是一开头就定义了,子程序和主程序都可以使用。


就是下面的 uint i 和 ichar j 可以在子程序和主程序的花括号里随意使 用,理解没?





1.054.jpg

回归正传。


1.055.jpg




del_ms 这名字在英文或符号之间(不是中文就行,因为这软件不懂

中文),你可以随你懂的命名字,比如你不太懂英文,直接写 yan_shi

也行,只要做到一看这名字就知道是什么样的子程序就行。

延时子程序调用方法,在主程序内调用。


1.056.jpg

del_ms(多少数字你定义);

记得后面不要漏了分号,这样做只要是告诉软件,你已经写完一条语 句,不然的话,程序会出错。


第二种:子程序在主程序下面写。

1.057.jpg

这种方式除了位置不同和加多一句“告诉单片机主程序”下面有子程

序外,其它一样,如果你在主程序下面写子程序而没有首先告诉单片 机,程序编译中会出错的,你可以自己试试,试过就知道了。



详细请打开编程软件和仿真软件浏览效果。

本实验配套的的仿真工程文件和源码下载地址:http://www.51hei.com/bbs/dpj-85401-1.html


回复

使用道具 举报

半路 发表于 2017-5-21 17:56 | 显示全部楼层
很详细的帖子,适合初学者。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|单片机论坛 |51黑电子论坛技术交流 QQ 管理员QQ:125739409;技术交流QQ群636986012

Powered by 单片机教程网

快速回复 返回顶部 返回列表