第一个实验:keil软件使用与点亮人生的第一只发光二极管
1.001.jpg (23.15 KB, 下载次数: 78)
2017-5-20 17:27 上传
本章详细介绍单片机程序常用编译软件 Keil 的用法,用一个完整的 C51 程序来操作发光二极管的点亮与熄灭,然后调用 C51 库函数来方 便地实现流水灯,从这一章开始我们将手把手地讲解单片机 C 语言编 程。认真学好本章,对于初学者来说将会是一个非常好的开头。
用实操点亮一只灯程序来学会使用编程软件 keil 的基本功能。
最终目标:点亮下图 D8 发光二极管。
1 电路走线如下:
1.002.jpg (57.33 KB, 下载次数: 71)
2017-5-20 17:27 上传
2 元件特性 发光二极管的原理
1.003.jpg (4.3 KB, 下载次数: 74)
2017-5-20 17:27 上传
正极这边为高电平,负极为低电平,发光二极管就行,两边为高电平, 发光二极管就不亮。
3 程序流程:把 P1.1~P1.7 置高电平,P1.0 置低电平即可。
4 程序的书写与调试。 我们要书写程序,需要一个 keil 软件。
Keil 的操作步骤。 详细操作步骤:
1.004.jpg (16.07 KB, 下载次数: 78)
2017-5-20 17:27 上传
从图片中不难看出,我们写的程序(子项目)都是围绕总项目转的, 然后从总项目输出我们想要的单片机程序。
第一步:新建总项目(打开软件跟着做,熟悉一下)
当我们安装好 Keil Uvision 3 编程软件后,就点 projec(t
项目)——new
prouect(新项目)来新建项目。
1.005.jpg (35.35 KB, 下载次数: 86)
2017-5-20 17:27 上传
点击完 new project 后,会有如下对话框。
1.006.jpg (22.51 KB, 下载次数: 76)
2017-5-20 17:27 上传
从上面不难看出,我们新建的单片机程序项目后缀名字是 uv2,而且
当 uv2 项目产生的时候,会自动附带很多其它 uv2 需要的文件,为了 防止我们产生浏览混乱,这个时候我们就需要“新建一个文件夹”, 把 uv2 存在里面,那么附带的文件也会自己存进去这个文件夹里面去 方便我们浏览和操作了。
1.007.jpg (33.48 KB, 下载次数: 80)
2017-5-20 17:27 上传
我命名字为“点亮一只灯”,并且双击进入这个文件夹里面。
1.008.jpg (26.56 KB, 下载次数: 69)
2017-5-20 17:27 上传
1.009.jpg (27.39 KB, 下载次数: 73)
2017-5-20 17:27 上传
CPU 选择是找到 Atmel 并点击其它+号。
1.010.jpg (32.4 KB, 下载次数: 75)
2017-5-20 17:27 上传
往下拉,找到 AT89C52(选择 51 类型的单片机)
1.011.jpg (31.94 KB, 下载次数: 76)
2017-5-20 17:27 上传
选择后,点确定按钮。
1.012.jpg (40.14 KB, 下载次数: 70)
2017-5-20 17:27 上传
是否复制 51 标准代码,这个暂时没有什么用,点否就可以。
1.013.jpg (13.58 KB, 下载次数: 77)
2017-5-20 17:27 上传
这个时候,我们才创建好总项目,从一开始的图片我们看到,还需要
为总项目“添加子项目”。
下面图片指针头指的是,点亮一盏灯的总项目,通过上面的操作,已 经创建完成。
1.014.jpg (29.37 KB, 下载次数: 69)
2017-5-20 17:27 上传
第二步:为总项目添加子项目
为总项目添加子项目之前,我们需要新建一个文件(程序编辑窗口), 点击软件 file 下面那个文本图标 create a newfile(创建一个新的文件)
1.015.jpg (23.12 KB, 下载次数: 82)
2017-5-20 17:27 上传
得到如下图的程序编辑窗口,在这里面编写单片机的程序。
1.016.jpg (30.43 KB, 下载次数: 97)
2017-5-20 17:27 上传
现在我们需要的是点亮一只灯的程序。
1.017.jpg (33.25 KB, 下载次数: 65)
2017-5-20 17:27 上传
#include Main()
{ P1=0xfe;
} 写好后,我们还不知道子项目里的程序有没有错,现在我们需要把这 个子项目添加到“点亮一只灯.uv2”的总项目里,去让软件查错,方 便我们修正,输出我们想要的单片机代码去让单片机工作,那需要如 何做呢?
很显然,当我们新建一个子项目编辑窗口时(子项目),软件是没有
把这个子项目存到总项目当中的,而是需要我们人手添加进去。
操作方法是:先保存,然后再把这个子项目添加到总项目去。
先保存。
需要点击如下图的图标 save the active document(保存活动文档),就 是保存当前编辑中的程序编辑窗口(子项目)。
1.018.jpg (32.86 KB, 下载次数: 68)
2017-5-20 17:27 上传
或许有些朋友很聪明,看到窗口上的*号就知道还没有保存的文件。
默认保存在我们创建的“点亮一只灯”文件夹当中,还有重要的一点
是,记得文件名后缀必须是“.c”,第二次:文件名后缀必须是“.c” 第三次:文件名后缀必须是“.c”,重要是事情说三遍,这样后面的 操作就会万无一失了。
1.019.jpg (30.62 KB, 下载次数: 75)
2017-5-20 17:27 上传
保存后,某些字母是有颜色的,这个就是保存好的象征,如下图所示:
1.020.jpg (31.85 KB, 下载次数: 77)
2017-5-20 17:27 上传
保存后,现在我们需要把子项目添加到总项目当中。
1.021.jpg (35.76 KB, 下载次数: 70)
2017-5-20 17:27 上传
鼠标右击“source group1”选择”add file to group ’source group1 ’”(添
加文件到组,根源组 1)
1.022.jpg (50.2 KB, 下载次数: 79)
2017-5-20 17:27 上传
默认打开的就是“点亮一只灯”文件夹下面的“点亮一点灯”的 C 语
言程序(就是我们刚刚保存的.c 文件) 然后点窗口上的 add(添加),
1.023.jpg (23.46 KB, 下载次数: 70)
2017-5-20 17:27 上传
Source group1 下有了“点亮一只灯”的 C 语言程序
1.024.jpg (30.04 KB, 下载次数: 79)
2017-5-20 17:27 上传
添加成功后,就退出上面那个添加窗口。
添加子项目到总项目后,我们还不知道我们写的程序有没有错,现在
1.025.jpg (43.57 KB, 下载次数: 73)
2017-5-20 17:27 上传
要做的是,让软件查错,那要如何做呢? 如下图所示。
如果总项目只有一个子项目的时候(就像点亮一只灯.c),我们就点 built target,如果有二个或以上的子项目,就点 built all target files, 就两个按钮就是这样用,这就为什么叫总项目和子项目的原因,因为 总项目中可以包含多个子项目的。
来看看点击后的效果。
这里只有一个子项目,只点 build target 就行。
1.026.jpg (38.84 KB, 下载次数: 67)
2017-5-20 17:27 上传
1.027.jpg (48.86 KB, 下载次数: 72)
2017-5-20 17:27 上传
从上图可以看到,build 完后,我们看到是 0 error (0 错误),0 warning
(0 警告)。
如果我们把 P1=0xff;,后面这个“;”分号去掉,看看是怎么样。
1.028.jpg (55.32 KB, 下载次数: 74)
2017-5-20 17:27 上传
很明显,它出来了一句,syntax error near (}
语法错误在花括号附近),
target not created(目标没创建)。
双击 syntax error near }这条语句时,光标就会出来在附近,让你改错。
1.029.jpg (61.5 KB, 下载次数: 77)
2017-5-20 17:27 上传
现在我们把分号加上后,它编译没有错误,证明程序可以运用,但是
软件还没有输出单片机运行需要的代码。
1.030.jpg (33.28 KB, 下载次数: 67)
2017-5-20 17:27 上传
第三步:输出单片机运行需要的代码
鼠标右击“target”点“options for target ‘target 1’”(选项对于目标 1)
1.031.jpg (42.96 KB, 下载次数: 72)
2017-5-20 17:27 上传
点第三列的 output “输出”按钮,然后把 create hex file“创建 16 进
制文件”勾上后,点确定。
1.032.jpg (37.99 KB, 下载次数: 54)
2017-5-20 17:27 上传
再点 built target
1.033.jpg (16.52 KB, 下载次数: 54)
2017-5-20 17:27 上传
这样在编译没有错误成功后,它就会产生一个 hex 文件(单片机需要 的代码),我们就可以用这个 hex 文件让我们的单片机工作啦!
它在什么位置?就在我们新建的“点亮一只灯”的文件夹里面。
1.034.jpg (22.49 KB, 下载次数: 74)
2017-5-20 17:27 上传
需要用的时候,我们需要到这个文件夹找出来,这样我们 P1.0 口的 发光二极管就可以点亮了。
1.035.jpg (38.74 KB, 下载次数: 55)
2017-5-20 17:27 上传
查找方法:
如果你是用仿真软件。 先双击 89C52
1.036.jpg (46.57 KB, 下载次数: 61)
2017-5-20 17:27 上传
再点击 program file 到点亮一盏灯文件夹里面,把点亮一只灯.hex 文 件,找出来就行。(如下图)
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)/*…*/ 斜扛与星号结合使用,这种写法可以注释任意行,即斜 扛星号与星号斜扛之间的所有文字都作为注释。
下图是第二种。
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,后面再加上一个分 号表示这是一条结束。
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,如果后面还有语句
就会接着一条条继续执行,直到 } 的这个结尾,继续又重新开始到
{ 这个开始继续执行,无限循环。
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;
}
语句解说:
1.041.jpg (16.58 KB, 下载次数: 54)
2017-5-20 17:27 上传
执行过程:
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 语 句继续往下面执行。
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,想计算准确的时间,先在软件里面设 置一下。
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 是细节语句执行,说的多不如动手试一试, 就会明白很多了。
1.045.jpg (28.62 KB, 下载次数: 51)
2017-5-20 17:27 上传
来看看执行分号之前的时间。
1.046.jpg (32.58 KB, 下载次数: 52)
2017-5-20 17:27 上传
从上图可以看到,执行一个分号之前的时间是,0.00044162 s(左边 的 sec 那里看到),0.00044162 s=0.00044162s*100 万=441.62us(小数 点向右移六位就行)
执行一次分号后的时间。
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++)
{
;
}
}
1.048.jpg (21.66 KB, 下载次数: 49)
2017-5-20 17:27 上传
很明显,C 语言是可以用于内嵌语句执行的,从上面图片不难看到, 执行完 230 次分号后(花 1ms),还要重复执行 1000 次 1ms 就是 1s 了。
一盏灯的一秒亮与灭
目标:一盏灯的一秒亮与灭
1 电路流程图:
2 元件特性 发光二极管的原理
正极这边为高电平,负极为低电平,发光二极管就行,两边为高电平, 发光二极管就不亮。
。
3 程序流程的概括
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(无符号整型)
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,这两个数内变化,现 在稍微了解就行,以后用就的时候你就明白了。
再来看看程序,和我们的流程图是一模一样。
1.051.jpg (28.44 KB, 下载次数: 58)
2017-5-20 17:27 上传
从上面图片我们发现,延时程序是一模一样的,那我们有没有方法把
同样的代码放在别处,需要的时候才调用出来,这样就可以减少很多 代码重写,不用浪费那么多单片机内部资源。
有两种方式: 第一种是在主程序(main)上面书写。 第二种是在主程序(main)下面书写。
来看看第一种,在主程序上面书写。
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:
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 可以在子程序和主程序的花括号里随意使 用,理解没?
1.054.jpg (24.7 KB, 下载次数: 66)
2017-5-20 17:27 上传
回归正传。
1.055.jpg (21.46 KB, 下载次数: 64)
2017-5-20 17:27 上传
del_ms 这名字在英文或符号之间(不是中文就行,因为这软件不懂
中文),你可以随你懂的命名字,比如你不太懂英文,直接写 yan_shi
也行,只要做到一看这名字就知道是什么样的子程序就行。
延时子程序调用方法,在主程序内调用。
1.056.jpg (19.46 KB, 下载次数: 69)
2017-5-20 17:27 上传
del_ms(多少数字你定义);
记得后面不要漏了分号,这样做只要是告诉软件,你已经写完一条语 句,不然的话,程序会出错。
第二种:子程序在主程序下面写。
1.057.jpg (37.45 KB, 下载次数: 71)
2017-5-20 17:27 上传
这种方式除了位置不同和加多一句“告诉单片机主程序”下面有子程
序外,其它一样,如果你在主程序下面写子程序而没有首先告诉单片 机,程序编译中会出错的,你可以自己试试,试过就知道了。
详细请打开编程软件和仿真软件浏览效果。
本实验配套的的仿真工程文件和源码下载地址:http://www.51hei.com/bbs/dpj-85401-1.html