- 基本概念
(1) 串行通信是指数据一位接一位地顺序发送或接收。
(2) 串行通信有SPI、IIC、UART等多种,最常见最通用的是指UART。
(3) 串行通信的制式有:单工、半双工、全双工三种。
(4) 波特率:每秒钟传输的位数,9600波特率就是指每秒钟传输9600位。
(5)注意:在51单片机中需要使用定时器1来产生波特率,因此,如果使用串口通信,则定时器1就不能做其他用途,在初始化串行接口模块的时候,除了要配置SCON寄存器之外,还有根据波特率参数设置定时器1的技术初值。 - 对于传统的51单片机,与串口相关的寄存器有:
(1)TH1和TL1:设置波特率参数。
(2)MOD:设置定时器1的工作模式。
(3)SBUF:串行通信数据的发送和接收缓冲器。
(4)SCON:串行接口控制寄存器。
(5)STC15F2K602单片机,还需要对新增的辅助寄存器AUXR进行设置,否则是无法进行串口数据收发的,对于传统的89C52单片机,则不需要这个步骤。 - 串口通信的编程思路
在串口通信的程序设计中,主要有串口初始化和数据收发两个部分。
在初始化函数中,基本步骤如下:
(1)设置定时器1的工作模式,也就是对TMOD寄存器赋值。
(2) 计算波特率参数,并赋值给TH1和TL1寄存器。
(3) 打开定时器1。
如果使用的是STC 12系统单片机,则要设置AUXR寄存器。
(4) 设置SCON寄存器。
(5) 使能串口中断ES。
(6) 使能总中断EA。
数据的发送通常采用查询方式,而数据的接收则采用中断方式。
利用单片机的串行接口与上位机建立传输信道进行数据的收发。
- 采用8位的UART模式,即模式1,波特率为9600BPS。
- 数据发送采用查询方式,数据接受采用中断方式。
- 系统上电初始化之后,单片机向上机位发送两个字节:0x5a和0xa5,然后等待接收上位机的数据,每接收到一个字节后,在该字节的基础上加1。
#include <STC15F2K60S2.H>
void send(unsigned char d);
void ruart();
sbit beer=P0^6;
void main()
{
P2=0xA0;beer=0;P2 &= 0x1f;;//上电电位不稳,先关闭蜂鸣器
ruart();
send(0x5a);
send(0xa5);
while(1);
}
//串口初始化函数
void ruart()
{
TMOD=0x20; //定时器1工作模式为自动重装
TH1=0xfd; //设置波特率为9600
TL1=0xfd; //11.0592M或12M的12分频
AUXR=0x00; //bit7=1:定时器1不分频,0则12分频
TR1=1; //启动定时器1
SCON = 0x50; //串口参数为模式1和允许接收
ES=1; //使能串口中断
EA=1; //使能总中断
}
unsigned char dat;
//串口中断服务函数
void serviceuart() interrupt 4
{
if(RI==1) //接收到一个完整的字节 如果RI==1就说明接收到一个完整的数据
{
RI=0; //人工清零 清除接收完成标志
dat=SBUF; //接收到的数据放在 dat 里面
send(dat+1);
}
}
//发送单个字节函数
void send(unsigned char d)
{
SBUF = d; //将数据放进SBUF缓冲器
while(TI == 0); //等待发送数据完成
TI = 0; //清除发送完成标志
}
串口调试:
利用单片机的串行接口与上位机建立传输数据信道。
- 采用8位的UART模式,即模式1,波特率为9600BPS。
- 数据发送采用查询方式,数据接受采用中断方式。
- 系统上电初始化之后,关闭蜂鸣器和继电器等无关设备,并向上位机发送字符串:“Welcome to XMF system!”,回车换行。
- 上位机通过串口发送单字节命令可以控制下位机的8个LED灯开关。
- 上位机通过串口发送单字节命令可以读取下位机运行信息。
- 通信规约如下表:
#include <STC15F2K60S2.H>
void init();
void uart();
void selectHC(unsigned char n);
void sendByte(unsigned char dat);
void sendString(unsigned char *str);
void working();
void main()
{
init();
uart();
sendString("Welcome to XMF system!\r\n");
while(1)
{
working();
}
}
void selectHC(unsigned char n)
{
switch(n)
{
case 4:P2=(P2&0x1f)|0x80;break; //LED灯
case 5:P2=(P2&0x1f)|0xa0;break; //蜂鸣器,继电器
case 6:P2=(P2&0x1f)|0xc0;break; //数码管位选
case 7:P2=(P2&0x1f)|0xe0;break; //数码管段选
case 0:P2=(P2&0x1f)|0x00;break;
}
}
//关闭蜂鸣器和继电器,LED灯都熄灭
void init()
{
selectHC(5);P0=0x00;
selectHC(4);P0=0xff;
}
//初始化
void uart()
{
TMOD=0X20; //定时器1工作模式为自动重装
TH1=0XFD; //设置波特率为9600, 11.0592M或12M的12分频
TL1=0XFD;
TR1=1; //启动定时器1
AUXR=0X00; //bit7=1:定时器1不分频,0则12分频
SCON = 0x50; //串口参数为模式1和允许接收
ES=1; //使能串口中断
EA=1; //使能总中断
}
//串口中断 串口数据接收
unsigned char c=0x00;
void serviceuart() interrupt 4
{
if(RI==1) //接收到一个完整的字节 如果RI==1就说明接收到一个完整的数据
{
c=SBUF; //接收到的数据放在 dat 里面
RI=0; //人工清零 清除接收完成标志
}
}
void working()
{
if(c!=0x00)
{
switch(c&0xf0) //取出高四位,判断是a还是b,进行对L1-L4还是L5-L8进行判断
{
case 0xa0: //输入的高4位是a,则对L1-L4进行操作
P0=(P0|0x0f)&(~c|0xf0);
c=0x00;
break;
case 0xb0: //输入的高4位是b,则对L5-L8进行操作
P0=(P0|0xf0)&((~c<<4)|0x0f);
c=0x00;
break;
case 0xc0: //输出c0,返回指定信息
sendString("The System is Running...\r\n");
c=0x00;
break;
}
}
}
//发送单字节
void sendByte(unsigned char dat)
{
SBUF=dat; //将数据放进SBUF缓冲器
while(TI==0); //等待发送数据完成
TI=0; //清除发送完成标志
}
//发送字符串
void sendString(unsigned char *str)
{
while(*str!='\0')
{
sendByte(*str++);
}
}