历史上的今天
返回首页

历史上的今天

今天是:2025年05月26日(星期一)

正在发生

2021年05月26日 | 认识C语言----适合初学C语言的朋友

2021-05-26 来源:eefocus

学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好。Keil软件是目前最流行开发80C51系列单片机的软件,Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(µVision)将这些部份组合在一起。


学习之前请先安装KEILC51软件,本站提供下载请到推荐栏里下载。。。


在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的实例介绍C语言编程的方法。图1-1所示电路图使用89c51单片机作为主芯片,这种单片机性属于80C51系列,其内部有8K的FLASH ROM,可以反复擦写,非常适于做实验。89c51的P1引脚上接8个发光二极管,P3.2~P3.4引脚上接4个按钮开关,我们的任务是让接在P1引脚上的发光二极管按要求发光。

1.1简单的C程序介绍

例1-1: 让接在P1.0引脚上的LED发光。

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


单灯闪烁程序


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

#include “reg51.h”//这一句是将51的常用端口,内部寄存器等的定义文件包含进这段程序

sbit P1_0=P1^0;

void main()

{ P1_1=0;

}

这个程序的作用是让接在P1.0引脚上的LED点亮。下面来分析一下这个C语言程序包含了哪些信息。

1)“文件包含”处理。

程序的第一行是一个“文件包含”处理。

所谓“文件包含”是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序虽然只有4行,但C编译器在处理的时候却要处理几十或几百行。这里程序中包含REG51.h文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量。这是如何做到的呢?

打开reg51.h可以看到这样的一些内容:

/*--------------------------------------------------------------------REG51.H


Header file for generic 80C51 and 80C31 microcontroller.


Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc.


All rights reserved.


--------------------------------------------------------------------------*/


/* BYTE Register */


sfr P0 = 0x80;


sfr P1 = 0x90;


sfr P2 = 0xA0;


sfr P3 = 0xB0;


sfr PSW = 0xD0;


sfr ACC = 0xE0;


sfr B = 0xF0;


sfr SP = 0x81;


sfr DPL = 0x82;


sfr DPH = 0x83;


sfr PCON = 0x87;


sfr TCON = 0x88;


sfr TMOD = 0x89;


sfr TL0 = 0x8A;


sfr TL1 = 0x8B;


sfr TH0 = 0x8C;


sfr TH1 = 0x8D;


sfr IE = 0xA8;


sfr IP = 0xB8;


sfr SCON = 0x98;


sfr SBUF = 0x99;


/* BIT Register */


/* PSW */


sbit CY = 0xD7;


sbit AC = 0xD6;


sbit F0 = 0xD5;


sbit RS1 = 0xD4;


sbit RS0 = 0xD3;


sbit OV = 0xD2;


sbit P = 0xD0;




/* TCON */


sbit TF1 = 0x8F;


sbit TR1 = 0x8E;


sbit TF0 = 0x8D;


sbit TR0 = 0x8C;


sbit IE1 = 0x8B;


sbit IT1 = 0x8A;


sbit IE0 = 0x89;


sbit IT0 = 0x88;




/* IE */


sbit EA = 0xAF;


sbit ES = 0xAC;


sbit ET1 = 0xAB;


sbit EX1 = 0xAA;


sbit ET0 = 0xA9;


sbit EX0 = 0xA8;




/* IP */


sbit PS = 0xBC;


sbit PT1 = 0xBB;


sbit PX1 = 0xBA;


sbit PT0 = 0xB9;


sbit PX0 = 0xB8;




/* P3 */


sbit RD = 0xB7;


sbit WR = 0xB6;


sbit T1 = 0xB5;


sbit T0 = 0xB4;


sbit INT1 = 0xB3;


sbit INT0 = 0xB2;


sbit TXD = 0xB1;


sbit RXD = 0xB0;




/* SCON */


sbit SM0 = 0x9F;


sbit SM1 = 0x9E;


sbit SM2 = 0x9D;


sbit REN = 0x9C;


sbit TB8 = 0x9B;


sbit RB8 = 0x9A;


sbit TI = 0x99;


sbit RI = 0x98;


熟悉80C51内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地址的对应关系。注意其中有


sfr P1 = 0x90;


这样的一行(上文中用黑体表示),即定义P1与地址0x90对应,P1口的地址就是0x90(0x90是C语言中十六进制数的写法,相当于汇编语言中写90H)。


从这里还可以看到一个频繁出现的词:sfr


sfr并标准C语言的关键字,而是Keil为能直接访问80C51中的SFR而提供了一个新的关键词,其用法是:


sfrt 变量名=地址值。


2)符号P1_0来表示P1.0引脚。


在C语言里,如果直接写P1.0,C编译器并不能识别,而且P1.0也不是一个合法的C语言变量名,所以得给它另起一个名字,这里起的名为P1_0,可是P1_0是不是就是P1.0呢?你这么认为,C编译器可不这么认为,所以必须给它们建立联系,这里使用了Keil C的关键字sbit来定义,sbit的用法有三种:


第一种方法:sbit 位变量名=地址值


第二种方法:sbit 位变量名=SFR名称^变量位地址值


第三种方法:sbit 位变量名=SFR地址值^变量位地址值


如定义PSW中的OV可以用以下三种方法:


sbit OV=0xd2 (1)说明:0xd2是OV的位地址值


sbit OV=PSW^2 (2)说明:其中PSW必须先用sfr定义好


sbit OV=0xD0^2 (3)说明:0xD0就是PSW的地址值


因此这里用sfr P1_0=P1^0;就是定义用符号P1_0来表示P1.0引脚,如果你愿意也可以起P10一类的名字,只要下面程序中也随之更改就行了。


3)main称为“主函数”。


每一个C语言程序有且只有一个主函数,切必须有一个主函数,其放置的位置不要求,可以放在程序最后(推荐),函数后面一定有一对大括号“{}”,在大括号里面书写其它程序。


从上面的分析我们了解了部分C语言的特性,下面再看一个稍复杂一点的例子。


例1-2 让接在P1.0引脚上的LED闪烁发光


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



单灯闪烁程序


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


#include "reg51.h"


#define uchar unsigned char


#define uint unsigned int


sbit P10=P1^0;




/*延时程序


由Delay参数确定延迟时间


*/


void mDelay(unsigned int Delay)


{ unsigned int i;


for(;Delay>0;Delay--)


{ for(i=0;i<124;i++)


{;}


}


}




void main()


{ for(;;)


{ P10=!P10; //取反P1.0引脚


mDelay(1000);


}


}


程序分析:主程序main中的第一行暂且不看,第二行是“P1_0=!P1_0;”,在P1_0前有一个符号“!”,符号“!”是C语言的一个运算符,就像数学中的“+”、“-”一样,是一种运算任号,意义是“取反”,即将该符号后面的那个变量的值取反。


注意:取反运算只是对变量的值而言的,并不会自动改变变量本身。可以认为C编译器在处理“!P1_0”时,将P1_0的值给了一个临时变量,然后对这个临时变量取反,而不是直接对P1_0取反,因此取反完毕后还要使用赋值符号(“=”)将取反后的值再赋给P1_0,这样,如果原来P1.0是低电平(LED亮),那么取反后,P1.0就是高电平(LED灭),反之,如果P1.0是高电平,取反后,P1.0就是低电平,这条指令被反复地执行,接在P1.0上灯就会不断“亮”、“灭”。


该条指令会被反复执行的关键就在于main中的第一行程序:for(;;),这里不对此作详细的介绍,读者暂时只要知道,这行程序连同其后的一对大括号“{}”构成了一个无限循环语句,该大括号内的语句会被反复执行。


第三行程序是:“mDelay(1000);”,这行程序的用途是延时1s时间,由于单片机执行指令的速度很快,如果不进行延时,灯亮之后马上就灭,灭了之后马上就亮,速度太快,人眼根本无法分辨。


这里mDelay(1000)并不是由Keil C提供的库函数,即你不能在任何情况下写这样一行程序以实现延时。如果在编写其它程序时写上这么一行,会发现编译通不过。那么这里为什么又是正确的呢?注意观察,可以发现这个程序中有void mDelay(…)这样一行,可见,mDelay这个词是我们自己起的名字,并且为此编写了一些程序行,如果你的程序中没有这么一段程序行,那就不能使用mDelay(1000)了。有人脑子快,可能马上想到,我可不可以把这段程序也复制到我其它程序中,然后就可以用mDelay(1000)了呢?回答是,那当然就可以了。还有一点需要说明,mDelay这个名称是由编程者自己命名的,可自行更改,但一旦更改了名称,main()函数中的名字也要作相应的更改。


mDelay后面有一个小括号,小括号里有数据(1000),这个1000被称之“参数”,用它可以在一定范围内调整延时时间的长短,这里用1000来要求延时时间为1000毫秒,要做到这一点,必须由我们自己编写的mDelay那段程序决定的,详细情况在后面循环程序中再作分析,这里就不介绍了。

推荐阅读

史海拾趣

HiRel Connectors Inc公司的发展小趣事
在POE供电方式下,供电和通讯共用网线,供电故障可能导致通讯中断。
Axon' Cable公司的发展小趣事

为了进一步扩大市场份额和提升竞争力,Axon' Cable公司开始实施全球化战略。公司在全球范围内设立了多个生产基地和研发中心,积极开拓国际市场。同时,Axon' Cable还加强了与国际知名企业的合作,共同推动技术创新和产业升级。这些举措使得Axon' Cable的产品在全球范围内得到了广泛应用,公司的国际影响力也逐步提升。

ANADIGICS公司的发展小趣事

为了进一步扩大市场份额和提升竞争力,Axon' Cable公司开始实施全球化战略。公司在全球范围内设立了多个生产基地和研发中心,积极开拓国际市场。同时,Axon' Cable还加强了与国际知名企业的合作,共同推动技术创新和产业升级。这些举措使得Axon' Cable的产品在全球范围内得到了广泛应用,公司的国际影响力也逐步提升。

Alpha Semiconductor公司的发展小趣事

经过多年的发展,Alpha Semiconductor已经成为一家高性能标准、半标准模拟和混合信号IC制造商。公司在这一领域的制造实力得到了业界的广泛认可。Alpha Semiconductor的产品广泛应用于通信、计算机、消费电子等领域,为电子行业的发展做出了重要贡献。

EETools公司的发展小趣事

面对快速变化的市场环境和不断涌现的新技术,EETools始终保持开放和创新的姿态。公司不仅持续关注行业动态和技术趋势,还积极探索新的业务领域和增长点。例如,EETools正在研发基于人工智能和物联网技术的嵌入式开发工具,以满足未来市场的需求。同时,公司还计划进一步拓展海外市场,提升品牌在国际市场的竞争力。这些举措将为EETools的未来发展奠定坚实的基础。

Cardinal Components公司的发展小趣事

2016年,Taitien收购了Cardinal Components,这一收购为公司带来了新的发展机遇和资源支持。随后,在2021年,Cardinal加入了Pletronics,进一步扩大了其在电子行业的影响力。这些收购与合作不仅为公司带来了更多的业务机会,也促进了其在技术研发和市场拓展方面的进步。

这五个故事只是Cardinal Components在电子行业发展中的一部分缩影。作为一家具有深厚历史底蕴和强大技术实力的公司,Cardinal将继续在电子行业中发挥重要作用,为行业的进步和发展做出更多贡献。

问答坊 | AI 解惑

FPGA设计流程简介及设计注意事项

    欢迎大家加入 FPGA技术群:63296979…

查看全部问答>

麻醉安全度智能监护仪研制成功

从重庆市信息产业局获悉,一项用于提高临床麻醉监护安全性的麻醉安全度智能监护仪日前在重庆工学院研制成功,这一成果有望提高外科手术中使用麻醉手段的安全程度。 麻醉是众多外科手术中必须的条件和前提,在全身麻醉手术中,病人在手术中发生知 ...…

查看全部问答>

单片机第六课:单片机的内外部结构分析(四)

上两次我们做过两个实验,都是让P1.0这个引脚使灯亮,我们可以设想:既然P1.0可以让灯亮,那么其它的引脚可不可以呢?看一下图1,它是8031单片机引脚的说明,在P1.0旁边有P1.1,P1.2….P1.7,它们是否都可以让灯亮呢?除了以P1开头的外,还有以P0, ...…

查看全部问答>

一个CCeCommandBar的问题

框架结构中,使用m_wndCommandBar.Create(this)创建命令栏,但不添加Menu,ToolBar,以及关闭按钮等,这样命令栏就显示不出来,请教高人如何才能得到一个空白命令栏呢?…

查看全部问答>

wince 5.0下的串口驱动是如何实现的?

如题: 本人接触的是XScale 270的平台,但是当我把整个串口驱动读完之后,切没有发现串口是否是使用中断来实现的? 为什么在代码里面看不到呢?急!!!!!!!…

查看全部问答>

ARM面试问题

面试官说ARM上调试程序时,如果知道了指令的16进制地址,就可以计算出对应的C源代码的地址,前提是在编译时需要使用一个命令行参数,问具体怎么做? 我说用-g参数结合debugger来做。可是面试官说我没有做过arm开发,他说做过arm开发的人应该知道怎 ...…

查看全部问答>

wince上ucp通信问题

请问各位大哥,pda能通过无线网络与pc之间进行udp通信吗?我用evc写的一个udp通信的程序,在pda上自己给自己发是可以收到的,但是给pc机发送时pc机收不到,pc机上的udp接收程序是用CB写的,不知道是不是我的程序有问题?望各位大虾指点一下,谢谢了!…

查看全部问答>

液晶和430接口问题

有没有哪位高手碰到16位的430单片机和8位液晶显示器连接,编程时时序不匹配的问题?是不是每次单片机输出到口线后给个延时,让液晶有足够的时间写入数据就够了?…

查看全部问答>

开发板申请

学习入门,降低功耗…

查看全部问答>