rtos.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #include <avr/sleep.h>
  2. #include <avr/interrupt.h>
  3. #include "rtos.h"
  4. static volatile uint8_t saveRegister;
  5. #define ENABLE_INTERRUPT sei()
  6. #define DISABLE_INTERRUPT saveRegister = SREG; cli()
  7. #define RESTORE_INTERRUPT SREG = saveRegister
  8. //использовать RESTORE только после DISABLE
  9. /*
  10. * Переменные модуля
  11. */
  12. static volatile task TaskArray[MAX_TASKS]; // очередь задач
  13. static volatile uint8_t arrayTail; // "хвост" очереди
  14. // внешние переменные
  15. extern uint8_t TWI_WDT;
  16. // счётчик задержки
  17. static volatile uint16_t TDelay;
  18. /*
  19. * Инициализация РТОС и t_delay, время тика - 1 мс
  20. */
  21. inline void RTOS_Init(void) {
  22. // настраиваем основной таймер
  23. TIMER_TCCR = TIMER_CSB;
  24. TIMER_TCNT = TIMER_CNT;
  25. TIMER_TIMSK |= TIMER_INT;
  26. // "хвост" в 0
  27. arrayTail = 0;
  28. }
  29. /*
  30. * Добавление задачи в список
  31. */
  32. void RTOS_SetTask (void (*taskFunc)(void), uint16_t taskDelay, uint16_t taskPeriod) {
  33. uint8_t i;
  34. if (!taskFunc) {
  35. return;
  36. }
  37. // поиск задачи в текущем списке
  38. for(i = 0; i < arrayTail; i++) {
  39. // если нашли, то обновляем переменные
  40. if (TaskArray[i].pFunc == taskFunc) {
  41. DISABLE_INTERRUPT;
  42. TaskArray[i].delay = taskDelay;
  43. TaskArray[i].period = taskPeriod;
  44. TaskArray[i].run = 0;
  45. RESTORE_INTERRUPT;
  46. // обновив, выходим
  47. return;
  48. }
  49. }
  50. // если такой задачи в списке нет
  51. if (arrayTail < MAX_TASKS) {
  52. // и есть место, то добавляем
  53. DISABLE_INTERRUPT;
  54. TaskArray[arrayTail].pFunc = taskFunc;
  55. TaskArray[arrayTail].delay = taskDelay;
  56. TaskArray[arrayTail].period = taskPeriod;
  57. TaskArray[arrayTail].run = 0;
  58. // увеличиваем "хвост"
  59. arrayTail++;
  60. RESTORE_INTERRUPT;
  61. } else {
  62. while(1);
  63. }
  64. }
  65. /*
  66. * Удаление задачи из списка
  67. */
  68. inline void RTOS_DeleteTask (void (*taskFunc)(void)) {
  69. uint8_t i;
  70. // проходим по списку задач
  71. for (i=0; i<arrayTail; i++) {
  72. // если задача в списке найдена
  73. if (TaskArray[i].pFunc == taskFunc) {
  74. DISABLE_INTERRUPT;
  75. // переносим последнюю задачу
  76. if (i != (arrayTail - 1)) {
  77. // на место удаляемой
  78. TaskArray[i] = TaskArray[arrayTail - 1];
  79. }
  80. // уменьшаем указатель "хвоста"
  81. arrayTail--;
  82. RESTORE_INTERRUPT;
  83. return;
  84. }
  85. }
  86. }
  87. /*
  88. * Диспетчер РТОС, вызывается в main
  89. */
  90. void RTOS_DispatchTask(void) {
  91. uint8_t i;
  92. void (*function) (void);
  93. // проходим по списку задач
  94. for (i=0; i<arrayTail; i++) {
  95. // если флаг на выполнение взведен,
  96. if (TaskArray[i].run != 0) {
  97. // запоминаем задачу, т.к. во время выполнения может измениться индекс
  98. function = TaskArray[i].pFunc;
  99. if (TaskArray[i].period == 0) {
  100. // если период равен 0, удаляем задачу из списка,
  101. RTOS_DeleteTask(TaskArray[i].pFunc);
  102. } else {
  103. // иначе снимаем флаг запуска
  104. TaskArray[i].run = 0;
  105. // если задача не изменила задержку
  106. if (!TaskArray[i].delay) {
  107. // задаем ее
  108. TaskArray[i].delay = TaskArray[i].period-1;
  109. // задача для себя может сделать паузу
  110. }
  111. }
  112. // выполняем задачу
  113. (*function)();
  114. }
  115. }
  116. }
  117. /*
  118. * Delay, msek
  119. * также, что-бы зря не терять время -- крутим диспетчер
  120. */
  121. void tdelay_ms(uint16_t msek) {
  122. TDelay = msek;
  123. do {
  124. if (TDelay > 1) {
  125. RTOS_DispatchTask();
  126. }
  127. // делать нехрен -- спим, ждём прерывание
  128. set_sleep_mode(SLEEP_MODE_IDLE);
  129. sleep_mode();
  130. } while (TDelay != 0);
  131. }
  132. /******************************************************************************************
  133. * Таймерная служба РТОС и tdelay (прерывание аппаратного таймера)
  134. */
  135. #pragma GCC optimize ("O3")
  136. ISR(TIMER_OVF_VECT) {
  137. // перезарядим таймер
  138. TIMER_TCNT = TIMER_CNT;
  139. /* RTOS_Timer */
  140. uint8_t i;
  141. // проходим по списку задач
  142. for (i=0; i<arrayTail; i++) {
  143. // если время до выполнения истекло
  144. if (TaskArray[i].delay == 0) {
  145. // взводим флаг запуска,
  146. TaskArray[i].run = 1;
  147. } else {
  148. // иначе уменьшаем время
  149. TaskArray[i].delay--;
  150. }
  151. }
  152. /* TDelay_Timer -- уменьшим счётчик */
  153. if (TDelay != 0) {
  154. TDelay --;
  155. }
  156. if (TWI_WDT != 0) {
  157. TWI_WDT --;
  158. }
  159. }