51单片机模拟串口的三种方法文档格式.docx
《51单片机模拟串口的三种方法文档格式.docx》由会员分享,可在线阅读,更多相关《51单片机模拟串口的三种方法文档格式.docx(10页珍藏版)》请在冰点文库上搜索。
现在就以11.0592M的晶振为例,谈谈三种模拟串口的方法。
方法一:
延时法
通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期。
#define
uchar
unsigned
char
sbit
P1_0
=
0x90;
P1_1
0x91;
P1_2
0x92;
RXD
P1_0
TXD
P1_1
WRDYN
44
//写延时
RDDYN
43
//读延时
//往串口写一个字节
void
WByte(uchar
input)
{
i=8;
TXD=(bit)0;
//发送启始
位
Delay2cp(39);
//发送8位数据位
while(i--)
TXD=(bit)(input&
0x01);
//先传低位
Delay2cp(36);
input=input>
>
1;
}
//发送校验位(无)
TXD=(bit)1;
//发送结束
Delay2cp(46);
//从串口读一个字节
RByte(void)
Output=0;
temp=RDDYN;
Delay2cp(RDDYN*1.5);
//此处注意,等过起始位
Output
=1;
if(RXD)
|=0x80;
//先收低位
Delay2cp(35);
//(96-26)/2,循环共
占用26个指令周期
while(--temp)
//在指定的
时间内搜寻结束位。
Delay2cp
(1);
if(RXD)break;
//收到结束位便退出
return
Output;
//延时程序*
Delay2cp(unsigned
char
i)
while(--i);
//刚好两个
指令周期。
此种方法在接收上存在一定的难度,主要是采样定位存在需较准确,另外还必须知道
每条语句的指令周期数。
此法可能模拟若干个串口,实际中采用它的人也很多,但如果你用Keil
C,本人不建议使用此种方法,上述程序在P89C52、AT89C52、W78E52三种单片机上实验通过。
方法二:
计数法
51的计数器在每指令周期加1,直到溢出,同时硬件置溢出标志位。
这样我们就可以
通过预置初值的方法让机器每96个指令周期产生一次溢出,程序不断的查询溢出标志来决定是否
发送或接收下一位。
//计数器初始化
S2INI(void)
TMOD
|=0x02;
//计数器0,方式2
TH0=0xA0;
//预值为256-96=140,十六进制A0
TL0=TH0;
TR0=1;
//开始计数
TF0=0;
//发送启始位
WaitTF0();
//发送结束位
TR0=0;
}
//查询计数器溢出标志位
WaitTF0(
)
while(!
TF0);
接收的程序,可以参考下一种方法,不再写出。
这种办法个人感觉不错,接收和发送
都很准确,另外不需要计算每条语句的指令周期数。
方法三:
中断法
中断的方法和计数器的方法差不多,只是当计算器溢出时便产生一次中断,用户可以
在中断程序中置标志,程序不断的查询该标志来决定是否发送或接收下一位,当然程序中需对中
断进行初始化,同时编写中断程序。
本程序使用Timer0中断。
TM0_FLAG
//设传输标志位
//计数器及中断初始化
//在发送或
接收才开始使用
ET0=1;
//允许定时
器0中断
EA=1;
//中断允许
总开关
//接收一个字符
RByte()
//启动Timer0
//等过起始
//位间延时
TM0_FLAG)
break;
//停止
Timer0
//中断1处理程序
IntTimer0()
interrupt
1
TM0_FLAG=1;
//设置标志位。
//查询传输标志位
TM0_FLAG);
TM0_FLAG=0;
//清标志位
中断法也是我推荐的方法,和计数法大同小异。
发送程序参考计数法,相信是件很容
易的事。
另外还需注明的是本文所说的串口就是通常的三线制异步通信串口(UART),只用RXD、TXD、
GND。
附:
51IO口模拟串口通讯C源程序(定时器计数法)
#include
BT_SND
=P1^0;
BT_REC
=P1^1;
/**********************************************
IO
口模拟232通讯程序
使用两种方式的C程序
占用定时器0
**********************************************/
MODE_QUICK
F_TM
F0
TIMER0_ENABLE
TIMER0_DISABLE
ACC0=
ACC^0;
ACC1=
ACC^1;
ACC2=
ACC^2;
ACC3=
ACC^3;
ACC4=
ACC^4;
ACC5=
ACC^5;
ACC6=
ACC^6;
ACC7=
ACC^7;
F_TM=1;
//发送一个字符
PSendChar(unsigned
inch)
#ifdef
ACC=inch;
F_TM=0;
BT_SND=0;
//start
bit
TIMER0_ENABLE;
//启动
F_TM);
BT_SND=ACC0;
//先送出低位
BT_SND=ACC1;
BT_SND=ACC2;
BT_SND=ACC3;
BT_SND=ACC4;
BT_SND=ACC5;
BT_SND=ACC6;
BT_SND=ACC7;
BT_SND=1;
TIMER0_DISABLE;
//停止timer
#else
ii;
ii=0;
while(ii<
8)
if(inch&
1)
else
ii++;
inch>
#endif
PGetChar()
//等过起始位
ACC0=BT_REC;
ACC1=BT_REC;
ACC2=BT_REC;
ACC3=BT_REC;
ACC4=BT_REC;
ACC5=BT_REC;
ACC6=BT_REC;
ACC7=BT_REC;
F_TM)
if(BT_REC)
ACC;
rch,ii;
rch=0;
rch>
rch|=0x80;
rch;
//检查是不是有起始位
bit
StartBitOn()
(BT_REC==0);
main()
gch;
TMOD=0x22;
/*定时器1为工作模式2(8位自动重装),0为模式2(8位
自动重装)
*/
PCON=00;
//在发送或接收才开始使用
TH0=(256-96);
//9600bps
就是
1000000/9600=104.167微秒
执行的
timer是
//
104.167*11.0592/12=
96
PSendChar(0x55);
PSendChar(0xaa);
PSendChar(0x00);
PSendChar(0xff);
while
(1)
if(StartBitOn())
gch=PGetChar();
PSendChar(gch);