曾经在BBS上有朋友问过我{}是什么意思?什么作用?在C中是有不少的括号,如{},[],()等,确实会让一些初入门的朋友不解。在VB等一些语言中同一个()号会有不同的作用,它可以用于组合若干条语句形成功能块,可以用做数组的下标等,而在C中括号的分工较为明显,{}号是用于将若干条语句组合在一起形成一种功能块,这种由若干条语句组合而成的语句就叫复合语句。复合语句之间用{}分隔,而它内部的各条语句还是需要以分号";"结束。复合语句是允许嵌套的,也是就是在{}中的{}也是复合语句。复合语句在程序运行时,{}中的各行单语句是依次顺序执行的。以C语言中可以将复合语句视为一条单语句,也就是说在语法上等同于一条单语句。对于一个函数而言,函数体就是一个复合语句,也许大家会因此知道复合语句中不单可以用可执行语句组成,还可以用变量定义语句组成。要注意的是在复合语句中所定义的变量,称为局部变量,所谓局部变量就是指它的有效范围只在复合语句中,而函数也算是复合语句,所以函数内定义的变量有效范围也只在函数内部。关于局部变量和全局变量的具体用法会在说到函数时具体说明。下面用一段简单的例子简单说明复合语句和局部变量的使用。

#include

#include

void main(void)

{

unsigned int a,b,c,d; //这个定义会在整个main函数中?

SCON = 0x50; //串口方式1,允许接收

TMOD = 0x20; //定时器1定时方式2

TH1 = 0xE8; //11.0592MHz1200波特率

TL1 = 0xE8;

TI = 1;

TR1 = 1; //启动定时器

a = 5;

b = 6;

c = 7;

d = 8; //这会在整个函数有效

printf("0: %d,%d,%d,%dn",a,b,c,d);

{ //复合语句1

unsigned int a,e; //只在复合语句1中有效

a = 10,e = 100;

printf("1: %d,%d,%d,%d,%dn",a,b,c,d,e);

{ //复合语句2

unsigned int b,f; //只在复合语句2中有效

b = 11,f = 200;

printf("2: %d,%d,%d,%d,%d,%dn",a,b,c,d,e,f);

}//复合语句2结束

printf("1: %d,%d,%d,%d,%dn",a,b,c,d,e);

}//复合语句1结束

printf("0: %d,%d,%d,%dn",a,b,c,d);

while(1);

}

运行结果:

0:5,6,7,8

1: 10,6,7,8,100

2: 10,11,7,8,100,200

1: 10,6,7,8,100

0:5,6,7,8

结合以上的说明想想为何结果会是这样。

看到题目后相信大家都会大概对条件语句这个概念有所认识。是的,就如学习语文中的条件语句一样,C语言也一样是"如果XX就XX"或是"如果XX就XX否则XX"。也就是当条件符合时就执行语句。条件语句又被称为分支语句,其关键字是由if构成。C语言提供了3种形式的条件语句:

1: if (条件表达式) 语句

当条件表达式的结果为真时,就执行语句,否则就跳过。

如 if (a==b) a++; 当a等于b时,a就加1

2: if (条件表达式) 语句1

else 语句2

当条件表达式成立时,就执行语句1,否则就执行语句2

如 if (a==b)

a++;

else

a--;

当a等于b时,a加1,否则a-1。

3:if (条件表达式1) 语句1

else if (条件表达式2) 语句2

else if (条件表达式3) 语句3

else if (条件表达式m) 语句n

else 语句m

这是由if else语句组成的嵌套,用来实现多方向条件分支,使用时因注意if和else的配对使用,要是少了一个就会语法出错,记住else总是与最临近的if相配对。

我们学习了条件语句,用多个条件语句可以实现多方向条件分支,但是可以发现使用过多的条件语句实现多方向分支会使条件语句嵌套过多,程序冗长,这样读起来也很不好读。这时使用开关语句同样可以达到处理多分支选择的目的,又可以使程序结构清晰。它的语法为下:

switch (表达式)

{

case 常量表达式1: 语句1; break;

case 常量表达式2: 语句2; break;

case 常量表达式3: 语句3; break;

case 常量表达式n: 语句n; break;

default: 语句

}

运行中switch后面的表达式的值将会做为条件,与case后面的各个常量表达式的值相对比,如果相等时则执行后面的语句,再执行break(间断语句)语句,跳出switch语句。如果case没有和条件相等的值时就执行default后的语句。当要求没有符合的条件时不做任何处理,则可以不写default语句。

在上面的课程中我们一直在用printf这个标准的C输出函数做字符的输出,使用它当然会很方便,但它的功能强大,所占用的存储空间自然也很大,要1K左右字节空间,如果再加上sCANf输入函数就要达到2K左右的字节,这样的话如果要求用2K存储空间的芯片时就无法再使用这两个函数,例如AT89C2051。在这些小项目中,通常我们只是要求简单的字符输入输出,这里以笔者发表在《无线电杂志》的一个简单的串口应用实例为例,一来学习使用开关语句的使用,二来简单了解51芯片串口基本编程。这个实例是用PC串口通过上位机程序与由AT89C51组成的下位机相通讯,实现用PC软件控制AT89C51芯片的IO口,这样也就可以再通过相关电路实现对设备的控制(这里是控制继电器)。在笔者的网站http://www.cdle.net还可以查看相关文章。所使用的硬件还是用回我们以上课程中做好的硬件,以串口和PC连接,用LED查看实验的结果。下面是源代码。

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

CDLE-J20_Main.c

PC串口控制IO口电路

可以用字符控制和读取IO口

简单版本V2.0

更加好的单片机版本和PC控制软件和DLL动态库

请访问磁动力工作室http://www.cdle.net

Copyright 2003 http://www.cdle.net

All rights reserved.

明浩 E-mail: pnzwzw@163.com

pnzwzw@cdle.net

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

#include

statICunsigned char data CN[4];

static unsigned char data CT;

unsigned char TS[8] = {254,252,248,240,224,192,128,0};

void main(void)

{

void InitCom(unsigned char BaudRate);

void ComOutChar(unsigned char OutData);

void CSToOut(void);

void CNToOut(void);

unsigned int a;

CT = 0; //接收字符序列

CN[0] = 0;

CN[1] = 51;

CN[2] = 51;

CN[3] = 0;

InitCom(6); //设置波特率为9600 1-8波特率300-57600

EA = 1;

ES = 1; //开串口中断

do

{

for (a=0; a<30000; a++)

P3_6 = 1;

for (a=0; a<30000; a++) //指示灯闪动

P3_6 = 0;

}

while(1);

}

//串口初始化晶振为11.0592M 方式1 波特率300-57600

void InitCom(unsigned char BaudRate)

{

unsigned char THTL;

switch (BaudRate)

{

case 1: THTL = 64; break; //波特率300

case 2: THTL = 160; break; //600

case 3: THTL = 208; break; //1200

case 4: THTL = 232; break; //2400

case 5: THTL = 244; break; //4800

case 6: THTL = 250; break; //9600

case 7: THTL = 253; break; //19200

case 8: THTL = 255; break; //57600

default: THTL = 208;

}

SCON = 0x50; //串口方式1,允许接收

TMOD = 0x20; //定时器1定时方式2

TCON = 0x40; //设定时器1开始计数

TH1 = THTL;

TL1 = THTL;

PCON = 0x80; //波特率加倍控制,SMOD位

RI = 0; //清收发标志

TI = 0;

TR1 = 1; //启动定时器

}

//向串口输出一个字符(非中断方式)

void ComOutChar(unsigned char OutData)

{

SBUF = OutData; //输出字符

while(!TI); //空语句判断字符是否发完

TI = 0; //清TI

}

//串口接收中断

void ComInINT(void) interrupt 4 using 1

{

if (RI) //判断是不是收完字符

{

if (CT>3)

{

CT = 0; //收完一组数据,序列指针清零

CN[0] = 0;

CN[1] = 51;

CN[2] = 51;

CN[3] = 0;

}

CN[CT] = SBUF;

CT++;

RI = 0; //RI清零

if (CN[0]==0x61 && CN[3]==0x61) //用aXXa的简单方式保证接收的可靠性,可以满足业余的要求

{ //a也可以为板下的ID号,在同一个串行口上可以挂上一块以上的板

CSToOut(); //收到的数据格式正确时,调用控制输出函数

} //要想更为可靠的工作则要用到数据检验和通讯协议

}

}

//根据全局变量输出相应的控制信号

void CSToOut(void)

{

unsigned char data a;

unsigned int data b;

switch(CN[1]) //aXXa的格式定义是第一个X为端口,0为P0,1为P1,2为P2,3为关闭所有(同时要第2个X为3,XX=33)

{ //XX=44为测试用,5为读取端口状态,大于5则为无效数据,

case 0: //第一个X小于3时,第二个X为要输出的数据。

P0 = CN[2];

CNToOut();

break;

case 1:

P1 = CN[2];

CNToOut();

break;

case 2:

P2 = CN[2];

CNToOut();

break;

case 3:

P0 = 0xFF;

P1 = 0xFF;

P2 = 0xFF;

CNToOut();

break;

case 4:

P0 = 0xFF;

P1 = 0xFF;

P2 = 0xFF;

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

{

P0 = TS[a];

for (b=0; b<50000; b++);

}

P0 = 0xFF;

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

{

P1 = TS[a];

for (b=0; b<50000; b++);

}

P1 = 0xFF;

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

{

P2 = TS[a];

for (b=0; b<50000; b++);

}

P2 = 0xFF;

CNToOut();

break;

case 5: //根据CN[2]返回所要读取的端口值

switch(CN[2])

{

case 0:

ComOutChar(CN[0]);

ComOutChar(CN[1]);

ComOutChar(P0);

ComOutChar(CN[3]);

break;

case 1:

ComOutChar(CN[0]);

ComOutChar(CN[1]);

ComOutChar(P1);

ComOutChar(CN[3]);

break;

case 2:

ComOutChar(CN[0]);

ComOutChar(CN[1]);

ComOutChar(P2);

ComOutChar(CN[3]);

break;

case 3:

ComOutChar(CN[0]);

ComOutChar(CN[1]);

ComOutChar(P3);

ComOutChar(CN[3]);

break;

}

break;

}

}

void CNToOut(void)

{

ComOutChar(CN[0]);

ComOutChar(CN[1]);

ComOutChar(CN[2]);

ComOutChar(CN[3]);

}

代码中有多处使用开关语句的,使用它对不同的条件做不同的处理,如在CSToOut函数中根据CN[1]来选择输出到那个IO口,如CN[1]=0则把CN[2]的值送到P0,CN[1]=1则送到P1,这样的写法比起用if (CN[1]==0)这样的判断语句来的清晰明了。当然它们的效果没有太大的差别(在不考虑编译后的代码执行效率的情况下)。

在这段代码其主要的作用就是通过串口和上位机软件进行通讯,跟据上位机的命令字串,对指定的IO端口进行读写。InitCom函数,原型为void InitCom(unsigned char BaudRate),其作用为初始化串口。它的输入参数为一个字节,程序就是用这个参数做为开关语句的选择参数。如调用InitCom(6),函数就会把波特率设置为9600。当然这段代码只使用了一种波特率,可以用更高效率的语句去编写,这里就不多讨论了。

看到这里,你也许会问函数中的SCON,TCON,TMOD,SCOM等是代表什么?它们是特殊功能寄存器,在以前也略提到过,51芯片的特殊功能寄存器说明可以参看附录二的'AT89C51特殊功能寄存器列表',在这里简单的说说串口相关的硬件设置。

SBUF 数据缓冲寄存器 这是一个可以直接寻址的串行口专用寄存器。有朋友这样问起过“为何在串行口收发中,都只是使用到同一个寄存器SBUF?而不是收发各用一个寄存器。”实际上SBUF包含了两个独立的寄存器,一个是发送寄存,另一个是接收寄存器,但它们都共同使用同一个寻址地址-99H。CPU在读SBUF时会指到接收寄存器,在写时会指到发送寄存器,而且接收寄存器是双缓冲寄存器,这样可以避免接收中断没有及时的被响应,数据没有被取走,下一帧数据已到来,而造成的数据重叠问题。发送器则不需要用到双缓冲,一般情况下我们在写发送程序时也不必用到发送中断去外理发送数据。操作SBUF寄存器的方法则很简单,只要把这个99H地址用关键字sfr定义为一个变量就可以对其进行读写操作了,如sfr SBUF = 0x99;当然你也可以用其它的名称。通常在标准的reg51.h或at89x51.h等头文件中已对其做了定义,只要用#include引用就可以了。

SCON 串行口控制寄存器 通常在芯片或设备中为了监视或控制接口状态,都会引用到接口控制寄存器。SCON就是51芯片的串行口控制寄存器。它的寻址地址是98H,是一个可以位寻址的寄存器,作用就是监视和控制51芯片串行口的工作状态。51芯片的串口可以工作在几个不同的工作模式下,其工作模式的设置就是使用SCON寄存器。它的各个位的具体定义如下:

51c语言字符,51单片机C语言教程(九) 语句应用相关推荐

  1. 矩阵键盘逐行扫描C语言,(原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf...

    (原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf /***************************************************** ...

  2. 51单片机c语言程序控制,51单片机C语言程序设计源代码

    <51单片机C语言程序设计源代码>由会员分享,可在线阅读,更多相关<51单片机C语言程序设计源代码(281页珍藏版)>请在人人文库网上搜索. 1.51 SCM c语言教程示例2 ...

  3. 51单片机蜂鸣器演奏《小苹果》C语言程序,51单片机C语言蜂鸣器发声生日快乐播放程序...

    <51单片机C语言蜂鸣器发声生日快乐播放程序>由会员分享,可在线阅读,更多相关<51单片机C语言蜂鸣器发声生日快乐播放程序(4页珍藏版)>请在人人文库网上搜索. 1.按键发音/ ...

  4. 单片机汉字点阵c语言程序,51单片机C语言多种点阵屏驱动程序(开发软件为keil C...

    51单片机C语言多种点阵屏驱动程序(开发软件为keil C 2016-08-23 1 0 0 暂无评分 其他 1 积分下载 如何获取积分? 51单片机C语言多种点阵屏驱动程序(开发软件为keil C ...

  5. 时钟加闹钟c语言程序,51单片机c语言电子钟(已加入调时、闹铃、整点报时功能)...

    <51单片机c语言电子钟(已加入调时.闹铃.整点报时功能)>由会员分享,可在线阅读,更多相关<51单片机c语言电子钟(已加入调时.闹铃.整点报时功能)(13页珍藏版)>请在技术 ...

  6. 单片机 中断秒表 c语言程序,51单片机c语言的秒表设计.doc

    51单片机c语言的秒表设计.doc 课程设计报告 基于AT89C51单片机的秒表设计 院 系 电子信息工程学院 专 业 电子信息工程 1 姓 名 摘 要 本设计是设计一个单片机控制的多功能秒表系统. ...

  7. 51单片机c语言程序控制,51单片机C语言编程基础及实例.pdf

    基础知识: 51 单片机编程基础 第一节:单数码管按键显示 第二节:双数码管可调秒表 第三节:十字路口交通灯 第四节:数码管驱动 第五节:键盘驱动 第六节:低频频率计 第七节:电子表 第八节:串行口应 ...

  8. 步进电机编写单4拍或4-8拍方式的汇编或c语言控制程序.,51单片机C语言和汇编控制28BYJ48步进电机程序...

    本文提供三个51单片机控制步进电机正反转的程序,2个C程序,1个汇编,. 步进电机正反转程序 28BYJ48,,,,四相五线制,,用拍的脉冲... 电机先正转一周,在反转一周,停止.. 本程序利用 S ...

  9. 单片机交通灯数码管c语言程序,51单片机C语言实现交通灯(红绿灯)源程序.doc

    51单片机用C语言实现交通灯(红绿灯)源程序 2009-10-29 23:00 交通灯,红黄绿灯交替亮,怎样实现呢?其实就是根据单片机定时器及倒计时的程序修改. 源程序如下: /*1.程序目的:使用定 ...

最新文章

  1. Compressor detection can only be called on some ……
  2. 如何读取抓取的wifi包内容
  3. python中str和int区别_Python如何比较string和int?
  4. 转: ajax跨域之JSONP
  5. boost::callable_traits的remove_varargs_t的测试程序
  6. ZooKeeper管理员指南
  7. 985计算机只考数据结构,初试只考数据结构的985院校
  8. 使用gogs搭建git私有仓库
  9. [Algorithm NLP] 文本深度表示模型——word2vecdoc2vec词向量模型
  10. 游戏设计艺术 第2版 (Jesse Schell 著)
  11. 建立U盘免疫病毒文件
  12. PHP Encoder (ioncube 10) 加密工具的使用
  13. 交互设计常识:设计模型分析
  14. 网站logo服务器更换显示以前,网站更换logo
  15. 计算机等级考试四级 网络工程师 之 操作系统原理1 适合懒人备考哈哈哈
  16. 将数组作为函数参数调用
  17. mysql 查询 系统字段 自然日_吴裕雄--天生自然python数据清洗与数据可视化:MYSQL、MongoDB数据库连接与查询、爬取天猫连衣裙数据保存到MongoDB...
  18. PyG搭建GNN实现链接回归预测
  19. macu盘格式化linux系统盘,Mac上制作Linux U盘启动盘
  20. 美容仪洁面器无线充电方案XS016

热门文章

  1. 大数据在政府中的应用案例
  2. java 创建word文件_Java 创建Word
  3. m1芯片 php,苹果M1 版 MacBook软件兼容实测:VS Code不能用 PHPStorm可运行
  4. 计算机网络网络安全实验报告,《计算机网络安全》实验报告
  5. STL源码剖析-第一章STL概论与版本简介
  6. 计算机辅助技术学什么课,《CADCAM》课程导学计划
  7. deepinV20一路艰辛系列六:更新微信到最新版本
  8. 中科院计算机控制学院难度,16年自动化所复试失败经验
  9. 「 机器人学 」“姿态角 roll、yaw、pitch”讲解
  10. [Android App] 内涵段子最新5.5.5 去广告去更新修改版