|
@@ -1245,7 +1245,7 @@ void stateCode(char event) {
|
|
|
// ....
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+```
|
|
|
|
|
|
In the above example, you could equally well have set the timer to start at zero
|
|
|
and increment until it hits the desired limit (100 in this case).
|
|
@@ -1262,7 +1262,8 @@ behalf of the tasks......
|
|
|
Let's create a centralized service called `setTimer(timer_index, timer_count)`.
|
|
|
|
|
|
A task can call this service with a unique `timer_index` and a requested count. The
|
|
|
-`timer_irq()` will then count out the ticks on behalf of the task, and when the tick
|
|
|
+`timer_irq()` uses a pool of timer registers, and will count out the ticks
|
|
|
+on behalf of the task, and when the tick
|
|
|
count is finished, the `timer_irq()` code can generate a unique event, perhaps
|
|
|
`EVT_TIMER_n`.
|
|
|
|
|
@@ -1290,14 +1291,14 @@ void stateCode(char event) {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-This makes the state code much simpler to read,
|
|
|
+This makes the state code simpler to read,
|
|
|
hiding all the increments/decrements and limit testing.
|
|
|
|
|
|
The overhead for this ends up in the `timer_irq()` code,
|
|
|
and might look something like this:
|
|
|
|
|
|
```C
|
|
|
-static unsigned int timers[NUM_TIMERS];
|
|
|
+static uint16 timers[NUM_TIMERS];
|
|
|
#define EVT_TIMER_OFFSET 100
|
|
|
enum {EVENT_TIMER_1=EVT_TIMER_OFFSET, EVENT_TIMER_2, EVENT_TIMER_3}; // 100, 101...
|
|
|
enum {TIMER_1, TIMER_2, TIMER_3}; // 0,1,2,....
|
|
@@ -1321,7 +1322,7 @@ void setTimer(int timerIndex, unsigned int timerCount) {
|
|
|
<details><summary>Reality Check</summary>
|
|
|
On a typical microcontroller running at 24MHz, with 5 timers, this adds about
|
|
|
2 microseconds of extra time to the `timer_irq()` code, which typically runs every
|
|
|
-10 or 100msec. It considerably simplifies the task code, makes it more legible
|
|
|
+10 or 100msec. It simplifies the task code, makes it more legible
|
|
|
and probably reduces bugs that may appear by duplication of code.
|
|
|
|
|
|
Another possible design for timers is to have the main `timer_isr()` increment
|
|
@@ -1502,22 +1503,22 @@ void main(void) {
|
|
|
/*********** task code, with states ************/
|
|
|
enum {LED_ON, LED_OFF};
|
|
|
enum {RTB_IDLE, RTB_ON}; // states
|
|
|
-static uint8 rtbState = RTB_IDLE;
|
|
|
-static uint16 rtbTimerCount = 0;
|
|
|
-const uint16 BUTTON_LED_ON_TIME = 150;
|
|
|
+static uint8 rtbState = RTB_IDLE;
|
|
|
+static uint16 rtbTimerCount = 0;
|
|
|
+const uint16 BUTTON_LED_ON_TIME = 150;
|
|
|
|
|
|
void respondToButtonTask(uint8 evt) {
|
|
|
switch(rtbState) {
|
|
|
case RTB_IDLE:
|
|
|
if (evt == EVT_BUTTON) {
|
|
|
rtbState = RTB_ON;
|
|
|
- rtbTimerCount = 0;
|
|
|
+ rtbTimerCount = BUTTON_LED_ON_TIME;
|
|
|
gpio_set(LED, LED_ON);
|
|
|
}
|
|
|
break;
|
|
|
case RTB_ON:
|
|
|
if (evt == EVT_TICK) {
|
|
|
- if (++rtbTimerCount > BUTTON_LED_ON_TIME) {
|
|
|
+ if (--rtbTimerCount == 0) {
|
|
|
gpio_set(LED, LED_OFF);
|
|
|
rtbState = RTB_IDLE;
|
|
|
}
|
|
@@ -1526,9 +1527,9 @@ void respondToButtonTask(uint8 evt) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const uint16 LED_ON_TIME = 150;
|
|
|
-const uint16 LED_OFF_TIME = 50;
|
|
|
-static uint8 ledState = LED_OFF;
|
|
|
+const int LED_ON_TIME = 150;
|
|
|
+const int LED_OFF_TIME = 50;
|
|
|
+static uint8 ledState = LED_OFF;
|
|
|
static uint16 ledTimerCount = 0;
|
|
|
|
|
|
void ledTask(uint8 evt) {
|
|
@@ -1537,14 +1538,14 @@ void ledTask(uint8 evt) {
|
|
|
if (evt == EVT_TICK) {
|
|
|
if (++ledTimerCount > LED_OFF_TIME) {
|
|
|
gpio_set(LED2, LED_ON);
|
|
|
- ledTimerCount = 0;
|
|
|
+ ledTimerCount = LED_ON_TIME;
|
|
|
ledState = LED_ON;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
case LED_ON:
|
|
|
if (evt == EVT_TICK) {
|
|
|
- if (++ledTimerCount > LED_ON_TIME) {
|
|
|
+ if (--ledTimerCount == 0) {
|
|
|
gpio_set(LED2, LED_OFF);
|
|
|
ledTimerCount = 0;
|
|
|
ledState = LED_OFF;
|
|
@@ -1631,6 +1632,7 @@ void rtbTaskCode(char event) {
|
|
|
break;
|
|
|
case STATE_FLASHING:
|
|
|
// count down flashCount, toggle LED halfway through
|
|
|
+ // effectively creating a substate
|
|
|
if (event == EVT_TICK) {
|
|
|
if (--flashCount == 0) {
|
|
|
setLED(OFF);
|
|
@@ -1728,7 +1730,7 @@ a subroutine, it's allowed to return a value
|
|
|
|
|
|

|
|
|
|
|
|
-This of course means that the prototype for task functions would change from
|
|
|
+To return a value means that the prototype for task functions would change from
|
|
|
|
|
|
```C
|
|
|
void taskCode(uint8 event);
|
|
@@ -1746,12 +1748,12 @@ uint8 SendMessage(int8 taskPointer(uint8), uint8 message) {
|
|
|
|
|
|
### Usage
|
|
|
|
|
|
-Why might one want to send a *message* between tasks?
|
|
|
+Why might one want to *send a message* between tasks?
|
|
|
|
|
|
Suppose you have a rotary encoder, which sends quadrant signals, which need
|
|
|
to be interpreted as *clockwise* and *counter clockwise*. You could have one
|
|
|
task devoted to determining the direction of the knob
|
|
|
-(and [debouncing](#debouncing)), and have it send clean
|
|
|
+(and [debouncing](#debouncing)), and have it *send* (or *post*) clean
|
|
|
EVT_CW and EVT_CCW *messages* to its sibgling tasks.
|
|
|
|
|
|
Another possible use of *messages* is to create alternate souces of input.
|
|
@@ -1774,7 +1776,7 @@ assignment was to code up a simulated automobile entertainment system, which inc
|
|
|
- task blue light to show bluetooth connectivity
|
|
|
- volume up/down sense and display
|
|
|
- radio channel select buttons
|
|
|
- - step single freq, or high-speed scan
|
|
|
+ - step single the radio frequency, or high-speed scan
|
|
|
- power on/off management
|
|
|
- remote control of volume/radio-select from the steering wheel (uart link)
|
|
|
- backlight for night-time viewing (auto sense from a light sensor)
|