文档库 最新最全的文档下载
当前位置:文档库 › 51单片机C语言入门教程详细解说

51单片机C语言入门教程详细解说

51单片机C语言入门教程详细解说
51单片机C语言入门教程详细解说

单片机c语言入门

相信很多爱好电子的朋友,对单片机这个词应该都不会陌生了吧。不过有些朋友可能只听说他叫单片机,他的全称是什么也许并不太清楚,

更不用说他的英文全称和简称了。单片机是一块在集成电路芯片上集成了一台有一定规模的微型计算机。简称为:单片微型计算机或单片机

(Single Chip Computer)。单片机的应用到处可见,应用领域广泛,主要应用在智能仪表、实时控制、通信、家电等方面。不过这一切都没

什么关系,因为我(当然也包括任何人)都是从不知道转变成知道的,再转变成精通的。现在我只想把我学习单片机的经历,详细地讲叙给大

家听听,可能有些大虾会笑话我,想:那么简单的东西还在这里卖弄。但是你错了,我只是把我个人学习的经历讲述一遍而已,仅仅对那些想

学习单片机,但又找不到好方法或者途径的朋友,提供一个帮助,使他们在学习过程中,尽量少走些弯路而已!

首先,你必须有学习单片机的热情,不是说今天去图书馆看了一个下午关于单片机的书,而明天玩上半天,后天就不知道那个本书在讲什

么东西了。还是先说说我吧,我从大二的第一个学期期末的时候才开始接触单片机,但在这之前,正如上面所说的:我知道有种芯片叫单片机,

但是具体长成什么样子,却一点也不知道!看到这里很多朋友一定会忍不住发笑。嘿嘿,你可千万别笑,有些大四毕业的人也同样不知道单片

机长成什么样子呢!而我对单片机的痴迷更是常人所不能想象的地步,大二的期末考试,我全放弃了复习,每当室友拿着书在埋头复习的时候,

我却捧着自己从图书馆借的单片机书在那看,虽然有很多不懂,但是我还是坚持了下来,当时我就想过,为了单片机值不值得我这样去付出,

或许这也是在一些三流学校的好处吧,考试挂科后,明年开学交上几十元一门的补考费,应该大部分都能过了。于是,我横下一条心,坚持看

我的单片机书和资料。

当你明白了单片机是这么一回事的时候,显而易见的问题出来了:我要选择那种语言为单片机编写程序呢?这个问题,困扰了我好久。具

体选择C51还是A51呢?汇编在我们大二之前并没有开过课,虽然看着人家的讲解,很容易明白单片机的每一时刻的具体工作情况,但是一合上

书或者资料,自己却什么也不知道了,根本不用说自己写程序了。于是,我最终还是决定学C51,毕竟C51和我们课上讲的C语言,有些类似,

编程的思想可以说是相通的。而且C51还有更大的优点就是编写大程序时的优越性更不言而喻,当然在那时,我并没有想的那么深远,C51的特

点,还是在后来的实践过程中,渐渐体会到的!朋友如果你选择了C51,那么请继续往下看,如果你选择了A51,那么你可以不要看了!因为下面讲

的全是C方面的,完全在浪费你的时间! 呵呵^_^

第二,既然你想学好单片机,你必须得舍得花钱,如果不买些芯片回来自己动手焊焊拆拆的(但是在后期会介绍给大家一个很好用的硬件

仿真软件,并不需要你用实验板和仿真器了,直接在你的PC上完成,但是软件毕竟是软件,从某个特定的意义上来说是并不能代替硬件的),即使

你每天捧着本书,把那本书翻烂,也永远学不会单片机的!刚接触单片机的朋友,看了资料,一定会对以下几个词见的比较多,但是具体的概

念还是比较模糊,现作如下说明:

(1)编程器编程器是用来烧单片机芯片的,是把HEX或者BIN文件烧到单片机ROM里的,供单片机运行的。

(2)实验板实验板是专为初学者根据某些要求而特做的板,一般上面就有一个单片机的最小系统,使用者只需写好程序,烧好芯片,放

到上面加以验证的这么一个工具。有了实验板,对与初学者来说,省去了焊个最小系统的麻烦。但是对于电子开发人员来说,作用并不是很大

(3)仿真器仿真器是直接把HEX或者BIN文件暂时放在一个芯片里,再通过这个芯片的引脚连接到实验板或者系统上工作。这样以来,可

以省去了来回插拔芯片带来的不必要麻烦。

我一开始也不知道上面3个的概念和作用,嘿嘿,原本想买个实验板(不想焊板,因为不可能为了点亮几个流水灯,而去焊个单片机的最小系统)

的,可是结果,确和我想的正好相反,人家出售的是编程器。等货物寄到后,才知道自己搞错了!汗。。。嘿嘿。现在想想实在是又气又笑。我花

了160大样买了个编程器(很不幸的是,这个编程器更本用不了,一烧芯片,芯片就烧坏了)把我给气的,这个编程器,现在还躺在我的抽屉里

呢不过,现在想想,唯一让我觉得欣慰的是,那个老板每次能解答我的问题,连那种超级幼稚的问题,他也能不嫌麻烦地尽量帮我解答!这点让

我很感动!

第三,想学单片机的必需品--PC。因为写程序,编译或者是仿真都是通过PC完成的。如果没有PC,什么也做不了!!!有了PC最好还要可

以上网,因为如果你没有可以和你交流单片机的人,遇到自己解决不了的问题,一直都想不通,那么估计你学习单片机的热情就会随着时间的

推移而慢慢耗尽。如果你能上网通过论坛或者QQ群,问题就很快得到解决。这样的学习效率一定很高!真正的高手是从论坛中泡出来的!

有了上述3个条件后,你就可以开始学你的单片机了。但是,真的做起来并没有我所说的那么简单。你一定会遇到很多很多的问题。比如

为了让单片机实现某个功能,你可能不知道怎么去写某个程序。或是你看懂了资料上某个相似的程序,你自己却写不出来。遇到类似的情况,

记住:千万不要急噪,就行!

(二)

说了这么多了,相信你也看了很多资料了,手头应该也有必备的工具了吧!(不要忘了上面讲过几个条件的哦)。那个单片机究竟有什么

功能和作用呢?先不要着急!接下来让我们点亮一个LED(搞电子的应该知道LED是什么吧^_^)

我们在单片机最小系统上接个LED,看我们能否点亮它!对了,上面也有好几次提到过单片机最小系统了,所谓单片机最小系统就是在单片机

上接上最少的外围电路元件让单片机工作。一般只须连接晶体、VCC、GND、RST即可,一般情况下,AT89C51的31脚须接高电平。

#include //头文件定义。或用#include其具体的区别在于:后者定义了更多的地址空间。

//在Keil安装文件夹中,找到相应的文件,比较一下便知!

sbit P1_0 = P1 ^ 0; //定义管脚

void main (void)

{

while(1)

{

P1_0 = 0;//低电平有效,如果把LED反过来接那么就是高电平有效

}

}

就那么简单,我们就把接在单片机P1_0上的LED点亮了,当然LED是低电平,才能点亮。因为我们把LED的正通过电阻接至VCC。

P1_0 = 0; 类似与C语言中的赋值语句,即把0 赋给单片机的P1_0引脚,让它输出相应的电平。那么这样就能达到了我们预先的要求了。

while(1)语句只是让单片机工作在死循环状态,即一直输出低电平。如果我们要试着点亮其他的LED,也类似上述语句。这里就不再讲了。

点亮了几个LED后,是不是让我们联想到了繁华的街区上流动的彩灯。我们是不是也可以让几个LED依次按顺序亮呢?答案是肯定的!其

实显示的原理很简单,就是让一个LED灭后,另一个立即亮,依次轮流下去。假设我们有8个LED分别接在P1口的8个引脚上。硬件连接,在

P1_1--P1_7上再接7个LED即可。例程如下:

#include

sbit P1_0 = P1 ^ 0;

sbit P1_1 = P1 ^ 1;

sbit P1_2 = P1 ^ 2;

sbit P1_3 = P1 ^ 3;

sbit P1_4 = P1 ^ 4;

sbit P1_5 = P1 ^ 5;

sbit P1_6 = P1 ^ 6;

sbit P1_7 = P1 ^ 7;

void Delay(unsigned char a)

{

unsigned char i;

while( --a != 0)

{

for(i = 0; i < 125; i++); //一个; 表示空语句,CPU空转。

} //i 从0加到125,CPU大概就耗时1毫秒

}

void main(void)

{

while(1)

{

P1_0 = 0;

Delay(250);

P1_0 = 1;

P1_1 = 0;

Delay(250);

P1_1 = 1;

P1_2 = 0;

Delay(250);

P1_2 = 1;

P1_3 = 0;

Delay(250);

P1_3 = 1;

P1_4 = 0;

Delay(250);

P1_4 = 1;

P1_5 = 0;

Delay(250);

P1_5 = 1;

P1_6 = 0;

Delay(250);

P1_6 = 1;

P1_7 = 0;

Delay(250);

P1_7 = 1;

}

}

sbit 定义位变量,unsigned char a 定义无符字符型变量a,以节省单片机内部资源,其有效值为0~255。main函数调用Delay()函数。

Delay函数使单片机空转,LED持续点亮后,再灭,下一个LED亮。while(1)产生循环。

(三)

上面我们讲了如何使LED产生流动,但是你是否发现一个问题:写的太冗长了!能不能再简单点呢?可以!可以使用C51的内部函数

INTRINS.H实现。函数unsigned char _crol_(unsigned char a, unsigned char n) 可以使变量a 循环左移n位,如果我们先给P1口赋

0000 0001那么当n为1时,便会产生和上面一样的效果!

#include

#include

void Delay(unsigned char a)

{

unsigned char i;

while( --a != 0)

{

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

}

}

void main(void)

{

unsigned char b, i;

while(1)

{

b = 0xfe;

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

{

P1 = _crol_(b, 1);

b = P1;

Delay(250);

}

}

}

INTRINS.H函数中的unsigned char _cror_(unsigned char a, unsigned char n)右移也可以实现同样的效果!这里就不再累述。

流水灯的花样很多,我还写过那种拉幕式的流动等,程序很简单,有兴趣的朋友,可以自己试着写写!

对了,讲了那么多,有些朋友一定还不知道编译软件怎么用?这里给大家介绍几个吧?WA VE(伟福)大家一定听说过吧!还有一个

就是KEIL2,我用的就是KEIL2,下面就来讲讲如何使用KEIL2这个编译软件!

1.安装软件,这个应该不用再讲了吧!

2.安装完后,启动KEIL软件左击Project-->New Project-->输入文件名-->选择我们所以使用

的芯片(这里我们一般用到Atmel的

AT89C51或AT89C2051,点确定。

3.点File-->New-->输入我们编写的程序,保存为.C文件。(一般情况下,我们保存的文件名和前面的工程名一样。)

4.展开Target 1 -->右击Source Group 1 -->Add Files to Group 'Source Group 1'-->选择刚才保存的.C文件点击ADD后,关闭对

话框。这样.C文件就被加到了Source Group 1 下。

5.右击Target 1-->Options for 'Target 1' -->Target中填写晶体的大小,Output中,在Create HEX Files 前打上钩,点确

定。

6.点Project-->Rebuild All Traget Files ,若提示

creating hex file from "XXX"...

"XXX" - 0 Error(s), 0 Waring(s).

表示编译和生成HEX文件成功!接下来的就是把HEX文件烧到单片机中,或是仿真器上,看是否达到预先的目的!

嘿嘿!现在是否自己好有成就感了,如果让你去做个流水彩灯,开发一个简单的产品,只要加上驱动电路,就可以做出漂亮的流动彩灯

了!到现在为止,你应该知道单片机的功能有多强大了吧,如果单纯的用数字电路或模拟电路的知识去设计一个流动彩灯,可能要花点工夫

和时间才行,有了单片机,那就不一样了,你只要写程序控制他就行!有人说过这样一句话,也并不无道理的,学单片机,程序思想很重要!

(四)

呵呵,朋友!相信你的流水灯也做的不错了吧,现在能玩出几种花样了?你可能会说,只要你想得到,想怎么流就怎么流!呵呵,是的。

但是工程师们设计这么一个单片机,并不是只为了让它做流水灯的,那样也太浪费点了吧... ^_^

学过数字电路的朋友,一定动手做过8路或者6路的抢答器。用纯粹的数字电路知识来做,自己设计电路,感到比较困难!抢答器上用的显

示器多为7段数码管,这里我们来讲讲,如何用单片机让数码管显示0-9。抢答器的实现,我们放到后面再来探讨,因为抢答器还涉及了键盘的

内容。8段数码管分为共阴和共阳两种。8段数码管是由8个LED组成(还包括一个小数点)。若为共阳,则8个LED的阳级是连接在一起的,同理

若为共阴,则阴极连接在一起。8个LED对应的标号如下:({0x3f, 0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0-9数字)

a 0 1 2 3 4 5 6 7 8 9

__ 0011 1111,0000 0110,0100 1111,0101 1011

f | | b

|__|

|g | c

e |__| . dp

d

一般情况下,为了计算或取码的方便,我们把a-dp依次接到单片机某个口上的Px.0--Px.7上。x表示0,1,2,3其中的一个。这样我们只

要给某个口,赋一个值,则相应的LED段就被点亮,但是在硬件连接上要注意了:单片机可能不能直接驱动LED,所以我们可以通过控制三级管

的导通或截止,来控制LED的亮与灭!

如果我们把共阴的数码管的a--dp依次接到单片机的P0.0--P0.7上,注意:P0口需接上拉电阻。何为上拉电阻,简单的说,就是把电平拉

高,以提高驱动能力。那么比如:P0 = 0X3F;则显示为数字0 。因为0X3F 即为2进制的0011 1111 我们低位往高位数,依次为1111 1100,

其I/O的电平分别为高、高、高、高、高、高、低、低,即对应的a--dp 为亮、亮、亮、亮、亮、亮、灭、灭,由上图我们可以看出g和dp段不

亮其他段均亮,即为我们所看到的数字0 字样。其他的数字或字符,也同理可以得到。但是有些朋友就会问,那我们每取一个字模,岂不是

很麻烦?还有自己考虑高低电平什么的?^-^ 呵呵,其实网上有很多LED取模软件,如果有一定计算机编程语言的朋友,也可以试着自己写个

取模的程序,让计算机为我们计算,诸如上述0X3F的数值。

#include

void Delay(unsigned char a)

{

unsigned char i;

while( --a != 0)

{

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

}

}

void main(void)

{

P0 = 0X3F; //显示0

Delay(250);//延时

P0 = 0X00;//短暂的关闭显示,若不关闭,可能会造成显示模糊不清。

P0 = 0X06; //显示1

Delay(250);

P0 = 0X00;

... //以下显示数字2-F,略。

}

看到这里,想必大家一定可以把0-F显示出来了吧!但是如果要你显示两位数,三位数

呢?或许,有的朋友会这么想:在P0口上接一个

数码管,再在P1口上接个数码管!但是,如果要显示4位、5位的数字呢?那岂不是一块AT8951都接不过来!难到就不能接4位或5位以上的吗?

肯定不是的!

说到这里,我们来讲讲数码管的显示方式,可分为两种:动态扫描和静态显示。上面我们所说的即为静态显示。但是如果我们采用动态扫

描显示,那么就可以解决上面的问题,即可以显示多个数码管了。上面我们所说的静态显示把数码管的COM脚接至VCC或GND端,其他的接至PX

口上,这样只要PX口上输出相应的高低电平,就可以显示对应的数字或字符。但是如果我们采用动态扫描的方法,比如显示6个数码管,硬件

连接可以这样解决:a--dp还是接至P0.0--P0.7上,还有6个COM脚再接至另外口的P2.0--P2.5。P0口作段选(控制数字字符)P2口作位选(选

通哪个数码管导通)这样我们控制P0和P2口就可以控制6个数码管了。但是,细心的朋友,会问这样的问题:P2位选,是让数码管一个一个亮

的,那还是不能控制6个一起亮或灭嘛!?^_^ 想想好象是对的哦?怎么办...难道错了?

嘿嘿,问你个问题?黑夜里,拿着一支烟,在你面前快速的晃动,你会发现什么样的现象?是不是原本不连续的点变成了一条看上去连

续的曲线或者直线!再回过头来,仔细想想我们的数码管!原理是一样的,你可别忘了,我们的单片机可是一个计算机哦,计算机的运算速

度,大家可想而知吧!

这里再说说51单片机的机器周期和时钟周期等概念。所谓机器周期就是访问一次存储器的时间。而1个机器周期包括12个时钟周期。如果

单片机工作在12M晶体下,那么一个时钟周期为:1/12微妙。一个机器周期12*1/12 = 1微妙。如果晶体为6M,时钟周期和机器周期各是多少呢

?在汇编中,我们还要关心,指令执行的机器周期长短不一,有1个周期、2个周期和4个周期等。

说着说着,跑了这么远了...还是回到原来的话题,如果我们把位选的P2也看作上面的“烟”一划而过,那么我们看到的是不是6个一起亮

或一起灭了!^_^ 哈哈,原来如此... 记住,在任何某一时刻,有且只有一个数码管能发光。如果你能把这句话理解了,你是真明白

我的意思了!朋友,现在给你个任务,让6个数码管分别显示1、2、3、4、5、6。看你自己可以搞定不?你自己先试着写写看咯...

#include

void Delay(unsigned char a)

{

unsigned char i;

while( --a != 0)

{

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

}

}

void main(void)

{

while(1)

{

P0 = 0x06;//1的码段

P2 = 0x01;//选通一位,或者P2_0 = 1;

Delay(20);//延时约20毫秒

P0 = 0X00;//关闭显示

P0 = 0x5b;//2的码段

P2 = 0x02; //选通一位,或者P2_1 = 1;

Delay(20);

P0 = 0X00;

P0 = 0x4f;//3的码段

P2 = 0x04; //选通一位,或者P2_2 = 1;

Delay(20);

P0 = 0X00;

P0 = 0x66;//4的码段

P2 = 0x08; //选通一位,或者P2_3 = 1;

Delay(20);

P0 = 0X00;

P0 = 0x6d;//5的码段

P2 = 0x10;//选通一位,或者P2_4 = 1;

Delay(20);

P0 = 0X00;

P0 = 0x7d;//6的码段

P2 = 0x20;//选通一位,或者P2_5 = 1;

Delay(20);

P0 = 0X00;

}

}

(五)

相信大家一定见过数字时钟,教学楼大厅一定有吧。每次路过,基本上只是随便瞟上一眼,根本没去想过他的工作原理什么。但是今天

你也可以把他做出来了,是不是觉得自己很有成就感呢!呵呵!^_^

接上面所讲的,我们先来做个简单的实验:在一个数码管上轮流显示0--9这10个数字。还楞着干什么,快动手写程序呀!好象有点难哦,

要不先不要往下看了,嘿嘿,关机吧,自己先去想想,怎么样?

#include

unsigned char code SEG_TAB[ ] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0-9数字

void Delay(unsigned int a) //unsigned int 定义为无符整形,取值范围为0--32768

{

unsigned char i;

while( --a != 0)

{

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

}

}

void main(void)

{

unsigned char i;

while(1)

{

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

{

P0 = SEG_TAB[ i ]; //取SEG_TAB数组中的值

P2 = 0X01;

Delay(1000);

}

}

}

是不是显示从0--9,跳动显示,你的心是不是也跟着一起跳呀,离我们的目标又迈进了一步!不错,继续努力!

上面只显示了一个数码管的数字0--9,但是怎么样要让他显示6个数字呢?这样我们就可以做个时钟出来玩玩了!还记不记得我们前面

讲过的P2口的位选作用!嘿嘿,没忘记就好!

#include

unsigned char hour = 12, min = 0, sec = 0;

unsigned char code SEG_TAB[ ] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0-9数字

void Delay(unsigned char a)

{

unsigned char i;

while( --a != 0)

{

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

}

}

void disp(void)

{

P0 = SEG_TAB[ sec % 10 ];//显示秒的个位P2 = 0X01;

Delay(15);

P2 = 0;

P0 = SEG_TAB[ sec / 10 ];//显示秒的十位

P2 = 0X02;

Delay(15);

P2 = 0;

P0 = SEG_TAB[ min % 10 ];//显示分的个位P2 = 0X04;

Delay(15);

P2 = 0;

P0 = SEG_TAB[ min / 10 ];//显示分的十位P2 = 0X08;

Delay(15);

P2 = 0;

P0 = SEG_TAB[ hour % 10 ];//显示时的个位P2 = 0X10;

Delay(15);

P2 = 0;

P0 = SEG_TAB[ hour / 10 ];//显示时的十位P2 = 0X20;

Delay(15);

P2 = 0;

}

void main(void)

{

while( 1 )

{

disp( );

}

}

编译烧录芯片后,观察运行现象。矣...怎么一直显示12:00:00,难道是时钟没有启动?还是,另外的原因呢?哦,原来是3个变量

sec,min,hour初始化后,其值一直没有改变!那我们怎么样才能让他改变数值呢?有的朋友一定会这么认为:让秒个位延时1秒,后加1,

而秒十位延时10秒后,再加1,一直加到6,分个位加1,依次类推...这样的想法是不错,但是朋友你有没有想过C语言的一般延时(除非你

把他放到中断里)极不精确!这样累计下来,一天24小时的误差,肯定很大很大,我曾经也用延时的方法写过时钟,1个小时误差8秒,那是

个什么概念!一天24小时就要24*8=192,约为3分钟,一个月就是10分钟...有没有其他的方法可以改进些呢?有!这里就要涉及到单片机中

另一个比较重要的核心部分:单片机的中断和定时器的运用!想写出比较精确(这里说的只的相对前面的做法而言比较精确而已,如果要做

更加精确的时钟,用时钟芯片比较好点,常用的有DS12887和DS1302等)的时钟程序,就一定要调用中断和定时器。还是大家先看看教材和书

吧,毕竟人家出的书,肯定比我要写的系统多了,下面我们再来简单的讲讲!

(六)

什么是中断呢?讲个比较通俗的例子:比如你正在家中看电视,突然电话响了,你的第一反应是什么?是不是先跑过去接电话!接完电话

后,继续看电视。这就是个中断的例子,中断是由电话引起了,你跑过去就是响应中断,接电话就是中断的处理!接完电话后,接续看电视,

即恢复中断,等待下个中断的到来!

但是这个好象和单片机没什么联系呀?有的朋友或许会这样疑问。是的。单片机当然不会看电视了,也不会接电话了!^_^ 但是,类

比一下:比如单片机正在执行某个任务,突然要有更重要的事件,要求单片机响应,单片机就会应答响应,去执行更为重要的任务(中断处理

),原来的任务就继续等待(现场的保护)。执行完更重要的任务后,回到中断的入口处,继续执行原来的任务(现场中断的恢复)。51系列

的单片机共有5个中断源,分别为:外中断0 、定时器T0中断、外中断1、定时器T1中断、串口中断。

或许,有些朋友已经大概领会了其中的意思,有些朋友还迷迷糊糊。不过不要紧,我们继续往下看,下面我们来讲讲单片机的定时器是什

么?如何工作的?定时器,大家从字面上就可以看出其大概的意思吧?简单的说:就是起定时作用!也就是让单片机计数。定时器分为:方式

0方式1、方式2和方式3等4种工作方式。有些朋友一定会问:定时器如何启动?风扇的定时器,相信大家一定都用过吧!但是单片机的定时器,

该如何启动呢?总不该也用手一拧定时器吧! ^_^ 当然不是,我们只要给单片机一些指令,就可以启动定时器了!下面我们就定时器0,来说

说怎么启动定时器0。

TMOD = 0X01;//设置定时器0 工作方式0

TH0 = (65536 - 5000) / 256;//载入高8位初值

TL0 = (65536 - 5000) % 256;//载入低8位初值

TR0 = 1; //启动定时器

^_^,简单吧,这样我们就可以把定时器启动了。其中TMOD为T/C方式控制寄存器:

D7 D6 D5 D4 D3 D2 D1 D0

_ _

GA TE C/T M1 M0 GA TE C/T M1 M0

|_________ __________| |_________ __________|

| T/C1 | | T/C0 |

C/T就是counter(记数器)和timer(定时器)的选择位,若值为1,则作计数器用。为0,则为定时期用!GATE为门控位。M1和M0工作方

式的选择:若M1=0;M0=0 则为方式0:13位定时/记数器。若M1=0;M0=1则为方式1,16定时/记数器。若M1=1;M0=0则为方式2,自动装载8位

定时/记数器。若M1=1;M0=1则为方式3,只适用于T/C0,2个8位定时/记数器。

说了一大堆,感到有点困惑了吧。那我们还是来说说上面的。TMOD= 0X01;//至于为什么是0X01,大家看:我们选择的是定时器0方式0,

所以T/C1全为0,而T/C0的M1为0。M0为1,所以D0-D7为0X01;0X01表示的是16进制数,这个大家应该都知道吧!还有D0-D7表示的是2进制数。

还需要转换一下!

TH0 = (65536 - 5000) / 256;//载入高8位初值。若在12M晶体下,定时5000微秒,即为5毫秒;但是如果不是在12M下,那又该怎么计算

了呢?如果是11.0592M呢?还记不记得,我们前面讲过的机器周期和时钟周期的概念?^_^忘了,还是看看前面吧!呵呵!没事,学习嘛,忘

了再翻翻书,看看就可以了!其实上诉的5000 = 1 * C 很显然C=5000,但是如果是11.0592M 那么就不是1了,应该是1.085了,那么5000 =

1.085 * C,则C就为5000 / 1.085 = ? 具体多少,大家自己去算算吧?同理TL0也是一样的!但是,细心的朋友会发现网上或者是资料上的

TH0,TL0并不是和上面一样的,而是直接TH0 = 0XEC;TL0 = 0X78 是不是和上面的一样的,别忘了单片机也是计算机的一种哦。用C的话,直

接写上计算公式就行,计算就交给单片机完成。

TR0 = 1;这句就是启动定时器0,开始记数!哦,还有一点,有些朋友会问,你是65536是哪里来的呢?呵呵你可别忘了:设置定时器0

工作方式0是16位的(2的16次方是多少,自己算算就知道了)简单吧?但是如何和中断一起使用呢?请继续看下面的讲解!

TMOD = 0X01;//设置定时器0 工作方式0

TH0 = (65536 - 5000) / 256;//载入高8位初值

TL0 = (65536 - 5000) % 256;//载入低8位初值

TR0 = 1; //启动定时器

EA = 1;//开总中断

ET0 = 1;//开定时器中断。若为0则表示关闭!

这样我们,就初始化定时器T0和中断了,也就是定时器满5毫秒后,产生一次中断。产生中断后,我们怎么处理呢?嘿嘿!仔细想想?

^_^

每次中断后,我们可以让一个变量自加1,那么200次中断后,不就是1秒的时间了吗?比起上面我们说的延时来出来是不是更加精确多了呢?

那是肯定的!但是想想1秒种的时间就让单片机产生那么多次的中断,单片机会不会累着呢?恩,那么不好。如果在12M的晶体下,T0每次中

断不是可以产生最多65.336毫秒的时间吗?那么我们让他每50毫秒中断一次好了!这样我们就20次搞定一秒的时间了!·爽·

好了,讲了那么多,现在我们来写个时间的程序吧!^_^

#include

#define HI ((65536 - 50000) / 256)

#define LO ((65536 - 50000) % 256)

#define _TH0_TL0_ (65536 - 50000)

#define M 20 //(1000/25)

/****************************************************************************** ****************/

unsigned hou = 12, min = 0, sec = 0;

unsigned char SEG_TAB_B[ ] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //0-9数字

unsigned char SEG_TAB_A[ ] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//0.-9.数字

/****************************************************************************** ***************/

void Delay(unsigned char a)//延时程序a*1MS

{

unsigned char j;

while(a-- != 0)

{

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

}

}

/****************************************************************************** ***************/

void Disp(void)//数码管显示

{

P2_0 = 1;

P1 = SEG_TAB_B[ hou / 10 ];

Delay(5);

P2_0 = 0;

P2_1 = 1;

P1 = SEG_TAB_A[ hou % 10 ];

Delay(5);

P2_1 = 0;

P2_2 = 1;

P1 = SEG_TAB_B[ min / 10 ];

Delay(5);

P2_2 = 0;

P2_3 = 1;

P1 =S EG_TAB_A[ min % 10 ];

Delay(5);

P2_3 = 0;

P2_4 = 1;

P1 = SEG_TAB_B[ sec / 10 ];

Delay(5);

P2_4 = 0;

P2_5 = 1;

P1 = SEG_TAB_B[ sec % 10 ];

Delay(5);

P2_5 = 0;

}

/****************************************************************************** **************/

void IsrTimer0(void) interrupt 1 using 1 //定时50ms

{

static unsigned char count = 0; //定义静态变量count

count++;

if(count == M)

{

count = 0;

sec++;

if(sec == 60)

{

min++;

sec = 0;

if(min == 60)

{

hou++;

min = 0;

if(hou == 24)

{

hou = 0;

}

}//if

}//if

}//if

}

/****************************************************************************** ************/

void Timer0Init(void) //定时器0

{

TMOD = 0x01;

TH0 = HI;

TL0 = LO;

TR0 = 1;

ET0 = 1;

EA = 1;

}

/****************************************************************************** ************/

void main(void) //主函数

{

Timer0Init();

while(1)

{

Disp();

}

}

简单吧,还是有点看不懂哦,那你自己慢慢体会吧,如果你自己能写个时钟程序来,那么你的51单片机也就学了80 % 了。中断和

定时/记数器器,是个很重要的东西,几乎用到单片机的地方都会涉及到中断和定时!所以大家要好好掌握哦!^_^

哈哈,赶紧编译HEX文件,搭好硬件,烧入单片机,上电看看效果先!呵呵,现在你应该有成就感了吧,想不到一个时钟居然那么

简单,嘿嘿!但是问题来了!时钟虽然做出来了,但是他的精度怎么样呢?一两个小时,或许看不出什么误差,但是一天或者一年呢?

晕,我的天呀,要是按年来算的话,那这个时钟根本没有实用价值!人家都说用C写不出,精度高的时钟程序来的!!!是不是有点后悔

了,去学汇编吧!但是既然选择了C,那么就不要后悔!嘿嘿,想想C的高级语言,怎么会输给汇编呢^_^ 呵呵!看下面这段代码:

static unsigned char count = 0;

TR0 = 0;

TL0 += (_TH0_TL0_ + 9) % 256;

TH0 += (_TH0_TL0_ + 9) / 256 + (char)CY;

TR0 = 1;

count++;

在中断处理服务程序中,我们加入上面的代码。TR0 = 0; 先关闭定时器T0,然后重新给TH0和TL0 赋值,再开启TR0 = 1;烧入单片

机看看效果,怎么样,你第一次精确多了吧。但是还是有误差!郁闷!为什么呢?那是硬件造成的误差,我们可以用软件来弥补!我们先

把时钟点亮,让他走上几个小时或者是几天,看看到底误差是多少!取个平均值。(这里比如我们10小时快1秒)那么可以通过以下语句

if(hour % 10 = 0)

{

sec--;

}

来弥补!这样可能会出现这样的现象:秒直接跳变!我们可以再通过细分来实现,不要10小时那么大,小些的就行!具体的操作还是留给

朋友们吧!

(七)

这回我们来讲讲键盘,大家肯定见过银行柜员机吧,取钱输入密码就要用到键盘,超市购物取回寄存物品要输入密码,还有你现在在

用的PC机的键盘。但是键盘的是怎么工作的呢?一般有2种方式:(1)扫描法,不断扫描键盘的状态,送CPU判断并处理。如果键盘数目一

大的话,显然不适合(2)线反转法,通过行列状态的改变来判断有无键被按下!

现在我们在P1口接个4*4的键盘,P1.0--P1.3接行,P1.4---P1.7接列,再接4个4K7的上拉电阻至VCC。代码如下:

//----键盘扫描法程序-------

//----用数码管显示相应的键值-----

//P1.0--P1.3接行-------

//P1.4---P1.7接列-------

#include

unsigned char code tab[ ]={0x3F,0x06,0x5B,0x4F,

0x66,0x6D,0x7D,0x07,

0x7F,0x6F,0x77,0x7C,

0x39,0x5E,0x79,0x71};//0到F的16个键植

/****************************************************************************** /

void Delayt(unsigned char t)//延时函数

{

unsigned char i;

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

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

}

/****************************************************************************** /

bit pkey(void)//判断键的否被按下,通过返回值确定

{

P1=0xf0;

if(P1!=0xf0)

{

Delayt(25);

if(P1!=0xf0)

return 1;

else

return 0;

}

else

return 0;

}

/****************************************************************************** /

void main(void)//主函数

{

unsigned char key,j,k,s;

while(1)

{

if(pkey()==1)

{

P1=0xfe;

k=0xfe;

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

{

s=P1&0xf0;

switch(s)

{

case 0xe0: key=4*j+0; break;

case 0xd0: key=4*j+1; break;

case 0xb0: key=4*j+2; break;

case 0x70: key=4*j+3; break;

default: break;

}

k=(k<<1)|0x01;

P1=k;

}//for

}//if

//if((P1&0xf0)==0xf0)

P0=tab[key];

P2=1;

Delayt(50);

}//while

}

还有一种就是线反转法,实现如下:

1.和扫描法相同,把列线置低电平,行置高,读行状态

2.与1相反,把行置低,列置高,读列状态

3.若有键按下,则为2次所读状态的结果即为键所在的位置,这样2次输出和2次读入可以完成键的识别!!!

子函数如下:

unsigned char key_vscan(void)

{

unsigned char row, col;

P1 = 0xF0;

row = P1&0xF0;

row = row&0xF0;

P1 = 0x0F;

col = P1&0x0F;

col = col&0x0F;

return(key_val(row|col));

}

下面我们再来介绍介绍一键多能的程序,即按下一个键,可以执行不同的命令!

void main (void)

{

unsigned char b = 0;

while( 1 )

{

if(P1_0 == 0)

{

Delay(10);

if(P1_0 == 0)

{

b++;

if( b == N )//N为键的功能数目

{

b = 0;

}

while(P3_2 == 0);//等待键松开

}

}

switch( b )

{

case 1: P2_0 = 0xFE;

break;

case 2: P2_1 = 0xfd;

//..............add your code here!

}

}

}

第7讲51单片机汇编语言程序设计.

标题:第四部分汇编语言程序设计 教学目标与要求: 1、理解源程序、目标代码、编辑、汇编等含义 2、了解汇编过程 3、掌握伪指令的使用 4、掌握顺序结构、分支结构及循环结构程序的编写方法授课时数: 8学时 教学重点:伪指令的使用 教学内容及过程: 一、程序设计概念 1、汇编程序设计步骤: 分析题意; 资源分配; 程序流程图 编写程序 调试程序 2、程序编写规则: 结构清晰,易读、易于移植 占用存储空间少; 运行时间短; 程序的编制、调试及排错所需时间短; 3、汇编程序功能 汇编指令与机器码指令有一一对应的关系。 汇编程序是一种翻译程序,将源程序翻译成目标程序。 4、汇编程序的汇编过程 汇编有两种方法:手工汇编、机器汇编。 1、手工汇编:

第一次汇编:确定地址,翻译成各条机器码,字符标号原样写出; 第二次汇编:标号代真,将字符标号用所计算出的具体地址值或偏移量代换。 源程序地址 目标程序 第一次汇编第二次汇编 ORG 1000H START: MOV R0,BUFFER-1 1000 A82F A82F MOV R2,#00H 1002 7A00 7A00 MOV A,@R0 1004 E6 E6 MOV R3,A 1005 FB FB INC R3 1006 0B 0B SJMP NEXT 1007 80NEXT 8005 LOOP; INC R0 1009 08 08 CJNE @R0,#44H,NEXT 100A B644NEXT B64401 INC R2 100D 0A 0A NEXT: DJNZ R3,LOOP 100E DBLOOP DBF9 MOV RESULT,R2 1010 8A2A 8A2A SJMP $ 1012 80FE 80FE BUFFER DATA 30H RESULT DATA 2AH END 2、机器汇编 两次扫描过程。 第一次扫描:检查语法错误,确定符号名字; 建立使用的全部符号名字表; 每一符号名字后跟一对应值(地址或数)。 第二次扫描:是在第一次扫描基础上,将符号地址转换成真地址(代真);利用操作码表将助记符转换成相应的目标码。 二、伪指令 伪指令是告诉汇编程序,如何汇编源程序的指令。 伪指令既不控制机器的操作,也不能被汇编成机器代码,故称为伪指令。 1、起始地址伪指令ORG ORG addr16 用于规定目标程序段或数据块的起始地址,设置在程序开始处。 2、汇编结束伪指令END 告诉汇编程序,对源程序的汇编到此结束。一个程序中只出现一次,在末尾。

51单片机汇编程序范例

16位二进制数转换成BCD码的的快速算法-51单片机2010-02-18 00:43在做而论道上篇博文中,回答了一个16位二进制数转换成BCD码的问题,给出了一个网上广泛流传的经典转换程序。 程序可见: http: 32.html中的HEX2BCD子程序。 .说它经典,不仅是因为它已经流传已久,重要的是它的编程思路十分清晰,十分易于延伸推广。做而论道曾经利用它的思路,很容易的编写出了48位二进制数变换成16位BCD码的程序。 但是这个程序有个明显的缺点,就是执行时间太长,转换16位二进制数,就必须循环16遍,转换48位二进制数,就必须循环48遍。 上述的HEX2BCD子程序,虽然长度仅仅为26字节,执行时间却要用331个机器周期。.单片机系统多半是用于各种类型的控制场合,很多时候都是需要“争分夺秒”的,在低功耗系统设计中,也必须考虑因为运算时间长而增加系统耗电量的问题。 为了提高整机运行的速度,在多年前,做而论道就另外编写了一个转换程序,程序的长度为81字节,执行时间是81个机器周期,(这两个数字怎么这么巧!)执行时间仅仅是经典程序的!.近来,在网上发现了一个链接: ,也对这个经典转换程序进行了改进,话是说了不少,只是没有实质性的东西。这篇文章提到的程序,一直也没有找到,也难辩真假。 这篇文章好像是选自某个著名杂志,但是在术语的使用上,有着明显的漏洞,不像是专业人员的手笔。比如说文中提到的:

“使用51条指令代码,但执行这段程序却要耗费312个指令周期”,就是败笔。51条指令代码,真不知道说的是什么,指令周期是因各种机型和指令而异的,也不能表示确切的时间。 .下面说说做而论道的编程思路。;----------------------------------------------------------------------- ;已知16位二进制整数n以b15~b0表示,取值范围为0~65535。 ;那么可以写成: ; n = [b15 ~ b0] ;把16位数分解成高8位、低8位来写,也是常见的形式: ; n = [b15~b8] * 256 + [b7~b0] ;那么,写成下列形式,也就可以理解了: ; n = [b15~b12] * 4096 + [b11~b0] ;式中高4位[b15~b12]取值范围为0~15,代表了4096的个数; ;上式可以变形为: ; n = [b15~b12] * 4000 + {[b15~b12] * (100 - 4) + [b11~b0]} ;用x代表[b15~b12],有: ; n =x * 4000 + {x * (100 - 4) + [b11~b0]} ;即: ; n =4*x (千位) + x (百位) + [b11~b0] - 4*x ;写到这里,就可以看出一点BCD码变换的意思来了。 ;;上式中后面的位:

(最新版)基于51单片机汇编语言的数字钟课程设计报告含有闹钟万毕业论文

单片微型计算机课程设计报告 多功能电子数字钟 姓 名 学

教师 许伟敏 电气二班 林卫

目录 一:概述 (1) 二:设计基本原理简介 (2) 三:设计要求及说明 (3) 四:整体设计方案 (4) 系统硬件电路设计 4 系统软件总流程设计模块划分及分析5 6 五:单模块流程设计 (8) 各模块设计概述、流程图模块源程序集合及注释8 13 六:单模块软件测试 (23) 七:系统检测调试 (24) 硬件电路调试 软件部分烧写调试 八:系统优化及拓展 (26) 九:心得体会 (28)

单片微型计算机课程设计 一、概述 基于汇编语言的电子数字钟概述 课程设计题目:电子数字钟 应用知识简介: ● 51 单片机 单片机又称单片微控制器,它不是完成某一个逻辑功能 的芯片,而是把一个计算机系统集成到一个芯片上。作为嵌 入式系统控制核心的单片机具有其体积小、功能全、性价比高等诸多优点。51 系列单片机是国内目前应用最广泛的单片机之一,随着嵌入式系统、片上系统等概念的提出和普遍接受及应用,51 系列单片机的发展又进入了一个新的阶段。在今后很长一段时间内51 系列单片机仍将占据嵌入式系统产品的中低端市场。 ●汇编语言 汇编语言是一种面向机器的计算机低级编程语言,通常是为特定的计算机或系列计算机专门设计的。汇编语言保持了机器语言的优点,具有直接和简捷的特点,其代码具有效率高实时性强等优点。但是对于复杂的运算或大型程序,用汇编语言编写将非常耗时。汇编语言可以与高级语言配合使用,应用十分广泛。 ● ISP ISP(In-System Programming)在系统可编程, 是当今流行的单片机编程模式,指电路板上的空白元器 件可以编程写入最终用户代码,而不需要从电路板上取 下元器件。已经编程的器件也可以用ISP方式擦除或再 编程。本次课程设计便使用ISP方式,直接将编写好的 程序下载到连接好的单片机中进行调试。 选题 系统功能分析 硬件电路设计 整体流程设计 及模块划分 模块流程设计 模块编 码测试 系统合成调 试编译 下载调试(含硬件电路调试及软件烧写调试) 验收 完成总结报告课程设计流程图↑ 选题目的及设计思想简介: 课程设计是一次难得的对所学的知识进行实践的机会,我希望通过课程设计独立设计一个简单的系统从而达到强化课本知识并灵活运用的目的。电子数字钟是日常生活钟随处可见的简单系统。对电子数字钟的设计比较容易联系实际并进行拓展,在设计中我将力求尽可能跳出课本的样板,从现实生活中寻找设计原型和设计思路,争取有所突破。 如图所示便是我本次课程设计流程图,设计的整个过程运用自顶向下分析、自底向上实现的

51单片机实用汇编程序库(word)

51 单片机实用程序库 4.1 流水灯 程序介绍:利用P1 口通过一定延时轮流产生低电平 输出,以达到发光二极管轮流亮的效果。实际应用中例如:广告灯箱彩灯、霓虹灯闪烁。 程序实例(LAMP.ASM) ORG 0000H AJMP MAIN ORG 0030H MAIN: 9 MOV A,#00H MOV P1,A ;灭所有的灯 MOV A,#11111110B MAIN1: MOV P1,A ;开最左边的灯 ACALL DELAY ;延时 RL A ;将开的灯向右边移 AJMP MAIN ;循环 DELAY: MOV 30H,#0FFH D1: MOV 31H,#0FFH D2: DJNZ 31H,D2 DJNZ 30H,D1 RET END 4.2 方波输出 程序介绍:P1.0 口输出高电平,延时后再输出低电 平,循环输出产生方波。实际应用中例如:波形发生器。 程序实例(FAN.ASM): ORG 0000H MAIN: ;直接利用P1.0 口产生高低电平地形成方波////////////// ACALL DELAY SETB P1.0 ACALL DELAY 10 CLR P1.0 AJMP MAIN ;////////////////////////////////////////////////// DELAY: MOV R1,#0FFH DJNZ R1,$ RET

五、定时器功能实例 5.1 定时1 秒报警 程序介绍:定时器1 每隔1 秒钟将p1.o 的输出状态改变1 次,以达到定时报警的目的。实际应用例如:定时报警器。程序实例(DIN1.ASM): ORG 0000H AJMP MAIN ORG 000BH AJMP DIN0 ;定时器0 入口 MAIN: TFLA G EQU 34H ;时间秒标志,判是否到50 个 0.2 秒,即50*0.2=1 秒 MOV TMOD,#00000001B;定时器0 工作于方式 1 MOV TL0,#0AFH MOV TH0,#3CH ;设定时时间为0.05 秒,定时 20 次则一秒 11 SETB EA ;开总中断 SETB ET0 ;开定时器0 中断允许 SETB TR0 ;开定时0 运行 SETB P1.0 LOOP: AJMP LOOP DIN0: ;是否到一秒//////////////////////////////////////// INCC: INC TFLAG MOV A,TFLAG CJNE A,#20,RE MOV TFLAG,#00H CPL P1.0 ;////////////////////////////////////////////////// RE: MOV TL0,#0AFH MOV TH0,#3CH ;设定时时间为0.05 秒,定时 20 次则一秒 RETI END 5.2 频率输出公式 介绍:f=1/t s51 使用12M 晶振,一个周期是1 微秒使用定时器1 工作于方式0,最大值为65535,以产生200HZ 的频率为例: 200=1/t:推出t=0.005 秒,即5000 微秒,即一个高电

51单片机中的汇编语言与C语言.

51单片机中的汇编语言与 C 语言 C 语言, 更多的是为了掌握单片机的应用, C 语言是高效的应用程序开发工具, 与汇编语言比却不是开发高效应用程序的工具。就目前而言, 更多的是为了应用单片机, 开发应用程序, 更多的是强调开发效率, 而不是程序的运行效率 (相对而言。再就是应用程序对单片机内部资源的使用效率, 这在过去, 单片机内部资源紧缺的年代, 特别的强调, 现在已经不是特别重要了。所以, 大多数人都认为,只用 C 语言,就可以应对大多数单片机的应用开发了。 其实,汇编语言跟 C 语言在本质上一样的,只是语言形式不同而已,一个接近底层逻辑, 一个接近人类语言, 本质上都是对寄存器或存储器的读写操作而已。 汇编语言中,用 MOV 来回传送数据, C 语言里,用等号表示数据传送。汇编语言中,用 call 转去执行子过程程序, C 语言里,用个函数名调用子程序。汇编语言中,用 JMP 完成分支转移, C 语言里用 if 、 switch 、 while 、 for 来判断跳转。汇编语言跟 C 一样可以给寄存器指定命名,然后对定义的名称进行操作。汇编语言提供了对很多标志位的操作, C51根据需要也进行了改进, C 语言可以通过 #include给存储器命名来简化操作。 我觉得, C 语言是最接近汇编语言的一种高级语言, 要说不同, 也许具有大量函数的函数库,是 C 语言与汇编语言的最大区别,也是 C 语言比汇编语言有更大开发效率的原因。 在应用汇编语言进行应用程序开发时, 如果精心规划好程序结构, 设计好各种数据结构、子程序、中断程序,积累大量的算法程序(相当于函数库,也可以高效率的用汇编语言进行单片机开发。倒是兼容性、可移植性是汇编语言的最大限制,因为不同单片机有不同的指令系统,而 C 语言把这个问题,交给了机器也就是编译器去解决了。其实, 计算机的发展, 就是把尽可能多的事情交个机器去解决。

51单片机汇编语言教程:13课单片机逻辑与或异或指令详解

51单片机汇编语言教程:第13课-单片机逻辑与或异或指令详解

结果11111001 而所有的或指令,就是将与指仿中的ANL换成ORL,而异或指令则是将ANL换成XRL。即或指令: ORL A,Rn;A和Rn中的值按位'或',结果送入A中 ORL A,direct;A和与间址寻址单元@Ri中的值按位'或',结果送入A中 ORL A,#data;A和立direct中的值按位'或',结果送入A中 ORL A,@Ri;A和即数data按位'或',结果送入A中 ORL direct,A;direct中值和A中的值按位'或',结果送入direct中 ORL direct,#data;direct中的值和立即数data按位'或',结果送入direct中。 异或指令: XRL A,Rn;A和Rn中的值按位'异或',结果送入A中 XRL A,direct;A和direct中的值按位'异或',结果送入A中 XRL A,@Ri;A和间址寻址单元@Ri中的值按位'异或',结果送入A中 XRL A,#data;A和立即数data按位'异或',结果送入A中 XRL direct,A;direct中值和A中的值按位'异或',结果送入direct中 XRL direct,#data;direct中的值和立即数data按位'异或',结果送入direct中。 练习: MOV A,#24H MOV R0,#37H ORL A,R0 XRL A,#29H MOV35H,#10H ORL35H,#29H MOV R0,#35H ANL A,@R0 四、控制转移类指令 无条件转移类指令 短转移类指令 AJMP addr11 长转移类指令

单片机控制系统汇编程序

; step motor control ; ASM for MCS51 mode equ 082h contrl equ 08003h ctl equ 08000h ;8255接口芯片PA口的地址值 Astep equ 01h ;对A相通电,PA口的赋值 Bstep equ 02h ;对B相通电,PA口的赋值 Cstep equ 04h ;对C相通电,PA口的赋值 Dstep equ 08h ;对D相通电,PA口的赋值 dly_c equ 10h ;启动初值(加速度)寄存器 sd1 equ 80 ;0--255 加速度初值:值越小,加速越快 sd2 equ 40 ;

51单片机经典编辑流水灯汇编程序

单片机流水灯汇编程序设计 流水灯汇编程序 8只LED为共阳极连接,即单片机输出端为低电平时即可点亮LED。 ;用最直接的方式实现流水灯 ORG 0000H START:MOV P1,#01111111B ;最下面的LED点亮 LCALL DELAY ;延时1秒 MOV P1,#10111111B ;最下面第二个的LED点亮 LCALL DELAY ;延时1秒 MOV P1,#11011111B ;最下面第三个的LED点亮(以下省略) LCALL DELAY MOV P1,#11101111B LCALL DELAY MOV P1,#11110111B LCALL DELAY MOV P1,#11111011B LCALL DELAY MOV P1,#11111101B LCALL DELAY MOV P1,#11111110B LCALL DELAY MOV P1,#11111111B ;完成第一次循环点亮,延时约0.25秒 AJMP START ;反复循环 ;延时子程序,12M晶振延时约250毫秒 DELAY: ;大约值:2us*256*256*2=260ms,也可以认为为250ms PUSH PSW ;现场保护指令(有时可以不加) MOV R4,#2 L3: MOV R2 ,#00H L1: MOV R3 ,#00H L2: DJNZ R3 ,L2 ;最内层循环:(256次)2个周期指令(R3减一,如果比1大,则转向L2) DJNZ R2 ,L1 ; 中层循环:256次 DJNZ R4 ,L3 ;外层循环:2次 POP PSW RET END

51单片机汇编程序集(二) 2008年12月12日星期五 10:27 辛普生积分程序 内部RAM数据排序程序(升序) 外部RAM数据排序程序(升序) 外部RAM浮点数排序程序(升序) BCD小数转换为二进制小数(2位) BCD小数转换为二进制小数(N位) BCD整数转换为二进制整数(1位) BCD整数转换为二进制整数(2位) BCD整数转换为二进制整数(3位) BCD整数转换为二进制整数(N位) 二进制小数(2位)转换为十进制小数(分离BCD码) 二进制小数(M位)转换为十进制小数(分离BCD码) 二进制整数(2位)转换为十进制整数(分离BCD码) 二进制整数(2位)转换为十进制整数(组合BCD码) 二进制整数(3位)转换为十进制整数(分离BCD码) 二进制整数(3位)转换为十进制整数(组合BCD码) 二进制整数(M位)转换为十进制整数(组合BCD码) 三字节无符号除法程序(R2R3R4/R7)=(R2)R3R4 余数R7 ;二进制整数(2位)转换为十进制整数(分离BCD码) ;入口: R3,R4 ;占用资源: ACC,R2,NDIV31 ;堆栈需求: 5字节 ;出口: R0,NCNT IBTD21 : MOV NCNT,#00H MOV R2,#00H IBD211 : MOV R7,#0AH LCALL NDIV31 MOV A,R7 MOV @R0,A INC R0 INC NCNT MOV A,R3 ORL A,R4 JNZ IBD211 MOV A,R0 CLR C SUBB A,NCNT MOV R0,A RET ;二进制整数(2位)转换为十进制整数(组合BCD码) ;入口: R3,R4 ;占用资源: ACC,B,R7 ;堆栈需求: 3字节

51单片机C语言程序设计复习资料

2013-2014学年上期51单片机C语言程序设计重修复习提纲考试方式:闭卷考试。 考试题型: 填空题(每空1分,共18分);单项选择题(每空2分,共18分);问答及计算题(每题4分,共16分);编程及程序阅读题(5小题,共48分)。 考试分数: 卷面成绩70%+平时成绩15%+实验成绩15%,未缺席、无课堂违纪、作业全交且认真完成的同学平时成绩可获得满分,缺席一次平时成绩扣30分,实验好评次数3次以上且实验报告全优的同学实验成绩可得满分,实验缺席一次扣30分。缺席实验和旷课共3次以上者,无考试资格。 考试时间: 18周周一(12月30日)下午14:00:16:00,考试地点:具体考室另行通知希望大家认真复习,认真听讲,不懂就问,考试成绩不及格允许查卷,如查卷卷面批阅无误成绩不做更改。 编程题为实验或实验类似的题目有3题,其余2题也取自课堂讲授例题,请务必认真复习。第一章单片机概述及单片机知识回顾 掌握什么是单片机、单片机的应用、常见单片机类型、十进制、十六进制、二进制数制转换知识。掌握单片机的硬件组成、CPU的结构、程序计数器PC的功能、存储器结构、机器周期的计算、会画出单片机的最小系统电路图及回答单片机最小系统的组成。 第二章C51语言程序设计基础(本章填空题和选择题比重较大请务必认真复习)掌握C51语言进行软件开发与汇编语言相比的优点、掌握C51的数据类型、特殊功能位的定义、C51的基本运算(位运算重点复习)、数组的定义、C51的结构及函数。 第三章AT89S51片内并行端口及编程(本章有编程题) 掌握P0-P3并行端口的特点,会开关量检测及流水灯程序的编程。 第四章AT89S51单片机的中断系统(本章有编程题) 掌握中断系统的结构、中断请求响应被满足的条件、外部中断的触发选择方式、外部中断的使用与编程。 第五章AT89S51单片机的定时器/计数器(本章有编程器) 掌握定时器的结构,TOMD及TCON的使用,定时器方式0和方式1的特点、会计算定时器初值,会用定时器中断产生PWM波形,会用定时器对外部事件进行计数。 第六章AT89S51单片机的串行口(本章有计算题) 掌握串行通信的基础知识(课本没有的内容请参照课堂讲授笔记或PPT)、串行口的四种工作方式的特点、会计算奇偶校验码、会根据波特率计算T1的初值。 第七章AT89S51单片机与输入/输出外设接口(本章有编程题) 掌握数码管动态显示的原理、掌握矩阵式键盘的原理与编程(矩阵键盘编程必考,但不会考4X4键盘)。 第八章AT89S51单片机与D/A与A/D转换器的接口(本章有编程题) 掌握AD与DA转换的接口、ADC和DAC的技术指标、常用AD和DA转换器。掌握ADC0809和TLC2543的使用与编程(2器件其中之一有编程题)。 第九章AT89S51单片机应用系统与调试(本章有编程题) 掌握单片机应用系统的软件抗干扰方法。

51单片机汇编语言教程:28课音乐程序设计

51单片机汇编语言教程:第28课-音乐程序设计

下面给出程序序清单,可直接在TD-III型学习机上演奏,对其它不一样型号的学习机,只需对应地改变一下地址即可。本程序演奏的是民歌“八月桂花遍地开”,C调,节奏为94拍/分。读者也能自行找出一首歌,按表1和表2给定的常数,将乐曲翻译成码表输入机器,而程序不变。本实验办法简便,即使不懂音乐的人,将一首陌生的曲子翻译成代码也是易事,和着机器的演奏学唱一首歌曲,其趣味无穷。 程序清单(略,请参看源程序的说明)。 程序框图如图2所示。 <单片机音乐程序的设计图> 本课由单片机教程网提供,有问题指出. 硬件连接说明: 随便找一个仿真机或者什么单片机实验板,只要能工作的就行,将程序输入,运行,然后找个音箱(你计算机旁边应当就有一对吧)拨出插头,插头的前端接在P1。0上,后面部分找根线接单片机的地,就应当有声了,然后怎么改进硬件连接就是你的事了。。。。 音乐程序汇编代码代码1-------------Voice.asm--------------------------ORG0000H

LJMP START ORG000BH INC20H;中断服务,中断计数器加1 MOV TH0,#0D8H MOV TL0,#0EFH;12M晶振,形成10毫秒中断 RETI START: MOV SP,#50H MOV TH0,#0D8H MOV TL0,#0EFH MOV TMOD,#01H MOV IE,#82H MUSIC0: NOP MOV DPTR,#DAT;表头地址送DPTR MOV20H,#00H;中断计数器清0 MOV B,#00H;表序号清0 MUSIC1: NOP CLR A MOVC A,@A+DPTR;查表取代码 JZ END0;是00H,则结束 CJNE A,#0FFH,MUSIC5 LJMP MUSIC3 MUSIC5: NOP MOV R6,A INC DPTR MOV A,B MOVC A,@A+DPTR;取节拍代码送R7

单片机汇编语言经典一百例

51单片机实用程序库 4.1 流水灯 程序介绍:利用P1 口通过一定延时轮流产生低电平 输出,以达到发光二极管轮流亮的效果。实际应用中例如:广告灯箱彩灯、霓虹灯闪烁。 程序实例(LAMP.ASM) ORG 0000H AJMP MAIN ORG 0030H MAIN: 9 MOV A,#00H MOV P1,A ;灭所有的灯 MOV A,#11111110B MAIN1: MOV P1,A ;开最左边的灯 ACALL DELAY ;延时 RL A ;将开的灯向右边移 AJMP MAIN ;循环 DELAY:

MOV 30H,#0FFH D1: MOV 31H,#0FFH D2: DJNZ 31H,D2 DJNZ 30H,D1 RET END 4.2 方波输出 程序介绍:P1.0 口输出高电平,延时后再输出低电 平,循环输出产生方波。实际应用中例如:波形发生器。 程序实例(FAN.ASM): ORG 0000H MAIN: ;直接利用P1.0口产生高低电平地形成方波////////////// ACALL DELAY SETB P1.0 ACALL DELAY 10 CLR P1.0 AJMP MAIN ;////////////////////////////////////////////////// DELAY: MOV R1,#0FFH

DJNZ R1,$ RET END 五、定时器功能实例 5.1 定时1秒报警 程序介绍:定时器1每隔1秒钟将p1.o的输出状态改变1 次,以达到定时报警的目的。实际应用例如:定时报警器。程序实例(DIN1.ASM): ORG 0000H AJMP MAIN ORG 000BH AJMP DIN0 ;定时器0入口 MAIN: TFLA G EQU 34H ;时间秒标志,判是否到50个 0.2秒,即50*0.2=1秒 MOV TMOD,#00000001B;定时器0工作于方式 1 MOV TL0,#0AFH MOV TH0,#3CH ;设定时时间为0.05秒,定时 20次则一秒 11 SETB EA ;开总中断

快速入门单片机大全语言

快速入门单片机汇编语言 简要: 单片机有通用型和专用型之分。专用型是厂家为固定程序的执行专门开发研制的一种单片机,其程序不可更改。通用型单片机是常用的一种供学习或自主编制程序的单片机,其程序需要自己写入,可更改。单片机根据其基本操作处理位数不同可以分为:1位、4位、8位、16、32位单片机。 正文: 在此我们主要讲解美国ATMEL公司的89C51单片机。 一、89C51单片机PDIP(双列直插式)封装引脚图: 其引脚功能如下: P0口(—):为双向三态口,可以作为输入/输出口。但在实际应用中通常作为地址/数据总线口,即为低8位地址/数据总线分时复用。低8位地址在ALE信号的负跳变锁存到外部地址锁存器中,而高8位地址由P2口输出。 P1口(—):其每一位都能作为可编程的输入或输出线。 P2口(—):每一位也都可作为输入或输出线用,当扩展系统外设时,可作为扩展系统的地址总线高8位,与P0口一起组成16位地址总线。对89c51单片机来说,P2口一般只作为地址总线使用,而不作为I/O线直接与外设相连。 P3口(—):其为双功能口,作为第一功能使用时,其功能与P1口相同。当作为第二功能使用时,每一位功能如下表所示。 XTAL1(xtal2):外接晶振一脚,分别接晶振的一端。 Gnd:电源地。 Vcc:电源正级,接+5V。 PROG\ALE:地址锁存控制端 PSEN:片外程序存储器读选通信号输出端,低电平有效。 EA\vpp:访问外部程序储存器控制信号,低电平有效。当EA为高电平时访问片内存储器,若超出范围则自动访问外部程序存储器。当EA为低电平时只访问外部程序存储器。 二、常用指令及其格式介绍: 1、指令格式:

51单片机C语言入门教程详细解说

单片机c语言入门 相信很多爱好电子的朋友,对单片机这个词应该都不会陌生了吧。不过有些朋友可能只听说他叫单片机,他的全称是什么也许并不太清楚, 更不用说他的英文全称和简称了。单片机是一块在集成电路芯片上集成了一台有一定规模的微型计算机。简称为:单片微型计算机或单片机 (Single Chip Computer)。单片机的应用到处可见,应用领域广泛,主要应用在智能仪表、实时控制、通信、家电等方面。不过这一切都没 什么关系,因为我(当然也包括任何人)都是从不知道转变成知道的,再转变成精通的。现在我只想把我学习单片机的经历,详细地讲叙给大 家听听,可能有些大虾会笑话我,想:那么简单的东西还在这里卖弄。但是你错了,我只是把我个人学习的经历讲述一遍而已,仅仅对那些想 学习单片机,但又找不到好方法或者途径的朋友,提供一个帮助,使他们在学习过程中,尽量少走些弯路而已! 首先,你必须有学习单片机的热情,不是说今天去图书馆看了一个下午关于单片机的书,而明天玩上半天,后天就不知道那个本书在讲什 么东西了。还是先说说我吧,我从大二的第一个学期期末的时候才开始接触单片机,但在这之前,正如上面所说的:我知道有种芯片叫单片机, 但是具体长成什么样子,却一点也不知道!看到这里很多朋友一定会忍不住发笑。嘿嘿,你可千万别笑,有些大四毕业的人也同样不知道单片 机长成什么样子呢!而我对单片机的痴迷更是常人所不能想象的地步,大二的期末考试,我全放弃了复习,每当室友拿着书在埋头复习的时候, 我却捧着自己从图书馆借的单片机书在那看,虽然有很多不懂,但是我还是坚持了下来,当时我就想过,为了单片机值不值得我这样去付出, 或许这也是在一些三流学校的好处吧,考试挂科后,明年开学交上几十元一门的补考费,应该大部分都能过了。于是,我横下一条心,坚持看 我的单片机书和资料。 当你明白了单片机是这么一回事的时候,显而易见的问题出来了:我要选择那种语言为单片机编写程序呢?这个问题,困扰了我好久。具 体选择C51还是A51呢?汇编在我们大二之前并没有开过课,虽然看着人家的讲解,很容易明白单片机的每一时刻的具体工作情况,但是一合上 书或者资料,自己却什么也不知道了,根本不用说自己写程序了。于是,我最终还是决定学C51,毕竟C51和我们课上讲的C语言,有些类似, 编程的思想可以说是相通的。而且C51还有更大的优点就是编写大程序时的优越性更不言而喻,当然在那时,我并没有想的那么深远,C51的特 点,还是在后来的实践过程中,渐渐体会到的!朋友如果你选择了C51,那么请继续往下看,如果你选择了A51,那么你可以不要看了!因为下面讲 的全是C方面的,完全在浪费你的时间! 呵呵^_^ 第二,既然你想学好单片机,你必须得舍得花钱,如果不买些芯片回来自己动手焊焊拆拆的(但是在后期会介绍给大家一个很好用的硬件 仿真软件,并不需要你用实验板和仿真器了,直接在你的PC上完成,但是软件毕竟是软件,从某个特定的意义上来说是并不能代替硬件的),即使

51单片机汇编语言教程

51单片机汇编语言教程:1课:单片机简叙 1、什么是单片机一台能够工作的计算机要有这样几个部份构成:CPU(进行运算、控制)、RAM(数据存储)、ROM(程序存储)、输入/输出设备(例如:串行口、并行输出口等)。在个人计算机上这些部份被分成若干块芯片,安装一个称之为主板的印刷线路板上。而在单片机中,这些部份,全部被做到一块集成电路芯片中了,所以就称为单片(单芯片)机,而且有一些单片机中除了上述部份外,还集成了其它部份如A/D,D/A等。 单片机是一种控制芯片,一个微型的计算机,而加上晶振,存储器,地址锁存器,逻辑门,七段译码器(显示器),按钮(类似键盘),扩展芯片,接口等那是单片机系统。 天!PC中的CPU一块就要卖几千块钱,这么多东西做在一起,还不得买个天价!再说这块芯片也得非常大了。 不,价格并不高,从几元人民币到几十元人民币,体积也不大,一般用40脚封装,当然功能多一些单片机也有引脚比较多的,如68引脚,功能少的只有10多个或20多个引脚,有的甚至只8只引脚。 为什么会这样呢? 功能有强弱,打个比方,市场上面有的组合音响一套才卖几百块钱,可是有的一台功放机就要卖好几千。另外这种芯片的生产量很大,技术也很成熟,51系列的单片机已经做了十几年,所以价格就低了。 既然如此,单片机的功能肯定不强,干吗要学它呢? 话不能这样说,实际工作中并不是任何需要计算机的场合都要求计算机有很高的性能,一个控制电冰箱温度的计算机难道要用PIII?应用的关键是看是否够用,是否有很好的性能价格比。所以8051出来十多年,依然没有被淘汰,还在不断的发展中。 2、MCS51单片机和8051、8031、89C51等的关系 更多单片机学习资料请来https://www.wendangku.net/doc/302939263.html, 我们平常老是讲8051,又有什么8031,现在又有89C51,89s51它们之间究竟是什么关系? MCS51是指由美国INTEL公司(对了,就是大名鼎鼎的INTEL)生产的一系列单片机的总称,这一系列单片机包括了好些品种,如8031,8051,8751,8032,8052,8752等,其中8051是最早最典型的产品,该系列其它单片机都是在8051的基础上进行功能的增、减、改变而来的,所以人们习惯于用8051来称呼MCS51系列单片机,而8031是前些年在我国最流行的单片机,所以很多场合会看到8031的名称。INTEL公司将MCS51的核心技术授权给了很多其它公司,所以有很多公

51单片机及C语言入门教程

51单片机 及C语言入门教程 注:排成16开版式,是为了方便自已打印阅读。请不要用于非法用途。 2007.12.20

51单片机及C语言入门教程 第一课 建立您的第一个C项目 使用C语言肯定要使用到C编译器,以便把写好的C程序编译为机器码,这样单片机才能执行编写好的程序。KEIL uVISION2是众多单片机应用开发软件中优秀的软件之一,它支持众多不同公司的MCS51架构的芯片,它集编辑,编译,仿真等于一体,同时还支持,PLM,汇编和C语言的程序设计,它的界面和常用的微软VC++的界面相似,界面友好,易学易用,在调试程序,软件仿真方面也有很强大的功能。因此很多开发51应用的工程师或普通的单片机爱好者,都对它十分喜欢。 以上简单介绍了KEIL51软件,要使用KEIL51软件,必需先要安装它。KEIL51是一个商业的软件,对于我们这些普通爱好者可以到KEIL中国代理周立功公司的网站上下载一份能编译2K的DEMO版软件,基本可以满足一般的个人学习和小型应用的开发。(安装的方法和普通软件相当这里就不做介绍了) 安装好后,你是不是迫不及待的想建立自己的第一个C程序项目呢?下面就让我们一起来建立一个小程序项目吧。或许你手中还没有一块实验板,甚至没有一块单片机,不过没有关系我们可以通过KEIL软件仿真看到程序运行的结果。 首先当然是运行KEIL51软件。怎么打开?噢,天!那你要从头学电脑了。呵呵,开个玩笑,这个问题我想读者们也不会提的了:P。运行几秒后,出现如图1-1的屏幕。 图1-1启动时的屏幕

接着按下面的步骤建立您的第一个项目: (1)点击Project菜单,选择弹出的下拉式菜单中的New Project,如图1-2。接着弹出一个标准Windows文件对话窗口,如图1-3,这个东东想必大家是见了N次的了,用法技巧也不是这里要说的,以后的章节中出现类似情况将不再说明。在"文件名"中输入您的第一个C程序项目名称,这里我们用"test",这是笔者惯用的名称,大家不必照搬就是了,只要符合Windows文件规则的文件名都行。"保存"后的文件扩展名为uv2,这是KEIL uVision2项目文件扩展名,以后我们可以直接点击此文件以打开先前做的项目。 图1-2New Project菜单 图1-3文件窗口 (2)选择所要的单片机,这里我们选择常用的Ateml公司的AT89C51。此时屏幕如图1-4

51单片机串行口汇编语言教程

51单片机汇编语言教程:22课:单片机串行口通信程序设计 1.串行口方式0应用编程8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。 <单片机串行口通信程序设计硬件连接图> 例:用8051单片机串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。串行口方式0的数据传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TI或RI标志。串行发送时,能靠TI置位(发完一帧数据后)引起中断申请,在中断服务程序中发送下一帧数据,或者通过查询TI的状态,只要TI为0就继续查询,TI为1就结束查询,发送下一帧数据。在串行接收时,则由RI引起中断或对RI查询来确定何时接收下一帧数据。无论采用什么方式,在开始通信之前,都要先对控制寄存器SCON进行初始化。在方式0中将,将00H送SCON 就能了。 -----------------单片机串行口通信程序设计列子-------------------------- ORG 2000H START: MOV SCON,#00H ;置串行口工作方式0 MOV A,#80H ;最高位灯先亮 CLR P1.0 ;关闭并行输出(避象传输过程中,各LED的"暗红"现象) OUT0: MOV SBUF,A ;开始串行输出 OUT1: JNB TI,OUT1 ;输出完否 CLR TI ;完了,清TI标志,以备下次发送 SETB P1.0 ;打开并行口输出 ACALL DELAY ;延时一段时间 RR A ;循环右移 CLR P1.0 ;关闭并行输出 JMP OUT0 ;循环 说明:DELAY延时子程序能用前面我们讲P1口流水灯时用的延时子程序,这里就不给出

51单片机汇编语言教程:4课第一个单片机小程序

51单片机汇编语言教程:第4课-第一个单片机小程序 (基于HJ-1G、HJ-3G实验板) 上一次我们的程序实在是没什么用,要灯亮还要重写一下片子,下面我们要让灯持续地闪烁,这就有一定的实用价值了,比如能把它当成汽车上的一个信号灯用了。怎样才能让灯持续地闪烁呢?实际上就是要灯亮一段时间,再灭一段时间,也就是说要P10持续地输出高和低电平。怎样实现这个要求呢?请考虑用下面的指令是否可行: SETB P10 CLR P10…… 这是不行的,有两个问题,第一,计算机执行指令的时间很快,执行完SETB P10后,灯是灭了,但在极短时间(微秒级)后,计算机又执行了CLR P10指令,灯又亮了,所以根本分辨不出灯曾灭过。第二,在执行完CLR P10后,不会再去执行SETB P10指令,所以以后再也没有机会让灭了。 为了解决这两个问题,我们能做如下设想,第一,在执行完SETB P10后,延时一段时间(几秒或零点几秒)再执行第二条指令,就能分辨出灯曾灭过了。第二在执行完第二条指令后,让计算机再去执行第一条指令,持续地在原地兜圈,我们称之为循环,这样就能完成任务了。 以下先给出程序(后面括号中的数字是为了便于讲解而写的,实际不用输入): ;主程序: LOOP:SETB P10;(1) LCALL DELAY;(2) CLR P10;(3) LCALL DELAY;(4) AJMP LOOP;(5) ;以下子程序 DELAY:MOV R7,#250;(6) D1:MOV R6,#250;(7) D2:DJNZ R6,D2;(8) DJNZ R7,D1;(9) RET;(10) END;(11) 按上面的设想分析一下前面的五条指令。 第一条是让灯灭,第二条应当是延时,第三条是让灯亮,第四条和第二条一模一样,也是延时,第五条应当是转去执行第一条指令。第二和第四条实现的原理稍后谈,先看第五条,LJMP是一条指令,意思是转移,往什么地方转移呢?后面跟的是LOOP,看一下,什么地方还有LOOP,对了,在第一条指令的前面有一个LOOP,所以很直观地,我们能认识到,它要转到第一条指令处。这个第一条指令前面的LOOP被称之为标号,它的用途就是给这一行起一个名字,便于使用。是否一定要给它起名叫LOOP呢?当然不是,起什么名字,完全由编程序的人决定,能称它为A,X等等,当然,这个时候,第五条指令LJMP后面的名字也得跟着改了。 第二条和第四条指令的用途是延时,它是怎样实现的呢?指令的形式是LCALL,这条指令称为调用子程序指令,看一下指令后面跟的是什么,DELAY,找一下DELAY,在第六条指令的前面,显然,这也是一个标号。这条指令的作用是这样的:当执行LCALL指令时,程序就转到LCALL后面的标号所标定的程序处执行,如果在执行指令的过程中遇到RET指令,则

51单片机声控智能小车C语言程序设计代码

51单片机声控智能小车C语言程序设计代码 #include #define uint unsigned int #define uchar unsigned char unsigned char code LEDShowData[]={0x9F,0x25,0x0D,0x99,0x49,0x41,0x1F,0x01,0x19,0x03}; sbit LED=P0^7; sbit m1a=P0^0; sbit m1b=P0^1; sbit m2a=P0^2; sbit m2b=P0^3; sbit B1=P0^4; uint m,n,x,y,z; void delayB1() { unsigned int delaytime=500; while(delaytime--); return; } void delayLED(uint ms) { uint a,b; for(a=0;a

TR0=1;//启动T0定时器 TR1=0;//关闭T1定时器 m1a=1; m2a=1; } void timer2(void) interrupt 5 { TF2=0;//软件对T2标志位清零 n++; if(n==250)//n控制查询周期时间 { n=0; switch(m) { case 1://低速挡,占空比77.8% { P2=LEDShowData[0];//七段数码管显示1 TH0=210; TL0=210;//对T0定时器赋初值 TH1=240; TL1=240;//对T1定时器赋初值 x=m; m=0; z=0; ET0=1; ET1=1; TR0=1;//启动T0定时器 break;//跳出switch } case 2://高速挡,占空比99.6% { P2=LEDShowData[1];//七段数码管显示2 TH0=1; TL0=1; //对T0定时器赋初值 TH1=255; TL1=255; //对T1定时器赋初值 x=m+1; m=0; z=0; ET0=1; ET1=1; TR0=1; //启动T0定时器 break;//跳出switch }

相关文档
相关文档 最新文档