题目: 一个8XX51单片机的双机通信系统波特率为9600bps,fosc=12MHz,用中断方式编写程序,将甲机片内RAM 30H ~ 3FH的数据块通过串行口传送到乙机的片内RAM 40 ~ 4FH单元中。
串口通信是一个字节一个字节的发送与接收,但实际上我们一般都是用来多字节的传输,而当我们用来多字节传输时,我们会发现,一旦我们传输速率加快,我们传输的数据就容易出错(我认为其实会出现数据传输不完全的情况)。
那这怎么解决呢?
这个就与我们单片机的晶振与我们设置的波特率有关了,当我们采用时钟周期为11.0592Mhz的晶振时,不管设置波特率多少(1200-115200范围,11.0592的最大波特率为115200,也是常用的波特率),误差为0,也就是说,假如当我们用11.0592Mhz的晶振产生9600的波特率,结果是刚刚好的。但是当我们采用12Mhz的晶振时,波特率越大误差越大, 这个时候一般常常使用波特率加倍减小误差(但是波特率越大,加倍其实也减小不了多少误差了,甚至误差不变)。
其实,我们可以通过延时来减小传输数据的误差,让其传输慢一点
比如题目要求我们要传输16个字节的数据,这个延时不加的话,会有问题(我出现了传输字节不够的情况,即没有传输到16个字节)。
发送数据时这个延时不能少,而当我们接收数据时,这个延时似乎是可以不要的(因为测试的时候我没有发现问题,原因我也不清楚),我为了保险,也进行了延时。
//发送数据
SBUF=*p; //将p指向的地址所存储的值放进缓存区
delay1ms(1); //延时1ms
//接收数据
*p=SBUF; //读取缓冲区的值
delay1ms(1); //延时1ms
完整代码如下
//发送数据
#include <reg52.h>
#include "Delay.h"
unsigned char *p; //指针,用来指向内存地址
void UART_Init()
{
TMOD=0x20; //设置计数器工作方式2
SCON=0x40; //串行口设置为工作方式1
TH1=0XFD; //计数器重装载值设置
TL1=0XFD; //计数器初始值设置
TR1=1; //打开计数器
ES=1; //打开接收中断
EA=1; //打开总中断
p=0x30; //p指向内存地址为0x30的空间
SBUF=*p; //将0x30这个地址所存储的值放进缓存区
delay1ms(1); //延时1ms
}
void main()
{
unsigned char k=0;
p=0x30;
*p=k;
while(p!=0x3F) //给30H ~ 3FH的内存地址赋值
{
p++;
k++;
*p=k;
}
UART_Init(); //中断初始化
while(1);
}
void UART_Routine() interrupt 4
{
TI=0; //清除发送完成位标志
p++;
SBUF=*p; //将值存入缓冲区
delay1ms(1); //延时1ms
if(P==0x3F)
EA=0; //关闭总中断
}
//接收数据
#include <reg52.h>
#include "Delay.h"
unsigned char *p;
void UART_Init()
{
TMOD=0x20; //设置计数器工作方式2
SCON=0x50; //串行口设置为工作方式1,并允许接受
TH1=0XFD; //计数器重装载值设置
TL1=0XFD; //计数器初始值设置
TR1=1; //打开计数器
ES=1; //打开接收中断
EA=1; //打开总中断
p=0x40;
}
void main()
{
UART_Init();
while(1);
}
void UART_Routine() interrupt 4
{
RI=0; //清除接收完成位标志
*p=SBUF; //读取缓冲区的值
delay1ms(1); //延时1ms
p++;
if(P==0x4F)
EA=0; //关闭总中断
}
测试结果
如果发现错误,请告知。