In the digital design, sometimes we need to detect the transition from '0' to '1' or '1' to '0' of a signal.
For example, suppose you design a counter with a input pin connected to a push button. When you push the button every time, the counter will count by one. The circuit diagram is shown as Figure 1.
Figure 1: Digital Counter
In other words, the counter counts the number of times the switch transitions from open to close state. The pseudoscope is shown as follows:
if (SW1 from open to close) counter ++;
Some microcontrollers provide edge detect circuitry, and you can configure edge detection on the desired pins. In this example, we configure it on PA3. If the edge is detected, a flag will be set in the status register, or trigger an interrupt to the CPU. In your C code, you just need to check the status register, or implement an ISR function to increase the counter value. But here, we only discuss how to implement edge detection using software.
Figure 2: Rising Edge and Falling Edge
If a digital signal rises from low (0) to high (1), this transition is called "rising edge". On the contrary, if it drop from high to low, it is called "falling edge". Each transition has two states — previous state and current state. Current state of input pins can be read from the port DATA register, but the previous state must be stored in a variable.
Every time you read the current input state, compare it to the previous state value. If current state is not equivalent to previous state, a transition had occurred. Before the next cycle starts to read the current input state, the previous state needs to be updated by the current state.
There are two methods to implement software edge detection:
Figure 3: Falling Edge
The falling edge occurs when the signal drops from high (1) to low (0). Hence, if the previous state is high and the current state is low, then the falling edge had just happened.
For example, the following system will toggle LED when the user presses the SW1. Its means the LED will be lit when you press SW1. If user presses the SW1 again, the LED will be turned off.
Figure 4: An Example of Detecting the Falling Edge
In the code, two variables (swState, swPreState) are needed to store the previous and current states for SW1 button.
State machine also can be use in this case.
Figure 6: State Machine for Falling Edge Detection
Polling operation in embedded programming refers to actively sampling the status of an external device. Polling is most often used in terms of input/output (I/O), and it is the process where the embedded system waits for an external device to check for its readiness or status. For example, we have a simple microcontroller device with one push button and one LED. When we press the button, LED will be lit. If we press the button again, then the LED will be off. The pseudocode code would be like:
if button pressed, toggle LED
In this program you can see that the microcontroller always checks the status of the button and then decides the LED condition.
A real-life example about polling method is you are working on homework in your room, and waiting for UPS to deliver an important package. The polling method is exactly like you often (may be every 5 minutes) go to the front door and open the door to check whether your package has come or not.
Polling basically means that the embedded system will check the all the status for each device at set intervals, which is called polling cycle. For example, check the switch state every 5 ms, detect the obstacle every 20 ms, and read the room temperature every 5 sec. The optimal polling cycle will vary according to several factors, including the desired speed of response and the overhead (e.g. processor time and bandwidth) of the polling.
For a simple embedded system, it is usually designed to execute multiple jobs in a single task, such as in the main() function. There are two types of polling methods can be used in the code, as shown below. Assume that the latency time on each job can be ignored.
Figure 1: Multi-Jobs with Same Polling Cycle
It is easy to implement If all the jobs have the same polling cycle. The following code uses a simple delay function for polling interval.
delay for 20 ms
Or, the following code uses SysTick to get more accurate time interval:
get the SysTick value to time1
loop until ( time1 - SysTick) greater then or equal to 20 ms
If a system functionality is where outputs depend on the order in which input events occur, or input events that occur at different times (states) will cause to different output, then these models are called "Time-Ordered Behavior". For example:
State machines are perhaps the most effective method for capturing Time-Ordered Behavior for embedded system. A state machine has several components:
The following tools are used to describe the time-ordered behaviors:
This simple model exemplifies a LED controller that embodies two states: LED off (S_IDLE) and LED on (S_1) and two inputs: SW1 and SW2. If the LED is in the S_IDLE state, and an input SW1 is presented, the state machine progresses to the S_1 state. If an input of SW1 is presented to the machine in the S_1 state the machine stays in the S_1 state.
There are two models for incorporating actions into state machines:
Moore and Mealy state machines have their own advantages and disadvantages. But one of great advantage of both is that they are not mutually exclusive, and these two models can be used together in the system.
The interior of the Moore state machine consists of three blocks:
Figure 2: Moore State Machine Architecture
Moore state machine has following characteristics:
The state diagram of a Moore state machine is shown below:
The state transition table of the above Moore state machine is shown below:
Table 2: State Transition Table for Moore State Machine
What are the difference between Moore and Mealy state machines? The following table shows the point the differences from a Moore machine to a Mealy machine:
|Moore State Machine||Mealy Sate Machine|
|Outputs depend on current state only
outputs = F(currentState);
nextState = F(inputs, currentState);
|Outputs depend on current state and the inputs
outputs = F(inputs, currentState);
nextState = F(inputs, currentState);
|Generally, it has more states then Mealy||Generally, it has fewer states than Moore|
|Output does not react immediately to input change (one clock cycle later)||Outputs have immediate reaction to inputs|
|Output is placed on states||Output is placed on transitions|
|Easy to design||It it difficult to design|
State machine for a stoplight controller is shown as Figure 5.
Figure 5: Stoplight Controller
A state diagram can be implement in three main ways: Nested Switch, the State Pattern, and State Tables.
State machines are a very useful programming model, especially when the system needs to act according to its history (state) and the environment (event). Implementing code using a state machine is very difficult to maintain, because the system reacts differently depending on the state and event. Therefore, a good documentation is very important.
Maybe you will confuse state machines with flowcharts. The most important difference between state machines and flowcharts is that the state machines perform to next actions (state) only in response to explicit events, they are event driven. In contrast, flowcharts do not need to be triggered by events; they are used to describe the progression of the task from beginning to end, step by step.
Figure 6: State Machine vs Flowchart
The distinction between state machines and flowcharts is especially important when analyzing system behavior. Because these two concepts represent two diametrically opposed programming paradigms: state machines are event-driven programming; and flowcharts are transformational programming.
When you design a state machine, you have to constantly thinking about available events (inputs). In contrast, events are not the first concern for flowcharts, but procedures.
In the embedded system design, the system needs to check the input state and then send signal to other devices, or change the state of the outputs. Since each GPIO pin is connected to a different device (some pins are input and other pins may be output or other functions), it is not possible to check the pin state by comparing with a constant value. Setting, clearing and toggling pins also have the same situation: constant values can not be assigned directly to the port DATA register. Because each GPIO pin is associated with the corresponding bit in the port DATA register, a bitwise operation can be used to solve these issues.
Figure 1: Example of Embedded System
Figure 2: Truth Table for Bitwise-OR
To turn certain bits on, the bitwise-OR operation can be used, following the principle that
n OR 1 = 1 and
n OR 0 = n. Therefore, to make sure a bit is on,
OR can be used with a
1. To leave a bit unchanged,
OR is used with a
Example: Setting 1 on bit 5 and 3, the other bits unchanged.
To light on the lamp which is connected on PB2, the bit 2 of the Port B DATA register needs to be set to 1. The following expression shows how to set bit 2 to 1:
PB = PB | _BIT2;
PB |= _BIT2;
The following functions get or set a particular bit of a variable can make programs easier to read.