使用时钟中断的问题

So1o 2003-06-25 03:46:22
使用IRQ0的时钟中断

#include <stdio.h>
#include <dos.h>

#define INT_CLK 0x08 /*时钟中断号*/
#define IRQ_CLK 0xFE /*时钟中断地址*/

#define IMR_ADDR 0x21 /* 中断屏蔽寄存器 Interrupt Mask Register port */
#define ICR_ADDR 0x20 /* 中断控制寄存器 Interrupt Control Port */
#define EOI 0x20 /* 中断结束 End Of Interrupt */

void interrupt(*oldTimer)(); /*保存函数指针*/
void interrupt OnTimer(); /*定时器中断处理函数*/

main()
{
unsigned char bb;

/*设置时钟中断*/
oldTimer = getvect(INT_CLK);
setvect(INT_CLK, OnTimer);
bb = inportb(IMR_ADDR) & IRQ_CLK;
outportb(IMR_ADDR, bb);

for (;;)
{
.....
}

setvect(INT_CLK, oldTimer);
bb = inportb(IMR_ADDR) & ~(IRQ_CLK);
outportb(IMR_ADDR, bb);
}

void interrupt OnTimer()
{
/*这里的代码怎么不起作用,Trace到这里就死翘翘了*/
printf("clk..\n");

outportb(ICR_ADDR, EOI);
}

还有在时间中断OnTimer里的时候,如果执行时间过长,会不会导致在中断里中断?
听说使用这个中断会影响系统的时钟? 谁给我讲讲
...全文
127 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
tuxw 2003-06-26
  • 打赏
  • 举报
回复
由于DOS不可重入,所以中断中一般不能调用诸如 printf 等系统函数
jiezhuang  2003-06-26
  • 打赏
  • 举报
回复
你可以改成這樣試一下

#include <stdio.h>
#include <dos.h>

int g_nSignal = 0;


void interrupt intr_ontimer()
{
g_nSignal = 1;
}


void main()
{
void interrupt (*funtimer)();
unsigned char bb;

funtimer = getvect( 0x08 );

setvect( 0x08, intr_ontimer );

bb = inportb( 0x21 ) & 0xFE;

outportb( 0x21, bb );

while(1)
{
if( g_nSignal )
{
printf( "\nDetect timer!" );
g_nSignal = 0;

}
}

setvect( 0x08, funtimer );
bb = inportb( 0x21 ) & ~0xFE;
outportb( 0x21, bb );
}


在這裡,由於對g_nSignal的操作不是原語,所以存在一個互斥問題。
So1o 2003-06-26
  • 打赏
  • 举报
回复
多谢 多谢
idontlikenickname 2003-06-26
  • 打赏
  • 举报
回复


DOS重入问题参见:
http://willflyme.8u8.com/prog/dos/dos%20re-enter.htm

yzb1000 2003-06-26
  • 打赏
  • 举报
回复
学习
So1o 2003-06-26
  • 打赏
  • 举报
回复
我的目的是实现定时调用,
我的main()处理键盘消息,串口中断处理接收,时间中断定时采集
main()
{
char c;
for (;;)
{
c = getch();
swicht (c)
{
...
}
}
}

void interrupt OnComm()
{
...
}

void interrupt OnTimer()
{
ticker_clk++;
if (ticker_clk < 500)
return;

ticker_clk = 0;
....
}

有没有更好的结构? 还有DOS重入指的是什么?
gzlucky 2003-06-25
  • 打赏
  • 举报
回复
DOS重入问题。
idontlikenickname 2003-06-25
  • 打赏
  • 举报
回复


一般来说在中断服务函数中需要使用disable()/enable()两个函数控制是否允许再发生同级或是低级中断~
interrupt _IntrHandler()
{
disable();
...
enable();
}

So1o 2003-06-25
  • 打赏
  • 举报
回复
是不是在一个中断服务函数中,不会再发生其中断?
So1o 2003-06-25
  • 打赏
  • 举报
回复
我的这个程序是运行在PC104上的(用于工控领域,就是一个386的计算机)
环境是DOS6.0 TC2
idontlikenickname 2003-06-25
  • 打赏
  • 举报
回复


你的这个程序如果是运行在windows环境下的,那它是运行在一个虚拟机中的,对windows没影响.
如果运行在纯dos下,对系统时钟是有影响的~

idontlikenickname 2003-06-25
  • 打赏
  • 举报
回复


好久没人提中断的问题了~呵呵~~
其实很简单,因为dos中断是不可重入的.尤其是在timer这种发生频率极高的的中断中使用printf()之类会涉及系统调用的函数时死机是必然的.
不知道你看没看过微软在msc6.0中的一个演示代码,它用bios功能调用实现了屏幕输出.
例子的代码如下,参考一下:


/* HARDERR.C illustrates handling of hardware errors using functions:
* _harderr _hardresume _hardretn (DOS-only)
*/

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <direct.h>
#include <string.h>
#include <dos.h>
#include <bios.h>

void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr );
int _bios_str( char *p );

void main()
{
/* Install our hard error handler. */
_harderr( hhandler );

/* Test it. */
printf( "Make sure there is no disk in drive A:\n" );
printf( "Press a key when ready...\n" );
getch();
if( mkdir( "a:\test" ) )
{
printf( "Failed" );
exit( 1 );
}
else
{
printf( "Succeeded" );
rmdir( "a:test" );
exit( 0 );
}
}

//
// 注意下列微软给出的注释及函数的用法
//
/* Handler to deal with hard error codes. Since DOS is not reentrant,
* it is not safe to use DOS calls for doing I/O within the DOS Critical
* Error Handler (int 24h) used by _harderr. Therefore, screen output and
* keyboard input must be done through the BIOS.
*/
void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr )
{
int ch;
static char buf[200], tmpbuf[10];

/* Copy message to buffer, then use BIOS to print it. */
strcpy( buf, "\n\rDevice error code: " );
strcat( buf, itoa( deverr, tmpbuf, 10 ) );
strcat( buf, "\n\rDOS error code: " );
strcat( buf, itoa( doserr, tmpbuf, 10 ) );
strcat( buf, "\n\r(R)etry, (F)ail, or (Q)uit? " );

/* Use BIOS to write strings and get a key. */
_bios_str( buf );
ch = _bios_keybrd( _KEYBRD_READ ) & 0x00ff;
_bios_str( "\n\r" );

switch( ch )
{
case 'R':
case 'r': /* Try again */
default:
_hardresume( _HARDERR_RETRY );
case 'Q':
case 'q': /* Quit program */

/* The following statement may fail in the PWB environment
* because of conflicts with PWB's hard error handler. The
* Quit selection falls through to the Fail selection. You
* can remove the comment to enable this line if you wish to
* test from the command line.
_hardresume( _HARDERR_ABORT );
*/
case 'F':
case 'f': /* Return to DOS with error code */
_hardretn( doserr );

}
}

/* Display a string using BIOS interrupt 0x0e (Write TTY). Return length
* of string displayed.
*/
int _bios_str( char *p )
{
union REGS inregs, outregs;
char *start = p;

inregs.h.ah = 0x0e;
for( ; *p; p++ )
{
inregs.h.al = *p;
int86( 0x10, &inregs, &outregs );
}
return p - start;
}

简而言之,使用_bios_str()函数代替你的printf():
void interrupt OnTimer()
{
/*这里的代码怎么不起作用,Trace到这里就死翘翘了*/
// printf("clk..\n");
_bios_str("clk..\n");

outportb(ICR_ADDR, EOI);
}

yzb1000 2003-06-25
  • 打赏
  • 举报
回复
中断是面向系统的所有程序的,完全有可能在我们的程序运行时中断被别的程序抢走
我们挂接中断时也很可能别的程序在用,所以中断程序在开始都要保存原来的状态,退出时恢复

系统中好像是有两个定时器
8号是提供给程序用的,应该不会影响系统的
这是我的理解,请指点
yzb1000 2003-06-25
  • 打赏
  • 举报
回复
中断程序有很多限制的
很多函数在中断情况下都不能用的
那种函数名前面带下划线的才是安全的
具体那些能用,那些不能,我也不会背

flyswift 2003-06-25
  • 打赏
  • 举报
回复
汇编里面好像就会影响,所以使用中断之后要恢复..
C里面的这个我就不太清楚了.

69,379

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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