51单片机的定时器0和串口同时使用问题,急!

yudewen0128 2009-09-14 09:36:11
[size=14px]这是我的程序:当定时器打开后就接收不到数据了,屏蔽掉定时器就可以了!请大侠指教原因所在!
/*************************************************************/
/*本设计采用STC89C52单片机 */
/* */
/*晶振为11.0592M */
/*************************************************************/
#include<reg52.h>
#include<absacc.h>

#define uchar unsigned char
/***************************变量定义***************************/
int timecount=0; //定时器计数
uchar flag=0; //是否超时未取走电池标志
uchar state=0; //状态标志
uchar rec=0x00; //接收数据
uchar f_rec=0; //接收标志
/***************************端口定义***************************/
sbit Battery=P1^0; // 有无电池
sbit Hand=P1^1; //有无手阻挡
sbit Output=P1^2; //夹具松开或闭合
/*************************************************************/
/*函数功能:初始化定时器0,定时时间设置为50ms */
/*入口参数:无 */
/*出口参数:无 */
/*************************************************************/
void init_timer0(void)
{
TMOD=0x01; //定时器工作在方式1
TH0=0x04; //定时初值设置为定时50ms
TL0=0xBF;
ET0=1;
}
/*************************************************************/
/*函数功能:定时器0中断服务程序 */
/*入口参数:无 */
/*出口参数:无 */
/*************************************************************/
void timer0() interrupt 1
{
TR0=0;
timecount++;
if(timecount==400) //当从CTS接收停止信号1时或夹具关闭到达20s
{
Output=1; //松开夹具
TR0=0; //关闭定时器
timecount=0; //定时计数清零
flag=1; //置位超时标志
}
else
{
init_timer0();
TR0=1;
}

}

/*************************************************************/
/*函数功能:串行接收中断服务程序 */
/*入口参数:无 */
/*出口参数:无 */
/*************************************************************/
void uart( ) interrupt 4
{
if(RI)
{
RI=0;
rec=SBUF; //接收一个数据
if(rec==0x01)
f_rec=1;

}
}
/*************************************************************/
/*函数功能:延时函数,最小延时单位1ms */
/*入口参数:延时时间 */
/*出口参数:无 */
/*************************************************************/
void delay(int t)
{
int i=0,j=0,k=0;
for(;t>0;t--)
for(;i<100;i++)
for(;i<120;i++);
}

void main()
{
TMOD=0x20;//设置定时器1为工作方式2
TH1=0xfd;
TL1=0xfd;
TR1=1; //开定时器
SCON=0x50;
PCON=0x80;
EA=1;//总中断
ES=1;//串口中断允许位
//IP=0x10; //设置串行中断为高优先级
P1=0x03; //置平P1.0及P1.1为输入模式
Output=1;
init_timer0( ); //默认情况下,夹具松开
while(1)
{

if(Battery==1&&Hand==0)
{
delay(500); //延时500ms以防止误判
if(Battery==1&&Hand==0) //当夹具上有电池且手已经拿开,闭合夹具
{

while(flag) //有超时未取走的电池时,等待将电池拿走
{
if(Battery==0&&Hand==0) //超时电阻已经取走
{
flag=0;
state=1;
f_rec=0;//清零f_rec
}
}
if(state==0)
{
TR0=1;

if(f_rec==1)

{

ES=0;
Output=1; //松开夹具
TR0=0; //关闭定时器
timecount=0; //定时计数清零
flag=1;

delay(10);
SBUF=rec;
while(!TI);
TI=0;
ES=1;
}
else Output=0;
}
else
{
state=0; //清状态标志
Output=1;
}
}
else Output=1;
}
else Output=1;
}
}
...全文
4202 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
fang 2012-11-02
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
定时器的长短不是关键,它只能改变两种中断冲突的概率。
[/Quote]
怎么定时器的时间长短不是关键想不明白,如果中断处理过程的处理时间要长过于定时器所设的时间,那问题不就来了啊。还请楼上的帮忙解释解释。
of123 2012-11-02
  • 打赏
  • 举报
回复
定时器的长短不是关键,它只能改变两种中断冲突的概率。

如果你的两个中断优先级相同,当定时中断比串口接收中断稍早一点触发,串口中断就被挂起。但串口是异步传输,发送端并不会停下来等你,因此会丢失数据。

如果定时中断比串口中断优先级高,则它会随时打断串口中断服务。

如果你的芯片能够设置中断级别,将串口中断设置得更优先就可以了。

如果没有这样的条件,就要更改协议。

1 主机端先发送一个 Test Ready 查询字符,转入接收模式。

2 如果设备端正常进入中断,正确收到此查询字符,关闭全局中断使能或定时器中断使能,转入发送,回送一个 Ready 标志字符。并转回接收模式。

3 主机端接收到 Ready 标志字符,则继续发送应发数据;否则随机延时之后,回到步骤 1 重试。

4 设备端接收完毕,退出服务时,重新打开关闭的中断。
cyymycc 2012-11-02
  • 打赏
  • 举报
回复 2
void init_timer0(void)
{
TMOD=0x01; //定时器工作在方式1
TH0=0x04; //定时初值设置为定时50ms
TL0=0xBF;
ET0=1;
}
应为
TMOD=0x21; //定时器0工作在方式1,定时器1工作在方式2

of123 2012-11-02
  • 打赏
  • 举报
回复
实际上,没有影响接收实时性的,是串口发生接收事件时,无法正常进入串口中断服务,也就是说它被“挂起”了,因为另外一个中断正在服务中。而此时,主机端传输是照样进行的。因此丢失数据了。如果丢失的是协议的起始字符,就失去了这次事务。

延长定时,只能是降低两个中断冲突的概率。还是有可能遇到定时中断先于串口中断来到的情况的,仍有概率使串口中断服务挂起。当然,如果定时中断服务执行的很快,远低于串口接收一个字节的时间,也是可以避过去的。串口通讯毕竟是超低速的。

中断处理过程的处理时间长过于定时器所设的时间间隔的情况,对于一个正常的应用几乎不可能发生。这样不仅是串口通讯不能工作,任何过程都停了,永远挂在定时中断服务中。用极端的情况来考虑问题,是不是有点那个了。

这个问题的关键,应该是中断优先级的问题。

另外,串口通讯是否需要同一个定时器?两者是否有冲突?也要考虑。
ymm198606 2012-11-01
  • 打赏
  • 举报
回复
定时器的定时时间太短了,程序跑进定时中断程序太频繁,导致其占用时间太多,无法执行UART的相应程序了;把定时时间调长点看看
aydf1 2012-10-27
  • 打赏
  • 举报
回复
问题出在你的init_timer0函数里,每次启动定时器中断后会执行init_timer0中的TMOD=0x01,这样定时器1的模式就不是串口模式下所需模式了,自然串口接收不到数据。应该成 TMOD |= 0x01;
另外在你的串口接收中断函数中,跳入中断时最好把EA关掉,处理完后在将EA置位
cgsoftware 2012-10-26
  • 打赏
  • 举报
回复
又试了一个多小时,关键还是在中断里的程序不能太大。一定要把大的处理程序(非即时的)放到主循环里去。
cgsoftware 2012-10-26
  • 打赏
  • 举报
回复
问题找到了,定时器0的重装计数值千万不能太大。
也就是说把定时器0的中断时间拉长一点,让程序有足够的时间去处理相应的指令。这些指令可能是串口中断里的,也可能是定时器里的。
AjunlintianxiaA 2011-02-11
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 zerolelouch 的回复:]

我暑假做一个单片机控制串口和一个舵机角度的东西,结果加入串口后对舵机角度的控制很不稳定。
最好不要那么用
[/Quote]
我现在也正急需做一个这样的东西,电脑通过串口给单片机数据,控制舵机角度,不知道您当时怎么做的,为什么我同时开串口和定时器,定时器就不受控制呢?51串口占用计数器1,定时占用计数器0,是不是相互影响了?
dereckgail 2010-10-22
  • 打赏
  • 举报
回复
支持一楼和六楼,串口用定时器1设置波特率,在中断程序中应该尽量简洁,设置一下标志位就行了
ningshao1945 2010-10-21
  • 打赏
  • 举报
回复
正解,这是最基本的操作啊。
[Quote=引用 3 楼 zhoushunda960 的回复:]
问题出在你的init_timer0函数里,每次启动定时器中断后会执行init_timer0中的TMOD=0x01,这样定时器1的模式就不是串口模式下所需模式了,自然串口接收不到数据。应该成 TMOD |= 0x01;
另外在你的串口接收中断函数中,跳入中断时最好把EA关掉,处理完后在将EA置位。
[/Quote]
ZEROLELOUCH 2010-10-20
  • 打赏
  • 举报
回复
我暑假做一个单片机控制串口和一个舵机角度的东西,结果加入串口后对舵机角度的控制很不稳定。
最好不要那么用
huqiming588 2009-12-14
  • 打赏
  • 举报
回复
学习了!
zhoushunda960 2009-09-18
  • 打赏
  • 举报
回复
问题出在你的init_timer0函数里,每次启动定时器中断后会执行init_timer0中的TMOD=0x01,这样定时器1的模式就不是串口模式下所需模式了,自然串口接收不到数据。应该成 TMOD |= 0x01;
另外在你的串口接收中断函数中,跳入中断时最好把EA关掉,处理完后在将EA置位。
changingfu 2009-09-17
  • 打赏
  • 举报
回复
我没看你的程序
中断优先级是不是有问题?
DISINHUI 2009-09-15
  • 打赏
  • 举报
回复
定时器中断占用CPU资源太多,应该只在定时器服务代码中设置计时标志字,在主代码中计时判断动作,否则定时器中断服务代码影响串口通信.

27,377

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧