目录
1.串口通信原理
2. 分类
1.RS232
2.USB转串口
3.串口的实例代码
4.普通IO口模拟串口通信
1.串口通信原理
一般用来实现单片机与单片机进行通信或者单片机与电脑(串口调试助手)。首先要明白什么是异步,异步就是收发不需要共同的时钟。而同步就是需要共同的时钟。接着什么是串行传输呢(只有一个通道发送一个字节要一个一个位发送,一般低位在前高位在后)而什么是并行传输呢(有多个通道假如有八个通道就可以一个字节发送)。异步串口通信是一种全双工通信。有三种传输方式。
- 单工:要么只可做接收,要么只可做发送。如:遥控器(发送)、收音机(接收)。
- 半双工:在同一时刻要么是接收要么是发送。如:对讲机
- 全双工:在同一时刻即可以接收也可以发送。如:通电话
下面思考2个问题:1.就是发送数据的时间。如发送一位要多长时间。这里就引出波特率。收发双方需要配置相同的波特率。才能保证数据传输不会出错。如发收方发送一位的速率是1/9600。而接收方接收一位的速率是1/115200。这样接收到的数据肯定会出错。2.接收方怎么知道你什么时候发送。当发送完怎么知道你发送结束。所以在发送一个字节时会先发送一个起始位。在空闲的时候因为是高电平。当发送起始位是0,当接收方收到0就知道你要发送数据了就准备好接收数据。当发完一个字节时。这时又会发送一个停止位1。当接收方接收到停止位1就知道你发送完了。发送一个字节需要发送10个位。起始位(一位)+ 一个字节(八位) + 起始位(一位)。如图:奇偶校验位可以不考虑。
2. 分类
1.RS232
九针九孔的接口,并且RS232是负逻辑(高电平是0,低电平是1),所以单片机的RXD、TXD不能直接接RS232的RXD、TXD。需要用MAX232转电平。这个已经用的很少了。比较流行是USB转串口。
2.USB转串口
它需要CH340芯片把USB数据转成串口数据给单片机。单片机可以把数据通过串口给串口调试助手。但是需要在电脑上安装一个CH340驱动。
3.串口的实例代码
#include<reg52.h>
void config(unsigned int b);
void main()
{
EA=1;
config(9600);
while(1); //等待进入中断
}
void config(unsigned int b)
{
SCON=0x50; //串口模式1
TMOD&=0x0f;
TMOD|=0x20; //串口模式1时 定时器必须是模式2
TH1=256-(11059200/12/2/16)/b; //记住公式
TL1=TH1; //定时器模式2自动重载 用TH1去装载TL1
ET1=0; //T1用来产生信号发生器(传产生指定波特率),所以不能使用它的中断
ES=1; //串口中断
TR1=1;
}
void InterruptES() interrupt 4
{
if(RI)
{
RI=0; //接收完成 软件清零
SBUF=SBUF+1;//接收的时 立马就发送
}
if(TI)
{
TI=0; //发送完 软件清零
}
}
在单片机电路中都会信号发生器直接产生波特率。并且只能是定时器1与定时器2不能是定时器0产生。如果看串口框图会发现串口的发送与接收是同一个寄存器(SBUF),并且地址也是一样的。在代码中自动能区分SBUF是接收还是发送。当接收完成与发送完成可以产生中断都是同一个中断。在中断中要软件清零。下面就是串口调试助手。要选择自己对应的COM口。波特率、停止位、数据位也要配置跟你代码里的一样。配置好就可以发送了。
4.普通IO口模拟串口通信(相当于用定时器的中断产生波特率)
#include<reg52.h>
sbit PIN_RXD=P3^0; //接收端口
sbit PIN_TXD=P3^1; //发送端口
bit flag=0;
bit R_end=0; //接收完毕标志位
bit T_end=0; //发送完毕标志位
unsigned char Rbuff=0; //接收缓冲区
unsigned char Tbuff=0; //发送缓冲区
void configUart(unsigned int baud);
void R_RXD();
void T_TXD(unsigned char date);
void main()
{
EA=1;
configUart(9600);
while(PIN_RXD); //当PIN_RXD为0 说明串口调试助手要发数据了
R_RXD(); //接收数据
while(!R_end); //等待接收完成
T_TXD(Rbuff); //发送数据(Rbuff+1)
while(!T_end); //等待发送完成
}
//每1/baud进一次中断
void configUart(unsigned int baud)
{
TMOD&=0xF0;
TMOD|=0x02;
TH0=256-(11059200/12)/baud; //T0的重载值(11059200/12)/baud;(机器周期的个数)
}
void R_RXD()
{
TL0=256-((256-TH0)>>1); //256-TH0是机器周期的个数然后右移一位就是除2 让TL0为半个波特率为开始
//因为在中间位置接收是最稳定的数据 而下次就是一个波特率 所以在第一位数据位的中间位置接收
ET0=1;
TR0=1;
R_end=0; // 清零接收标志位
flag=0; //flag=0 代表当前为接收状态
}
void T_TXD(unsigned char date)
{
Tbuff=date+1; //接收到的数据+1 放到Tbuff
ET0=1;
TR0=1;
PIN_TXD=0; //发送起始位为0
T_end=0; // 清零发送标志位
flag=1; //flag=1 代表当前为发送状态
}
void InterrputTime0() interrupt 1
{
static unsigned char index=0; //接收发送每位计数
if(flag) //发送
{
index++;
if(index<=8)
{
PIN_TXD=Tbuff&0x01; //把最低位给
Tbuff>>=1; //把次低位右移到最低位
}
else if(index==9) //发送第十位
{
PIN_TXD=1; //结束位为1
}
else
{
index=0;
TR0=0;
if(PIN_TXD)
{
T_end=1; //发送完成标志位
}
}
}
else //接收
{
if(index==0)
{
if(!PIN_RXD) //确认接收到起始位0
{
Rbuff=0;
index++;
}
else //没有接收到起始位
{
TR0=0;
}
}
else if(index<=8)
{
Rbuff>>=1; //因为接收先接收是低位 所以要右移低位
if(PIN_RXD) //PIN_RXD是0 就不处理
{
Rbuff|=0x80;
}
index++;
}
else //结束位(第十位)
{
TR0=0; //关闭定时器
index=0;
if(PIN_RXD)
{
R_end=1; //结束完成标志位
}
}
}
}
自己的单片机串口收发引脚需要看自己的原理图,这里我的单片机是P3.0接收 P3.1 发送。