使用普通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--){
}
}
}
}