当前位置:首页 > 单片机 > 单片机
[导读] 曾经在BBS上有朋友问过我{}是什么意思?什么作用?在C中是有不少的括号,如{},[],()等,确实会让一些初入门的朋友不解。在VB等一些语言中同一个()号会有不同的作用,它可以用于组合若干条语句形成功能块

曾经在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寄存器。它的各个位的具体定义如下:

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

单片机是一种嵌入式系统,它是一块集成电路芯片,内部包含了处理器、存储器和输入输出接口等功能。

关键字: 单片机 编写程序 嵌入式

在现代电子技术的快速发展中,单片机以其高度的集成性、稳定性和可靠性,在工业自动化、智能家居、医疗设备、航空航天等诸多领域得到了广泛应用。S32单片机,作为其中的佼佼者,其引脚功能丰富多样,是实现与外部设备通信、控制、数据...

关键字: s32单片机引脚 单片机

在微控制器领域,MSP430与STM32无疑是两颗璀璨的明星。它们各自凭借其独特的技术特点和广泛的应用领域,在市场上占据了重要的位置。本文将深入解析MSP430与STM32之间的区别,探讨它们在不同应用场景下的优势和局限...

关键字: MSP430 STM32 单片机

该系列产品有助于嵌入式设计人员在更广泛的系统中轻松实现USB功能

关键字: 单片机 嵌入式设计 USB

单片机编程语言是程序员与微控制器进行交流的桥梁,它们构成了单片机系统的软件开发基石,决定着如何有效、高效地控制和管理单片机的各项资源。随着微控制器技术的不断发展,针对不同应用场景的需求,形成了丰富多样的编程语言体系。本文...

关键字: 单片机 微控制器

单片机,全称为“单片微型计算机”或“微控制器”(Microcontroller Unit,简称MCU),是一种高度集成化的电子器件,它是现代科技领域的关键组件,尤其在自动化控制、物联网、消费电子、汽车电子、工业控制等领域...

关键字: 单片机 MCU

STM32是由意法半导体公司(STMicroelectronics)推出的基于ARM Cortex-M内核的32位微控制器系列,以其高性能、低功耗、丰富的外设接口和强大的生态系统深受广大嵌入式开发者喜爱。本文将详细介绍S...

关键字: STM32 单片机

在当前的科技浪潮中,单片机作为嵌入式系统的重要组成部分,正以其强大的功能和广泛的应用领域受到越来越多行业的青睐。在众多单片机中,W79E2051以其卓越的性能和稳定的工作特性,成为市场上的明星产品。本文将深入探讨W79E...

关键字: 单片机 w79e2051单片机

单片机,又称为微控制器或微处理器,是现代电子设备中的核心部件之一。它集成了中央处理器、存储器、输入输出接口等电路,通过外部信号引脚与外部设备进行通信,实现对设备的控制和管理。本文将详细介绍单片机的外部信号引脚名称及其功能...

关键字: 单片机 微控制器 中央处理器

随着科技的飞速发展,单片机和嵌入式系统在现代电子设备中的应用越来越广泛。它们不仅提高了设备的智能化水平,还推动了各行各业的创新与发展。在单片机和嵌入式系统的开发中,编程语言的选择至关重要。本文将深入探讨单片机和嵌入式系统...

关键字: 单片机 嵌入式系统 电子设备
关闭
关闭