51单片机的定时器0和串口同时使用问题,急!
[问题点数:0分]
|
楼主
发表于: 2009-09-14 21: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; } } |
|
#1得分:0
回复于: 2009-09-15 09:57:11
定时器中断占用CPU资源太多,应该只在定时器服务代码中设置计时标志字,在主代码中计时判断动作,否则定时器中断服务代码影响串口通信.
|
|
#2得分:0
回复于: 2009-09-17 20:08:25
我没看你的程序
中断优先级是不是有问题? |
|
#3得分:0
回复于: 2009-09-18 10:14:24
问题出在你的init_timer0函数里,每次启动定时器中断后会执行init_timer0中的TMOD=0x01,这样定时器1的模式就不是串口模式下所需模式了,自然串口接收不到数据。应该成 TMOD |= 0x01;
另外在你的串口接收中断函数中,跳入中断时最好把EA关掉,处理完后在将EA置位。 |
|
#4得分:0
回复于: 2009-12-14 00:11:23
学习了!
|
|
#5得分:0
回复于: 2010-10-20 22:04:31
我暑假做一个单片机控制串口和一个舵机角度的东西,结果加入串口后对舵机角度的控制很不稳定。
最好不要那么用 |
|
#6得分:0
回复于: 2010-10-21 11:10:51
正解,这是最基本的操作啊。
|
|
#7得分:0
回复于: 2010-10-22 22:10:38
|
|
#8得分:0
回复于: 2010-10-22 22:26:30
支持一楼和六楼,串口用定时器1设置波特率,在中断程序中应该尽量简洁,设置一下标志位就行了
|
|
#9得分:0
回复于: 2011-02-11 13:51:25
我现在也正急需做一个这样的东西,电脑通过串口给单片机数据,控制舵机角度,不知道您当时怎么做的,为什么我同时开串口和定时器,定时器就不受控制呢?51串口占用计数器1,定时占用计数器0,是不是相互影响了? |
|
#10得分:0
回复于: 2012-10-26 23:19:50
问题找到了,定时器0的重装计数值千万不能太大。
也就是说把定时器0的中断时间拉长一点,让程序有足够的时间去处理相应的指令。这些指令可能是串口中断里的,也可能是定时器里的。 |
|
#11得分:0
回复于: 2012-10-26 23:57:38
又试了一个多小时,关键还是在中断里的程序不能太大。一定要把大的处理程序(非即时的)放到主循环里去。
|
|
#12得分:0
回复于: 2012-10-27 10:06:46
问题出在你的init_timer0函数里,每次启动定时器中断后会执行init_timer0中的TMOD=0x01,这样定时器1的模式就不是串口模式下所需模式了,自然串口接收不到数据。应该成 TMOD |= 0x01;
另外在你的串口接收中断函数中,跳入中断时最好把EA关掉,处理完后在将EA置位 |
|
#13得分:0
回复于: 2012-10-27 11:00:47
|
|
#14得分:0
回复于: 2012-11-01 17:22:55
定时器的定时时间太短了,程序跑进定时中断程序太频繁,导致其占用时间太多,无法执行UART的相应程序了;把定时时间调长点看看
|
|
#15得分:0
回复于: 2012-11-02 09:00:56
定时器的长短不是关键,它只能改变两种中断冲突的概率。
如果你的两个中断优先级相同,当定时中断比串口接收中断稍早一点触发,串口中断就被挂起。但串口是异步传输,发送端并不会停下来等你,因此会丢失数据。 如果定时中断比串口中断优先级高,则它会随时打断串口中断服务。 如果你的芯片能够设置中断级别,将串口中断设置得更优先就可以了。 如果没有这样的条件,就要更改协议。 1 主机端先发送一个 Test Ready 查询字符,转入接收模式。 2 如果设备端正常进入中断,正确收到此查询字符,关闭全局中断使能或定时器中断使能,转入发送,回送一个 Ready 标志字符。并转回接收模式。 3 主机端接收到 Ready 标志字符,则继续发送应发数据;否则随机延时之后,回到步骤 1 重试。 4 设备端接收完毕,退出服务时,重新打开关闭的中断。 |
|
#16得分:0
回复于: 2012-11-02 11:31:06
怎么定时器的时间长短不是关键想不明白,如果中断处理过程的处理时间要长过于定时器所设的时间,那问题不就来了啊。还请楼上的帮忙解释解释。 |
|
#17得分:0
回复于: 2012-11-02 14:18:19
实际上,没有影响接收实时性的,是串口发生接收事件时,无法正常进入串口中断服务,也就是说它被“挂起”了,因为另外一个中断正在服务中。而此时,主机端传输是照样进行的。因此丢失数据了。如果丢失的是协议的起始字符,就失去了这次事务。
延长定时,只能是降低两个中断冲突的概率。还是有可能遇到定时中断先于串口中断来到的情况的,仍有概率使串口中断服务挂起。当然,如果定时中断服务执行的很快,远低于串口接收一个字节的时间,也是可以避过去的。串口通讯毕竟是超低速的。 中断处理过程的处理时间长过于定时器所设的时间间隔的情况,对于一个正常的应用几乎不可能发生。这样不仅是串口通讯不能工作,任何过程都停了,永远挂在定时中断服务中。用极端的情况来考虑问题,是不是有点那个了。 这个问题的关键,应该是中断优先级的问题。 另外,串口通讯是否需要同一个定时器?两者是否有冲突?也要考虑。 |
|
#18得分:0
回复于: 2012-11-02 17:41:05
void init_timer0(void)
{ TMOD=0x01; //定时器工作在方式1 TH0=0x04; //定时初值设置为定时50ms TL0=0xBF; ET0=1; } 应为 TMOD=0x21; //定时器0工作在方式1,定时器1工作在方式2 |