单片机IO口模拟串口程序发送+接收.docx

上传人:b****3 文档编号:5068465 上传时间:2022-12-13 格式:DOCX 页数:12 大小:18.28KB
下载 相关 举报
单片机IO口模拟串口程序发送+接收.docx_第1页
第1页 / 共12页
单片机IO口模拟串口程序发送+接收.docx_第2页
第2页 / 共12页
单片机IO口模拟串口程序发送+接收.docx_第3页
第3页 / 共12页
单片机IO口模拟串口程序发送+接收.docx_第4页
第4页 / 共12页
单片机IO口模拟串口程序发送+接收.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

单片机IO口模拟串口程序发送+接收.docx

《单片机IO口模拟串口程序发送+接收.docx》由会员分享,可在线阅读,更多相关《单片机IO口模拟串口程序发送+接收.docx(12页珍藏版)》请在冰豆网上搜索。

单片机IO口模拟串口程序发送+接收.docx

单片机IO口模拟串口程序发送+接收

/***************************************************************

*在单片机上模拟了一个串口,使用P2.1作为发送端

*把单片机中存放的数据通过P2.1作为串口TXD发送出去

***************************************************************/

#include

#include

#include

typedefunsignedcharuchar;

inti;

ucharcodeinfo[]=

{

0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55

};

sbitnewTXD=P2^1;//模拟串口的发送端设为P2.1

voidUartInit()

{

SCON=0x50;//SCON:

serailmode1,8-bitUART

TMOD|=0x21;//T0工作在方式1,十六位定时

PCON|=0x80;//SMOD=1;

TH0=0xFE;//定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bpsfosc=11.0592MHz

TL0=0x7F;//定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bpsfosc=11.0592MHz

//TH0=0xFD;//定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bpsfosc=18.432MHz

//TL0=0x7F;//定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bpsfosc=18.432MHz

}

voidWaitTF0(void)

{

while(!

TF0);

TF0=0;

TH0=0xFE;//定时器重装初值fosc=11.0592MHz

TL0=0x7F;//定时器重装初值fosc=11.0592MHz

//TH0=0xFD;//定时器重装初值fosc=18.432MHz

//TL0=0x7F;//定时器重装初值fosc=18.432MHz

}

voidWByte(ucharinput)

{

//发送启始位

ucharj=8;

TR0=1;

newTXD=(bit)0;

WaitTF0();

//发送8位数据位

while(j--)

{

newTXD=(bit)(input&0x01);//先传低位

WaitTF0();

input=input>>1;

}

//发送校验位(无)

//发送结束位

newTXD=(bit)1;

WaitTF0();

TR0=0;

}

voidSendata()

{

for(i=0;i

{

WByte(info[i]);

}

}

voidmain()

{

UartInit();

while

(1)

{

Sendata();

}

}

##############################################################################

/***************************************************************

*模拟接收程序,这个程序的作用从模拟串口接收数据,然后将这些数据发送到实际串口

*在单片机上模拟了一个串口,使用P3.2作为发送和接收端

*以P3.2模拟串口接收端,从模拟串口接收数据发至串口

***************************************************************/

#include

#include

#include

typedefunsignedcharuchar;

//这里用来切换晶振频率,支持11.0592MHz和18.432MHz

//#defineF18_432

#defineF11_0592

uchartmpbuf2[64]={0};

//用来作为模拟串口接收数据的缓存

struct

{

ucharrecv:

6;//tmpbuf2数组下标,用来将模拟串口接收到的数据存放到tmpbuf2中

ucharsend:

6;//tmpbuf2数组下标,用来将tmpbuf2中的数据发送到串口

}tmpbuf2_point={0,0};

sbitnewRXD=P3^2;//模拟串口的接收端设为P3.2

voidUartInit()

{

SCON=0x50;//SCON:

serailmode1,8-bitUART

TMOD|=0x21;//TMOD:

timer1,mode2,8-bitreload,自动装载预置数(自动将TH1送到TL1);T0工作在方式1,十六位定时

PCON|=0x80;//SMOD=1;

#ifdefF11_0592

TH1=0xE8;//Baud:

2400fosc=11.0592MHz2400bps为从串口接收数据的速率

TL1=0xE8;//计数器初始值,fosc=11.0592MHz因为TH1一直往TL1送,所以这个初值的意义不大

TH0=0xFF;//定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bpsfosc=11.0592MHz

TL0=0xA0;//定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bpsfosc=11.0592MHz

#endif

#ifdefF18_432

TH1=0xD8;//Baud:

2400fosc=18.432MHz2400bps为从串口接收数据的速率

TL1=0xD8;//计数器初始值,fosc=18.432MHz因为TH1一直往TL1送,所以这个初值的意义不大

TH0=0xFF;//定时器0初始值,延时104us,目的是令模拟串口的波特率为9600bpsfosc=18.432MHz

TL0=0x60;//定时器0初始值,延时104us,目的是令模拟串口的波特率为9600bpsfosc=18.432MHz

#endif

IE|=0x81;//中断允许总控制位EA=1;使能外部中断0

TF0=0;

IT0=1;//设置外部中断0为边沿触发方式

TR1=1;//启动TIMER1,用于产生波特率

}

voidWaitTF0(void)

{

while(!

TF0);

TF0=0;

#ifdefF11_0592

TH0=0xFF;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

TL0=0xA0;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

#endif

#ifdefF18_432

TH0=0xFF;

//定时器重装初值fosc=18.432MHz

TL0=0x60;

//定时器重装初值fosc=18.432MHz

#endif

}

//接收一个字符

ucharRByte()

{

ucharOutput=0;

uchari=8;

TR0=1;//启动Timer0

#ifdefF11_0592

TH0=0xFF;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

TL0=0xA0;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

#endif

#ifdefF18_432

TH0=0xFF;//定时器重装初值fosc=18.432MHz

TL0=0x60;//定时器重装初值fosc=18.432MHz

#endif

TF0=0;

WaitTF0();//等过起始位

//接收8位数据位

while(i--)

{

Output>>=1;

if(newRXD)Output|=0x80;//先收低位

WaitTF0();//位间延时

}

TR0=0;//停止Timer0

returnOutput;

}

//向COM1发送一个字符

voidSendChar(ucharbyteToSend)

{

SBUF=byteToSend;

while(!

TI);

TI=0;

}

voidmain()

{

UartInit();

while

(1)

{

if(tmpbuf2_point.recv!

=tmpbuf2_point.send)//差值表示模拟串口接收数据缓存中还有多少个字节的数据未被处理(发送至串口)

{

SendChar(tmpbuf2[tmpbuf2_point.send++]);

}

}

}

 

//外部中断0,说明模拟串口的起始位到来了

voidSimulated_Serial_Start()interrupt0

{

EX0=0;//屏蔽外部中断0

tmpbuf2[tmpbuf2_point.recv++]=RByte();//从模拟串口读取数据,存放到tmpbuf2数组中

IE0=0;//防止外部中断响应2次,防止外部中断函数执行2次

EX0=1;//打开外部中断0

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

以上是两个独立的测试程序,分别是模拟串口发送的测试程序和接收的测试程序

上面两个程序在编写过程中参考了这篇文章《51单片机模拟串口的三种方法》(在后文中简称《51》),但在它的基础上做了一些补充,下面是若干总结的内容:

1、《51》在接收数据的程序中,采用的是循环等待的方法来检测起始位(见《51》的“附:

51IO口模拟串口通讯C源程序(定时器计数法)”部分),这种方法在较大程序中,可能会错过起始位(比如起始位到来的时候程序正好在干别的,而没有处于判断起始位到来的状态),或者一直在检测起始位,而没有办法完成其他工作。

为了避免这个问题,在本接收程序中采用了外部中断的方法,将外部中断0引脚作为模拟串口的接收端,设IT0=1(将外部中断0设为边缘触发)。

这样当起始位(低电平)到来时,就会引发外部中断,然后在外部中断处理函数中接收余下的数据。

这种方法可以保证没数据的时候程序该干什么干什么,一旦模拟串口接收端有数据,就可以立即接收到。

2、加入了模拟串口接收缓冲区。

在较大程序中,单片机要完成的工作很多,在模拟串口接收到了数据之后立即处理的话,有可能处理不过来造成丢失数据,或者影响程序其他部分执行。

本程序中加入了64个字节的缓冲区,从模拟串口接收到的数据先存放在缓冲区中。

这样就算程序一时没工夫处理这些数据,腾出手来之后也能在缓冲区中找到它们。

3、《51》文中的WByte函数和RByte函数中都先打开计数器后关闭计数器。

如果使用本文的外部中断法来接收数据,并且外部中断处理函数里外都调用了WByte或RByte的话,需要将这两个函数中的TR0=1,TR0=0操作的语句除去,并在UartInit()中加入一句TR0=1;即让TR0始终开着就可以。

由于之前没有意识到这个问题,因此在具体应用时出现了奇怪的问题:

表现为中断处理函数执行完毕之后,似乎回不到主程序,程序停在了一个不知道的地方。

后来经过排查后找到了问题所在,那个程序的中断处理函数中用了RByte,中断处理函数外用到了WByte,而这两个函数的最后都有TR0=0。

这样当中断处理函数执行完毕后,TR0实际上是为0的,返回主程序后(中断前的主程序可能正好处于其他的WByte或RByte执行中),原先以来定时器0溢出改变TF0才能执行下去的WByte函数就无法进行下去,从而导致整个程序停下来不动。

(在本文的接收测试程序中不存在这个问题,因为中断处理程序中虽调用了RByte,但中断处理程序外却没有调用RByte或WByte)

下面是修改后的RByte、WByte和WaitTF0函数,仅供参考:

/**********************************************

*定时器0溢出后重装初值

**********************************************/

voidWaitTF0(void)

{

TF0=0;

#ifdefF11_0592

TH0=0xFF;//定时器重装初值fosc=11.0592MHz

TL0=0xA0;//定时器重装初值fosc=11.0592MHz

#endif

#ifdefF18_432

TH0=0xFF;//定时器重装初值fosc=18.432MHz

TL0=0x60;//定时器重装初值fosc=18.432MHz

#endif

while(!

TF0);

TF0=0;

}

/**********************************************

*从串口B接收一个字符

**********************************************/

ucharRByte()

{

ucharOutput=0;

uchari=8;

//TR0=1;//启动Timer0

/*

#ifdefF11_0592

TH0=0xFF;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

TL0=0xA0;//定时器重装初值模拟串口的波特率为9600bpsfosc=11.0592MHz

#endif

#ifdefF18_432

TH0=0xFF;//定时器重装初值fosc=18.432MHz

TL0=0x60;//定时器重装初值fosc=18.432MHz

#endif

*/

WaitTF0();//等过起始位

//接收8位数据位

while(i--)

{

Output>>=1;

if(newRXD)Output|=0x80;//先收低位

WaitTF0();//位间延时

}

//while(!

TF0)if(newRXD)break;//此句和下一句不能加,如果加上了将导致耗时过长,影响下一个字节的接收

//WaitTF0();//等过结束位

//TR0=0;//停止Timer0

returnOutput;

}

/**********************************************

*发送一个字节到串口B

**********************************************/

voidWByte(ucharinput)

{

//发送启始位

ucharj=8;

//TR0=1;

newTXD=(bit)0;

WaitTF0();

//发送8位数据位

while(j--)

{

newTXD=(bit)(input&0x01);//先传低位

WaitTF0();

input=input>>1;

}

//发送校验位(无)

//发送结束位

newTXD=(bit)1;

WaitTF0();

//TR0=0;

}

4、在上面的新修改后的RByte()函数中,有被注释掉的如下两句:

//while(!

TF0)if(newRXD)break;//此句和下一句不能加,如果加上了将导致耗时过长,影响下一个字节的接收

//WaitTF0();//等过结束位

这两句在《51》文中的程序是存在的,但是使用中断接收法后,加上这两句后出现了问题。

表现为接收到的下一个字节的数据不完整或直接接收不到,似乎这两句占用了过多的时间。

看这两句的目的似乎是要延时以跳过结束位,但是我感觉这个结束位可以不用管它,反正结束位是个高电平,不会妨碍下一个字节是否到来的判断(下一个字节的起始位是低电平)。

那就由它去吧,没有必要为了它而占用CPU的时间。

在本文的程序中,去掉这两句后程序执行正确,如果其他朋友在使用时真的出现问题,可以试着再把它们加上试一下。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1