DSP

【第6章】实现一个不太精确的延迟函数

2019-07-13 15:56发布

     我们在上一篇实现了一个得到当前发生时钟中断次数的函数,在那时看来这个函数没有什么用处,但如果我们知道两次时钟中断发生的间隔时间是多少,那么就能够写一个不太精确的延时函数来取代我们之前简陋粗暴的Delay函数了。      那么怎么知道这个间隔时间呢,书上说得很清楚,这里就不再赘述了,我们需要做的就是先决定我们想要的间隔时间,比如说10毫秒,那么就拿计算机的输入频率除以10,得到填充到8253的count0寄存器的值,确定相应的模式,填充进去就好。具体填充的指令字和端口号看书就好,懒得在这里啰嗦。在Init_PCB中添加配置8253的代码吧: Code:
  1. Out_Byte(0x43,0x34);   
  2. Out_Byte(0x40,(u16)(1193182L / 100));   
  3. Out_Byte(0x40,(u16)((1193182L / 100) >> 8));  
     好了,现在时钟中断每隔10毫秒就发生一次,编译链接运行一下,发现星号的数量增加了,如图所示:      好了,接下来就来写新的延迟函数Milli_Delay,写在proc.c中,延迟形参指定的时间: Code:
  1. void Milli_Delay(u32 milli_sec)   
  2. {   
  3.     u32 cur_ticks = Get_Ticks();   
  4.     while((Get_Ticks() - cur_ticks) * 10 < milli_sec)   
  5.     {   
  6.     }   
  7. }  
     别忘了在proto.h中加入相应的声明: Code:
  1. void Milli_Delay(u32 milli_sec);  
     最后让这个新添加的函数来取代我们原来的Delay函数: Code:
  1. void Proc_A()   
  2. {   
  3.     while(1)   
  4.     {   
  5.         Disp_Color_Str("A",0xc);   
  6.         Disp_Int(Get_Ticks());   
  7.         Disp_Color_Str(".",0xc);   
  8.         Milli_Delay(1000);   
  9.     }   
  10. }   
  11.   
  12. void Proc_B()   
  13. {   
  14.     while(1)   
  15.     {   
  16.         Disp_Color_Str("B",0xd);   
  17.         Disp_Int(Get_Ticks());   
  18.         Disp_Color_Str(".",0xd);   
  19.         Milli_Delay(1000);   
  20.     }   
  21. }  
     编译链接,运行,结果如图所示:      由图看出,发生了很多次中断重入,由于现在从进程进入到内核态只有两种方式,一种是时钟中断,一种就是Get_Ticks系统调用,由于我们已经禁止了时钟中断自身的重入,那么惟一可能发生的重入就是进行系统调用的过程发生了时钟中断,我们已经做了相应的措施来应付重入,因此不用多虑。      还有一个问题就是这个新的延迟函数还不够精确,比如上图的前四行,B0x01和B0x65之间差了0x64,刚好就是100,这就很精确了。但A0x00和A0x6D差了6D,多延迟了90ms。其中有多进程的原因,来看图分析,当发生了0x64次时钟中断时,CPU的控制权在进程B中,进程A还没能从Milli_Delay中返回而跳回去打印当前的ticks。另外,调用Disp_Color_Str函数中也有可能发生时钟中断,从而也造成一些延迟。那我们就把进程的数量减为1,同时把发生时钟中断打印星号以及发生中断重入打印感叹号的语句注释掉,结果如图所示:      大约1秒钟打印一次,每次间隔正好为0x64。