串口基本认识:
串行接口 简称 串口。 也称 串行通信接口 or 串行 通讯接口(通常com口),是才用串行通信方式的扩展接口。
串行接口是指 数据一位一位的顺序传送。
特点 : 通信线路简单,只要一对传输线就可以实现双向通信
-- 低成本 ,远距传送,速度慢- 是设备间接线通信的一种方式
- 是数据一位一位的顺序传送
- 双向通信, 全双工
- 传送速度相对较慢
三种通信方式——单工、半双工和双工通信
一、单工通信(simplex)
单工通信只支持信号在一个方向上传输(正向或反向),任何时候不能改变信号的传输方向。
为保证正确传送数据信号,接收端要对接收的数据进行校验,若校验出错,则通过监控信道发
送请求重发的信号。
此种方式适用于数据收集系统,如气象数据的收集、电话费的集中计算等。
例如计算机和打印机之间的通信是单工模式,因为只有计算机向打印机传输数据,而没有相反
方向的数据传输。还有在某些通信信道中,如单工无线发送等。
二、半双工通信(half-duplex)
半双工通信允许信号在两个方向上传输,但某一时刻只允许信号在一个信道上单向传输。
因此,半双工通信实际上是一种可切换方向的单工通信。
此种方式适用于问讯、检索、科学计算等数据通信系统;
传统的对讲机使用的就是半双工通信方式。由于对讲机传送及接收使用相同的频率,不允许同
时进行。因此一方讲完后,需设法告知另一方讲话结束(例如讲完后加上’OVER’),另一方
才知道可以开始讲话。
三、全双工(full-duplex)
全双工通信允许数据同时在两个方向上传输,即有两个信道,因此允许同时进行双向传输。
全双工通信是两个单工通信方式的结合,要求收发双方都有独立的接收和发送能力。
全双工通信效率高,控制简单,但造价高。
计算机之间的通信是全双工方式。一般的电话、手机也是全双工的系统,因为在讲话时可以听到对方的声音。
总结
通常四线线路实现全双工数据传输,二线线路实现单工或半双工数据传输。在采用频分法、时间压缩法、回波抵消技术时,二
线线路也可实现全双工数据传输。
————————————————
分类(按电器标准和协议):
RS-232-C、RS-422、RS-485RS-232-C -- 标准串口 - 1 个设备,15米, 速度20 kb/s
实例: 电脑等本地设备RS-422 -- 升级 -- 接10个节点 -1219米
RS-485 -- 32 个设备
================================
串口的电平:
UART(异步串行)-- 包括 RS-232电平 和 TTL 电平
RS-232电平:
逻辑1:-15 ~ -3V
逻辑0: 3 ~ 15V
TTL 电平:
逻辑1 : 5V
逻辑0: 0V
输出高电平: >=2.4V 输出低电平<= 0.4V
输入高电平 >=2.0V 输入高电平 <= 0.8V
// 笔记本 通过 TTL 电平与 单片机 通信 TX-发送线-3.1 RX- 接收线-3.0
// 软件工程师 只关心 1-- 高电平 0-- 低电平 即可
==================================================
窜口接线方式 -- 交叉接线 -- RX接TX -- 发送 接 接收, 接收 接 发送
SBUF
-- 99H地址 -- 输入/输出的数据缓冲器 -- 2个独立的 8位寄存器
代码体现:
接收数据: char data =SBUF发送数据: SBUF = data
=========================================
串口通信协议
波特率 -- 数据传输的速度 (与晶振有关系) (晶振又与定时器挂钩)
校验位 、 起始位 、停止位 的 选择
实例1:发送单个 字节
编程 让单片机发送数据给 电脑
#include"reg52.h"
sfr AUXR = 0x8E;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR &= 0xBF; //定时器1时钟为Fosc/12,即12T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式 -- 0010
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void main()
{
// data在51中的关键字,不能用作变量名
char data_msg='a';
//配置C51串口的 通信方式:
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区 写入数据-- 就完成数据的发送
SBUF = data_msg;}
}
======================================
串口初始化程序解读:
倍率控制
PCON &= 0x7F; //波特率不倍速
7 --0111 F- 1111 &0x7F -- 高8位清零,其他位不变
SMOD : 波特率 选择位: 0-- 不变 1--加倍
SMOD0: 帧错误检测有效控制位
选择串口模式
SCON = 0x50; //8位数据,可变波特率
5 0: 0101 0000 -- B4--REN--配置为1,允许串口接收 B6--SM0 SM1:0 1模式 --8为UART 波特率可变
设置 定时器 1的 模式:
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
2 0: 0010 0000 | -->M1 M0: 1 0 ,8位自动重装方式,8位自动重装方式
设置初值
TL1 = 0xFD; //设定定时初值 - - FD 是9600 MHZ计算出来的
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
===========================
void UartInit(void) //9600bps@11.0592MHz
{
AUXR=0x01; //减少定时器辐射 -- 抗干扰
SCON =0x40; //配置 窗口工作方式1,REN不使能接收
//不配 PCON -- 不设置倍数关系
//配置定时器1为 8位自动重装
TMOD &=0xF0; //高位清零
TMOD |=0x20; //00 10 -- 配置为定时器1为: 1 0 模式 -- 8位自动重装
//定义初值
TL1=0xFD;
TH1=0xFD; // 9600 波特率的初值
TR1= 1; // 定时器 -- 启动
}
==================================
实例2:发送字符串
-- 注意在串口中 -- “\r\n” -- 表示换行
#include"reg52.h"
sfr AUXR = 0x8E;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;i = 2;
while (--i);
}void UartInit(void) //9600bps@11.0592MHz
{
AUXR=0x01; //减少定时器辐射 -- 抗干扰
SCON =0x40; //配置 串口口工作方式1,REN不使能接收
//不配 PCON -- 不设置倍数关系
//配置定时器1为 8位自动重装
TMOD &=0xF0; //高位清零
TMOD |=0x20; //00 10 -- 配置为定时器1为: 1 0 模式 -- 8位自动重装
//定义初值
TL1=0xFD;
TH1=0xFD; // 9600 波特率的初值
TR1= 1; // 定时器 -- 启动
}
void sendByte(char a) // 发送单个字节
{
SBUF = a;
while(!TI);
TI=0;
}
void sendString(char *str) // 发送字符串 -- 指针遍历 的形式
{while(*str!='\0')
{
sendByte(*str);
str++;
}
}
void main()
{//配置C51串口的 通信方式:
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区 写入数据-- 就完成数据的发送
sendString("mengxianggiegie\r\n");}
}
=====================================
实例3:通过串口点亮led
SCON -- bit4 REN -- 允许数据接收
#include"reg52.h"sfr AUXR = 0x8E;
sbit D5 = P3^7;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}void UartInit(void) //9600bps@11.0592MHz
{
AUXR=0x01; //减少定时器辐射 -- 抗干扰
SCON =0x50; //配置 串口口工作方式1,REN 使能接收
//不配 PCON -- 不设置倍数关系
//配置定时器1为 8位自动重装
TMOD &=0xF0; //高位清零
TMOD |=0x20; //00 10 -- 配置为定时器1为: 1 0 模式 -- 8位自动重装
//定义初值
TL1=0xFD;
TH1=0xFD; // 9600 波特率的初值
TR1= 1; // 定时器 -- 启动
}
void sendByte(char a)
{
SBUF = a;
while(!TI);
TI=0;
}
void sendString(char *str)
{while(*str!='\0')
{
sendByte(*str);
str++;
}}
void main()
{
char cmd;
D5=1;//配置C51串口的 通信方式:
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区 写入数据-- 就完成数据的发送
sendString("mengxianggiegie\r\n");
//怎么知道已经收到数据: RI -- 不断查询RI的值 1 -- (收到数据后由硬件置1) -- RI响应中断后必须软件复位 -- 代码清零
if(RI==1){ //确认收到数据
RI=0;
cmd = SBUF;
if(cmd == 'o'){//收到 o-pen 开灯
D5=0;
}
else if(cmd == 'c'){//收到c-lose 关灯
D5=1;
}
}}
}
===================================
实例4 : 中断控制 优化实例3的延时函数
如果使用C语言 -- 中断查询次序号 就是中断号
例如:
void initRoutine(void) interupt 0;
EA =1; // 开启总中断
ES=1; // 开启串口中断#include"reg52.h"
sfr AUXR = 0x8E;
sbit D5 = P3^7;char cmd;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}void UartInit(void) //9600bps@11.0592MHz
{
AUXR=0x01; //减少定时器辐射 -- 抗干扰
SCON =0x50; //配置 串口口工作方式1,REN 使能接收
//不配 PCON -- 不设置倍数关系
//配置定时器1为 8位自动重装
TMOD &=0xF0; //高位清零
TMOD |=0x20; //00 10 -- 配置为定时器1为: 1 0 模式 -- 8位自动重装
//定义初值
TL1=0xFD;
TH1=0xFD; // 9600 波特率的初值
TR1= 1; // 定时器 -- 启动
EA =1; // 开启总中断
ES=1; // 开启串口中断
}
void sendByte(char a)
{
SBUF = a;
while(!TI);
TI=0;
}
void sendString(char *str)
{while(*str!='\0')
{
sendByte(*str);
str++;
}}
void main()
{
D5=1;//配置C51串口的 通信方式:
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区 写入数据-- 就完成数据的发送
sendString("mengxianggiegie\r\n");
}
}void uartHandler() interrupt 4
{
if(RI) // 中断处理函数中,对于接收中断的响应
{
RI=0; //清楚接收中断标志位
cmd = SBUF;
if(cmd == 'o'){//收到 o-pen 开灯
D5=0;
}
else if(cmd == 'c'){//收到c-lose 关灯
D5=1;
}
}
}
// 总结 -- 无论发送还是接收都会引起串口中断 -- 需要if 判断RI
使用之前要EA =1;ES=1; 来都打开串口中断
===================================
ASCLL 码值 常见的坑:
ASCLL 码 文本模式的 1 位49 文本模式的0 是 48 ,但是字符'1' 就是1即49ASCLL码
当然我们也可以在 发送缓冲区调位HEX模式,这时候的1,0也可以直接生效
==================================================
实例5: 匹配字符串命令
背景: 需要多个字符操作我们的命令 -- 数组
static 的作用 --
函数在调用的过程中 ,如果没有static 每次的初始化操作都会被执行,static修饰打的初始化操作只会执行一次
strstr(Str,str) -- Str包含子串 str 返回1 ,否则0
#include"reg52.h"
#include<string.h>#define SIZE 12
sfr AUXR = 0x8E;
sbit D5 = P3^7;char cmd[SIZE];
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}void UartInit(void) //9600bps@11.0592MHz
{
AUXR=0x01; //减少定时器辐射 -- 抗干扰
SCON =0x50; //配置 串口口工作方式1,REN 使能接收
//不配 PCON -- 不设置倍数关系
//配置定时器1为 8位自动重装
TMOD &=0xF0; //高位清零
TMOD |=0x20; //00 10 -- 配置为定时器1为: 1 0 模式 -- 8位自动重装
//定义初值
TL1=0xFD;
TH1=0xFD; // 9600 波特率的初值
TR1= 1; // 定时器 -- 启动
EA =1; // 开启总中断
ES=1; // 开启串口中断
}
void sendByte(char a)
{
SBUF = a;
while(!TI);
TI=0;
}
void sendString(char *str)
{while(*str!='\0')
{
sendByte(*str);
str++;
}}
void main()
{
D5=1;//配置C51串口的 通信方式:
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区 写入数据-- 就完成数据的发送
sendString("mengxianggiegie\r\n");
}
}void uartHandler() interrupt 4
{
static i = 0;
if(RI) // 中断处理函数中,对于接收中断的响应
{
RI=0; //清楚接收中断标志位
cmd[i] = SBUF;
i++;
if(i==SIZE)
i=0;
if(strstr(cmd,"en")){//收到 o-pen 开灯
D5=0;
i=0;
memset(cmd,'\0',SIZE);
}
else if(strstr(cmd,"se")){//收到c-lose 关灯
D5=1;
i=0;
memset(cmd,'\0',SIZE);
}
}
}
-置
=========================================
串口通讯的协议: 波特率 起始位 数据位 的设置
串行 工作模式一 -- 8位UART,波特率可变
SCON : SM0 SM1: 0 1 -- 串行通信以模式1 工作
次模式为58位UART模式,一帧信息为10位: 1位起始位,8位数据位还让 1为停止位
TX -- P3.1 RX --P3.0