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楼: 回复主题:关于前后台程序操作同一个变量的问题
恩,楼上有道理。 |