4 设定多个定时器(harib09d)

在上一节做的超时功能,超时结束后如果再设定1000的话,那我们就可以让它每10秒显示一次,或是让它一闪一灭地显示。另外,间隔不仅限于10秒,我们还可以设定得更长一些或更短一些。比如设定为0.5秒的间隔可以用于文字输入时的光标闪烁。

开发操作系统时,超时功能非常方便,所以在很多地方都可以使用它。比如可以让电子时钟每隔1秒重新显示一次;演奏音乐时,可以用它计量音符的长短;也可以让它以0.1秒1次的频率来监视没有中断功能的装置1 ;另外,还可以用它实现光标的闪烁功能。

1 像键盘和鼠标等是通过中断告知我们有数据过来的,但是还有些装置,即使状态有变化也不会发生中断。大家可能会想:“设计这种装置的人想什么呢!”但生气也于事无补,我们只能定期去查询装置的状态。就算是状态没有变化也得查询,实在是浪费电能。

为了简单地实现这些功能,我们要准备很多能够设定超时的定时器。

比起文字说明来,还是直接看程序更易于理解。

■■■■■

首先把struct TIMERCTL修改成下面这样。

本次的bootback.h节选

  1. #define MAX_TIMER 500
  2. struct TIMER {
  3. unsigned int timeout, flags;
  4. struct FIFO8 *fifo;
  5. unsigned char data;
  6. };
  7. struct TIMERCTL {
  8. unsigned int count;
  9. struct TIMER timer[MAX_TIMER];
  10. };

这样超时定时器最多就可以设定为500个了,flags则用于记录各个定时器的状态。

■■■■■

下面,我们把函数也相应地修改一下吧。

本次的timer.c节选

  1. #define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */
  2. #define TIMER_FLAGS_USING 2 /* 定时器运行中 */
  3. void init_pit(void)
  4. {
  5. int i;
  6. io_out8(PIT_CTRL, 0x34);
  7. io_out8(PIT_CNT0, 0x9c);
  8. io_out8(PIT_CNT0, 0x2e);
  9. timerctl.count = 0;
  10. for (i = 0; i < MAX_TIMER; i++) {
  11. timerctl.timer[i].flags = 0; /* 未使用 */
  12. }
  13. return;
  14. }
  15. struct TIMER *timer_alloc(void)
  16. {
  17. int i;
  18. for (i = 0; i < MAX_TIMER; i++) {
  19. if (timerctl.timer[i].flags == 0) {
  20. timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
  21. return &timerctl.timer[i];
  22. }
  23. }
  24. return 0; /* 没找到 */
  25. }
  26. void timer_free(struct TIMER *timer)
  27. {
  28. timer->flags = 0; /* 未使用 */
  29. return;
  30. }
  31. void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data)
  32. {
  33. timer->fifo = fifo;
  34. timer->data = data;
  35. return;
  36. }
  37. void timer_settime(struct TIMER *timer, unsigned int timeout)
  38. {
  39. timer->timeout = timeout;
  40. timer->flags = TIMER_FLAGS_USING;
  41. return;
  42. }
  43. void inthandler20(int *esp)
  44. {
  45. int i;
  46. io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC*/
  47. timerctl.count++;
  48. for (i = 0; i < MAX_TIMER; i++) {
  49. if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
  50. timerctl.timer[i].timeout--;
  51. if (timerctl.timer[i].timeout == 0) {
  52. timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
  53. fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
  54. }
  55. }
  56. }
  57. return;
  58. }

程序稍微有些长,但只要前面的程序大家都明白了,这里应该也没什么困难。

■■■■■

最后来看HariMain函数。我们不一定都设定为10秒,也尝试一下设为3秒吧。另外,我们还要编写类似光标闪烁那样的程序。

本次的bootback.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. struct FIFO8 timerfifo, timerfifo2, timerfifo3;
  5. char s[40], keybuf[32], mousebuf[128], timerbuf[8], timerbuf2[8], timerbuf3[8];
  6. struct TIMER *timer, *timer2, *timer3;
  7. (中略)
  8. fifo8_init(&timerfifo, 8, timerbuf);
  9. timer = timer_alloc();
  10. timer_init(timer, &timerfifo, 1);
  11. timer_settime(timer, 1000);
  12. fifo8_init(&timerfifo2, 8, timerbuf2);
  13. timer2 = timer_alloc();
  14. timer_init(timer2, &timerfifo2, 1);
  15. timer_settime(timer2, 300);
  16. fifo8_init(&timerfifo3, 8, timerbuf3);
  17. timer3 = timer_alloc();
  18. timer_init(timer3, &timerfifo3, 1);
  19. timer_settime(timer3, 50);
  20. (中略)
  21. for (;;) {
  22. (中略)
  23. io_cli();
  24. if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) + fifo8_status(&timerfifo)
  25. + fifo8_status(&timerfifo2) + fifo8_status(&timerfifo3) == 0) {
  26. io_sti();
  27. } else {
  28. if (fifo8_status(&keyfifo) != 0) {
  29. (中略)
  30. } else if (fifo8_status(&mousefifo) != 0) {
  31. (中略)
  32. } else if (fifo8_status(&timerfifo) != 0) {
  33. i = fifo8_get(&timerfifo); /* 首先读入(为了设定起始点) */
  34. io_sti();
  35. putfonts8_asc(buf_back, binfo->scrnx, 0, 64, COL8_FFFFFF, "10[sec]");
  36. sheet_refresh(sht_back, 0, 64, 56, 80);
  37. } else if (fifo8_status(&timerfifo2) != 0) {
  38. i = fifo8_get(&timerfifo2); /* 首先读入(为了设定起始点) */
  39. io_sti();
  40. putfonts8_asc(buf_back, binfo->scrnx, 0, 80, COL8_FFFFFF, "3[sec]");
  41. sheet_refresh(sht_back, 0, 80, 48, 96);
  42. } else if (fifo8_status(&timerfifo3) != 0) { /* 模拟光标 */
  43. i = fifo8_get(&timerfifo3);
  44. io_sti();
  45. if (i != 0) {
  46. timer_init(timer3, &timerfifo3, 0); /* 然后设置0 */
  47. boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);
  48. } else {
  49. timer_init(timer3, &timerfifo3, 1); /* 然后设置1 */
  50. boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);
  51. }
  52. timer_settime(timer3, 50);
  53. sheet_refresh(sht_back, 8, 96, 16, 112);
  54. }
  55. }
  56. }
  57. }

■■■■■

下面就是期盼已久的“make run”了。我们执行一下,当然会顺利运行了,结果如下图。

4 设定多个定时器(harib09d) - 图1

都显示出来啦!