点亮第一盏灯的c语言编程,单片机点亮第一盏灯实验详细教程

第一个实验:keil软件使用与点亮人生的第一只发光二极管

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.001.jpg (23.15 KB, 下载次数: 78)

2017-5-20 17:27 上传

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

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

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

1 电路走线如下:

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.002.jpg (57.33 KB, 下载次数: 71)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.003.jpg (4.3 KB, 下载次数: 74)

2017-5-20 17:27 上传

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

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

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.004.jpg (16.07 KB, 下载次数: 78)

2017-5-20 17:27 上传

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

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

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

项目)——new

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.005.jpg (35.35 KB, 下载次数: 86)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.006.jpg (22.51 KB, 下载次数: 76)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.007.jpg (33.48 KB, 下载次数: 80)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.008.jpg (26.56 KB, 下载次数: 69)

2017-5-20 17:27 上传

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.009.jpg (27.39 KB, 下载次数: 73)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.010.jpg (32.4 KB, 下载次数: 75)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.011.jpg (31.94 KB, 下载次数: 76)

2017-5-20 17:27 上传

选择后,点确定按钮。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.012.jpg (40.14 KB, 下载次数: 70)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.013.jpg (13.58 KB, 下载次数: 77)

2017-5-20 17:27 上传

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

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.014.jpg (29.37 KB, 下载次数: 69)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.015.jpg (23.12 KB, 下载次数: 82)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.016.jpg (30.43 KB, 下载次数: 97)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.017.jpg (33.25 KB, 下载次数: 65)

2017-5-20 17:27 上传

#include Main()

{ P1=0xfe;

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

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

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

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

先保存。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.018.jpg (32.86 KB, 下载次数: 68)

2017-5-20 17:27 上传

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

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.019.jpg (30.62 KB, 下载次数: 75)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.020.jpg (31.85 KB, 下载次数: 77)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.021.jpg (35.76 KB, 下载次数: 70)

2017-5-20 17:27 上传

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

加文件到组,根源组 1)

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.022.jpg (50.2 KB, 下载次数: 79)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.023.jpg (23.46 KB, 下载次数: 70)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.024.jpg (30.04 KB, 下载次数: 79)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.025.jpg (43.57 KB, 下载次数: 73)

2017-5-20 17:27 上传

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

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

来看看点击后的效果。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.026.jpg (38.84 KB, 下载次数: 67)

2017-5-20 17:27 上传

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.027.jpg (48.86 KB, 下载次数: 72)

2017-5-20 17:27 上传

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

(0 警告)。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.028.jpg (55.32 KB, 下载次数: 74)

2017-5-20 17:27 上传

很明显,它出来了一句,syntax error near (}

语法错误在花括号附近),

target not created(目标没创建)。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.029.jpg (61.5 KB, 下载次数: 77)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.030.jpg (33.28 KB, 下载次数: 67)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.031.jpg (42.96 KB, 下载次数: 72)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.032.jpg (37.99 KB, 下载次数: 54)

2017-5-20 17:27 上传

再点 built target

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.033.jpg (16.52 KB, 下载次数: 54)

2017-5-20 17:27 上传

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.034.jpg (22.49 KB, 下载次数: 74)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.035.jpg (38.74 KB, 下载次数: 55)

2017-5-20 17:27 上传

查找方法:

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.036.jpg (46.57 KB, 下载次数: 61)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.037.jpg (40.3 KB, 下载次数: 81)

2017-5-20 17:27 上传

找出来后,再点右上角的 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)/*…*/ 斜扛与星号结合使用,这种写法可以注释任意行,即斜 扛星号与星号斜扛之间的所有文字都作为注释。

下图是第二种。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.038.jpg (25.15 KB, 下载次数: 67)

2017-5-20 17:27 上传

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

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

练习:

把 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,后面再加上一个分 号表示这是一条结束。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.039.jpg (8.4 KB, 下载次数: 55)

2017-5-20 17:27 上传

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,如果后面还有语句

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.040.jpg (8.57 KB, 下载次数: 53)

2017-5-20 17:27 上传

现在我们可以了解到,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;

}

语句解说:

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.041.jpg (16.58 KB, 下载次数: 54)

2017-5-20 17:27 上传

执行过程:

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.042.jpg (27.71 KB, 下载次数: 64)

2017-5-20 17:27 上传

上图文字说明:

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 语 句继续往下面执行。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.043.jpg (15.18 KB, 下载次数: 64)

2017-5-20 17:27 上传

要点:

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,想计算准确的时间,先在软件里面设 置一下。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.044.jpg (37.26 KB, 下载次数: 57)

2017-5-20 17:27 上传

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

后点确定。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.045.jpg (28.62 KB, 下载次数: 51)

2017-5-20 17:27 上传

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.046.jpg (32.58 KB, 下载次数: 52)

2017-5-20 17:27 上传

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

执行一次分号后的时间。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.047.jpg (31.25 KB, 下载次数: 68)

2017-5-20 17:27 上传

从 上 图 可 以 看 到, 执 行 完 一 次 分号 之 后 的 时 间 是: 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++)

{

;

}

}

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.048.jpg (21.66 KB, 下载次数: 49)

2017-5-20 17:27 上传

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

一盏灯的一秒亮与灭

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

1 电路流程图:

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

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

3 程序流程的概括

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.049.jpg (19.32 KB, 下载次数: 46)

2017-5-20 17:27 上传

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

来看看程序。

#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(无符号整型)

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.050.jpg (10.83 KB, 下载次数: 56)

2017-5-20 17:27 上传

还记得我们上面学过的 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,这两个数内变化,现 在稍微了解就行,以后用就的时候你就明白了。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.051.jpg (28.44 KB, 下载次数: 58)

2017-5-20 17:27 上传

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

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

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.052.jpg (37.92 KB, 下载次数: 45)

2017-5-20 17:27 上传

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

延时子程序讲解

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

{

for(i=0;i

{

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

{

;

}

}

}

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

del_ms(uint k)

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

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

就懂。

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.053.jpg (11.2 KB, 下载次数: 63)

2017-5-20 17:27 上传

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

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

del_ms(uint k)

{

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

}

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.054.jpg (24.7 KB, 下载次数: 66)

2017-5-20 17:27 上传

回归正传。

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.055.jpg (21.46 KB, 下载次数: 64)

2017-5-20 17:27 上传

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

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

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.056.jpg (19.46 KB, 下载次数: 69)

2017-5-20 17:27 上传

del_ms(多少数字你定义);

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

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

3f829e29e76caa8c3b1f630a6b27d58d.gif

1.057.jpg (37.45 KB, 下载次数: 71)

2017-5-20 17:27 上传

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值