目录
1. 串口通信原理
串口通信是通信设备间在一条传输线上串行逐个比特的发送数据的通信方式。串行通信又可分为同步和异步两种通信方式。同步通信是在同一时钟信号控制下进行收发信号,异步通信中需要双方规定一致发送和接收频率。
数据传输的方向可分为单工(只能向一个方向传输);半双工(不同时间在一根线上向不同方向传输);全双工(可同时向不同方向传输)。
图1.常见串行通信接口接口
UART是一种采用异步串行通信的通用异步收发器,在发送时将并行数据转换成串行数据,接收端则将串行数据转换成并行数据。此外UART一般需要两根数据,一根端口发送,一根端口接收。
图2.硬件连接
图3.一般协议层数据格式
常见串口通信速率为(9600、19200、38400、57600、115200)bps。
UART串口物理层常用电平标准(51单片机使用TTL电平,由下不要直接将DB接口引线接到单片机会烧毁(15v > 5v)):
- TTL电平:+5V 表示1,0V表示0
- RS232电平(常用于DB 接口):-3~-15V表示1,+3~+15V表示0
- RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
2. 51单片机串口通信
图2.1.CPU线路图
图2.2.USB转TTL
STC89C52rc有1个UART,有四种工作模式:(常用方式1)
2.1 串口简要模式图
图2.3 串口简要模式图
图2.4 中断结构局部图
SBUF为串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器。SMOD控制控制是否加倍速(置1相当于加倍)
2.2 相关寄存器
(1)PCON、SCON、SBUF
STC89C52RC及同系列单片机串行口设两个控制寄存器,串行控制寄存器SCON和 波特率选择特殊功能寄存器PCON
PCON(不可位寻址):
SCON(可位寻址):
TI/RI为中断标志位,一般是当要发生中断事情发送才标志中断,所以一般初始化置0由上,当我们 想要简单的在模式1下向主机发送数据:
SCON(SM0=0,SM1=1,SM2=0,REN=0/1,TB8=0,RB8=0,T1=0,R1=0)=> 0x40
且因为需要分频,需要波特率加倍,不然速率太低。
PCON(SM0D=1,SMOD0=0) => PCON | 0x80
SBUF串行口缓冲寄存器:
虽然地址相同,但SBUF是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器
软件操作上,我们可以只操作SBUF,要发送时,将要发送数据赋值给SBUF,同时注意在停止位发送后将TI复位。
(2)IE、IPH、IP
与串行口中断相关的寄存器有IE和IPH、IP。
串行口中断允许位ES位于中断允许寄存器IE中;串行口中断优先级控制位PS/PSH位于中断优先级控制寄存器IP/IPH中
IE(可位寻址):
IP与PH(不可位寻址):
为了简单,可以仅考虑两个优先级,只操作PS=0/1
当我们不需要中断操作,也可以不设置中断EA、ES
(3)配置T1定时器
串行通信模式1的波特率是可变的,可变的波特由定时器/计数器T1或独立波特率发生器
生 ,因此我们需要配置T1定时器,常选用定时器计数器T1的工作方式2(8位自动重装) 作为波特率的溢出率。
对于TMOD,T1模式控制为前四位:(x,x,1,0)=> (TMOD & 0x0f) | 0x02
对于TCNO模式1控制位:
不需要计时器发送中断,只需要它的溢出:ET1 = 0;
允许T1开始计时:TR1 = 1;
(4)使用STC-ISP配置寄存器
本系列单片机没有AUXR,系统时钟为11.0592MHZ(因为串口通信要求较精准,如果使用12mhz与板子晶振频率不符传输错误率较大,此外通信两端波特率也要一致)
2.3 波特率和系统时钟和TH1和TL1计算
建议使用STC-ISP设置TH1和TL1
对于串口模式1,定时器1使用模式2(8位自动重装)。利用公式逆着推从溢出率推出波特率。
- 当TL1 = 0xf4,
- (ff +1)- f4 = 12 //计数12次溢出
- 1 /(11.0592MHZ/12)= 1.0850694444444us //定时器12分频下计数一次的时间
- 12*1.0850694444444us = 13.0208333333328us
- 溢出率:1/13.0208333333328us = 0.07680000000000314572800000012885
- 波特率 = 2^1/32 * 溢出率 = 0.00480000000000019660800000000805HZ 约等于4800MHZ
- 误差 = (0.00480000000000019660800000000805-0.0048)/0.0048 约等于0
3.串口通信简单收发使用代码
3.1 在STC-isp使用端口助手,从单片机发送字节
#include <REGX52.H>
void UartInit(void) //4800bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x40; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF4; //设置定时初始值
TH1 = 0xF4; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
//中断加不加都行,因为我们不需要中断操作
//EA =1;
//ES =1;
}
//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
SBUF = byte;
//当发送完成,TI位硬件自动置1
while(TI == 0);
TI = 0;
}
int main()
{
UartInit();
UART_SendByte(0x66);
while(1)
{
}
}
3.2 通过端口助手利用主机输入数据在中断中控制LED
#include <REGX52.H>
void UartInit(void) //4800bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF4; //设置定时初始值
TH1 = 0xF4; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
//我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
EA =1;
ES =1;
//为了简便,不配置优先级,选用默认优先级
}
int main()
{
UartInit();
while(1)
{
}
}
void UART_Routine() interrupt 4 {
//主机发送数据到SBUF后,RI会置1
//单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
if(RI == 1)
{
//中断后响应的操作
//利用主机发送给SBUF中数控制LED,如发送1就是除了LED1,其他都点亮
P2 = SBUF;
//RI必须软件复位
RI = 0;
}
}
3.3 利用中断把主机发送来数据发送回主机
中断逻辑在注释中解释
#include <REGX52.H>
void UartInit(void) //4800bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF4; //设置定时初始值
TH1 = 0xF4; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
//我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
EA =1;
ES =1;
//为了简便,不配置优先级,选用默认优先级
}
//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
SBUF = byte;
//当发送完成,TI位硬件自动置1
while(TI == 0);
TI = 0;
}
int main()
{
UartInit();
while(1)
{
}
}
void UART_Routine() interrupt 4 {
//主机发送数据到SBUF后,RI会置1
//单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
if(RI == 1)
{
//中断后响应的操作
//此时SBUF内容为主机发来的数据,通过UART_SendByte函数发送回到主机
//因为该中断由接受端发起,发送操作已经中断,所以现在不会有接收操作与发送操作冲突
UART_SendByte(SBUF);
//RI必须软件复位
RI = 0;
}
}