1、第一, 初始化串口的波特率中颖 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. UAR
2、T 工作在不同的工作方式下,波特率发生器有所不同,具体内容如下:方式 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 时,
3、波特率固定,波特率发生器为系统时钟的分频。通过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的波特率发生器。第二, 初始化串口的
4、控制器 SCON和其它部分(比如中断和波特率加倍位等)串口0 的控制寄存器为SCON,串口1 的控制寄存器为SCON1,其内容与51 的相同,但要注意中颖51 的串口为与其它功能复用,因而要将管脚配置好方向,输入引脚配置好上拉电阻,而输出引脚全部输出为高电平1,这样才能可靠的发送,发送完成后,状态符合串行通讯的要求。Demo 程序如下,采用定时器1作波特率发生器,也适用于普通51单片机使用。串口初始化示例程如下,以中颖 79F32平台验证,在8.192M系统时钟时,波特率为9600/*void InitSys(void)功能说明: 系统寄存器初始化其他说明: Bit7 Bit6 Bit5 Bi
5、t4 Bit3 Bit2 Bit1 Bit0IEN0 EA EADC ET2 ES0 ET1 EX1 ET0 EX0IEN1 EFCOF EI2C EPWM ESCM EHSEC ES1 EX2 ESPI输入: 无输出:*/P0SS = Bin(00000000); /P0 as ioP1SS = Bin(00000000); /P1 as ioP0CR = Bin(00000000);P0PCR = Bin(00000000);P0 = Bin(00000000);P1CR = Bin(00000000);P1PCR = Bin(00000000);P1 = Bin(00000000);P2
6、CR = 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; /stop timer1TR2 = 0; /stop timer2/-TF0 = 0;TF1 = 0;/ TMOD = Bin(00
7、010001); /设置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 用于产生波特率(baudrategenerator)/ T2CON = Bin(00110000);/设
8、置串口通讯方式为8位异步通讯,波特率可变。SCON = Bin(01010000);/ RCAP2L = LOBYTE(UART_BAUDRATE);/ TL2 = LOBYTE(UART_BAUDRATE);/ RCAP2H= HIBYTE(UART_BAUDRATE);/ TH2 = HIBYTE(UART_BAUDRATE);TR0 = 1;TR1 = 1; /start timer1/ TR2 = 1; /start timer2/开启EUART和Timer0中断IEN0 = Bin(00010010);/ IEN0 = Bin(00000010); /禁止串行中断IEN1 = Bin
9、(00000000);TI = 1;三、如何将程序中的变量内容输出到串行口在程序调试过程中,出现了问题,用仿真器跟踪当然是最直接和高效的方法,但如果没有仿真器,较好的方法是将相关的变量全部输出到串口,然后通过PC 机上的串口调试助手软件来查看相关内容。通过对关键变量的查看结合源程序分析,很快能找到BUG所在。软件中的变量常用的有好几种类型。那是否有通用的函数能完成将此变量的信息通过串口送PC 来监视呢?C-51 有这样的现成函供供您调用。它就是我要隆重向您推荐的printf()库函数,学过PC 机上的C 语言的同学对此应该比较熟悉。使用printf前要做以下几个工作1. 初始化串口波特率和模式
10、,并置TI 为1;2. 在源程序中包含头文件。3. 如果是定时器1 作为波特率发生器,还可通过Keil-C51 软件仿真先在IDE 的虚拟设备串口上看看printf()的工作情况做好前面的工作后就可输出变量内容了。字符型变量的输出用如下语句printf(“字符变量X 的值为:%dn”,(unsigned int )ucTemp);其中ucTemp 为一个字节型的变量整型变量的输出用如下语句printf(“整形变量X 的值为:%dn”,uiTemp); 其中uiTemp 为一个整形变量长整型变量(4 字节)的输出用如下语句printf(“长整形变量X 的值为:%ldn”,ulTemp); 其中u
11、lTemp 为一个长整形变量串口输出程序中的变量的 Demo程序如下(在中颖79F32 评估板上测试通过)#define uchar unsigned char#define uint unsigned int#define ulong unsigned longvoid main(void)uchar ucCount;uint uiCount;ulong ulCount;EA =0;RSTSTAT = 0x00; /feed watchdogInitSys();EA =1;ucCount =0;uiCount = 0;ulCount = 0;while(1)printf(HolleWorld
12、!n);ucCount Value is %dn,(uint)ucCount);uiCount Value is %dn,uiCount);ulCount Value is %ldnn,ulCount);ucCount Value is %02xnuiCount Value is %04XnulCount Value is %l08XnnucCount+;uiCount+;ulCount+;测试过程中的电脑屏幕截图如下:可在中颖79F32评估版上直接调试和验证的完整工程项目详见压缩包。四、如何编程实现串口数据包的接收与发送l 串口数据通讯,比较实用的模式有两种4 1 发送和接收都采用中断模式发
13、送和接收操作都要设数据缓冲区,占用内存较大,但CPU 的利用效率最高,无空耗情况发生。42 发送采用查询,接收采用中断当设备要向外发送数据时,由于发送的数据的数量是已知的,因而在特定的波特率下,完成发送操作的时间也是可以预测的。因而采用查询操作发送可简化发送数据过程,减小内存的占用。数据接收只有采用中断方式才能高效可靠,应用中CPU 通常要完成基本功能的运转,只有在收到串口命令时才临时解析命令,完成相应的功能,完成后还有基本功能要做。l 串口数据通讯时常采用的封包技术串口通讯时,通常将数据内容组织成一个数据包,才能完成应用层相关协议的功能。通常的包包括“包头+数据内容+校验内容+包尾”构成。例
14、如,我们在产品中常用的联机命令如下1B 10 00 01 88 /其中1B 10为包头,00 为约定的命令号01 为后续数据的长度,88 为包尾字符。l 接收和解析数据包采用状态机较易实现针对以上介绍的数据包,我们可以定义以下几种状态#define c_UART_RCV_Status_Idle 0 /空闲态#define c_UART_RCV_Status_Head0 1 /接收到包头字符0 后进入的状态#define c_UART_RCV_Status_Head1 2 /接收到包头字符1 后进入的状态#define c_UART_RCV_Status_CMD 3 /接收到命令字符后进入的状态
15、#define c_UART_RCV_Status_DataLength 4 /接收到数据长度后进入的状态#define c_UART_RCV_Status_DataContent 5 /接收指定长度的数据内容的状态/#define c_UART_RCV_Status_PackageTail 6 /接收包尾数据#define c_UART_RCV_Status_ReceiveEnd 7 /数据接收完成的状态为了保存接收到的数据和控制状态机的切换,还要定义如下几个数据结构变量uchar ucRCV_StatusMachineValue; /定义串口接收状态机的当前状态值uchar ucRCV_C
16、ommandValue; /定义无符号字符型的串口数据命令字uchar ucRCV_DataLength; /定义附加数据体的长度。#define c_MaxDataLength 16 /定义串口数据的最大长度uchar ucRCV_DataBuffc_MaxDataLength; /定义用于保存串口接收数据的缓冲区uchar *pucDataBuff; /定义用于操纵串口缓冲区的指针bool bCOM_ReceivePackageEndFlag; /串口接收数据完成时的标志位其它常量定义如下#define c_PackageHead0 0x1B#define c_PackageHead1 0
17、x10#define true 1#define false 0建立在上述数据结构上的功能实现/*void EUART0_ISP(void) interrupt 4 串口通讯中断响应程序 TI1-发送完一个字节RI1-接收完一个字节*/EA = 0;UartInterface();EA = 1;串口数据中断处理函数如下,实现状态的跳转与数据的保存void UartInterface(void) 串口通讯接收、发送处理程序uchar ucReceiveData; /临时存储串口接收到的数据内容/*-数据发送-*/if(TI) /发送完一个数据/是发送数据完成后的中断,不做处理,采用查询方式发送/
18、*-数据接收-*/if(RI) /接收完一个数据ucReceiveData = SBUF;RI = 0;switch(ucRCV_StatusMachineValue)case c_UART_RCV_Status_Idle:if(ucReceiveData = c_PackageHead0)ucRCV_StatusMachineValue = c_UART_RCV_Status_Head0;break;case c_UART_RCV_Status_Head0:if(ucReceiveData = c_PackageHead1)ucRCV_StatusMachineValue = c_UART_
19、RCV_Status_CMD;pucDataBuff = ucRCV_DataBuff;/将指针指向串口数据缓冲区的首端case c_UART_RCV_Status_CMD:/合法性检查及数据的保存操作ucRCV_CommandValue = ucReceiveData;*pucDataBuff+ = ucReceiveData;/跳转到下一状态ucRCV_StatusMachineValue = c_UART_RCV_Status_DataLength;case c_UART_RCV_Status_DataLength:ucRCV_DataLength = ucReceiveData;/避免
20、指针越界的冗余设计if(ucRCV_DataLength c_MaxDataLength-2)ucRCV_DataLength = c_MaxDataLength-2;ucRCV_StatusMachineValue = c_UART_RCV_Status_DataContent;case c_UART_RCV_Status_DataContent:/数据包中的附加变长数据体内容存入缓冲区 0)ucRCV_DataLength-;if(ucRCV_DataLength = 0)/串口接收数据包完成的标芯位置位/通知主进程进行串口数据包的处理bCOM_ReceivePackageEndFlag
21、= true;/接收完最后一个字符.ucRCV_StatusMachineValue =c_UART_RCV_Status_ReceiveEnd;case c_UART_RCV_Status_ReceiveEnd:/接收数据溢出时的处理,可报警或点灯default:/默认的处理,防错ucRCV_StatusMachineValue = c_UART_RCV_Status_Idle;/主进程循环监测数据包接收是否完成,并执行喂狗操作。void UARTProcess(void) 数据接收完成处理 当数据接收完成,进行接收完成处理/process of uartbCOM_ReceivePackageEndFlag = false;if(_testbit_(bCOM_ReceivePackageEndFlag) ) /是否接收完一个数据包UartDecode();下面再讲一下查询方式发送数据到串口的相关代码/通过串口发送一字
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1