本讲任务:
讲述计算机串行通信基础知识和51单片机的串口编程。
计算机通信:
通信是指通过某种媒体将信息从一地传送到另一地。古代飞鸽传书和今天电话、手机,都是人与人之间的通信。计算机通信是将计算机技术和通信技术的相结合,完成计算机与外部设备或计算机与计算机之间的信息交换。上面所说的计算机与计算机之间的通信分下面3种情况:
1:PC机与PC机通信;
2:PC机与单片机通信(本讲只讲这一种);
3:单片机与单片机通信。
为什么要进行计算机通信:
计算机通信的出现,大大拓展了计算机的应用范围。 PC机与单片机通信,可以实现:
1、实现远程测控。
2、组成计算机网络。
计算机通信的分类:
通信有并行通信和串行通信两种方式。在多微机系统以及现代测控系统中信息的交换多采用串行通信方式。
串行通讯与并行通讯:
计算机通信是将计算机技术和通信技术的相结合,完成计算机与外部设备或计算机与计算机之间的信息交换 。可以分为两大类:并行通信与串行通信。
并行通信通常是将数据字节的各位用多条数据线同时进行传送 。
串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送。
并行通信的特点:控制简单、传输速度快;由于传输线较多,长距离传送时成本高且接收方的各位同时接收存在困难。
串行通信的特点:传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。
并行通信:数据多位同时传送。控制简单,传输速度快,传输线较多。
串行通信:数据字节一位一位在一条传输线上逐个传送。传输线少,可利用电话网,但传送控制复杂。
串行通信的传输方向:
1、单工:单工是指数据传输仅能沿一个方向,不能实现反向传输。
2、半双工:半双工是指数据传输可以沿两个方向,但需要分时进行。
3、全双工:全双工是指数据可以同时进行双向传输。
单工 半双工 全双工
串行通信的错误校验:
1、奇偶校验
在发送数据时,数据位尾随的1位为奇偶校验位(1或0)。奇校验时,数据中“1”的个数与校验位“1”的个数之和应为奇数;偶校验时,数据中“1”的个数与校验位“1”的个数之和应为偶数。接收字符时,对“1”的个数进行校验,若发现不一致,则说明传输数据过程中出现了差错。
2、代码和校验
代码和校验是发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和”进行比较,相符则无差错,否则即认为传送过程中出现了差错。
3、循环冗余校验
这种校验是通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对磁盘信息的传输、存储区的完整性校验等。这种校验方法纠错能力强,广泛应用于同步通信中。
传输速率与传输距离:
传输速率
比特率:每秒钟传输二进制代码的位数。
波特率:每秒钟调制信号变化的次数,即每秒钟发送的位数,单位是:波特(Baud)。
传输距离与传输速率的关系:
传输距离随传输速率的增加而减小。
串口结构:
有两个物理上独立的接收、发送缓冲器SBUF,它们占用同一地址99H ;接收器是双缓冲结构 ;发送缓冲器,因为发送时单片机是主动的,不会产生重叠错误。
串行通信的数据结构:
工作方式寄存器SCON:
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
功能 | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
RI:接收中断标志位
接收结束时,会由硬件置1,向单片机发出中断请求。(要由软件复位)
TI:发送中断标志位
发送结束时,会由硬件置1,向单片机发出中断请求。(要由软件复位)
TB8:用来存放发送的第9位。
RB8:用来存放接收的第9位。
REN:是串行接收允许位。1时:允许串行接收,0时:禁止串行接收。
SM2:多机通信控制位。
因为多级通信是在工作方式2和工作方式3下进行的,因此SM2主要用在工作方式2和工作方式3。
当SM2=0时:不论接收的第9位是0还是1,都接收数据,产生中断。当SM2=1时:只有在接收到的第9位为1时,才接收数据,并产生中断;而如果接收到的第9位为0时,则将接收到的数据丢弃,不产生中断。
工作方式寄存器PCON:
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
功能 | SMOD | - | - | - | - | - | - | - |
PCON是没有位寻址的,也就是说不能直接操作SMOD要直接操作PCON寄存器。
SMOD:是波特率是否加倍的选择位。0时:波特率不加倍,1时:波特率加倍。
波特率的概念:
波特率的定义:串行口每秒钟发送的位数称为波特率。比如说2400的波特率就是每秒钟发送2400个位数。
串行口的波特率是用定时器T1作为波特率发生器的,这是定时器自动设置在工作方式2(可自动重装初值)。
串口的操作步骤:
先设置波特率
设置定时器T1为工作方式2(设置TMOD寄存器)
给计数器赋初值(工作方式2会自动重装)
设置串口工作方式
设置SCON
如果使用中断方式,那么打开相应的中断和总中断
打开定时器T1,开始产生波特率
设置TRx
例程:
/*************************串口收发数据**************************
*单片机型号:STC89C52RC
*开发环境:KEIL
*功能:计算机发送0123456给单片机,单片机接收到数据后发送SSLV-JY给主机。
单片机接到其它数据,蜂鸣器报警。LCD1602显示接收数据的ASCII码。
*注:接收和发送都用字符格式
******************************************************************/
#include <reg52.h>
#include <intrins.h>
//FOSC = 11.0592MHz,12T模式,SMOD=0
#define reload_count_1200bps 0xe8
#define reload_count_2400bps 0xf4
#define reload_count_4800bps 0xfa
#define reload_count_9600bps 0xfd
#define LCD_Data P0
#define Busy 0x80
#define uchar unsigned char
#define uint unsigned int
sbit BEEP=P2^3;
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_E=P2^5;
uchar buf;
uchar rev_flag=0x00;
uchar code table0[]={" SL-51A "};
uchar code table1[]={"SERILA BAUD:9600"};
uchar code table2[]={" REV: 0123456 "};
uchar code table5[]={" SEND:SSLV-JY "};
uchar code table6[]={" "};
void serial_port_initial(char TH,char TL);
void send_UART(unsigned char i);
char UARTReceive(void);
void delay(int In,int Out);
void Delay5Ms(void);
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD,BuysC);
unsigned char ReadStatusLCD(void);
void LCDInit(void);
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData);
void init(void);
void display(void);
void init(void)
{
serial_port_initial(reload_count_9600bps,reload_count_9600bps);
LCDInit();
DisplayListChar(0,0,table0);
DisplayListChar(0,1,table1);
}
void serial_port_initial(char TH,char TL)
{
SCON=0x50;TMOD=0x20;PCON=0x00;
TH1=TH;TL1=TL;
ES=1;EA=1;TR1=1;
}
void send_UART(unsigned char i)
{
SBUF=i;
while(TI==0);
TI=0;
}
void Delay5Ms(void)
{
unsigned int TempCyc=3552;
while(TempCyc--);
}
void WriteDataLCD(unsigned char WDLCD)
{
ReadStatusLCD();
LCD_Data=WDLCD;
LCD_RS=1;
LCD_RW=0;
LCD_E=0;
LCD_E=0;
LCD_E=1;
}
void WriteCommandLCD(unsigned char WCLCD,BuysC)
{
if (BuysC)ReadStatusLCD();
LCD_Data=WCLCD;
LCD_RS=0;
LCD_RW=0;
LCD_E=0;
LCD_E=0;
LCD_E=1;
}
unsigned char ReadStatusLCD(void)
{
LCD_Data=0xFF;
LCD_RS=0;
LCD_RW=1;
LCD_E=0;
LCD_E=0;
LCD_E=1;
while(LCD_Data&Busy);
return(LCD_Data);
}
void LCDInit(void)
{
LCD_Data=0;
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,1);
WriteCommandLCD(0x08,1);
WriteCommandLCD(0x01,1);
WriteCommandLCD(0x06,1);
WriteCommandLCD(0x0C,1);
}
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData)
{
Y&=0x1;X&=0xF;
if(Y)X|=0x40;
X|=0x80;
WriteCommandLCD(X,0);
WriteDataLCD(DData);
}
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData)
{
unsigned char ListLength;ListLength=0;
Y&=0x1;X&=0xF;
while(DData[ListLength]>=0x20)
{
if(X<=0xF)
{
DisplayOneChar(X,Y,DData[ListLength]);
ListLength++;
X++;
}
}
}
void display(void)
{
if(rev_flag==0x36)
{
DisplayOneChar(0,1,table6[0]);
DisplayOneChar(1,1,table2[1]);
DisplayOneChar(2,1,table2[2]);
DisplayOneChar(3,1,table2[3]);
DisplayOneChar(4,1,table2[4]);
DisplayOneChar(5,1,0x30);
DisplayOneChar(6,1,0x31);
DisplayOneChar(7,1,0x32);
DisplayOneChar(8,1,0x33);
DisplayOneChar(9,1,0x34);
DisplayOneChar(10,1,0x35);
DisplayOneChar(11,1,0x36);
DisplayOneChar(12,1,table6[0]);
DisplayOneChar(13,1,table6[0]);
DisplayOneChar(14,1,table6[0]);
DisplayOneChar(15,1,table6[0]);
}
}
void main(void)
{
init();
while(1){display();}
}
void serial() interrupt 4
{
ES=0;
RI=0;
buf=SBUF;
switch(buf)
{
case 0x30: //接受到0,发送字符'S'给计算机
{BEEP=1;rev_flag=0x30;send_UART('S');}break;
case 0x31: //接受到2,发送字符'S'给计算机
{BEEP=1;rev_flag++;send_UART('S');}break;
case 0x32: //接受到3,发送字符'L'给计算机
{BEEP=1;rev_flag++;send_UART('L');}break;
case 0x33: //接受到4,发送字符'V'给计算机
{BEEP=1;rev_flag++;send_UART('V');}break;
case 0x34: //接受到5,发送字符'-'给计算机
{BEEP=1;rev_flag++;send_UART('-');}break;
case 0x35: //接受到5,发送字符'J'给计算机
{BEEP=1;rev_flag++;send_UART('J');}break;
case 0x36: //接受到5,发送字符'Y'给计算机
{BEEP=1;rev_flag++;send_UART('Y');}break;
default: //接受到其它数据,报警
{BEEP=0;}break;
}
ES=1; //允许串口中断
}
最后,求求看到的此文的小伙伴点赞和关注支持一下下哦。毕竟,码字不容易哦,您的支持是我最大的动力呀!!!呜呜呜~~~