单片机与ARM平台通信课设报告 2

单片机与ARM平台通信课设报告 2

单片机与ARM平台通信课设报告 2

课程设计报告

课程名称嵌入式系统

课题名称单片机与ARM 平台通信

专业计算机科学与技术

班级

学号

姓名

指导教师郭鹏刘铁武李杰君

2012年9月3 日

湖南工程学院

课程设计任务书

课程名称嵌入式系统

课题单片机与ARM平台通信

专业班级

学生姓名

学号

指导老师郭鹏刘铁武李杰君

任务书下达日期 2012年9 月 3 日

任务完成日期2012年9 月8 日

嵌入式系统课程设计任务书

设计课题1:单片机与ARM 平台通信

1、问题描述:

智能家居系统中,单片机扩展板用于感知周围环境的物理信息,并将这些信息数字化通过RS232串口传送给ARM平台。单片机串口编程是单片机工程师必须掌握的基本技能之一,串口中断、串口协议的设计是此类设计的核心问题。

2、功能设计要求:

1)本系统利用AT89C52系列单片机的串口实现与ARM平台串口的通信连接,涉及单片机串口中断程序的编写,以及串口通信协议的设计。

2)设计串口通信协议,协议内容包括:

发送头标识信息

发送字节长度

具体发送内容

效验和信息

3)串口函数要求:

串口初始化函数:进行串口初始化定义

串口中断函数:接收函数中对通信协议进行解析,对错误包信息进行容错处理;发送函数中对发送内容进行处理。

3、要求:

1)用Keil C环境实现系统;

2)函数功能要划分好(结构化程序设计);

3)串口协议及串口中断函数加必要的注释;

4)提供程序测试方案(可用PC串口小助手等测试工具)。

目录

一、系统介绍 (1)

二、总体设计 (2)

2.1程序模块 (2)

2.2.函数分析 (2)

2.3.总体结构 (2)

三.主要模块的实现 (3)

四.程序调试 (7)

五.总结与体会 (8)

六.源程序清单 (9)

一、系统介绍

数据采集系统中由于单片机侧重于控制,数据处理能力较弱,对采集的数据进行运算处理比较繁琐,如果通过串口与ARM通信,利用ARM强大的数据处理能力和友好的控制界面对数据进行处理和显示则可以提高设计效率。串口通信以其简单的硬件连接,成熟的通信协议,成为上下位机之间通信的首选。移植了Linux 操作系统的ARM平台可以在Linux 环境下操作串口,降低了串口操作的难度,可以使开发者集中精力开发大规模的应用程序,而不必在操作底层设计上耗费时间。

智能家居系统中,单片机扩展板用于感知周围环境的物理信息,并将这些信息数字化通过RS232串口传送给ARM平台。智能家居,或称智能住宅,即利用先进的计算机技术、自控技术、网络通信技术和综合布线技术,将与家居生活有关的各种子系统有机地结合在一起,通过统筹管理,让家居生活更舒适、安全、有效。智能家居是以住宅为平台,兼备建筑设备、网络通信、信息家电和设备自动化,集系统、结构、服务、管理于一体的高效、舒适、安全、便利、环保节能的居住和生活环境。

二、总体设计

2.1程序模块

这个课题可以分为两大模块:串口通信模块与串口通信协议模块。

(1)串口初始化函数:进行串口初始化定义

串口中断函数:接收函数中对通信协议进行解析,对错误包信息进行容错处理;发送函数中对发送内容进行处理。

(2)串口通信协议模块:

设计的协议内容包括:发送头标识信息、发送字节长度、具体发送内容、效验和信息等。

a.定义数据包格式

单片机与ARM平台通信课设报告 2

图2.1 串口通信数据包格式

2.2.函数分析

程序包括几个功能函数:

1)调用open()函数打开串口设备文件,若出错则返回-1,成功则返回文件句柄。2)设置串口属性的函数set_attr(int fd),其中又包括函数tcsetattr 可以设置串口的结构属性,tcgetatt( )可以得到串口的结构属性。在termios 结构中,最重要的是c_cflag,用户通过对其进行赋值可以实现串口波特率、数据位、停止位、奇偶校验位等参数的设置。

3)设置完通信参数后,就可以用标准的文件读写命令read()和write()操作串口了。最后在退出之前,用close()函数关闭串口。

2.3.

单片机与ARM平台通信课设报告 2

三.主要模块的实现

单片机与ARM平台通信课设报告 2

第一步:打开串口

调用open()函数打开串口设备文件,若出错则返回- 1,成功则返回文件句柄。

#define UART1 /dev /ttySAC1

int fd;

fd = open(“UART1”,O_RDWR) /* 以可读可写方式打开串口设备* / 第二步:设置串口属性

函数tcsetattr 可以设置串口的结构属性,tcgetatt()可以得到串口的结构属性。在termios 结构中,最重要的是c_cflag,用户通过对其进行赋值可以实现串口波特率、数据位、停止位、奇偶校验位等参数的设置。c_cc 数组中的两个变量VMIN 和VTIME 判断是否返回输入,c _cc[VTIME]设定字节输入时间计时器,c _cc[VMIN]设定满足读取功能的最低接收字节数。

这两个变量的值要设定合理,才能保证串口的通信成功率。

int set_attr( int fd)

{

struct termios newtio,oldtio;

tcgetattr( fd,&oldtio) ;

cfsetispeed( &newtio,B9600) ; /* 设置读波特率为9600* /

cfsetospeed( &newtio,B9600) ; /* 设置写波特率为9600* /

memset(&newtio,0, sizeof( newtio));

newtio. c_cflag = CS8 | CREAD; /* 设置数据位为8 位并且使能接收* / newtio. c_cflag & = ~ PARENB; /* 不进行奇偶校验* /

newtio. c_cflag & = ~ CSTOPB; /* 1 位停止位* /

newtio. c_cc[VMIN]= 1; /* 当接收到一个字节数据就读取* /

newtio. c_cc[VTIME]= 0; /* 不使用计时器* /

tcflush( fd,TCIOFLUSH) ; /* 刷清输入输出缓冲区* /

tcsetattr( fd,TCSANOW,&newtio) /* 使设置的终端属性立即生效* / }

第三步:串口读写,串口关闭

设置完通信参数后,就可以用标准的文件读写命令read()和write()操作串口了。最后在退出之前,用close()函数关闭串口。

void rd_wr()

{

write( fd,wbuf,10) ;

usleep( 500000) ; /* 延时50 ms 等待下位机发送数据* /

read( fd, rbuf,10) ;

printf(“read string is %s ”, rbuf) ;

}

Linux 下串口通信协议设计:

现约定双方通信协议如下:

(1)波特率为9600bit/s,帧格式为1 - 8 - N - 1(1位起始位,8位数

据位,无奇偶校验,1位停止位);(2)由于上位机ARM 的速度远远高于下位

机单片机的速度,所以采用上位机主动联络,下位机等待的方式。在数据传送前

ARM 先发送联络信号/0xaa,单片机收到后回答一个/0xbb,表示可以发送,否则

继续联络;(3)单片机端可以有中断和查询方式收发串口数据。本文采用中断

(4)ARM 处理器s3c2440 采用UART1 和单片机通信,UART0 则作为s3c2440 方式;

终端控制台。

下位机单片机的通信程序设计:

选用C8051F021 的定时器T1 作为波特率发生器,晶振采用11.0592 MHz,

定时器工作在方式2,计数初值为0xfd,串口工作在串行方式1( 1 - 8 - N - 1),

采用中断方式收发数据。程序流程图如图3.2 所示。

Linux 下的串口通信程序在PC 机Linux RHEL5下用arm - linux - gcc 4.4.3

交叉编译工具编译通过NFS 挂载在s3c2440 上运行,单片机端的通信程序用

Cygnal 的集成开发环境(IDE)编译并下载到C8051F021 中运行。

单片机与ARM平台通信课设报告 2

图3.2程序流程图

四.程序调试

单片机与ARM平台通信课设报告 2

传感器网络截图

五.总结与体会

经过这两个星期的课程设计,我对嵌入式系统有了更深一层的了解,尤其是它在智能家居方面的运用。我做的课题是单片机与ARM平台通信,尽管难度不是很大。但是由于自己本身对linux不是很熟悉,加上平时也没有认真去钻研嵌入式,在初步完成这个课题的时候还是遇到了许多问题,如编译不成功,不知道该如何操作ARM平台等等,通过上网查阅一些资料和询问同学也逐渐有了一点解决的思路和方向,最终还是基本完成了课题的基本要求。课程设计培养了学生综合运用所学知识,并从中提出、分析并解决实际问题,是对学生实际工作能力的具体训练和考察过程。

随着近年来嵌入式Linux 在国内的应用范围日益壮大,基于ARM 平台的嵌入式Linux 设备也将会越来越多地用在数据采集中作为上位机对数据进行处理、显示、存储、发送。对于Linux 下ARM 和单片机的串口通信设计,我们只需根据自己的实际需要修改或重新制定通信协议即可。另外需要注意的是由于上位机ARM 的速度比单片机快很多,所以一次不能发送过多的数据,否则极有可能使发送缓冲区溢出而出现数据丢失的现象,我们要根据通信双方设备的状况选择合适的帧长度,以达到最佳的传输状态。

总之,从理论到实践,我们不仅可以巩固以前学过的知识,而且学到了很多在书本上所没有学到的东西。通过这次课程设计,提高了自己实际动手能力和独立思考的能力。

参考文献

【1】《单片机原理及应用》——电子工业出版社,林立等编著

【2】《单片机的C语言应用》——西安电子科技大学出版社,张玉馥主编【3】《Linux环境下的串口通信》——2005年01期,马文辉,李兰友主编

六.源程序清单

#include < ter-mios.h >

BYTE ComBuf[18];//串口通讯数据缓存,发送和接收都使用

UINT nAddress;//ROM中地址计数

UINT nTimeOut;//超时计数

ProWork pw;//编程器一般操作

void Delay_us(BYTE nUs)//微秒级延时<255us

{

TH0=0;

TL0=0;

TR0=1;

while(TL0

}

TR0=0;

}

void Delay_ms(UINT nMs)//豪秒级的延时<65535ms

{

UINT n=0;

TR0=1;

while(n

TH0=0;

TL0=20;

while(TH0<4)

{

}

n++;

}

TR0=0;

}

BOOL WaitComm()//等待上位机的命令,18字节

{

BYTE n=0;

RI=0;

while(!RI){}//等待第一个字节

ComBuf[n]=SBUF;

RI=0;

n++;

for(n;n<=17;n++)

{

nTimeOut=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>10000)//后17个字节都有超时限制

return 0;

}

ComBuf[n]=SBUF;

RI=0;

}

return 1;

}

BOOL WaitResp()//等待上位机回应,1字节,有超时限制

{

nTimeOut=0;

RI=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>50000)

{

return 0;

}

}

RI=0;

ComBuf[0]=SBUF;

return 1;

}

BOOL WaitData()//写器件时等待上位机数据,18字节,有超时限制{

BYTE n;

RI=0;

for(n=0;n<=17;n++)

{

nTimeOut=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>10000)

{

return 0;

}

}

RI=0;

ComBuf[n]=SBUF;

}

return 1;

}

void SendData()//发送数据或回应操作完成,18字节

{

BYTE n=0;

for(n;n<=17;n++)

{

TI=0;

SBUF=ComBuf[n];

while(!TI){}

TI=0;

}

}

void SendResp()//回应上位机1个字节,在写器件函数中使用{

TI=0;

SBUF=ComBuf[0];

while(!TI){}

TI=0;

}

void SetVpp5V()//设置Vpp为5v

{

P3_4=0;

P3_3=0;

}

void SetVpp0V()//设置Vpp为0v

{

P3_3=0;

P3_4=1;

}

void SetVpp12V()//设置Vpp为12v

{

P3_4=0;

P3_3=1;

}

void RstPro()//编程器复位

{

pw.fpProOver();//直接编程结束

SendData();//通知上位机,表示编程器就绪,可以直接用此函数因为协议号(ComBuf[0])还没被修改,下同

}

void ReadSign()//读特征字

{

pw.fpReadSign();

SendData();//通知上位机,送出读出器件特征字

}

void Erase()//擦除器件

{

pw.fpErase();

SendData();//通知上位机,擦除了器件

}

void Write()//写器件

{

BYTE n;

pw.fpInitPro();//编程前的准备工作

SendData();//回应上位机表示进入写器件状态,

可以发来数据

while(1)

{

if(WaitData())//如果等待数据成功

{

if(ComBuf[0]==0x07)//判断是否继续写

{

for(n=2;n<=17;n++)//ComBuf[2~17]为待写入数据块

{

if(!pw.fpWrite(ComBuf[n]))//<<< <<<<<<调用写该器件一个单元的函数

{

pw.fpProOver();//出错了就结束编程

ComBuf[0]=0xff;

SendResp();//回应上位机一个字节,

表示写数据出错了

WaitData();//等待上位机的回应后就结束

return;

}

nAddress++;//下一个单元

}

ComBuf[0]=1;//回应上位机一个字节,表示数据块顺利完成,请求继续

SendResp();

}

else if(ComBuf[0]==0x00)//写器件结束

break;

else//可能是通讯出错了

{

pw.fpProOver();

return;

}

}

else//等待数据失败

{

pw.fpProOver();

return;

}

}

pw.fpProOver();//编程结束后的工作

Delay_ms(50);//延时等待上位机写线程结束

ComBuf[0]=0;//通知上位机编程器进入就绪状态

SendData();

}

void Read()//读器件

{

BYTE n;

pw.fpInitPro();//先设置成编程状态

SendData();//回应上位机表示进入读状态

while(1)

{

if(WaitResp())//等待上位机回应1个字节

{

if(ComBuf[0]==0)//ComBuf[0]==0表示读结束

{

break;

}

else if(ComBuf[0]==0xff)//0xff表示重发

{

nAddress=nAddress-0x0010;

}

for(n=2;n<=17;n++)//ComBuf[2~17]保存读出的数据块

{

ComBuf[n]=pw.fpRead();//<<<<<<<<<<调用写该器件一个单元的函数nAddress++;//下一个单元

}

ComBuf[0]=6;//向上位机发送读出的数据块

SendData();

}

else

break;//等待回应失败

}

pw.fpProOver();//操作结束设置为运行状态

ComBuf[0]=0;//通知上位机编程器进入就绪状态SendData();

}

void Lock()//写锁定位

{

pw.fpLock();

SendData();

}

/////////////////////////////////////////////////////////////////////////////////

//所支持的FID,请在这里继续添加

///////////////////////////////////////////////////////////////////////////// extern void PreparePro00();//FID=00:AT89C51编程器extern void PreparePro01();//FID=01:AT89C2051编程器extern void PreparePro02();//FID=02:AT89S51编程器void main()

{

SP=0x60;

SetVpp5V();//先初始化Vpp为5v

SCON=0x00;

TCON=0x00;

//PCON=0x00;//波特率*2

IE=0x00;

//TMOD: GATE|C/!T|M1|M0|GATE|C/!T|M1|M0

// 0 0 1 0 0 0 0 1

TMOD=0x21;//T0用于延时程序

TH1=0xff;

TL1=0xff;//波特率28800*2,注意PCON

//SCON: SM0|SM1|SM2|REN|TB8|RB8|TI|RI

// 0 1 0 1 0 0 0 0

SCON=0x50;

TR1=1;

Delay_ms(1000);//延时1秒后编程器自举

ComBuf[0]=0;

SendData();

while(1)//串口通讯采用查询方式

{

if(!WaitComm())//如果超时,通讯出错

{

Delay_ms(500);

ComBuf[0]=0;//让编程器复位,使编程器就绪

}

switch(ComBuf[1])//根据FID设置(ProWork)pw中的函数指针

{

case 0: //at89c51编程器

PreparePro00(); break;

case 1: //at89c2051编程器

PreparePro01(); break;

case 2: //at89s51编程器

PreparePro02(); break;

default: ComBuf[0]=0xff;

ComBuf[1]=0xff; //表示无效的操作

break;

}

switch(ComBuf[0])//根据操作ID跳到不同的操作函数

{

case 0x00:

RstPro();break; / /编程器复位

case 0x01:

ReadSign();break; //读特征字

case 0x02:

Erase();break;//擦除器件

case 0x03:

Write();break;//写器件

case 0x04:

Read();break;//读器件

case 0x05:

Lock();break;//写锁定位

default: SendData();break;

}

}

}

void InitSerial(void)

{

TMOD = 0x20; // T1 方式2

PCON=0x00; // PCON=00H,SMOD=0 PD = PCON.2 = 1 进入掉电模式

相关推荐
相关主题
热门推荐