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); //用数码管输出显示秒表计数值}}。
T2_BTL28800: ;用T2作波特率发生器的初始化设置MOV 98H,#01100011B ;98H=SCON 仿真P89C664时不识别SCON; MOV SCON,#01100011B ;串行口工作为方式1,位9(停止位)必须为1接收才有效,发送位9预设为1(方式1时自动设置);TI=1为不用定时器1作波特率用定时器2(位TI位未理解清楚)LI=1MOV PCON,#00000000B ;波特率不加倍;MOV PCON,#10000000B ;波特率加倍MOV T2MOD,#00000000B ;定时不输出MOV T2CON,#00110100B ;T2用做发送接收时钟,置RCLK接收时钟与TCLK发送时钟,TR2=1启动T2,定时且自动重装MOV RCAP2H,#0FFH ;12M 8052MOV RCAP2L,#LOW(0FFFFH-13) ;12M;MOV RCAP2L,#LOW(0FFFFH-(13*2)) ;24M; CLR TR2 ;仿真P89C664时不识别TR2CLR T2CON.2 ;TR2 ;仿真P89C664时不识别TR2MOV TH2,#0FFH ;12M 8052MOV TL2,#LOW(0FFFFH-13) ;12M;MOV TL2,#LOW(0FFFFH-(13*2)) ;24M; SETB TR2 ;仿真P89C664时不识别TR2SETB T2CON.2 ;TR2 ;仿真P89C664时不识别TR2RET;T2计算公式:;12M/(32*(65536-(RCAP2H,RCAP2L)))=28800 8051式; ( 13 ) 78;===================================;T1_BTL4800: ;用T1作波特率发生器的初始化设置; MOV SCON,#01101000B ;串行口工作为方式1,位9(停止位)必须为1接收才有效,发送位9预设为1(方式1时自动设置);(位TI位未理解清楚); MOV PCON,#00000000B ;波特率不加倍; MOV TMOD,#00100000B ;T1工作于方式2为8位重装; MOV TH1,#0F9H; MOV TL1,#0F9H; RET;SCON 串行通信控制寄存器; D7 D6 D5 D4 D3 D2 D1 D0;SM0 SM1 SM2 REN TB8 RB8 TI RI;(1)SM0、SM1:串行口工作方式控制位。
单片机串口通信在嵌入式系统中具有非常重要的作用,而其中串口中断的编写方式更是至关重要。
今天我们来讨论一下51单片机串口中断的两种写法。
1. 外部中断写法在51单片机中,串口通信一般使用串口中断来实现。
外部中断写法是一种常见的串口中断编写方式。
其具体步骤如下:1)需要设置串口工作参数,包括波特率、数据位、停止位和校验位等。
2)在主程序中使能串口中断,并设置中断优先级。
3)在中断服务函数中进行接收数据的处理,可以通过接收缓冲区、中断标志位等来判断接收数据的情况,并进行相应的处理。
2. 定时器中断写法除了外部中断写法,定时器中断也是一种常见的串口中断编写方式。
其具体步骤如下:1)同样需要设置串口工作参数,包括波特率、数据位、停止位和校验位等。
2)在主程序中初始化定时器,并使能定时器中断。
3)在定时器中断服务函数中进行接收数据的处理,同样可以通过接收缓冲区、中断标志位等来判断接收数据的情况,并进行相应的处理。
总结无论是外部中断写法还是定时器中断写法,都是实现51单片机串口通信的常见方式。
在选择具体的编写方式时,需要根据具体的应用场景和需求来进行选择。
在实际应用中,可以根据具体情况来灵活选择合适的串口中断编写方式,以便更好地满足系统的需求。
在实际编写中断服务函数时,需要注意以下几点:1)处理数据时需要考虑数据的完整性和准确性,可以通过校验位等手段来验证数据的正确性。
2)在中断服务函数中应尽量减少对全局变量的访问,以避免出现数据冲突和竞争的情况。
3)合理设置中断优先级,避免产生中断嵌套和冲突。
通过合理的中断编写方式和注意事项,可以更好地实现串口通信功能,提高系统的稳定性和可靠性,为嵌入式系统的应用提供良好的技术支持。
对于外部中断写法和定时器中断写法,两者各有优缺点。
外部中断写法在串口数据到达时能够即刻响应中断、处理数据。
但是,如果数据传输速率较快或需要高精度的数据处理,外部中断写法可能无法满足要求。
在这种情况下,定时器中断写法显得更加合适。
1.1 串口发数1.1.1串口发数的原理在模拟外部晶振为11.0592 MHz、波特率为9 600 bps的情况下,设置常量BAUD为0xFE80,并将该常量赋值到TL0、TH0两个寄存器中,实现定时。
每到相应时间触发定时中断程序,将外部引脚的状态读入并存入预先设定的数组中,完成模拟串口读入字节的任务。
常用的波特率配置如图 1.1-1所示。
由于STC15L104E没有串口,因而必须利用定时器模拟串口。
其方法是,定义一个常量,根据所需要的波特率对该常量赋值,并将该常量值赋到定时所用的寄存器中。
图1.1-1 常用波特率配置对于BAUD的具体算法是BAUD=65536-SYSclk/3/BAUDRATE/M(1T:M=1;12T:M=12)。
65536是定时器T0的溢出值,因为T0定时器为16位定时器,所以溢出值为2^16,SYSclk为系统时钟频率11.0592MHZ,BAUDRATE为波特率9600bps,而我们使用的是单周期M=1,所以我们要像定时器里存入0xfe80。
对于BAUD的算法,上一节讲到定时器中断的原理,定时器计时65536位的时候就会溢出,然后进入中断。
而我们要模拟的串口波特率为9600bps,我们想要每一位执行的时间T1就是1/9600s,而系统晶振震荡一次读一位的时间T2为1/11.0592us(单周期),那么我们要读的位数就为T1/T2。
那算法公式中的3是什么呢,这是因为我们每读一位要抽样三次来检查读取的数据。
我们要计数SYSclk/3/BAUDRATE/M位的时候产生中断,就要用65536-SYSclk/3/BAUDRATE/M,赋值给定时器,定时器定期检查串口,实现串口模拟。
本实验中我们用到的寄存器有AUXR、TMOD、TCON、IE、IP,前两节都已经详细介绍,本节不做深入讲解。
1.1.2硬件连接模拟串口的硬件连接须将单片机两个引脚分别定义为收数据发数据,在这里我们定义P3.1为发送数据,P3.0为接收数据。
串口编程的一般步骤及相关函数讲解串口编程是指通过串口与外部设备进行通信的程序设计。
一般步骤包括串口初始化、设置串口参数、打开串口、发送数据、接收数据和关闭串口等。
1. 串口初始化:首先需要导入串口编程相关的库文件,如pyserial 库。
然后通过serial.Serial(函数创建一个串口对象,指定串口号、波特率、停止位、数据位等参数,如:``````这里将串口号设置为/dev/ttyUSB0,波特率设置为9600,超时时间设置为1秒。
2.设置串口参数:通过串口对象的相关方法设置串口参数,如:```serial_port.setBaudrate(9600)serial_port.setParity(serial.PARITY_NONE)serial_port.setStopbits(serial.STOPBITS_ONE)serial_port.setByteSize(serial.EIGHTBITS)```这里设置了波特率为9600,无奇偶校验位,1位停止位,8位数据位。
3. 打开串口:使用串口对象的open(方法打开串口,如:serial_port.open```注意,打开串口之前要确保串口没有被其他程序占用。
4. 发送数据:使用串口对象的write(方法向串口发送数据,如:```data = 'Hello, World!'serial_port.write(data.encode()```这里将字符串'Hello, World!'转码为字节型数据并发送到串口。
5. 接收数据:使用串口对象的read(方法从串口读取数据,如:```received_data = serial_port.read(10)print(received_data.decode()```这里从串口读取10字节的数据,并将其解码为字符串输出。
6. 关闭串口:使用串口对象的close(方法关闭串口,如:```serial_port.close在程序结束时,记得关闭串口以释放资源。
单片机从机的波特率自适应设置一、硬件原理图说明:DB9接到PC机的串口上。
晶体震荡器可以用诸如11.0592MHz,14.7456MHz,对本文的介绍没有影响等等。
这里,单片机为机为,PC机为主机。
二、自动设置理论原理AT89C52的串行口有4种工作方式,方式1、3最常用。
T2的波特率发生方式类似于常数自动重装入方式。
用X16代替(RCAP2H,RCAP2L),则串行口方式1、3的波特率公式为:波特率=fosc/[32 x (65536-X16 )]..……………………..……..…(A)由(A)可得,单片机每接收1bit需要的时间为接受1bit的时间=[32 x (65536- X16 )]/ fosc……………………(B)单片机A T89C52为12分频指令系统,所以其机器周期为:机器周期= 12/fosc……………………………………….….….……(C )我们可以很容易得到单片机接收1bit所需要的机器周期,假定为NUM,则由(B),(C)得NUM x 12/ fosc=[32 x (65536- X16)]/ fosc…………………………...(D)由(D)可得,波特率定时时间常数为:X16=NUM x 3/8……………………………….…………………….….(E)由此,关键需要得到单片机接受1 bit的机器周期数NUM。
三、自动检测主机信息的方法不失一般性,假定串行通讯的字符协议为1起始位,8数据位,无奇偶校验位,1停止位,如下(图2)所示,由定时器2工作原理(图3)知道,C/T2=0,TR2=0,则其加1计数,其计数速率为fosc/12,每加1需要的时间等于12/fosc,刚好就是一个机器周期。
所以,只要我们在传输数据的某位开始处启动定时器,在传输该位结束时停止计数器,然后获取该范围的计数值,就是我们上面公式(E)中的NUM。
(定时器2工作原理,图3)由图2知,如果主机(PC机)发给单片机01H(十六进制),则单片机P3.0接收数据如下波形(图4)。