第八课 语 句(4)-开关语句
我们学习了条件语句,用多个条件语句可以实现多方向条件分支,但是可以发现使用过多的条件语句实现多方向分支会使条件语句嵌套过多,程序冗长,这样读起来也很不好读。这时使用开关语句同样可以达到处理多分支选择的目的,又可以使程序结构清晰。它的语法为下:
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 static unsigned 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]);