打印
[AVR单片机]

请教一个很捆饶的问题,关于定时器的

[复制链接]
1337|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dudongdao|  楼主 | 2008-10-8 13:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    有这么一个问题想请教一下大家如何解决~   定时中断中有一个16位的定时器在跑如u16timer++;   我在主函数中读这个变量来判断当前时间,读的时候应该怎么处理,直接读理论上会出现一种错误情况。如u16timer=0x00ff的时候,我在主程序中读,可能现在读了u16timer的低字节0xff,这时候发生中断了,
中断程序里u16timer变成了0x0100,中断返回的时候主程序继续读高字节变成了0x01,这样整个数就变成了0x01ff,其实现在是0x0100,怎么避免这种情况呢,或者这种情况在理论上存在,但是在实际中极少出现吗?

相关帖子

沙发
zyok| | 2008-10-8 13:52 | 只看该作者

不久才有人问过~~

https://bbs.21ic.com/club/bbs/bbsView.asp

使用特权

评论回复
板凳
dudongdao|  楼主 | 2008-10-8 13:58 | 只看该作者

谢谢

好我去看看,谢谢

使用特权

评论回复
地板
dudongdao|  楼主 | 2008-10-8 14:00 | 只看该作者

不过没看到,能给个具体的联接吗

使用特权

评论回复
5
zyok| | 2008-10-8 14:45 | 只看该作者

...

 xiaoing 发表于 2008-10-7 19:02 侃单片机 ←返回版面    

楼主: 关于前后台程序操作同一个变量的问题 

今天写了个单片机测频的程序,突然想到关于前后台程序操作同一个变量的问题,实例代码如下。其中MsuFqy是有可能前后台程序同时操作的变量,这里的计数器0中断对变量MsuFqy进行写操作,函数MsuReadFqy对MsuFqy进行读操作,那么有没有必要在函数MsuReadFqy中先关总中断,然后才读取MsuReadFqy的值,重新打开总中断?还是直接读就可以了?大家都知道如果函数MsuReadFqy是对MsuFqy变量进行写操作,因为变量MsuFqy是int型的有两个字节组成,不能一条指令完成读写操作,也就是说如果函数MsuReadFqy正在对变量MsuFqy进行写操作,还没完成写操作,此时进入计时器0中断,同样对变量MsuFqy进行写操作,那么就会破坏变量变量MsuFqy,导致函数MsuReadFqy写变量MsuFqy错误,所以对于写操作,必须通过开关中断来避免这种情况。那么对于这里的读操作,是否也有这个必要?说了这么多,不知道大家有没有明白我的意思?呵呵

#include <reg52.h>


static unsigned int MsuFqy;    /* 测量频率 */


void MsuTimer0Init (void)
{
  TMOD &= 0xF0;               /* 清零与定时器0相关的位,与定时器1相关的位不变 */
  TMOD |= 0x01;               /* 定时器0工作模式1 */

  TH0 = 0x9E;                 /* 定时25ms对应的定时器0重装值 */
  TL0 = 0x58;

  TF0 = 0;                    /* 清零定时器0中断标志位 */
  ET0 = 1;                    /* 允许定时器0中断 */
  TR0 = 1;                    /* 启动定时器0 */
}

void MsuTimer0Isr (void) interrupt 1
{
  EA = 0;                     /* 关总中断 */

  TR0 = 0;                    /* 停止定时器0 */

#if 1
    TR1 = 0;                  /* 停止计数器1 */

    MsuFqy = (unsigned int)TH1 << 8;
    MsuFqy |= (unsigned int)TL1;

    TR1 = 1;                  /* 启动计数器1 */
#endif

  TH0 = 0x9E;                 /* 定时25ms对应的定时器0重装值 */
  TL0 = 0x58;

  TR0 = 1;                    /* 重新启动定时器0 */

  EA = 1;                     /* 关总中断 */
}

unsigned int MsuReadFqy (void)
{
  unsigned int k;

  EA = 0;                     /* 这里有没有必要开关总中断? */
  k = MsuFqy;
  EA = 1;                     /* 这里有没有必要开关总中断? */

  return (k);
}

void main (void)
{
  unsigned int fqy;

  MsuTimer0Init();
  EA = 1;

  while (1)
  {
    fqy = MsuReadFqy();
  }
}






热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 zyok 发表于 2008-10-7 19:23 侃单片机 ←返回版面    

2楼: 有必要~ 

 




热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 xiaoing 发表于 2008-10-7 19:38 侃单片机 ←返回版面    

3楼: 回复主题:关于前后台程序操作同一个变量的问题 

    以下再贴上上述代码的Keil反汇编代码,为便于大家阅读,我整理了下。大家可以发现变量MsuFqy其实是0x08(MSB)和0x09(LSB)组成的,当函数MsuReadFqy正在对变量MsuFqy进行读操作时,即语句:
          MOV      R6,0x08  ;MSB
          MOV      R7,0x09  ;LSB
若此时,只执行了“MOV R6,0x08”,“MOV R7,0x09”还没有执行,此时刚好产生计数器0中断,对变量MsuFqy进行写操作,改写单元0x08和0x09,写完毕后返回函数MsuReadFqy继续读操作即执行“MOV R7,0x09”,此时0x09单元的值已经被改写了,所以函数MsuReadFqy读取量MsuFqy的值其实是错误的,所以说我认为在读写变量时都有必要开关中断。不知各位大牛如何认为?


          ORG      0000H
          LJMP     start

          ORG      000BH
          LJMP     MsuTimer0Isr


;-----------------------------------------------------
; MsuReadFqy()
;-----------------------------------------------------
MsuReadFqy:
          CLR      EA

          MOV      R6,0x08  ;MSB
          MOV      R7,0x09  ;LSB

          SETB     EA

          RET


;-----------------------------------------------------
; MsuTimer0Isr()
;-----------------------------------------------------
MsuTimer0Isr:

          PUSH     ACC        ; 保护现场
          PUSH     PSW


          MOV      PSW,#0x00

          ;-------------------------------------------
          PUSH     0x04       ; 保护寄存器
          PUSH     0x05
          PUSH     0x06
          PUSH     0x07

          CLR      EA
          CLR      TR0

          ;-------------------------------------------
          CLR      TR1

          MOV      R7,TH1
          MOV      A,R7
          MOV      R6,A
          MOV      R5,TL1
          MOV      R4,#0x00

          CLR      A
          ADD      A,R5
          MOV      0x09,A

          MOV      A,R4
          ADDC     A,R6
          MOV      0x08,A

          SETB     TR1
          ;-------------------------------------------

          MOV      TH0,#0x9E
          MOV      TL0,#0x58

          SETB     TR0
          SETB     EA

          ;-------------------------------------------
          POP      0x07       ; 恢复寄存器
          POP      0x06
          POP      0x05
          POP      0x04


          POP      PSW        ; 恢复现场
          POP      ACC

          RETI

;-----------------------------------------------------
; MsuTimer0Init()
;-----------------------------------------------------
MsuTimer0Init:
          ANL      TMOD,#0xF0
          ORL      TMOD,#0x01
          MOV      TH0,#0x9E
          MOV      TL0,#0x58
          CLR      TF0
          SETB     ET0

          RET      



;-----------------------------------------------------
; main()
;-----------------------------------------------------
main:
          LCALL    MsuTimer0Init
          SETB     EA

loop1:
          LCALL    MsuReadFqy
          MOV      0x0A,R6      ; R6 is MSB
          MOV      0x0B,R7      ; R7 is LSB
          SJMP     loop1



;-----------------------------------------------------
; start()
;-----------------------------------------------------
start:
          MOV      R0,#0x7F
          CLR      A

loop2:    MOV      @R0,A
          DJNZ     R0,loop2
          MOV      SP,#0x0B
          LJMP     MAIN






热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 5880527 发表于 2008-10-7 19:52 侃单片机 ←返回版面    

4楼: 没必要,以前讨论过 

在函数读字节之前先把某一位单元清0,在中断里需要修改此字节的地方把那位单元置1,函数读完后字节后再判断一下此标志是否给置1了,如还是0则读到的数据可以用,是1就再读一次就可以了






热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 xiaoing 发表于 2008-10-7 20:36 侃单片机 ←返回版面    

5楼: 回复主题:关于前后台程序操作同一个变量的问题 

楼上的也是一个解决方法,但前提条件是两次中断有足够的时间间隔!想想还是开关中断简单。






热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 johnwjl 发表于 2008-10-7 20:52 侃单片机 ←返回版面    

6楼: 关中断,和操作系统中的临界段一样。 

 




热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 5880527 发表于 2008-10-7 21:18 侃单片机 ←返回版面    

7楼: 为什么要关 

把那两字节读过来放到临时单元里,就两条语句而已,如果真那么短的时间又来中断,你咋就不怕关了中断后的那两条读字节语句丢失了一次中断呢,你主循环根本就谈不上及时性啥的,如果那位单元给置1了那本次调用函数直接跳过,不进行任何相关操作便是






热门讲座:多锁相环可编程时钟替代晶体和CMOS晶振

邀您参加“克服步进电机和系统共振新思路”研讨会
 
 

 xiaoing 发表于 2008-10-8 13:33 侃单片机 ←返回版面    

8楼: 回复主题:关于前后台程序操作同一个变量的问题 

恩,楼上有道理。
 
 

使用特权

评论回复
6
dudongdao|  楼主 | 2008-10-8 14:51 | 只看该作者

哈哈~ 高着~

   明白了~  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

413

帖子

1

粉丝