51单片机串口通信实例
- 格式:doc
- 大小:59.00 KB
- 文档页数:8
51单片机串口通信及通信实例串口通信(SerialCommunicaTIons)的概念非常简单,串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
它很简单并且能够实现远距离通信。
比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
典型地,串口用于ASCII 码字符的传输。
通信使用3根线完成,分别是地线、发送、接收。
由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
其他线用于握手,但不是必须的。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通信的端口,这些参数必须匹配。
a,波特率:这是一个衡量符号传输速率的参数。
指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。
一般调制速率大于波特率,比如曼彻斯特编码)。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。
如何设置取决于你想传送的信息。
比如,标准的ASCII码是0~127(7位)。
扩展的ASCII码是0~255(8位)。
如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。
每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。
由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
51单片机串口通信实例一、原理简介51 单片机内部有一个全双工串行接口。
什么叫全双工串口呢?一般来说,只能接受或只能发送的称为单工串行;既可接收又可发送,但不能同时进行的称为半双工;能同时接收和发送的串行口称为全双工串行口。
串行通信是指数据一位一位地按顺序传送的通信方式,其突出优点是只需一根传输线,可大大降低硬件成本,适合远距离通信。
其缺点是传输速度较低。
与之前一样,首先我们来了解单片机串口相关的寄存器。
SBUF 寄存器:它是两个在物理上独立的接收、发送缓冲器,可同时发送、接收数据,可通过指令对SBUF 的读写来区别是对接收缓冲器的操作还是对发送缓冲器的操作。
从而控制外部两条独立的收发信号线RXD(P3.0)、TXD(P3.1),同时发送、接收数据,实现全双工。
串行口控制寄存器SCON(见表1) 。
表1 SCON寄存器表中各位(从左至右为从高位到低位)含义如下。
SM0 和SM1 :串行口工作方式控制位,其定义如表2 所示。
经验分享:学习单片机重要的是实践,所以开发板是很重要,给大家推荐些淘宝上信誉良好并且软硬件及小零件等、售前售后服务良好的皇冠级金钻店铺给大家,在硬件购买上少走弯路。
按住Ctrl键单击即可:慧净电子单片机(一皇冠)【天津商盟】天津锐志(电子)单片机经营部(两皇冠)金沙滩工作室(5钻)深圳育松电子元件,模块,传感器,批发部:淘宝最全最平价(5皇冠)志宏电子(4钻)表2 串行口工作方式控制位其中,fOSC 为单片机的时钟频率;波特率指串行口每秒钟发送(或接收)的位数。
SM2 :多机通信控制位。
该仅用于方式2 和方式3 的多机通信。
其中发送机SM2 = 1(需要程序控制设置)。
接收机的串行口工作于方式2 或3,SM2=1 时,只有当接收到第9 位数据(RB8)为1 时,才把接收到的前8 位数据送入SBUF,且置位RI 发出中断申请引发串行接收中断,否则会将接受到的数据放弃。
当SM2=0 时,就不管第位数据是0 还是1,都将数据送入SBUF,并置位RI 发出中断申请。
51单片机串口通信(相关例程) 51单片机串口通信(相关例程)一、简介51单片机是一种常用的微控制器,它具有体积小、功耗低、易于编程等特点,被广泛应用于各种电子设备和嵌入式系统中。
串口通信是51单片机的常见应用之一,通过串口通信,可以使单片机与其他外部设备进行数据交互和通信。
本文将介绍51单片机串口通信的相关例程,并提供一些实用的编程代码。
二、串口通信基础知识1. 串口通信原理串口通信是通过串行数据传输的方式,在数据传输过程中,将信息分为一个个字节进行传输。
在51单片机中,常用的串口通信标准包括RS232、RS485等。
其中,RS232是一种常用的串口标准,具有常见的DB-9或DB-25连接器。
2. 串口通信参数在进行串口通信时,需要设置一些参数,如波特率、数据位、停止位和校验位等。
波特率表示在单位时间内传输的比特数,常见的波特率有9600、115200等。
数据位表示每个数据字节中的位数,一般为8位。
停止位表示停止数据传输的时间,常用的停止位有1位和2位。
校验位用于数据传输的错误检测和纠正。
三、串口通信例程介绍下面是几个常见的51单片机串口通信的例程,提供给读者参考和学习:1. 串口发送数据```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_SendChar(unsigned char dat){SBUF = dat; // 发送数据while (!TI); // 等待发送完成TI = 0; // 清除发送完成标志}void main(){UART_Init(); // 初始化串口while (1){UART_SendChar('A'); // 发送字母A}}```2. 串口接收数据```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_Recv(){unsigned char dat;if (RI) // 检测是否接收到数据{dat = SBUF; // 读取接收到的数据 RI = 0; // 清除接收中断标志// 处理接收到的数据}}void main(){UART_Init(); // 初始化串口EA = 1; // 允许中断ES = 1; // 允许串口中断while (1)// 主循环处理其他任务}}```3. 串口发送字符串```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_SendString(unsigned char *str){while (*str != '\0')SBUF = *str; // 逐个发送字符while (!TI); // 等待发送完成TI = 0; // 清除发送完成标志str++; // 指针指向下一个字符}}void main(){UART_Init(); // 初始化串口while (1){UART_SendString("Hello, World!"); // 发送字符串}}```四、总结本文介绍了51单片机串口通信的基础知识和相关编程例程,包括串口发送数据、串口接收数据和串口发送字符串。
原创:51单⽚机串⼝通信(字符串接收和发送)下⾯的⽰例代码基于51单⽚机,⽤于快速⼆次开发实现基于串⼝字符串通信控制程序(⽐如要实现电脑控制单⽚机的开灯和关灯),⽰例很⾔简意赅,并附上了详尽的注释,本⽰例代码经过了更新,新版本代码更加友好了,1 #include<reg52.h>23//------------------串⼝通信的数据包协议-----------------//4/*5此程序的串⼝字符串通信使⽤到下⾯的⼀个⾃定义协议,每次通信都是发送或接收⼀个数据包,数据包格式解释如下(长度恒为15):6例如:A01_fmq_01Off___#7 A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)8 01-----设备代号9 fmq_01Off___--------指令(长度恒为10),指令的前4个⼈字符是指令头部,指令的后6个字符是指令尾部10 #---------数据包的结束标记1112例如:A02_SenT010250#13 A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)14 02-----设备代号15 SenT010250--------指令(长度恒为10),指令的前4个⼈字符是指令头部,指令的后6个字符是指令尾部16 #---------数据包的结束标记17*/18char RecvString_buf[16]; //定义数据包长度为15个字符19#define deviceID_1Bit '0' //⽤于串⼝通信时,定义本地设备ID的第1位20#define deviceID_2Bit '2' //⽤于串⼝通信时,定义本地设备ID的第2位21#define datapackage_headflag 'A' //⽤于串⼝通信时,定义数据包头部的验证标记2223char DataPackage_DS18B20[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','S','e','n','T','X','X','X','X','X','X','#'}; //这个是曾经⽤来控制温度传感模块(DS18B20)的数据包24char HeartBeat[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','B','e','a','t','X','X','X','X','X','X','#'}; //我随便定义了⼀个数据包⽤来做"⼼跳包",⽐如单⽚机系统向电脑每2秒发送⼀次该数据包,如果电脑没有按时接收到,就认为 25//----------------------------------------------//26/*******************************27串⼝通信28 MCU:89C52RC 11.0592MHz2930//11.0592MHz 0xd0 1200bps31//12MHz 0xcc 1200bps32//11.0592MHz 0xfa 9600bps33//0xf4 11.0592MHz 0xf3 12MHz 4800bps34//均在SMOD=1的情况下(波特率倍增模式)35*******************************/36//串⼝发送函数37void PutString(unsigned char *TXStr)38 {39 ES=0;40while(*TXStr!=0)41 {42 SBUF=*TXStr;43while(TI==0);44 TI=0;45 TXStr++;46 }47 ES=1;48 }49//串⼝接收函数50 bit ReceiveString()51 {52char * RecStr=RecvString_buf;53char num=0;54 unsigned char count=0;55 loop:56 *RecStr=SBUF;57 count=0;58 RI=0;59if(num<14) //数据包长度为15个字符,尝试连续接收15个字符60 {61 num++;62 RecStr++;63while(!RI)64 {65 count++;66if(count>130)return0; //接收数据等待延迟,等待时间太久会导致CPU运算闲置,太短会出现"数据包被分割",默认count=13067 }68goto loop;69 }70return1;71 }72//定时器1⽤作波特率发⽣器73void Init_USART()74 {75 SCON=0x50; //串⼝⽅式1,使能接收76 TMOD|=0x20; //定时器1⼯作⽅式2(8位⾃动重装初值)77 TMOD&=~0x10;78 TH1=0xfa; //9600bps79 TL1=0xfa;80 PCON|=0x80; //SMOD=181 TR1=1;82 TI=0;83 RI=0;84//PS=1; //提⾼串⼝中断优先级85 ES=1; //开启串⼝中断使能86 }87//⽐较指令头部88 bit CompareCMD_head(char CMD_head[])89 {90 unsigned char CharNum;91for(CharNum=0;CharNum<4;CharNum++) //指令长度为10个字符92 {93if(!(RecvString_buf[CharNum+4]==CMD_head[CharNum]))94 {95return0; //指令头部匹配失败96 }97 }98return1; //指令头部匹配成功99 }100//⽐较指令尾部(start:从哪⾥开始⽐较,quality:⽐较多少个字符,CMD_tail[]:要⽐较的字符串)101 bit CompareCMD_tail(unsigned char start,unsigned char quality,char CMD_tail[])102 {103 unsigned char CharNum;104for(CharNum=0;CharNum<quality;CharNum++)105 {106if(!(RecvString_buf[start+CharNum]==CMD_tail[CharNum]))107 {108return0;109 }110 }111return1;112 }113 bit Deal_UART_RecData() //处理串⼝接收数据包函数(成功处理数据包则返回1,否则返回0)114 {115//PutString(RecvString_buf);116if(RecvString_buf[0]==datapackage_headflag&&buf_string[14]=='#') //进⾏数据包头尾标记验证117 {118switch(RecvString_buf[1]) //识别发送者设备ID的第1位数字119 {120case'0':121switch(RecvString_buf[2]) //识别发送者设备ID的第2位数字122 {123case'3':124if(CompareCMD_head("Ligt")) //判断指令头部是否为"Ligt"125 {126//下⾯是指令尾部分析127switch(RecvString_buf[8])128 {129case'0':130switch(RecvString_buf[9])131 {132case'0':133134return0;135case'1':136if(CompareCMD_tail(10,3,"Off")) //判断整个数据包是否为:A03_Ligt01Off_#137 {138//如果是则执⾏以下代码139return1;140 }141if(CompareCMD_tail(10,3,"On_")) //判断整个数据包是否为:A03_Ligt01On__#142 {143//如果是则执⾏以下代码144return1;145 }146return0;147default:148return0;149 }150default:151return0;152 }153 }154return0;155156default:157return0;158 }159default:160return0;161 }162 }163return0;164 }165/************************166中断函数167************************/168//串⼝中断服务函数-----------169void USART() interrupt 4//标志位TI和RI需要⼿动复位,TI和RI置位共⽤⼀个中断⼊⼝170 {171if(ReceiveString())172 {173//数据包长度正确则执⾏以下代码174 Deal_UART_RecData();175 }176else177 {178//数据包长度错误则执⾏以下代码179//LED1=~LED1;180 }181 RI=0; //接收并处理⼀次数据后把接收中断标志清除⼀下,拒绝响应在中断接收忙的时候发来的请求182 }183/***************************184主函数185***************************/186void main()187 {188 EA=1; 189 Init_USART(); //初始化串⼝中断通信,当串⼝接受完数据包后,如果检测到数据包包含有效指令,则⾃动执⾏对应的代码,执⾏完⾃动返回到主函数,为了尽可能不影响主函数的时序,串⼝中断函数的执⾏代码不要过复杂190while(1)191 {192//下⾯可以放要经常运⾏的⽤户代码,使⽤PutString()函数来发送数据包,如PutString(HeartBeat); 注:空格的ASCLL码是:0x20,回车是:0x0D193194195 }196 }。
51单片机与PC机串口通信的仿真与实现作者:李健来源:《电脑知识与技术》2018年第32期摘要:介绍了利用几种常见软件实现的51单片机与PC机串口通信的仿真过程,可以在单片机课程的理论教学中加以应用,具有效率高、成本低等优点,有助于教师的教学和学生对知识的掌握和应用。
关键词:51单片机;PC机;串口通信;仿真中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2018)32-0038-02在实际应用中,单片机与PC机间的通信非常普遍[1]。
这时单片机主要完成现场数据采集和设备监控[2],PC机接收单片机发来的数据进行分析、处理,并对结果再次发送单片机进行现场控制等。
笔者在单片机课程的理论教学中,由于课堂上受到条件的约束,采用了纯软件的方法对单片机串口通信进行仿真和演示,便于实现和让学生理解。
下面通过一个实例来介绍51单片机与PC机之间串口通信的仿真与实现过程。
1 所需软件使用到的软件有:VSPD、Proteus、Keil和串口助手[3]。
VSPD是一个虚拟串口小软件,可以虚拟出一对串行接口用于仿真;Proteus是一款流行的单片机仿真软件,用于建立串口通信仿真电路;Keil是用于编写单片机程序的软件;串口助手是用于上位机即PC机的软件,用来向单片机发送数据,或者接收单片机发送来的数据并进行显示。
2 设计与仿真过程预期实现的功能为:PC机通过串口助手向单片机发送一个字节数据,单片机接收到后将数据的二进制形式通过八个数码管的亮灭显示出来,接收的“1”对应的灯亮,接收的“0”对应的灯灭。
同时单片机将接收的数据发回给PC机,PC机将数据在串口助手中再显示出来。
2.1 利用Proteus设计仿真电路如图1所示,在Proteus软件中选用AT89C51单片机、COMPIM、电阻和发光二极管组成仿真电路。
COMPIM在仿真中相当于PC机上配置的RS232标准串行接口,为D型九针插座[4]。
在实际中,单片机和PC机之间需要通过MAX232芯片进行电平转换才能连接,但在仿真图中可以直接将两者的RXD(接收数据)和TXD(发送数据)连接起来进行串行通信。
51 单片机串口多机通信的实现和编程
一、51 单片机的主从模式,首先要设定工作方式3:(主从模式+波特率可变)
SCON 串口功能寄存器:SM0=1;SM1=1(工作方式3)
注:主机和从机都要为工作方式3。
【工作方式2 (SM0 SM1 :1 0):串行口为11 位异步通信接口。
发送或接收
一帧信息包括1 位起始位0、8 位数据位、1 位可编程位、1 位停止位1。
发
送数据:发送前,先根据通信协议由软件设置TB8 为奇偶校验位或数据标识位,然后将要发送的数据写入SBUF,即能启动发送器。
发送过程是由执行任何一条以SBUF 为目的寄存器的指令而启动的,把8 位数据装入SBUF,
同时还把TB8 装到发送移位寄存器的第9 位上,然后从TXD(P3.1)端口输出
一帧数据。
接收数据:先置REN=1,使串行口为允许接收状态,同时还要将RI 清0。
然后再根据SM2 的状态和所接收到的RB8 的状态决定此串行口在
信息到来后是否置R1=1,并申请中断,通知CPU 接收数据。
当SM2=0 时,
不管RB8 为0 还是为1,都置RI=1,此串行口将接收发送来的信息。
当
SM2=1 时,且RB8=1,表示在多机通信情况下,接收的信息为地址帧, 此时
置RI=1,串行口将接收发来的地址。
当SM2=1 时,且RB8=0,表示在多机通
信情况下,接收的信息为数据帧, 但不是发给本从机的,此时RI 不置为1,。
51系列串口通讯例程.rar > serial.c,1.// 题目:串口初始化C代码2.// 要求:3.// 1.波特率1200bps,无奇偶校验,停止位1,数据位84.// 2.定时器T1做波特率发生器5.// 软件模拟测试说明:6.// 1.这个测试采用查询方式进行串口通讯7.// 2.将软件仿真环境的晶震设为11.0592 MHz8.// 3.软件模拟全速运行, 观察波特率是1200bps9.// 4.在串口1中输入数字或字母,可观察到通讯是否有误。
10.//#pragma src11.#include <REG51.H>12.//串口初始化13.void serial_init(void)14.{15.//ET1 = 0; //CLR 0ABH ;禁止T1中断16. TMOD = 0x20; //MOV 89H,#20H ;timer 1 mode 2: 8-Bit reload(定时器T1 模式2: 8位自动初值重装)17. TH1 = 0xE8; //MOV 8DH,#0E8H18. TL1 = 0xE8; //MOV 8BH,#0E8H ;1200bps, 11.05919. TR1 = 1; //SETB 8EH ;启动定时器120. SCON = 0x50; // mode 1: 10-bit UART, enable receiver//(模式1: 10位异步发送/接收, 使能接收允许位)21.//SM1 = 1; // ;串行口模式122.//SM0 = 0;23.//REN = 1; // ;允许串行中断接收24. SM2 = 1; //SETB O9DH ;收到有效的停止位时才将RI置125. ES = 1; //SETB 0ACH ;允许串行中断26. EA = 1; //SETB 0AFH ;总中断开27.}28.//中断方式处理串口数据29.void serial(void) interrupt 4 using 130.{31.if(RI)32. {33.// RI = 0;34.// 串口接收, 采用临时缓冲35. }36.#if 037.if(TI)38. {39.// TI = 0;40.// 串口发送, 没有必要使用中断方式41. }42.#endif43.}44.// 查询方式接收串口数据45.unsigned char getchar(void)46.{47.while(!RI);// 没有收到串口数据则一直等待48. RI=0;49.return SBUF;50.}51.// 查询方式发送串口数据52.void putchar(unsigned char ch)53.{54. SBUF=ch;55.while(!TI);56. TI=0;57.}58.code unsigned char HEX_TAB []="0123456789ABCDEF";59.void puthex(unsigned char ch)60.{61. unsigned char i,j;62. i=ch>>4;63. j=ch&0x0f;64. putchar(HEX_TAB[i]);65. putchar(HEX_TAB[j]);66.}51系列串口通讯例程.rar > test.c1.// 采用查询方式进行串口通讯的例子2.// 采用这种方式的弊端:3.// 1.如果对方没有发送数据,则本机无限等待,而不能做其它事情4.// 2.如果对方发送数据而本机正做其它事情,那么有可能丢失数据。
//工作晶振为11.0592MHz,否则出现返回值错误,一个字节的发送#include<regx52.h〉#define uchar unsigned char#define uint unsigned intuchar a,flag;uchar table[]={”very good "};//-———---—-——初始化定时器和串口-void inital_timer1(){TMOD=0X20;//必须使用定时器1,串口使用规定TH1=0Xfd;//定时器1,工作方式2,8位自动重装TL1=0Xfd;//高8位与低8位数值必须相同TR1=1; //定时器1允许位REN=1; //串口使能SM0=0;//串口工作方式设置,工作方式1SM1=1;ES=1; //串口中断使能EA=1; // 总中断使能}//——-—-—————串口中断——--—--—-void gorpe() interrupt 4{RI=0;//接受中断标志位,硬件置1,必须软件置0 a=SBUF;// 特殊功能寄存器flag=1;// 检测标志位}//————-接收数据,并向上位机作出反应(即发送返回数据)—--void display(){uchar i;if(flag==1){ES=0;//关闭串口中断,接下来要发送数据,否则发送完一个数据仍会产生中断,产生死循环for(i=0;i〈10;i++){SBUF=table[i];while(!TI);//判断是否发送完成TI=0;//发送中断标志位}SBUF=a;while(!TI);TI=0;ES=1;flag=0;}}。
51单片机串口通信例子小记:本例子是在别人的版本修改而来的,因本人没有11.0592MHz的晶振,进而采用12MHz的,经过波特率的调整发现在波特率为1200时,定时器工作在方式二,穿口工作在模式二,且SMOD=1.此时定时器的TH1=TL1=0xCC,此时调试串口没有错误。
发送例子:#include<reg52.h>#include<stdio.h>void delay(unsigned int i);char code message[]="welcome";unsigned char a;void main(void){SCON=0x50; //REN=1 ,串口工作模式2;TMOD=0x20; //定时器工作方式2;PCON=0x80;TH1=0xCC;TL1=0xCC;TR1=1;//启动定时器ES=1; //串行中断允许EA=1;//开总终端while(1){a=0;while(message[a]!='\0'){SBUF=message[a];while(!TI) //等待一帧数据(一个字符)发完,TI置1,TI=0; //让TI为0就继续接收,直至跳出while。
a++; //接收下一字符delay(1000);}}void delay(unsigned int i){unsigned char j;for(i;i>0;i--)for(j=200;j>200;j--);}接收例子:#include<reg52.h>#include<stdio.h>sbit BEEP=P1^4;unsigned char b;void main(void){.................BEEP=1;while(1){if(RI==1) //如果一帧数据接收完毕{RI=0; //RI清零;继续接收下一帧数据P1=SBUF; //数据送P1口}} //如果P1^4为0或1,可驱动蜂鸣器发声} //即发送的数据bit4为0或1发送加接收例子:#include<reg52.h>bit flag;unsigned int redata,sendata;void main(void){..................while(1){if(flag==1){SBUF=sendata; //发送数据while(TI==0);//等待发送完毕TI=0; //发送完毕,TI=0flag=0; //flag清零}}}void ser_int(void) interrupt 4 using 1 {if(RI==1) //数据接收完毕{RI=0; //等待接收下一帧数据redata=SBUF;sendata=redata; //将接收的数据发回flag=1; //flag置1,发回接收数据}}。
51系列单片机串口通信实例教程
单片机的串口通信看起来是很复杂的,主要是因为他用到了更多的寄存器,与前面的知识相比他更具综合能力,写起来考虑的问题自然也变多了.而前面学习过的定时器与中断将是单片机通信的基础.
单片机的中断系统中第4个中断就是串口中断,要进行串口通信首先就要打开CPU 总中断EA,还要打开串口通信中断ES,这是串口通信的前堤,而串口通信也跟计时器一样有很多的模式,因此我们还要设置SCON寄存器来指定采用哪一种方式进行通信,而在通信的过程中,我们还要设定通信的波特率,不然的话,单片机是没办法进行采样的,这样也不会得到正确的结果了.我在实验过程中用到的是1号定时器来设定的波特率,用到了计时器方式2,也就是8位自动重装,这样可以简化编程,它的实现思想就是将常数放入TH,而TL中则是初始化参数,当溢出时,单片机会自动将TH中的常数装入TL中.
再来说说波特率,我们为什么要设定波特率,因为单片机会以16倍波特率的速度进行采样,而在实验中我们用的是10位异步收发方式,因此要将SM0置0,SM1置1.而其中的1 0位有8位数据位,第一位和最后一位是发送数据的起始与结束.采用高的皮特率就不会出错啦.而波特率是有一个公式的:
方式0的波特率 = fosc/12
方式2的波特率 =(2SMOD/64)· fosc
方式1的波特率 =(2SMOD/32)·(T1溢出率)
方式3的波特率 =(2SMOD/32)·(T1溢出率)
T1 溢出率= fosc /{12×[256 -(TH1)]}
根据公式我们很容易就算出当晶振为110592HZ时,要达到9600的波特率,我们只需要将TL1置FDH即可,如下图:
除此之外,你还要将SCON中的REN位置1,不然的话,单片机是不会接收数据的.
还有不要忘了选择定时器的工作方式,设置TMOD为0x20既是工作方式2,8位自动重装定时器.
这样一来,初始批工作算是差不多了.而串口通信分为中断方式,和查询方式,如果你想用查询方式你也不用设置IE寄存器了.
在串口通信中,还有一个很重要的寄存器SBUF,其实也不是一个,是两个,只是它们共用同一个地址,再根据表达式的不同,单片机会自动选择使用哪一个SBUF.
下面是我写的一个例子程序,产生的效果是:向单片机发送任一个0~255之间的数,将会被显
示到数码管上.并且单片机还会自动把刚才传过去的数又发送回来 ,实验过程中用到了几个工具如下:
串口调试助手V2.1.exe,51串口波特率计算器.exe(我已打包在附件中)还有一些必用的就不说了.
C代码
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit sda = P1^0;
sbit clk = P1^1;
sbit dig1 = P1^2;
sbit dig2 = P1^3;
sbit dig3 = P1^4;
sbit dig4 = P1^5;
uchar r,flag;
uchar code table[]={0x7e,0x0c,0xb6,0x9e,
0xcc,0xda,0xfa,0x0e,
0xfe,0xde,0xef,0xf9,
0x72,0xb8,0xf2,0xe2};
void init();
void write(uchar);
void display(uchar);
void delay(uchar);
void main()
{
init();
while(1)
{
//查询方式通信
//if(RI==1) //RI为1表示收到一字节数据
//{
// RI = 0;//此步必不可少,因为硬件不能将其置0 // r = SBUF;
//}
display(r); //中断方式通信
delay(10);
if(flag==1)
{
flag = 0;
ES = 0;
SBUF = r; //放送数据
while(!TI);
TI = 0;
ES = 1;
}
}
/** 串口中断 **/
void ser() interrupt 4 {
RI = 0;
r = SBUF;
flag = 1;
}
/** 延迟函数 **/
void delay(uchar t) {
uchar x,y;
for(x=t;x>0;x--)
for(y=101;y>0;y--);
}
/** 初始化 **/
void init()
{
dig1 = 1;
dig2 = 1;
dig3 = 1;
dig4 = 1;
r = 0xff;
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1; //启动定时器1,从而设定了串口通信的波特率SM0 = 0;
SM1 = 1; //设定串口通信方式为十位异步收发器
REN = 1; //打开串口通信
EA = 1;
ES = 1;
}
/** 向数据码管写入一个字节数据 **/
void write(uchar u)
{
uchar i;
for(i=0;i<8;i++)
{
clk = 1;
sda = u&0x80;
clk = 0;
u = u<<1;
}
}
/** 显示一个3位的整数 **/
void display(uchar num)
{
uchar bai,shi,ge; bai = num/100;
shi = num%100/10; ge = num%10;
/* 显示个位 */
dig4 = 0;
write(table[ge]); delay(10);
dig4 = 1;
/* 显示百位 */
if(bai!=0)
{
dig2 = 0;
write(table[bai]); delay(10);
dig2 = 1;
/* 显示十位 */
dig3 = 0;
write(table[shi]); delay(10);
dig3 = 1;
}
else
{
if(shi==0)
{
dig3 = 1;
//delay(10);
}
else
{
/* 显示十位 */
dig3 = 0;
write(table[shi]); delay(10);
dig3 = 1;
}
}
}。