一、原理
1、串行通信
单片机通信是指单片机与计算机或单片机与单片机之间的信息交换,单片机与计算机之间的通信通常用得较多。通信有并行和串行两种方式,在单片机系统及现代单片机测控系统中,信息得交换多采用串行通信方式。
串行通信是将数据字节分成一位一位的形式在一条传输线上逐个传输,此时只需要一条数据线,外加一条公共信号地线和若干控制信号线。因为一次只能传输一位,所以1字节的数据至少要分为8位才能传输完毕。
串行通信的必要过程是:发送时把并行数据变成串行数据发送到线路上,接收时把串行数据信号再变成并行数据,这样才能被计算机及其他设备处理。
串行通信传输线少,长距离传输时成本低,且可以利用电话网等现成的设备,但数据的传输控制比并行通信复杂。
串行通信有两种方式:异步串行通信和同步串行通信。
2、51单片机串行通信
51单片机的串行口是一个可编程全双工的通信接口,具有UART(通用异步收发器)的全部功能,能同时进行数据的发送和接收,也可作为同步移位寄存器使用。
51单片机的串行口主要由两个独立的串行数据缓冲寄存器SBUF(一个发送缓冲寄存器,一个接收缓冲寄存器)和发送控制器、接收控制器、输入移位寄存器及若干控制门电路组成。
与串行口紧密相关的一个特殊功能寄存器是串行口控制寄存器SCON,它用来设定串行口的工作方式、接收/发送控制以及设置状态标志等。
发送控制器 标志位 TI 发送数据时TI=0 数据发送结束TI=1
接收控制器 标志位 RI 接收数据时RI=0 数据接收完毕RI=1
标志位可以查询,或者产生中断。
串口在发送接收的时候,单片机波特率配置要跟PC一致,比赛时应该会规定波特率。
配置波特率,是对定时器T1进行编程,可以在下载软件自动生成。
3、串行口控制寄存器
串行口控制寄存器SCON在特殊功能寄存器中,字节地址为98H,可位寻址,用来设定串行口的工作方式,接收/发送控制以及设置状态标志等。单片机复位时,SCON全部被清0。其各位的定义如下表所示。
位序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位符号 | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
SM0、SM1——工作方式选择位。串行口有四种工作方式,它们由SM0、SM1设定,对应关系表如下表所示。
SM0 | SM1 | 方式 | 功能说明 |
0 | 0 | 0 | 同步移位寄存器方式(通常用于扩展I/O口) |
0 | 1 | 1 | 10位异步收发(8位数据),波特率可变(由定时器1的溢出率控制) |
1 | 0 | 2 | 11位异步收发(9位数据),波特率固定 |
1 | 1 | 3 | 11位异步收发(9位数据),波特率可变(由定时器1的溢出率控制) |
SM2——多机通信控制位。主要用于方式2和方式3。在方式0时SM2必须为0;在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1。
REN——允许串行接收位。REN=1,允许串行口接收数据;REN=0,禁止串行口接收数据。
TB8——方式2、3中发送数据的第九位,该位未用。
RB8——方式2、3中接收数据的第九位,该位未用。
TI——发送中断请求标志位。发送数据结束TI=1,需要软件清0。
RI——接收中断请求标志位。接收数据结束RI=1,需要软件清0。
二、串口通信分析(方式1)
方式1是十位数据的异步通信口,其中1位起始位,8位数据位,1位停止位。TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。其传输波特率是可变的。对于51单片机,波特率由定时器1的溢出率决定。通常我们在做单片机与单片机串口通信、单片机与计算机串口通信、计算机与计算机串口通信时,基本选择方式1,因此这种方式大家务必要完全掌握。
- 初始化串口的工作方式——方式1,SCON
- 设置波特率
- 数据发送/接收 发送数据用查询(TI,RI),接收数据用中断(ES,EA,interrupt 4)
三、代码实现
中断方式
串口助手 8位显示在数码管上
#include <STC15F2K60S2.h>
void display();//数码管显示函数
void Timer0Init(void);//定时器0初始化函数
void UartInit(void);//定时器1初始化函数
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};//共阳数码管段码
unsigned char dspbuf[8]={0,0,0,0,0,0,0,0};//显示缓冲区
unsigned char dspcom=0;
unsigned char rxbuf[11]={0,0,0,0,0,0,0,0};
unsigned char rxcnt=0;
unsigned char i;
bit rx_over=0;//命令接收完成标志位
//主函数
void main()
{
Timer0Init();
UartInit();
EA=1;
ES=1;
ET0=1;
while (1)
{
if (rx_over)
{
for (i=0;i<8;i++)
{
dspbuf[i]=rxbuf[i]-0x30;
}
rx_over=0;
ES=1;
}
}
}
//定时器0初始化函数
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
//定时器1初始化函数
void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
//数码管显示函数
void display()
{
//消隐
P2=((P2&0x1f)|0xe0);
P0=0xff;
P2&=0x1f;
//位选
P2=((P2&0x1f)|0xc0);
P0=(1<<dspcom);
P2&=0x1f;
//段选
P2=((P2&0x1f)|0xe0);
P0=tab[dspbuf[dspcom]];
P2&=0x1f;
if (++dspcom==8)
dspcom=0;
}
//定时器0中断服务函数
void isr_timer_0(void) interrupt 1
{
display();
}
//串口中断服务函数
void isr_uart(void) interrupt 4
{
if (RI)
{
RI=0;//清除接收标志位
rxbuf[rxcnt]=SBUF;
rxcnt++;
if (rxcnt==8)
{
rx_over=1;
rxcnt=0;
ES=0;
}
}
}
查询方式
#include <STC15F2K60S2.h>
void UartInit(void);
void SendData(unsigned char dat);
unsigned char dat1;
//主函数
void main()
{
UartInit();
while(1)
{
while(RI==0);
dat1=SBUF;
SendData(dat1);
RI=0;
}
}
//定时器初始化
void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
//SendData函数
void SendData(unsigned char dat)
{
SBUF=dat;
while(TI==0);
TI=0;
}