(玩电子) 电子技术学习与研讨
当时方位:单片机教程网 >> 根底教程 >> 阅览文章

第十五课 C51数组的运用

作者:佚名   来历:本站原创   点击数:x  更新时刻:2007年07月12日   【字体:

前面的文章中,都是介绍单个数据变量的运用,在“走马灯”等的比如中略有运用到数组,不难看出,数组不过便是同一类型变量的有序调集。形象的能这样去了解,就像一个 校园在操场上排队,每一个级代表一个数据类型,每一个班级为一个数组,每一个学生便是 数组中的一个数据。数据中的每个数据都能用仅有的下标来确认其方位,下标能是一维 或多维的。就如在校园的方队中要找一个学生,这个学生在 I 年级 H 班 X 组 Y 号的,那么 能把这个学生看做在 I 类型的 H 数组中(X,Y)下标方位中。数组和一般变量相同,要

求先界说了才干运用,下面是界说一维或多维数组的办法:

数据类型

数组名

[常量表达式];

数据类型

数组名

[常量表达式 1]...... [常量表达式 N];

“数据类型”是指数组中的各数据单元的类型,每个数组中的数据单元只能是同一数据

类型。“数组名”是整个数组的标识,命名办法和变量命名办法是相同的。在编译时体系会 依据数组巨细和类型为变量分配空间,数组名能说便是所分配空间的首地址的标识。“常 量表达式”是表明数组的长度和维数,它有必要用“[]”括起,括号里的数不能是变量只能是 常量。

unsigned int xcount [10]; //界说无符号整形数组,有 10 个数据单元

char inputstring [5]; //界说字符形数组,有 5 个数据单元

float outnum [10],[10];//界说浮点型数组,有 100 个数据单元

在 C 言语中数组的下标是从 0 开端的而不是从 1 开端,如一个具有 10 个数据单元的数

组 count,它的下标便是从 count[0]到 count[9],引证单个元素便是数组名加下标,如 count[1] 便是引证 count 数组中的第 2 个元素,假如错用了 count[10]就会有过错呈现了。还有一点要 留意的便是在程序中只能逐一引证数组中的元素,不能一次引证整个数组,可是字符型的数 组就能一次引证整个数组。

数组也是能赋初值的。在上面介绍的界说办法只适用于界说在内存  DATA  存储器使 用的内存,有的时分咱们需要把一些数据表寄存在数组中,一般这些数据是不用在程序中改 变数值的,这个时分就要把这些数据在程序编写时就赋给数组变量。由于  51  芯片的片内  RAM 很有限,一般会把 RAM 分给参加运算的变量或数组,而那些程序中不变数据则应寄存在片 内的 CODE 存储区,以节约名贵的 RAM。赋初值的办法如下:

数据类型  [存储器类型]  数组名  [常量表达式] = {常量表达式};

数据类型  [ 存储器类型]  数组名  [ 常量表达式  1]......  [ 常量表达式  N]={{ 常量表达 式}...{常量表达式 N}};

在界说并为数组赋初值时,开端学习的朋友一般会搞错初值个数和数组长度的联络,而致使 编译犯错。初值个数有必要小于或等于数组长度,不指定数组长度则会在编译时由实践的初值 个数主动设置。

unsigned char LEDNUM[2]={12,35}; //一维数组赋初值

int Key[2][3]={{1,2,4},{2,2,1}}; //二维数组赋初值

unsigned char IOStr[]={3,5,2,5,3}; //没有指定数组长度,编译器主动设置

unsigned char code skydata[]={0x02,0x34,0x22,0x32,0x21,0x12}; //数据保存在 code 区

下面的一个简略比如是对数组中的数据进行排序,运用的是冒泡法,一来了解数组的使 用,二来把握根本的排序算法。冒泡排序算法是一种根本的排序算法,它每次次序取数组中 的两个数,并按需要按其巨细摆放,鄙人一次循环中则取下一次的一个数和数组中下一个数 进行排序,直到数组中的数据悉数排序完结。


#include <AT89X51.H>

#include <stdio.h>

void taxisfun (int taxis2[])

{

unsigned char TempCycA,TempCycB,Temp;

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

for (TempCycB=0; TempCycB<=8-TempCycA; TempCycB++)

{//TempCycB<8-TempCycA 比用 TempCycB<=8 少用许多循环

if  (taxis2[TempCycB+1]>taxis2[TempCycB])  //当后一个数大于前一个 数

{

Temp = taxis2[TempCycB]; //前后 2 数交流

taxis2[TempCycB] = taxis2[TempCycB+1];

taxis2[TempCycB+1]  =  Temp;  //因函数参数是数组名调用形

参的变化影响实参

}

}

}

void main(void)

{

int taxis[] = {113,5,22,12,32,233,1,21,129,3};

char Text1[] = {"source data:"}; //"源数据"

char Text2[] = {"sorted data:"}; //"排序后数据"

unsigned char TempCyc;

SCON = 0x50; //串行口办法 1,答应接纳

TMOD = 0x20; //守时器 1 守时办法 2

TCON = 0x40; //设守时器 1 开端计数

TH1 = 0xE8;   //11.0592MHz 1200 波特率

TL1 = 0xE8; TI = 1;

TR1 = 1; //发动守时器

printf("%s\n",Text1); //字符数组的全体引证

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

printf("%d ",taxis[TempCyc]);

printf("\n----------\n");

taxisfun (taxis); //以实践参数数组名 taxis 做参数被函数调用

printf("%s\n",Text2);

for (TempCyc=0; TempCyc<10; TempCyc++) //调用后 taxis 会被改动

printf("%d ",taxis[TempCyc]);


while(1);

}

比如中能看出,数组相同能作为函数的参数进行传递。数组做参数时是用数组名进

行传递的,一个数组的数组名表明该数组的首地址,在用数组名作为函数的调用参数时,它 的传递办法是采用了地址传递,便是将实践参数数组的首地址传递给函数中的形式参数数 组,这个时分实践参数数组和形式参数数组实践上是运用了同一段内存单元,当形式参数数组在 函数体中改动了元素的值,一起也会影响到实践参数数组,由于它们是寄存在同一个地址的。 上面的比如一起还运用到字符数组。字符数组中每一个数据都是一个字符,这样一个一 维的字符数组就组成了一个字符串,在  C  言语中字符串是以字符数组来表达处理的。为了 能测定字符串的长度,C 言语中规则以‘\o’来做为字符串的完毕标识,编译时会主动在字 符串的最终参加一个‘\o’,那么要留意的是假如用一个数组要保存一个长度为 10 字节的字 符串则要求这个数组至少能保存 11 个元素。‘\o’是转义字符,它的意义是空字符,它的 ASCII 码为 00H,也便是说当每一个字符串都是以数据 00H 完毕的,在程序中操作字符数 据组时要留意这一点。字符数组除了能对数组中单个元素进行拜访,还能拜访整个数组, 其实整个拜访字符数组便是把数组名传到函数中,数组名是一个指向数据寄存空间的地址指 针,函数依据这个指针和‘/o’就能完好的操作这个字符数组。关于这一段所说的,能 参看下面一例 1602LCD 显现模块的驱动演示比如进行了解。这儿要留意便是能用单个字

符数组元从来进行运算,但不能用整个数组来做运算,由于数组名是指针而不是数据。

/*============================================================

运用 1602 液晶显现的试验比如  明浩  2004/2/27

==============================================================

SMC1602A(16*2)模仿口线接线办法 衔接线图:

---------------------------------------------------

|LCM-----51      | LCM-----51        |    LCM------51 |

---------------------------------------------|

|DB0-----P1.0 | DB4-----P1.4 | RW-------P2.0 |

|DB1-----P1.1 | DB5-----P1.5 | RS-------P2.1 |

|DB2-----P1.2 | DB6-----P1.6 | E--------P2.2 |

|DB3-----P1.3 | DB7-----P1.7 | VLCD 接 1K 电阻到 GND|

---------------------------------------------------

[注:AT89S51 运用 12M 晶体震动器]

=============================================================*/

#define LCM_RW P2_0 //界说引脚

#define LCM_RS P2_1

#define LCM_E P2_2

#define LCM_Data P1

#define Busy 0x80 //用于检测 LCM 状况字中的 Busy 标识

#include <at89x51.h>


void WriteDataLCM(unsigned char WDLCM);

void WriteCommandLCM(unsigned char WCLCM,BuysC);

unsigned char ReadDataLCM(void); unsigned char ReadStatusLCM(void); void LCMInit(void);

void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);

void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData);

void Delay5Ms(void);

void Delay400Ms(void);

unsigned char code cdle_net[] = {"www.kp0519.com"};

unsigned char code email[] = {"pnzwzw@kp0519.com"};

void main(void)

{

Delay400Ms(); //发动等候,等 LCM 讲入作业状况

LCMInit(); //LCM 初始化

Delay5Ms(); //延时顷刻(可不要)

DisplayListChar(0, 0, cdle_net); DisplayListChar(0, 1, email); ReadDataLCM();//测试用句无意义 while(1);

}

//写数据

void WriteDataLCM(unsigned char WDLCM)

{

ReadStatusLCM(); //检测忙 LCM_Data = WDLCM; LCM_RS = 1;

LCM_RW = 0;

LCM_E = 0; //若晶体震动器速度太高能在这后加小的延时

LCM_E = 0; //延时

LCM_E = 1;

}

//写指令

void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC 为 0 时疏忽忙检测

{

if (BuysC) ReadStatusLCM(); //依据需要检测忙

LCM_Data = WCLCM; LCM_RS = 0; LCM_RW = 0;

LCM_E = 0;


LCM_E = 0; LCM_E = 1;

}

//读数据

unsigned char ReadDataLCM(void)

{

LCM_RS = 1; LCM_RW = 1; LCM_E = 0; LCM_E = 0; LCM_E = 1; return(LCM_Data);

}

//读状况

unsigned char ReadStatusLCM(void)

{

LCM_Data = 0xFF; LCM_RS = 0; LCM_RW = 1; LCM_E = 0; LCM_E = 0; LCM_E = 1;

while (LCM_Data & Busy); //检测忙信号

return(LCM_Data);

}

void LCMInit(void) //LCM 初始化

{

LCM_Data = 0;

WriteCommandLCM(0x38,0); //三次显现形式设置,不检测忙信号

Delay5Ms(); WriteCommandLCM(0x38,0); Delay5Ms(); WriteCommandLCM(0x38,0); Delay5Ms();

WriteCommandLCM(0x38,1); //显现形式设置,开端要求每次检测忙信号

WriteCommandLCM(0x08,1); //封闭显现 WriteCommandLCM(0x01,1); //显现清屏 WriteCommandLCM(0x06,1); //  显现光标移动设置 WriteCommandLCM(0x0C,1); //  显现开及光标设置

}


//按指定方位显现一个字符

void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)

{

Y &= 0x1;

X &= 0xF; //约束 X 不能大于 15,Y 不能大于 1

if (Y) X |= 0x40; //当要显现第二行时地址码+0x40; X |= 0x80; //算出指令码

WriteCommandLCM(X, 0); //这儿不检测忙信号,发送地址码

WriteDataLCM(DData);

}

//按指定方位显现一串字符

void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)

{

unsigned char ListLength;

ListLength = 0; Y &= 0x1;

X &= 0xF; //约束 X 不能大于 15,Y 不能大于 1

while (DData[ListLength]>0x20) //若抵达字串尾则退出

{

if (X <= 0xF) //X 坐标应小于 0xF

{

DisplayOneChar(X, Y, DData[ListLength]); //显现单个字符

ListLength++; X++;

}

}

}

//5ms 延时

void Delay5Ms(void)

{

unsigned int TempCyc = 5552;

while(TempCyc--);

}

//400ms 延时

void Delay400Ms(void)

{

unsigned char TempCycA = 5; unsigned int TempCycB; while(TempCycA--)

{

TempCycB=7269;


while(TempCycB--);

};

}

宣布谈论】【告知老友】【保藏此文】【封闭窗口

文章谈论

相关文章