串口通讯(uart ,232,485)

串口通讯(uart ,232,485)uart 232 485 通讯 uart 转 485

大家好,欢迎来到IT知识分享网。

目录

一.uart一般配置

二.USAT模块通讯配置   

1、硬件电路

2.电平转换元件

三、寄存器配置(以51为准)              

 1.STC89C52/51有1个UART。  STC89C52/51的UART有四种工作模式:

 3.UART寄存器工作原理图 ​编辑

 4.PCON:电源控制寄存器(不可位寻址)

 5. TMOD(配置定时器)

 6.波特率

 7.单字节/多字节发送

8.返回字符串(可以返回中文,)

9.串口控制io口并返回提示 

10.485(差分传输)

一.uart一般配置
 

串口协议 UART
1. 设置定时器TOMN类型,与发送时间
2. 设置SCON确定发送数据位数和接收功能是否开启
3. 设置PCON确定波特率是否翻倍,以及确定是否有校验位
4. 设置IE开启串口中断,

(6)定时器都可以理解为独立的外设,数据的收发也是独立于cpu运转的。

二.USAT模块通讯配置   

1、硬件电路

(1)主要是2部分,1.接线  2.端口电平

串口通讯(uart ,232,485)
 (2)232通讯线有交叉和平行的两种。如果电路板上绘制时是反接的,就选用平行的如果是正常接的输出时要选择交叉线。反正通讯一定是RX接TX,TX接RX.

2.电平转换元件

 串口通讯(uart ,232,485)

 这是双路电平转换,10.11为mcu输出引脚接TX端。12.9为输入引脚接RX端。转换输出引脚14,和7必须要接PC端的RX,输入13.8必须要接PC端的TX。

三、寄存器配置(以51为准)              

 1.STC89C52/51有1个UART。
  STC89C52/51的UART有四种工作模式:

串口通讯(uart ,232,485)
     2.相关寄存器 串口通讯(uart ,232,485) 1.SCON:串口控制寄存器(可位寻址)
 串行控制寄存器SCON用于选择串行通信的工作方式和起到提示的功能。其格式如下:
 串口通讯(uart ,232,485)  串口通讯(uart ,232,485)       注意:1.一般使用定时器1来作为波特率发生器。主要对于51系列uart模块时钟部分,硬件  上 只  与T1相连,不与定时器T0相连。52系列架构上多了个T2与uart模块相连。
                 2.系统工作时钟频率就是外部晶振频率。



 总的来说就是串口中断是在接收或发送到停止位后触发1次,数据传输由定时器和SBUF寄存器控制

对于51来说物理串口上收发是完全独立的两个寄存器,但是公用同一个地址,也就是说,物理上是可以作到同时收发,但是软件同一时间只可以处理一个,所以说,51是本质是伪全双工;

但对于切换速率不快的场合可以当作全双工使用。

 3.UART寄存器工作原理图
 串口通讯(uart ,232,485)

 1.可以看出是串口的收发是基于定时器1完成。但对于52系列单片机也可以用定时器    T2来做也是可以的。至于为什么要用自动重装,避免再次重装,减少软件上对波特率的干扰。

2.波特率产生是时钟产生,执行中断cpu执行的,中 断产生时也是一直运行的

3.当接收或发送完毕,会调用cpu执行中断,本身是会继续接收或者发送。

4.如果串口中断执行时间大于串口接收的时间,定时器会继续用执行产生波特率如果继续接收数据就会出现丢帧的现象(根据固有优先级规则)然后在次触发(根据中断产生要求)。

4.PCON:电源控制寄存器(不可位寻址)

串口通讯(uart ,232,485)

其他位对于51系列均为虚设位,没用

5. TMOD(配置定时器)

串口通讯(uart ,232,485)

串口通讯(uart ,232,485)

 6.波特率

 串口通讯(uart ,232,485)

 7.单字节/多字节发送

//程序功能本质是单个字符发送。但是多个数据写入也可以体现连续发送效果。 #include <REGX52.H> #include <stdio.h> //定义串口 void uart_inte() { SCON=0X50;//设置方式1开启收发 TMOD=0X20;//开启定时器1设置为8位自动重装模式 PCON=0X80;//开启倍频 TH1=0XF4;//设置波特率为4800 TL1=0XF4;//自动重装值 TR1=1;//开启定时器1 IE=0X90;//开启中断 } void main() { uart_inte();//串口初始化 while(1) { } } //值得注意的是串口中断不是定时器到了就触发而是发送完再触发 //对于单片机在这里是下位机是先PC发送给单片机,单片机在应答,所以应该是先接受后发送 void uart()interrupt 4//串口中端4 { unsigned int returnDate; returnDate=SBUF//将SBUF数据存储到returnDate中 RI=0; //清除接收中断标志位 SBUF=returnDate;//将数据送到发送端发送 while(!TI); //等待发送数据完成,定时器属于外部资源,单片机只能对其配置和调用, //不停止调用,他就会一直运行。即使软件属于死循环。因此定时器可以用做软件狗。 TI=0; //清除发送完成标志位 }

 效果跟上面一样就是多了个数组进行储存数据,可以用来调用。

#include <reg52.h> #define uint unsigned int #define uchar unsigned char //定义接收 数组 uchar Buffer[5]={0}; uchar i=0,j=0; //串口初始化函数 void URATinit( ) { TMOD=0x20;//方式2,8位自动重装 SCON=0x50;//方式1,8位串口数据,可以接受 EA=1; ES=1; TR1=1; TH1=0xfd; TL1=0xfd; } //中断函数 void receive() interrupt 4 { if(RI) { Buffer[0]=SBUF; RI=0; } SBUF=Buffer[0]; while(!TI) ; TI=0; i++; if(i>=5){ i=0; } } //主函数 void main() { URATinit( ); } 

8.返回字符串(可以返回中文,)

/BST-V51实验开发板例程 + Keil U3 + STC89C52 * 名称:往串口发送一字节数据(可通过超级终端或者串口调试助手显示出来, 超级终端波特率选为9600)。 超级终端设置好后,每按下一次S2键,松开后均会在超级终端 上显示一串字母"abcdefg哈哈"。 * 淘宝:bstmcu.taobao.com * 日期:2012-8-14 * 晶振:11.0592MHZ / #include <reg52.h> #define jingzhen UL /*使用22.1184M晶体*/ #define botelv 9600UL /*波特率定义为9600*/ unsigned char zifuchuan[]="abcdefg哈哈"; //待显示字符。 volatile unsigned char sending; void delay(unsigned char i) { unsigned char j,k; for(j=i;j>0;j--) for(k=90;k>0;k--); } void init(void) //串口初始化 { EA=0; //暂时关闭中断 TMOD&=0x0F; //定时器1模式控制在高4位 TMOD|=0x20; //定时器1工作在模式2,自动重装模式 SCON=0x50; //串口工作在模式1 TH1=256-jingzhen/(botelv*12*16); //计算定时器重装值 TL1=256-jingzhen/(botelv*12*16); PCON|=0x80; //串口波特率加倍 ES=1; //串行中断允许 TR1=1; //启动定时器1 EA=1; //允许中断 } void send(unsigned char d) //发送一个字节的数据,形参d即为待发送数据。 { SBUF=d; //将数据写入到串口缓冲 sending=1; //设置发送标志 while(sending); //等待发送完毕 } void sendc(unsigned char * pd) { while((*pd)!='\0')//发送字符串,直到遇到0才结束 { send(*pd); //发送一个字符 pd++; //移动到下一个字符 } } void main() { init(); while(1) { sendc(zifuchuan); } } void uart(void) interrupt 4 //串口发送中断 { if(RI) //收到数据 { RI=0; //清中断请求 } else //发送完一字节数据 { TI=0; sending=0; //清正在发送标志 } }

9.串口控制io口并返回提示 

返回中文前提必须先预存在数组中,串口助手如果选择文本输入那每个1位都会转化为1个字节输入,如果选择16进制,则输入数值不超过最大255都是以一个字节输入的。

#include <reg52.h> #define jingzhen UL /*使用11.0592M晶体*/ #define botelv 9600UL /*波特率定义为9600*/ unsigned char zifuchuan[]="led1关闭"; //待显示字符。 unsigned char zifuchuan1[]="led1打开"; //待显示字符。 volatile unsigned char sending; unsigned int a; void delay(unsigned char i) { unsigned char j,k; for(j=i;j>0;j--) for(k=90;k>0;k--); } void init(void) //串口初始化 { EA=0; //暂时关闭中断 TMOD&=0x0F; //定时器1模式控制在高4位 TMOD|=0x20; //定时器1工作在模式2,自动重装模式 SCON=0x50; //串口工作在模式1 TH1=256-jingzhen/(botelv*12*16); //计算定时器重装值 TL1=256-jingzhen/(botelv*12*16); PCON|=0x80; //串口波特率加倍 ES=1; //串行中断允许 TR1=1; //启动定时器1 EA=1; //允许中断 } void send(unsigned char d) //发送一个字节的数据,形参d即为待发送数据。 { SBUF=d; //将数据写入到串口缓冲 sending=1; //设置发送标志 while(sending); //等待发送完毕 } void sendc(unsigned char * pd) { while((*pd)!='\0')//发送字符串,直到遇到0才结束 { send(*pd); //发送一个字符 pd++; //移动到下一个字符 } } void main() { init(); while(1) { if(a==1) { sendc(zifuchuan); a=0; } if(a==2) { sendc(zifuchuan1); a=0; } } } void uart(void) interrupt 4 //串口发送中断 { if(RI) //收到数据 { RI=0; //清中断请求 a=SBUF; if(a==1) { P1=0xff; } if(a==2) { P1=0x00; } } else //发送完一字节数据 { TI=0; sending=0; //清正在发送标志 } } 

4.这个是有问题的,有兴趣的可以看一下问题出现在那里。 

#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 #define jingzhen UL//设置晶振频率 #define botelv 9600UL//设置波特率 sbit LED1=P1^0;//定义端口 sbit LED2=P1^1;//定义端口 typedef unsigned int u16; //对数据类型进行声明定义 typedef unsigned char u8; u8 Data_buff[]="点亮LED1"; //设定数据存储位 u8 Data_buff1[]="点亮LED2"; //设定数据存储位 u8 Flag=0;//发送标志位 /* * 函数名 :UsartInit() * 函数功能 :设置串口 * 输入 : 无 * 输出 : 无 */ void UsartInit() { SCON=0X50; //设置为工作方式1 TMOD=0X20; //设置计数器工作方式2 PCON=0X80; //波特率加倍 TH1=256-jingzhen/(botelv*12*16);//设置波特波特率 TL1=256-jingzhen/(botelv*12*16); IE=0X90; //打开总中断打开串口中断。 TR1=1; //打开计数器1 } //发送一个字节的数据,形参d即为待发送数据。 void send(u8 d) { SBUF=d; //将数据写入到串口缓冲 Flag=1; while(!Flag); //等待发送数据完成 } //将数组提取出来 void sendc(u8 * pd) { while((*pd)!='\0')//发送字符串,直到遇到0才结束 { send(*pd); //发送一个字符 pd++; //移动到下一个字符 } } /* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 */ void main() { UsartInit(); // 串口初始化 while(1); } /* * 函数名 : Usart() interrupt 4 * 函数功能 : 串口通信中断函数 * 输入 : 无 * 输出 : 无 */ void Usart() interrupt 4 { u8 a; if(RI==1) { a=SBUF;//出去接收到的数据 RI = 0;//清除接收中断标志位 if(a==1) { LED1= !LED1; sendc(Data_buff); a=0; } else if(a==2) { LED2= !LED2; sendc(Data_buff1); a=0; } } TI=0; //清除发送完成标志位 Flag=0; //标志位为1 } 

这里实际是因为你的循环是在中端函数而且循环前还有一个if判断语句,当第1个字节发收完毕时,外部串口请求打开串口中端,这时cpu会重新调用串口中断从头在执行,这时RI=0的,if进不去,直接执行TI=0,Flag=0;然后回到while循环。(相当于跳出循环了)所以每一次串口发送后led可以执行,而串口返回的数据是不完全的。

这本质属于中断嵌套,可以理解为属于同级之间,但是由于是同一个中断函数,所以每次触发后都会打断当前然后重新执行。之所以返回数据不完全是因为中断触发是以一个字节为准,多字节发送很定会被打断的。

四.485通讯(半双工)

软件端还是usat,只是硬件上做了更改,通过485将单片机输入的ttl信号转换为差分信号输出,接送端再使用485芯片转换回ttl信号,单片机再接收处理。

要注意的是485转换是半双工工作模式,且通过硬件上进行规定的。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/132706.html

(0)
上一篇 2025-07-29 16:15
下一篇 2025-07-29 16:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信