区分:串口,COM口,UART,USART_usart和串口区别-CSDN博客
串口、COM口、UART口, TTL、RS-232、RS-485区别详解-CSDN博客
(1)人和人之间的通信:说话,写信
(2)人和计算机之间的通信:按键,显示器,鼠标
(3)计算机和计算机之间的通信
(1)事先约定
(2)基本的信息单元
(3)有效信息的编码,传输和解码
(1)同步和异步:同一个步调
(2)单工,半双工,全双工:数据传输方向
(3)并行和串口:并行(多根线),串行(单根线)
(4)电平信号【传输近,易受干扰】和差分信号【传输远,不易受干扰】:电平是通过高低电平进行区分,差分是相对的
(1)一种特定的通信协议【电平通信】
(2)串行通信,串口通信,UART,USART
(3)串口通信的特点:异步,串行,全双工
(1)早期:计算机之间短距离通信(1.5米内),完备通信机制
(2)现在:CPU之间近距离通信【CPU和周边芯片】,调试信息输入输出,非完备通信
(1)3根线(GND,RxD【接收线】,TxD【发送线】---recive ,transmit)---不完备通信
或者9根线(DB9)-完备通信
(2)发送方有发送位移寄存器,接收方有接收移位寄存器
(3)数据在发送方和接收方的CPU中都以字节为单位整字节处理
(4)数据在通信线上以位为单位逐个bit的传输
传输都是一帧一帧的发
开始之前要发送一个起始位
比如我们传输“A”,转换为ASCII就是8位二进制,这8位就叫做8位数据位【有效数据】
数据位要双方沟通确定的
判断传输过程中是否出错
判断是否结束
串行通信的速度
一秒钟传输多少给bit位,发送方和接收方必须波特率设置为一样【波特率越小,传输速度慢,抗干扰能力越强】
速率协商,现在一般要禁用掉
SoC:把CPU以及其他功能集成到一个芯片上
(1)串行通信功能是SoC的一个(内部)外设提供的,与CPU无关【CPU=运算器+控制器】--CPU本身无法通信
(2)各种不同的SoC的串行通信大同小异【内部差不多,编程时候可能不同】
(3)串行通信经常作为主控SoC与其他外部芯片之间的通信接口【串行通信==SoC与外部其他芯片的通信】
(1)查询方式。硬盘在发送完一帧数据后会将一个标志位置位(标志位本来是0),软件需要不断读取这个标志位的值来判断硬件是否完成了发送(如果读出来的是0就表示硬件还在发还在发还没完还在忙,所以我们就不能认为硬件发完了,所以就不能给硬件安排下一帧数据的发送;如果读出来的是1则说明硬件已经发完了上一帧数据,这时候软件就应该给硬件在给一帧数据去发送)
(2)因为串口发送完这个事件对CPU来说是个异步事件(因为不知道什么时候发送消息),所以这里查询方式来处理和之前讲过的查询方式处理按键是非常类似的。
(3)常见情况下:串口发送会使用查询方式,串口接收会使用中断方式【因为不知道什么时候会接收到信息,使用中断才不会过度销毁CPU】
PCON中的SMOD
所谓波特率加倍,就是正常计算出的波特率假设是2400,那么SMOD=1时则实际波特率就是4800;当SMOD=0时不加倍,也就是2400还是2400
(1)目标:将PC机和51单片机通过串口连接起来
(2)PC机的串口情况:台式机串口,笔记本USB转串口
(3)开发板原理图分析
什么都不用动,默认就是使用这个,最简单最省事,最推荐
用DB9接口的USB转串口线
注意:跳线帽接到DB9一侧
只接三根线:TxD,RxD,GND
此时无法进行程序下载
//串口初始化函数
//预设一个串口条件:8位数据位,1停止位,0校验位,波特率4800
//初始化的主要工作就是去设置相关的寄存器
void uart_init(void){
SCON=0x50; //串口工作在模式1(8位串口),允许接收
PCON=0x80; //波特率加倍,意思是本来需要波特率4800,等一下计算时按照2400去计算就好
}
SMOD---》判断是否进行波特率加倍【如果加倍则为1,不加倍则为0】
查看数据手册中”串行通信中波特率的设置“
接着查看定时/计数器1的工作方式2的寄存器设置情况
TMOD=0x20; //设置T1为模式2
TR1=1; //开启T1让它开始工作
我们刚刚在上面计算出TH1=243;,所以进行设置
TH1=243;
TL1=243; //8位自动重装,意思就是TH1用完了下一个周期TL1会自动重装到TH1中
注意点:51单片机不一样,要先发送在检验有没有在发送
其他MCU都是先检验在发送
如果为【0】则表示在忙,如果为【1】则表示发送结束
//串口发送函数,发送一个字节
void uart_send_byte(unsigned char c){
//【第一步】发送一个字节
SBUF=c;
//【第二步】先确认串口发送部分没有在忙
while(!TI);//TI=0,表示在忙
//【第三步】软件复位TI标志位---数据手册要求的
TI=0;
}
#include
//函数声明
void uart_init(void);
void uart_send_byte(unsigned char c);
void delay();
void main(){
//第一步:初始化好串口到正确的状态
uart_init();
while(1){//为了调试方便,让A循环发送,才好监视
//第二步:通过串口发送信息出去
uart_send_byte('A');
delay();
}
}
void delay(){
unsigned char i,j;
for(i=0;i<100;i++){
for(j=0;j<200;j++);
}
}
//串口初始化函数
//预设一个串口条件:8位数据位,1停止位,0校验位,波特率4800
//初始化的主要工作就是去设置相关的寄存器
void uart_init(void){
//波特率不加倍的例子
SCON=0x50; //串口工作在模式1(8位串口),允许接收
PCON=0x00; //波特率不加倍
//通信波特率相关的设置
//此处我们使用【方式1】---对应数据手册
TMOD=0x20; //设置T1为模式2
TR1=1; //开启T1让它开始工作
TH1=249;
TL1=249; //8位自动重装,意思就是TH1用完了下一个周期TL1会自动重装到TH1中
//中断初始化
ES=1;//串口中断初始化
EA=1;//整个中断初始化
}
//串口发送函数,发送一个字节
void uart_send_byte(unsigned char c){
//【第一步】发送一个字节
SBUF=c;
//【第二步】先确认串口发送部分没有在忙
while(!TI);//TI=0,表示在忙
//【第三步】软件复位TI标志位---数据手册要求的
TI=0;
}
因为我们算出来的TH1和TL1=6.5,所以精确度可能会受到影响,我们将其设置为250 或者 249则结果都会输出乱码
我们前面算出TH1=6.5【这里我们的波特率为4800】,所以如果为9600则我们应该将【6.5/2=3.25】才是我们9600的结果
//波特率为9600
SCON=0x50; //串口工作在模式1(8位串口),允许接收
PCON=0x00; //波特率不加倍
//通信波特率相关的设置
//此处我们使用【方式1】---对应数据手册
TMOD=0x20; //设置T1为模式2
TR1=1; //开启T1让它开始工作
TH1=253;
TL1=253; //8位自动重装,意思就是TH1用完了下一个周期TL1会自动重装到TH1中
//中断初始化
ES=1;//串口中断初始化
EA=1;//整个中断初始化
#include
//函数声明
void uart_init(void);
void uart_send_byte(unsigned char c);
void delay();
void uart_send_string(unsigned char *str);
void main(){
//第一步:初始化好串口到正确的状态
uart_init();
while(1){
//发送字符串,也可以发送中文
uart_send_string("abcdefg");
delay();
}
}
void delay(){
unsigned char i,j;
for(i=0;i<100;i++){
for(j=0;j<200;j++);
}
}
//串口初始化函数
//预设一个串口条件:8位数据位,1停止位,0校验位,波特率4800
//初始化的主要工作就是去设置相关的寄存器
void uart_init(void){
//波特率加倍的例子
SCON=0x50; //串口工作在模式1(8位串口),允许接收
PCON=0x80; //波特率加倍,意思是本来需要波特率4800,等一下计算时按照2400去计算就好
//通信波特率相关的设置
//此处我们使用【方式1】---对应数据手册
TMOD=0x20; //设置T1为模式2
TR1=1; //开启T1让它开始工作
TH1=243;
TL1=243; //8位自动重装,意思就是TH1用完了下一个周期TL1会自动重装到TH1中
//中断初始化
ES=1;//串口中断初始化
EA=1;//整个中断初始化
}
//串口发送函数,发送一个字节【单个字节】
void uart_send_byte(unsigned char c){
//【第一步】发送一个字节
SBUF=c;
//【第二步】先确认串口发送部分没有在忙
while(!TI);//TI=0,表示在忙
//【第三步】软件复位TI标志位---数据手册要求的
TI=0;
}
//发送字符串【多个字符】
void uart_send_string(unsigned char *str)
{
while (*str != '\0')
{
uart_send_byte(*str); // 发送1个字符
str++; // 指针指向下一个字符
}
}
因为我们在程序执行过程中如果要接收PC机传输过来的数据,则表示程序要进行中断,则要进行中断处理。
void uart_isr(void) interrupt 4 using 1{
}
#include
//函数声明
void uart_init(void);
void uart_send_byte(unsigned char c);
void delay();
void uart_send_string(unsigned char *str);
void main(){
//第一步:初始化好串口到正确的状态
uart_init();
uart_send_string("串口回环测试\n");
while(1);
}
void delay(){
unsigned char i,j;
for(i=0;i<100;i++){
for(j=0;j<200;j++);
}
}
//串口初始化函数
//预设一个串口条件:8位数据位,1停止位,0校验位,波特率4800
//初始化的主要工作就是去设置相关的寄存器
void uart_init(void){
//波特率加倍的例子
SCON=0x50; //串口工作在模式1(8位串口),允许接收
PCON=0x80; //波特率加倍,意思是本来需要波特率4800,等一下计算时按照2400去计算就好
//通信波特率相关的设置
//此处我们使用【方式1】---对应数据手册
TMOD=0x20; //设置T1为模式2
TR1=1; //开启T1让它开始工作
TH1=243;
TL1=243; //8位自动重装,意思就是TH1用完了下一个周期TL1会自动重装到TH1中
//中断初始化
ES=1;//串口中断初始化
EA=1;//整个中断初始化
}
//串口发送函数,发送一个字节【单个字节】
void uart_send_byte(unsigned char c){
//【第一步】发送一个字节
SBUF=c;
//【第二步】先确认串口发送部分没有在忙
while(!TI);//TI=0,表示在忙
//【第三步】软件复位TI标志位---数据手册要求的
TI=0;
}
//发送字符串【多个字符】
void uart_send_string(unsigned char *str)
{
while (*str != '\0')
{
uart_send_byte(*str); // 发送1个字符
str++; // 指针指向下一个字符
}
}
//中断处理程序
void uart_isr(void) interrupt 4 using 1
{
unsigned char tmp;
if(RI){
tmp=SBUF; //读取SBUF,其实就是读出串口接收到的1个字节
//RI:串行口1接收中断标志
RI=0;
}
//自此已经读到了PC发给单片机的一个字节,但是单片机没有显示器无法显示
//我们用最简单的方法,就是直接回发
uart_send_byte(tmp);
}
(1)理论上RS232不超过15米--电脑的COM端口【DB9】
(2)理论上TTL电平通信距离更短---TTL是在单片机上使用
(3)实际上几百米也有人宣称做到了,但是稳定性不能保证
(4)波特率越高通信距离越短【速度越快,通信距离越短】
(1)提高电压标准
(2)提高通信线抗干扰能力,降低阻抗
(3)使用差分信号--抗干扰能力强【RS485/RS422】
(1)最大通信距离1200多米,最快通信速率10Mbps,距离和速度成反比(USB接口,网线)
(2)差分信号负逻辑【5V代表---0 -3V代表----1】
(3)更远距离可以加中继器【中继器---多个485的节点连接起来--放大】
(4)半双工【如果要实现全双工,则使用4根线】
(5)RS485只提高物理层通信能力,不提供数据层协议,需要用户自定义,或者使用标准协议如MODBUS协议。
MAX485就是相当于UART与RS485之间的信号转换
(1)CPU本身只会提供URAT接口,而不会提供RS485接口。CPU根本不认识RS485
(2)RS485使用场景:CPUA-->UART转RS485------>远距离通信----->RS485转UART---->CPUB
(3)对RS485的理解:RS485是纯硬件实现的,硬件芯片如MAX485来管理的,根本不涉及软件编程。软件工程师只关注串口,只通过串口将数据发送出去或者接收回来即可。UART转485和485转UART对CPU来说是透明的。