<meta name="keywords" content="必胜时时彩开户,keywords" /> 第十五课 C51数组的应用 联系我们

第十五课 C51数组的应用

前面的文章中,都是简介单个数据变量的应用,在“走马灯”等的例子中略有应用到数组,欠悦目出,数组不外就是统一类型变量的有序荟萃。笼统的能这样去明确,就像一个 黉舍在操场上排队,每个级代表一个数据类型,每个班级为一个数组,每个师长教员就是 数组中的一个数据。数据中的每个数据都能用唯一的下标来一定其职位,下标能是一维 或多维的。就如在黉舍的方队中要找一个师长教员,这个师长教员在 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[] = {"mamjap.com"};

unsigned char code email[] = {"pnzwzw@51hei.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--);

};

}