51单片机的串行通讯程序Word文件下载.docx
- 文档编号:19411889
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:16
- 大小:514.21KB
51单片机的串行通讯程序Word文件下载.docx
《51单片机的串行通讯程序Word文件下载.docx》由会员分享,可在线阅读,更多相关《51单片机的串行通讯程序Word文件下载.docx(16页珍藏版)》请在冰豆网上搜索。
第一,初始化串口的波特率
中颖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();
下面再讲一下查询方式发送数据到串口的相关代码
//通过串口发送一字
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 51 单片机 串行 通讯 程序