51单片机的串行通讯程序Word文件下载.docx

上传人:b****5 文档编号:19411889 上传时间:2023-01-06 格式:DOCX 页数:16 大小:514.21KB
下载 相关 举报
51单片机的串行通讯程序Word文件下载.docx_第1页
第1页 / 共16页
51单片机的串行通讯程序Word文件下载.docx_第2页
第2页 / 共16页
51单片机的串行通讯程序Word文件下载.docx_第3页
第3页 / 共16页
51单片机的串行通讯程序Word文件下载.docx_第4页
第4页 / 共16页
51单片机的串行通讯程序Word文件下载.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

51单片机的串行通讯程序Word文件下载.docx

《51单片机的串行通讯程序Word文件下载.docx》由会员分享,可在线阅读,更多相关《51单片机的串行通讯程序Word文件下载.docx(16页珍藏版)》请在冰豆网上搜索。

51单片机的串行通讯程序Word文件下载.docx

第一,初始化串口的波特率

中颖8051中,波特率可以设置为系统时钟的分频或定时器的分频。

设置注意事项及规则如下:

A.波特率不能等于系统时钟频率或定时器溢出率,只能为其分频值。

B.当为串口方式1或3时,波特率发生器通过T2CON的TCLK和RCLK来选择。

TCLK

和RCLK为1时,选Timer2;

TCLK和RCLK为0时,选Timer1。

C.当使用EUART1时,不能使用Timer1产生波特率。

不管TCLK和RCLK为1或0,

波特率发生器都为定时器2。

但是当TCLK或RCLK为1时,波特率为TCLK或RCLK

为0时的波特率的二分频。

D.UART工作在不同的工作方式下,波特率发生器有所不同,具体内容如下:

方式0时,波特率固定,波特率发生器为系统时钟的分频。

当SM2=1时,波特率为系

统时钟的4分频;

当SM2=0时,波特率为系统时钟的12分频。

当使用32.768K并PLL

倍频后,系统时钟为8.192MHZ

当为方式1时,波特率可变,通过设置TCLK和RCLK来选择Timer1或Timer2作为波

特率发生器。

通过SMOD位(二倍频控制位)来选择分频值。

当SMOD=1时,波特率为定时

器1或2溢出率/32的二倍频,即16分频;

当SMOD=0时,波特率为定时器1或2溢

出率的32分频。

当为方式2时,波特率固定,波特率发生器为系统时钟的分频。

通过SMOD位(二倍频控

制位)来选择分频值。

当SMOD=1时,波特率为系统时钟/64的二倍频,即32分频;

当SMOD=0时,波特率为系统时钟的64分频。

当为方式3时,波特率可变,通过设置TCLK和RCLK来选择Timer1或Timer2作为波

小结一下:

1.串口方式0和方式2为不可变波特率,方式1和方式3为可变波特率,可变值由T1或

T2控制

2.中颖单片机只用一个串口0时,可选T1或T2作为波特率发生器。

3.中颖单片机使用两个串口时,T1为串口0波特率发生器,T2为串口1的波特率发生器。

第二,初始化串口的控制器SCON和其它部分(比如中断和波特率加倍位等)

串口0的控制寄存器为SCON,串口1的控制寄存器为SCON1,其内容与51的相同,但要注

意中颖51的串口为与其它功能复用,因而要将管脚配置好方向,输入引脚配置好上拉电阻,

而输出引脚全部输出为高电平1,这样才能可靠的发送,发送完成后,状态符合串行通讯的

要求。

Demo程序如下,采用定时器1作波特率发生器,也适用于普通51单片机使用。

串口初始化示例程如下,以中颖79F32平台验证,在8.192M系统时钟时,波特率为9600

/****************************************************************************

voidInitSys(void)

功能说明:

系统寄存器初始化

其他说明:

Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0

IEN0EAEADCET2ES0ET1EX1ET0EX0

IEN1EFCOFEI2CEPWMESCMEHSECES1EX2ESPI

输入:

输出:

*****************************************************************************/

{

P0SS=Bin(00000000);

//P0asio

P1SS=Bin(00000000);

//P1asio

P0CR=Bin(00000000);

P0PCR=Bin(00000000);

P0=Bin(00000000);

P1CR=Bin(00000000);

P1PCR=Bin(00000000);

P1=Bin(00000000);

P2CR=Bin(00000000);

P2PCR=Bin(00000000);

P2=Bin(00000000);

//将P30,P31初始化为串行通讯口

P3CR=Bin(00000010);

P3PCR=Bin(00000001);

P3=Bin(00000011);

P4CR=Bin(00000000);

P4PCR=Bin(00000000);

P4=Bin(00000000);

/*--------------------EUART初始化-------------------*/

TR0=0;

TR1=0;

//stoptimer1

TR2=0;

//stoptimer2

//----------------------------------------------------

TF0=0;

TF1=0;

//TMOD=Bin(00010001);

//设置Timer1为定时模式,工作方式一

(16bit,用于)

//定时器1为8位自装载,波特率发生器功能

TMOD=Bin(00100001);

TL0=LOBYTE(CLOCK_1MS);

TH0=HIBYTE(CLOCK_1MS);

//TL1=LOBYTE(CLOCK_1MS);

//TH1=HIBYTE(CLOCK_1MS);

TH1=0xe5;

TL1=0xe5;

TF2=0;

//T2MOD=Bin(00000000);

//设置Timer2用于产生波特率(baudrate

generator)

//T2CON=Bin(00110000);

//设置串口通讯方式为8位异步通讯,波特率可变。

SCON=Bin(01010000);

//RCAP2L=LOBYTE(UART_BAUDRATE);

//TL2=LOBYTE(UART_BAUDRATE);

//RCAP2H=HIBYTE(UART_BAUDRATE);

//TH2=HIBYTE(UART_BAUDRATE);

TR0=1;

TR1=1;

//starttimer1

//TR2=1;

//starttimer2

//开启EUART和Timer0中断

IEN0=Bin(00010010);

//IEN0=Bin(00000010);

//禁止串行中断

IEN1=Bin(00000000);

TI=1;

}

三、如何将程序中的变量内容输出到串行口

在程序调试过程中,出现了问题,用仿真器跟踪当然是最直接和高效的方法,但如果

没有仿真器,较好的方法是将相关的变量全部输出到串口,然后通过PC机上的串口调试助

手软件来查看相关内容。

通过对关键变量的查看结合源程序分析,很快能找到BUG所在。

软件中的变量常用的有好几种类型。

那是否有通用的函数能完成将此变量的信息通过串

口送PC来监视呢?

C-51有这样的现成函供供您调用。

它就是我要隆重向您推荐的printf()

库函数,学过PC机上的C语言的同学对此应该比较熟悉。

使用printf前要做以下几个工作

1.初始化串口波特率和模式,并置TI为1;

2.在源程序中包含<

stdio.h>

头文件。

3.如果是定时器1作为波特率发生器,还可通过Keil-C51软件仿真先在IDE的虚拟

设备串口上看看printf()的工作情况

做好前面的工作后就可输出变量内容了。

字符型变量的输出用如下语句

printf(“字符变量X的值为:

%d\n”,(unsignedint)ucTemp);

其中ucTemp为一个字节

型的变量

整型变量的输出用如下语句

printf(“整形变量X的值为:

%d\n”,uiTemp);

其中uiTemp为一个整形变量

长整型变量(4字节)的输出用如下语句

printf(“长整形变量X的值为:

%ld\n”,ulTemp);

其中ulTemp为一个长整形变量

串口输出程序中的变量的Demo程序如下(在中颖79F32评估板上测试通过)

#defineucharunsignedchar

#defineuintunsignedint

#defineulongunsignedlong

voidmain(void)

ucharucCount;

uintuiCount;

ulongulCount;

EA=0;

RSTSTAT=0x00;

//feedwatchdog

InitSys();

EA=1;

ucCount=0;

uiCount=0;

ulCount=0;

while

(1)

printf("

HolleWorld!

\n"

);

ucCountValueis%d\n"

(uint)ucCount);

uiCountValueis%d\n"

uiCount);

ulCountValueis%ld\n\n"

ulCount);

ucCountValueis%02x\n"

uiCountValueis%04X\n"

ulCountValueis%l08X\n\n"

ucCount++;

uiCount++;

ulCount++;

测试过程中的电脑屏幕截图如下:

可在中颖79F32评估版上直接调试和验证的完整工程项目详见压缩包。

四、如何编程实现串口数据包的接收与发送

l串口数据通讯,比较实用的模式有两种

4.1发送和接收都采用中断模式

发送和接收操作都要设数据缓冲区,占用内存较大,但CPU的利用效率最高,无空耗

情况发生。

4.2发送采用查询,接收采用中断

当设备要向外发送数据时,由于发送的数据的数量是已知的,因而在特定的波特率下,完

成发送操作的时间也是可以预测的。

因而采用查询操作发送可简化发送数据过程,减小内存

的占用。

数据接收只有采用中断方式才能高效可靠,应用中CPU通常要完成基本功能的运转,只

有在收到串口命令时才临时解析命令,完成相应的功能,完成后还有基本功能要做。

l串口数据通讯时常采用的封包技术

串口通讯时,通常将数据内容组织成一个数据包,才能完成应用层相关协议的功能。

通常的

包包括“包头+数据内容+校验内容+包尾”构成。

例如,我们在产品中常用的联机命令如下

1B10000188//其中1B10为包头,00为约定的命令号01为后续数据的长度,88为包

尾字符。

l接收和解析数据包采用状态机较易实现

针对以上介绍的数据包,我们可以定义以下几种状态

#definec_UART_RCV_Status_Idle0//空闲态

#definec_UART_RCV_Status_Head01//接收到包头字符0后进入的状态

#definec_UART_RCV_Status_Head12//接收到包头字符1后进入的状态

#definec_UART_RCV_Status_CMD3//接收到命令字符后进入的状态

#definec_UART_RCV_Status_DataLength4//接收到数据长度后进入的状态

#definec_UART_RCV_Status_DataContent5//接收指定长度的数据内容的状态

//#definec_UART_RCV_Status_PackageTail6//接收包尾数据

#definec_UART_RCV_Status_ReceiveEnd7//数据接收完成的状态

为了保存接收到的数据和控制状态机的切换,还要定义如下几个数据结构变量

ucharucRCV_StatusMachineValue;

//定义串口接收状态机的当前状态值

ucharucRCV_CommandValue;

//定义无符号字符型的串口数据命令字

ucharucRCV_DataLength;

//定义附加数据体的长度。

#definec_MaxDataLength16//定义串口数据的最大长度

ucharucRCV_DataBuff[c_MaxDataLength];

//定义用于保存串口接收数据的缓冲区

uchar*pucDataBuff;

//定义用于操纵串口缓冲区的指针

boolbCOM_ReceivePackageEndFlag;

//串口接收数据完成时的标志位

其它常量定义如下

#definec_PackageHead00x1B

#definec_PackageHead10x10

#definetrue1

#definefalse0

建立在上述数据结构上的功能实现

/**************************************************************************

**

voidEUART0_ISP(void)interrupt4

串口通讯中断响应程序

TI1---发送完一个字节

RI1---接收完一个字节

***************************************************************************

**/

EA=0;

UartInterface();

EA=1;

串口数据中断处理函数如下,实现状态的跳转与数据的保存

voidUartInterface(void)

串口通讯接收、发送处理程序

ucharucReceiveData;

//临时存储串口接收到的数据内容

/*--------------------------数据发送--------------------------*/

if(TI)//发送完一个数据

//是发送数据完成后的中断,不做处理,采用查询方式发送

/*--------------------------数据接收--------------------------*/

if(RI)//接收完一个数据

ucReceiveData=SBUF;

RI=0;

switch(ucRCV_StatusMachineValue)

casec_UART_RCV_Status_Idle:

if(ucReceiveData==c_PackageHead0)

ucRCV_StatusMachineValue=c_UART_RCV_Status_Head0;

break;

casec_UART_RCV_Status_Head0:

if(ucReceiveData==c_PackageHead1)

ucRCV_StatusMachineValue=c_UART_RCV_Status_CMD;

pucDataBuff=ucRCV_DataBuff;

//将指针指向串口数据缓冲区的

首端

casec_UART_RCV_Status_CMD:

//合法性检查及数据的保存操作

ucRCV_CommandValue=ucReceiveData;

*pucDataBuff++=ucReceiveData;

//跳转到下一状态

ucRCV_StatusMachineValue=c_UART_RCV_Status_DataLength;

casec_UART_RCV_Status_DataLength:

ucRCV_DataLength=ucReceiveData;

//避免指针越界的冗余设计

if(ucRCV_DataLength>

c_MaxDataLength-2)

ucRCV_DataLength=c_MaxDataLength-2;

ucRCV_StatusMachineValue=c_UART_RCV_Status_DataContent;

casec_UART_RCV_Status_DataContent:

//数据包中的附加变长数据体内容存入缓冲区

0)

ucRCV_DataLength--;

if(ucRCV_DataLength==0)

//串口接收数据包完成的标芯位置位

//通知主进程进行串口数据包的处理

bCOM_ReceivePackageEndFlag=true;

//接收完最后一个字符.

ucRCV_StatusMachineValue=

c_UART_RCV_Status_ReceiveEnd;

casec_UART_RCV_Status_ReceiveEnd:

//接收数据溢出时的处理,可报警或点灯

default:

//默认的处理,防错

ucRCV_StatusMachineValue=c_UART_RCV_Status_Idle;

//主进程循环监测数据包接收是否完成,并执行喂狗操作。

voidUARTProcess(void)

数据接收完成处理

当数据接收完成,进行接收完成处理

//processofuart

bCOM_ReceivePackageEndFlag=false;

if(_testbit_(bCOM_ReceivePackageEndFlag))//是否接收完一

个数据包

UartDecode();

下面再讲一下查询方式发送数据到串口的相关代码

//通过串口发送一字

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1