52单片机串口波特率设置函数
- 格式:doc
- 大小:28.00 KB
- 文档页数:1
51单片机串口通信波特率设置51单片机串口通信波特率设置MCS-51单片机具有一个全双工的串行通信接口,能同时进行发送和接收。
它可以作为UART(通用异步接收和发送器)使用,也可以作为同步的移位寄存器使用。
1. 数据缓冲寄存器SBUFSBUF是可以直接寻址的专用寄存器。
物理上,它对应着两个寄存器,即一个发送寄存器一个接收寄存器,CPU写SBUF就是修改发送寄存器;读SBUF就是读接收寄存器。
接收器是双缓冲的,以避免在接收下一帧数据之前,CPU未能及时的响应接收器的中断,没有把上一帧的数据读走而产生两帧数据重叠的问题。
对于发送器,为了保持最大的传输速率,一般不需要双缓冲,因为发送时CPU是主动的,不会产生重叠问题。
2. 状态控制寄存器SCONSCON是一个逐位定义的8位寄存器,用于控制串行通信的方式选择、接收和发送,指示串口的状态,SCON即可以字节寻址也可以位寻址,字节地址98H,地址位为98H~9FH。
它的各个位定义如下:MSB LSBSM0和SM1是串口的工作方式选择位,2个选择位对应4种工作方式,如下表,其中Fosc是振荡器的频率。
SM2在工作方式2和3中是多机通信的使能位。
在工作方式0中,SM2必须为0。
在工作方式1中,若SM2=1且没有接收到有效的停止位,则接收中断标志位RI不会被激活。
在工作方式2和3中若SM2=1且接收到的第9位数据(RB8)为0,则接收中断标志RB8不会被激活,若接收到的第9位数据(RB8)为1,则RI置位。
此功能可用于多处理机通信。
REN为允许串行接收位,由软件置位或清除。
置位时允许串行接收,清除时禁止串行接收。
TB8是工作方式2和3要发送的第9位数据。
在许多通信协议中该位是奇偶位,可以按需要由软件置位或清除。
在多处理机通信中,该位用于表示是地址帧还是数据帧。
RB8是工作方式2和3中接收到的第9位数据(例如是奇偶位或者地址/数据标识位),在工作方式1中若SM2=0,则RB8是已接收的停止位。
// AM 系列读IIC 使用范例//单片机:AT89S52 或STC89C52RC// 功能:串口发送温湿度数据波特率9600// 晶振:12M (用户系统时钟如不是12M 请更改相关宏定义及注释的延时时间)// 编译环境: Keil3// 公司:奥松电子//****************************************************************//#include "reg52.h"#include <intrins.h>#define USE_T2#define FOSC 12000000#define BAUD 9600//端口位定义,可修改sbit SDA=P1A0;sbit SCL=P"1;//内部数据定义#define IIC_Add 0xB8 //器件地址#define IIC_RX_Length 15unsigned char IIC_TX_Buffer[]={0x03,0x00,0x04}; // 读温湿度命令(无CRC 校验) unsigned char IIC_RX_Buffer[IIC_RX_Length] = {0x00};// 读回的温湿度unsigned char Uart_RX_Buffer[30] = {0x00}; unsigned char *String;unsigned char WR_Flag;//字符串定义#define S_Function "Function: 03 04"#define S_Temp "Temp:"#define S_RH "RH:"#define S_CRCT "CRC: True"#define S_CRCF "CRC: Wrong"#define S_Data "Data: "#define S_NotS "Sensor Not Connected"void Ack(void);void NoAck(void); void delay10us(void) // 这个延时函数要大于5US 以上_nop_(); _nop_(); _nop_();_nop_(); _nop_(); _nop_(); }void delay1ms(unsigned int t){unsigned int i;unsigned int j;for(j=t;j>0;j--) for(i=124;i>0;i--);}void InitUART(void) {unsigned int iTmpBaud;unsigned long lTmpBaud; iTmpBaud = 0;//首先选定定时器 2 作为波特率发生器 ,16位定时器 ,自动装载SCON = 0x50; //SM0 SM1 SM2 REN TB8 RB8 TI RI //0 1 0 1 0 00 0PCON = 0x00; //PCON 的地址是 87H, 这里 SMOD =0//TF2 EXF2 RCLK TCLK EXEN2 TR2 C(/T2) CP(/RL2) //0 0 1 1 0 0 0 // / / / / / / T2OE DCEN //0 0 0 0 0 0 0 0//fosc = 22.1184M,6T: 144, 设置波特率//(RCAP2H,RCAP2L) = 65536- fosc/(n*Baud) 。
上位机和单片机串口编程---API函数编程上位机和单片机串口编程不用MSComm控件,那看起来只能是使用Windows API了,因为MFC貌似没有什么类封装了串口API函数的。
用Windows API 编写串口程序本身是有巨大优点的,因为控制能力会更强,效率也会更高,而且对于那些纯绿色软件追求者来说,没有ActiveX控件比什么都重要――呵呵,我也是这么认为。
API编写串口,过程一般是这样的:1、创建串口句柄,用CreateFile;2、对串口的参数进行设置,其中比较重要的是波特率(BaudRate),数据宽度(BytesBits),奇偶校验(Parity),停止位(StopBits),当然,重要的还有端口号(Port);3、然后对串口进行相应的读写操作,这时候用到ReadFile 和WriteFile函数;4、读写结束后,要关闭串口句柄,用CloseFile;下面依次大致讲讲个步骤的过程:第一步,从字面上去理解,大家也可以发现CreateFile实际上表明Windows是把串口当作一个文件来处理的,所以它也有文件那样的缓冲区、句柄、读写错误等,不同的是,这个文件名字只有固定的几个(一般为四个),而且始终存在(__G),而且在调用CreateFile的时候请注意它的参数。
CreateFile函数原型如下:HANDLE CreateFile(__ lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,__ITY___TES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile );lpFileName是你需要创建的端口号,默认情况下是COM1;dwDesiredAccess是表明你想让你创建的串口以何种方式存在于你的应用程序中,因为串口通常是可读可写的,所以这里必须设置为___READ|___WRITE;dwShareMode是用来设置串口共享属性的,因为串口属于临界资源,当然不能共享,所以这里也必须设置为0;lpSecurityAttributes是设置安全模式,一般采用默认的安全模式就可以了,选择NULL;dwCreationDisposition是设置是否打开新的“文件”(上面说过了,Windows是把串口等端口当作文件来处理的),因为串口属于硬件端口,当然不能随便重复创建,所以这里必须告诉Windows,每次创建的时候必须使用已经存在的串口,所以这里设置OPEN___G;dwFlagsAndAttributes,这个参数可以设置的值比较多,大家若需要深入了解可以查找MSDN,这里因为我们接下去要做的是异步通讯,所以需要设置FILE_FLAG___PED;最后一个参数hTemplateFile是指定模板文件,串口没有模板,选择NULL;所以最后我们设置的CreateFile函数如下:m_hCom=CreateFile(m_sPort,___READ|___WRITE,0,上位机和单片机串口编程NULL,OPEN___G,FILE_FLAG___PED,NULL);在创建完串口后,最后进行句柄测试:if(m_hCom==___HANDLE_VALUE){AfxMessageBox(“打开串口失败!");return;}上面说到了异步,那什么是异步呢?异步是相对同步这个概念而言的。
串口波特率设置说明:建议波特率不要设置太高,不是说设置高了不能用
波特率设置过高会导致传输数据不稳定,会出现丢包的现象。
怎么设置波特率的问题:这款芯片有两种方法来产生波特率
第一种:用定时器来产生波特率(脉冲信号),有弊端就是占用定时器。
第二种:用BRT寄存器(波特率专用定时器)来产生波特率,但是只有一个。
所以如果需要双串口同时通讯,则必须使用一个定时器,和一个BRT定时器。
一般串口发送数据都是选择模式一,或者模式三(波特率可变)。
(因为模式二和模式四波特率是固定的)。
所以在此我不多说波特率二和四。
T1X12这个标志位是来定义时钟分频(关系到定时器的速度,如果设置为1,则定时器不12倍分频,则波特率速度快12倍)。
默认为0,就是不设置,则定时器时钟12分频,和普通52速度一样。
BRTX12 这个标志位和T1X12差不多,只是它是来设置的快速波特率时钟分频,设置为1,不分频。
默认为0,则12分频,(波特率慢12倍)。
我自己理解的,错了请指正。
例:11.0592MHZ晶振,1T工作模式
波特率设置值=256 - INT(1105920/9600/(32+0.5))
=256 - 3
=253
十六进制,加上修正值是FD。
51单片机的2个串口资源分别通信的方法当使用51单片机的2个串口资源进行通信时,比如用一个串口与PLC的串口使用RS485协议通信,一个串口通过蓝牙模块和另一个单片机无线通信时,该如何处理呢?传统的51单片机只有1个串口资源,只能采用分时复用的方法。
STC的15系列增强版51单片机具有多个串口资源,本文将描述如何使用IAP15W4K58S单片机用一个串口资源与PLC的RS485有线通信,另一个串口资源与Arduino单片机通过蓝牙模块无线通信,该通讯连接过程中PLC作为主机,IAP15W4K58S作为中间机,Arduino单片机作为最低层级。
工作过程是按下启动按键,PLC发信息给IAP15W4K58S单片机发高速脉冲控制步进电机驱动的机械臂运动取走货物,当货物取走后,IAP15W4K58S单片机通过蓝牙模块通知Arduino单片机控制的小车将新货物运送过来。
连接结构示意图如下图所示。
本例程使用的单片机型号为:IAP15W4K58S,该单片机有4个采用UART 工作方式的全双工异步串行通信接口(分别为串口1、串口2、串口3和串口4),每个串行口由2个数据缓冲器、1个移位寄存器、1个串行控制寄存器和1个波特率发生器等组成。
本项目使用串行口1和串行口2。
串行口1的两个缓冲器共用寄存器SBUF (99H),串行口2的两个缓冲器共用寄存器S2BUF(9BH)。
10位(1起始位,8位数据位,1停止位)可变波特率(9600)。
串口1对应的硬件部分是TxD和RxD,串行口2对应硬件部分是TxD2和RxD2。
串口1选择引脚P3.0(RxD)和P3.1(TxD),串口2选择引脚P1.0(RxD)和P1.1(TxD)。
串口1既可以选择T1作为波特率发生器,也可以选择T2作为波特率发生器。
本文串口1提供2个选择(T1和T2),串口2只能选择T2作波特率发生器。
但是当串口1和串口2的波特率相同时,可以共用T2作为波特率发器,当T2工作在1T模式时,串行口1的波特率=SYSclk/(65536-[RL_TH2,RL_TL2])/4,SYSclk表示系统时钟频率,[RL_TH2,RL_TL2]表示T2H,T2L的定时初值设置值。
《51系列单片机_串口通信》源文件此程序使用单片机89SC52//1.说明:首先由上位机发送一个字符数据给单片机,单片机接收到字符数据后产生中断,由中断程序将接收到的字符存储到tmp中// 然后由单片机将字符串"Get the char: "和接收到的字符发送给上位机#include<reg52.h>char str[]=" Get the char: ", flag, tmp;//串行通信初始化void init(){ //设置通信波特率TMOD = 0x20; //设置T1定时器工作于方式2(8位计数自动重装)TH1 = TL1 = 0xfd; //此计数初值,使得晶振11.0592MHZ串口通信方式1产生波特率9600bps的通信速率TR1 = 1; //开启定时器1//设置串行通信模式SCON = 0x50; //01(设置串行口工作于10位数据异步通信) 01(允许串行口接收数据) 0000EA = 1; //开总中断ES = 1; //开串行口中断}//发送字符cvoid send(char c){SBUF = c; //将字符c存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1TI = 0; //发送完成后将TI请0}//发送字符串strvoid sendS(char str[]){int i=0;while(str[i++]!=0) //字符串未到达结尾时,发送字符{SBUF = str[i]; //将字符str[i]存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1TI = 0; //发送完成后将TI请0}}//使用串行口中断接收数据void ser_Int() interrupt 4 //串行口中断,接收完数据(RI置1) 或发送完数据(TI置1)时,产生中断{tmp = SBUF; //将接收到的数据放入tmp中保存flag = 1; //标志位置1,表示接收到新数据RI = 0; //接收完数据,清除中断标志}void main(){init(); //串行口初始while(1){if(flag==1) //当接收到新数据tmp时,将字符串str[]="Get the char: " 和tmp一起发送给上位机{ES = 0; //发送数据时暂时关闭串口中断,使得数据发送完成时不进入串口中断,串口中断在此程序中即用于接收数据sendS(str); //发送字符串strsend(tmp); //发送字符tmpES = 1; //数据发送完成重启串口中断flag = 0; //标志位清0}}}//2.串口通信应用秒表简单记录秒数值//说明:上位机发送一个字符数据'S'或者'C'给单片机,单片机根据接收到的字符数据控制定时器T0进行计时和暂停操作,并将计数值用数码管加以显示#include<reg52.h>#define iniNum 45872 //晶振频率为11.0592计时50ms的计数值int num, count;char str[]=" 'S' to start or stop the timer; 'C' to continue timing ", flag, tmp;void delay_ms(unsigned int n){ //软件延时函数,延时n毫秒unsigned int i, j;for(i=n;i>0;i--)for(j=110;j>0;j--);}void display(int num,int rep) //控制数码管按位输出显示数值num,显示时间为2*rep 毫秒{char BitSet[8] ={0x7f, 0xbf, 0xdf, 0xef,0xf7, 0xfb, 0xfd, 0xfe}; //用于设置(低电平位选)数码管的位选信号,从低到高对应8个数码管char NumberCode[16] ={0x3f, 0x06, 0x5b, 0x4f,0x66, 0x6d, 0x7d, 0x07,0x7f, 0x6f, 0x77, 0x7c,0x39, 0x5e, 0x79, 0x71,}; //用于设置(共阴极)数码管的段选信号,从0~f共16个数值int n, r = rep, i;while(r-- > 0){n = num;i = 0;while(n>=0){P0 = 0xff; //关闭数码管当前位的显示,共阳极关闭显示段选信号P2 = BitSet[i]; //选中数码管对应的位P0 = ~NumberCode[n%10]; //向数码管的对应位中送入该位数值对应的段选信号delay_ms(2); //每一位延时显示2msP2 = 0xff; //关闭所有位选i++; //位标记n=n/10; //取数值n的商if(n==0) break; //当取得的商为0时退出while循环}}}//发送字符cvoid send(char c){SBUF = c; //将字符c存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1TI = 0; //发送完成后将TI请0}//发送字符串strvoid sendS(char str[]){int i=0;while(str[i++]!=0) //字符串未到达结尾时,发送字符{SBUF = str[i]; //将字符str[i]存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1TI = 0; //发送完成后将TI请0}}void int_T0() interrupt 1 //定时器T0中断,此程序中用于计时{count++;TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256;}//使用串行口中断接收数据void ser_Int() interrupt 4 //串行口中断,接收完数据(RI置1) 或发送完数据(TI置1)时,产生中断{tmp = SBUF; //将接收到的数据放入tmp中保存flag = 1; //标志位置1,表示接收到新数据RI = 0; //接收完数据,清除中断标志}void main(){TMOD = 0x21; //设置T1定时器工作于方式2(8位计数自动重装),T0定时器工作于方式方式1(16位定时计数)//设置通信波特率TH1 = TL1 = 0xfd; //此计数初值,使得晶振11.0592MHZ串口通信方式1产生波特率9600bps的通信速率TR1 = 1; //开启定时器1//设置串行通信模式SCON = 0x50; //01(设置串行口工作于10位数据异步通信) 01(允许串行口接收数据) 0000EA = 1; //开总中断ES = 1; //开串行口中断//为定时器0装入初值TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256; //计iniNum数,每次计时50msET0=1; //开定时器0中断ES = 0; //发送数据时暂时关闭串口中断sendS(str); //发送操作提示字符串,给出提示信息ES = 1; //数据发送完成重启串口中断while(1){if(flag==1) //当接收到新数据tmp时{ES = 0; //发送数据时暂时关闭串口中断,使得数据发送完成时不进入串口中断,串口中断在此程序中即用于接收数据//开始计时if(tmp=='S' | tmp=='s'){if(TR0==0) //当计时器停止时启动计时{num=0; //计数值清0,计数器重装初值TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256;TR0=1; //启动定时器0,进行计时sendS(" the tiner started ");}if(TR0==1) //当计时器已经启动时{TR0=0; //暂停计时sendS(" the tiner paused ");}}//继续计时else if(tmp=='C' | tmp=='c'){TR0=1; //启动定时器0,继续计时sendS(" tiner continue ");}else sendS(str);//发送操作提示字符串ES = 1; //数据发送完成重启串口中断flag = 0; //标志位清0}if(count==20) //每20次中断即每1s,处理一次{num++; //显示数值加1count=0;P1=~P1; //指示灯状态取反}display(num, 1); //用数码管输出显示num}}//3.串口通信应用秒表按时分秒格式显示//说明:上位机发送一个字符数据'S'或者'C'给单片机,单片机根据接收到的字符数据控制定时器T0进行计时和暂停操作,并将计数值用数码管加以显示#include<reg52.h>#define iniNum 45872 //晶振频率为11.0592计时50ms的计数值int count, time[4]=0;char str[]=" 'S' to start or stop the timer; 'C' to continue timing ", flag, tmp;void delay_ms(unsigned int n){ //软件延时函数,延时n毫秒unsigned int i, j;for(i=n;i>0;i--)for(j=110;j>0;j--);}void timer_display(int time[], int rep)//控制数码管按位输出显示time数组中的时分秒值数值,显示时间为2*rep 毫秒{char BitSet[8] ={0x7f, 0xbf, 0xdf, 0xef,0xf7, 0xfb, 0xfd, 0xfe}; //用于设置(低电平位选)数码管的位选信号,从低到高对应8个数码管char NumberCode[16] ={0x3f, 0x06, 0x5b, 0x4f,0x66, 0x6d, 0x7d, 0x07,0x7f, 0x6f, 0x77, 0x7c,0x39, 0x5e, 0x79, 0x71,}; //用于设置(共阴极)数码管的段选信号,从0~f共16个数值int n, r = rep, i, j, zero=0;while(r-- > 0){i = 0;for(j=3; j>=0; j--){n = time[j];if((j==2|j==1|j==0) & time[j]<10) zero=1;//当时、分、秒三位的数值小于10时,显示对应数值后在高位添加一个0while(n>=0){P0 = 0xff; //关闭数码管当前位的显示,共阳极关闭显示段选信号P2 = BitSet[i]; //选中数码管对应的位if(i==1|i==3|i==5){ //在数码管倒数第1,3,5(时,分,秒)三个位置的数值后加上小数点P0 = ~(NumberCode[n%10]+0x80);}else{ //向数码管的对应位中送入该位数值对应的段选信号P0 = ~NumberCode[n%10];}delay_ms(2); //每一位延时显示2msP2 = 0xff; //关闭所有位选i++; //位标记n=n/10; //取数值n的商if(n==0) break;//当取得的商为0时退出while循环}if(zero==1) //在数码管高位添加0{P0 = 0xff; //关闭数码管显示P2 = BitSet[i]; //选中数码管对应的位P0 = ~NumberCode[0]; //显示数值0delay_ms(2); //每一位延时显示2msP2 = 0xff; //关闭所有位选i++; //位标记zero=0;}}}}//发送字符cvoid send(char c){SBUF = c; //将字符c存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1 TI = 0; //发送完成后将TI请0}//发送字符串strvoid sendS(char str[]){int i=0;while(str[i++]!=0) //字符串未到达结尾时,发送字符{SBUF = str[i]; //将字符str[i]存入SBUF中,由CPU自行发送while(!TI); //等待发送完毕,发送完成时TI会被置1TI = 0; //发送完成后将TI请0}}void int_T0() interrupt 1 //定时器T0中断,此程序中用于计时{count++;TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256;}//使用串行口中断接收数据void ser_Int() interrupt 4 //串行口中断,接收完数据(RI置1) 或发送完数据(TI置1)时,产生中断{tmp = SBUF; //将接收到的数据放入tmp中保存flag = 1; //标志位置1,表示接收到新数据RI = 0; //接收完数据,清除中断标志}void main(){TMOD = 0x21; //设置T1定时器工作于方式2(8位计数自动重装),T0定时器工作于方式方式1(16位定时计数)//设置通信波特率TH1 = TL1 = 0xfd; //此计数初值,使得晶振11.0592MHZ串口通信方式1产生波特率9600bps的通信速率TR1 = 1; //开启定时器1//设置串行通信模式SCON = 0x50; //01(设置串行口工作于10位数据异步通信) 01(允许串行口接收数据) 0000EA = 1; //开总中断ES = 1; //开串行口中断//为定时器0装入初值TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256; //计iniNum数,每次计时50msET0=1; //开定时器0中断ES = 0; //发送数据时暂时关闭串口中断sendS(str); //发送操作提示字符串,给出提示信息ES = 1; //数据发送完成重启串口中断while(1){if(flag==1) //当接收到新数据tmp时{ES = 0; //发送数据时暂时关闭串口中断,使得数据发送完成时不进入串口中断,串口中断在此程序中即用于接收数据//开始计时if(tmp=='S' | tmp=='s'){if(TR0==0) //当计时器停止时启动计时{int i;for(i=0; i<4;i++) time[i]=0; //计数值清0,计数器重装初值TH0=(65536-iniNum)/256;TL0=(65536-iniNum)%256;TR0=1; //启动定时器0,进行计时sendS(" the tiner started ");}if(TR0==1) //当计时器已经启动时{TR0=0; //暂停计时sendS(" the tiner paused ");}}//继续计时else if(tmp=='C' | tmp=='c'){TR0=1; //启动定时器0,继续计时sendS(" tiner continue ");}else sendS(str);//发送操作提示字符串ES = 1; //数据发送完成重启串口中断flag = 0; //标志位清0}if(count==2) //每2次中断即每0.1s,处理一次{time[4]++; //秒表最低位(1/10秒)值加1if(time[4]==10) //进位{time[4]=0; //清零time[3]++; //秒进位if(time[3]==60){time[3]=0;time[2]++; //分进位if(time[2]==60){time[2]=0;time[1]++; //时进位}}}count=0;}timer_display(time, 1); //用数码管输出显示秒表计数值}}。