51单片机模拟串口通信
admin · 经验心得 · 2024年09月27日

使用普通IO口来模拟串口通信,串口通信中使用两根信号线来进行发送和接收,RXD获取数据TXD发送数据,两个设备的RXD和TXD要交叉连接

然后发送频需要根据波特率来设置,比如9600的波特率在11.0592Mhz晶振的单片机中的发送延时就是104us

也就是发送1比特为需要的高电平时间,这个延时需要比较精确否则就有可能通信失败

USART串口协议如下,开始是空闲信号线高电平变为低电平且保存104us(以9600波特率为例)为开始信号,之后依次发送每一位比特的高低电平,发送是以低电平开始发送,直到发送完8字节,然后如果没有奇偶校验等的话就是结束信号,将电平保存高电平大于104us即为结束信号

接收和发送情况是一样的,接收的数据是从低字节到高字节顺序获取每一位

怎么判断接收完成?因为结束标志完毕之后如果继续发送数据,电平会被拉低,所以只需要获取到结束标志之后循环判断一定的时间(大于104us,比如取110us),如果在次判断是低电平说明数据还有需要继续接收,否则就是接收完毕。

代码比较简单,一般去读串口数据都是取延时中值的结果,(比如104us的一半时间52us,电平为低时延时52us,之后间隔104us)这样比较准确,也可以使用中断的方式来获取。

关于缓存数组,因为串口数据的发送时间间隔很短,没有多余的时间用于对数据的处理,所以一般都是先将数据放入到一个缓存中,待数据接收完毕之后再处理,否则可能会导致不能及时获取数据导致数据丢失。

代码如下,经过测试可以完成发送和接收:


#include <reg52.h>

#include <intrins.h>

sbit RXD2 = P2^2;

sbit TXD2 = P2^3;

unsigned char str[21] = "http://192.168.0.112/";

unsigned char buffer[50] = {0}; //接收缓存

int getbuffernum,putbuffernum,num;

void delay(void);

void delay2(void);

void Delay10ms(unsigned int c);

void putdata(unsigned char str);

void getdata(void);

void main(){

unsigned char i;

  while(1){

getbuffernum = 0;

//读取串口数据

if(RXD2 == 0){

  int maxnum = 1000;

  while(maxnum--){

  if(RXD2 == 0){

  getdata();

  maxnum = 1000;

}

  };

}else{

  if(buffer[0] != 0){

for(i=0;i<49;i++){

if(buffer[i] != 0){

putdata(buffer[i]);

buffer[i] = 0;

}else{

break;

}

}

getbuffernum = 0;

putdata(0x0d);

putdata(0x0a);

}

num = 0;

}

  }

}

void getdata(){

unsigned int i;

unsigned char str = 0x0;

if(RXD2 == 0){//起始信号

num = 0;

delay2();

if(RXD2 == 0){

//接收数据

for(i=0;i<8;i++){

str >>= 1;

delay();

if(RXD2 == 1){

str |= 0x80;

}

}

}

delay();

buffer[getbuffernum] = str;

getbuffernum++;

}else{

num++;

}

}

void putdata(unsigned char str){

TXD2 = 0;

delay();

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

str >>= 1;

TXD2 = str & 0x1;

delay();

TXD2 = 1;

delay();

}

//104us 9600波特率是通过计算得出来的 num为7 表示 104us 误差 0.05us

void delay(){

//i=134 2400 (415us)通过 i=67 4800 (208us)通过 i=32 9600 (104us)通过

  unsigned char i;

  for(i=0;i<134;i++){} 

}

void delay2(){

  unsigned char i;

  for(i=0;i<67;i++){} 

}

////误差 0us

void Delay10ms(unsigned int c){

unsigned char a,b;

    for(;c>0;c--){

        for(b=38;b>0;b--){

            for(a=130;a>0;a--){

}

}

}

}


标签1 ( 15 )
标签2 ( 12 )
标签3 ( 4 )
标签4 ( 2 )
标签5 ( 7 )
标签6 ( 5 )
标签 ( 2 )