You are on page 1of 44

Dr.

Le Trong Nhan
Mục lục

Chapter 1. Buttons/Switches 7
1 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3 Basic techniques for reading from port pins . . . . . . . . . . . . . . . 10
3.1 The need for pull-up resistors . . . . . . . . . . . . . . . . . . . . 10
3.2 Dealing with switch bounces . . . . . . . . . . . . . . . . . . . . 10
4 Reading switch input (basic code) using STM32 . . . . . . . . . . . . . 15
4.1 Input Output Processing Patterns . . . . . . . . . . . . . . . . . 15
4.2 Setting up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2.1 Create a project . . . . . . . . . . . . . . . . . . . . . . . 16
4.2.2 Create a file C source file and header file for input
reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.3 Code For Read Port Pin and Debouncing . . . . . . . . . . . . . 18
4.3.1 The code in the input_reading.c file . . . . . . . . . . 18
4.3.2 The code in the input_reading.h file . . . . . . . . . . 19
4.3.3 The code in the timer.c file . . . . . . . . . . . . . . . . 19
4.4 Button State Processing . . . . . . . . . . . . . . . . . . . . . . . 20
4.4.1 Finite State Machine . . . . . . . . . . . . . . . . . . . . 20
4.4.2 The code for the FSM in the input_processing.c file 21
4.4.3 The code in the input_processing.h . . . . . . . . . . 21
4.4.4 The code in the main.c file . . . . . . . . . . . . . . . . 22
5 Exercises and Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.1 Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2 Exercise 1: Sketch an FSM . . . . . . . . . . . . . . . . . . . . . . 24
5.3 Exercise 2: Proteus Schematic . . . . . . . . . . . . . . . . . . . . 25
5.4 Exercise 3: Create STM32 Project . . . . . . . . . . . . . . . . . . 25

Microcontroller Page 5
5.5 Exercise 4: Modify Timer Parameters . . . . . . . . . . . . . . . 27
5.6 Exercise 5: Adding code for button debouncing . . . . . . . . . 27
5.6.1 The code in the input_reading.h file . . . . . . . . . . 27
5.6.2 The code for button debouncing and reading but-
ton in the input_reading.c file . . . . . . . . . . . . . . 28
5.6.3 Code for change mode when press first button in
the ouptut_processing.c file . . . . . . . . . . . . . . . 29
5.7 Exercise 6: Adding code for displaying modes . . . . . . . . . . 32
5.7.1 Code for display mode on 7-SEG in led_display.h file 32
5.7.2 Code for display mode on 7-SEG in led_display.c file 32
5.7.3 The code for display 7SEG and led blinky in the out-
put_processing.c file . . . . . . . . . . . . . . . . . . . . 34
5.7.4 The code for traffic led in traffic_led.c file . . . . . . . 37
5.8 Exercise 7: Adding code for increasing time duration value for
the red LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.9 Exercise 8: Adding code for increasing time duration value for
the amber LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.10 Exercise 9: Adding code for increasing time duration value for
the green LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.11 Exercise 10: To finish the project . . . . . . . . . . . . . . . . . . 44

Microcontroller Page 6
CHƯƠNG 1

Buttons/Switches
1 Objectives

In this lab, you will

• Learn how to add new C source files and C header files in an STM32 project,

• Learn how to read digital inputs and display values to LEDs using a timer
interrupt of a microcontroller (MCU).
• Learn how to debounce when reading a button.

• Learn how to create an FSM and implement an FSM in an MCU.

2 Introduction

Embedded systems usually use buttons (or keys, or switches, or any form of me-
chanical contacts) as part of their user interface. This general rule applies from the
most basic remote-control system for opening a garage door, right up to the most
sophisticated aircraft autopilot system. Whatever the system you create, you need
to be able to create a reliable button interface.
A button is generally hooked up to an MCU so as to generate a certain logic level
when pushed or closed or “active" and the opposite logic level when unpushed or
open or “inactive." The active logic level can be either ‘0’ or ‘1’, but for reasons both
historical and electrical, an active level of ’0’ is more common.
We can use a button if we want to perform operations such as:

• Drive a motor while a switch is pressed.

• Switch on a light while a switch is pressed.

• Activate a pump while a switch is pressed.

These operations could be implemented using an electrical button without using


an MCU; however, use of an MCU may well be appropriate if we require more com-
plex behaviours. For example:

• Drive a motor while a switch is pressed.


Condition: If the safety guard is not in place, don’t turn the motor. Instead
sound a buzzer for 2 seconds.
• Switch on a light while a switch is pressed.
Condition: To save power, ignore requests to turn on the light during daylight
hours.
• Activate a pump while a switch is pressed
Condition: If the main water reservoir is below 300 litres, do not start the
main pump: instead, start the reserve pump and draw the water from the
emergency tank.

Microcontroller Page 8
In this lab, we consider how you read inputs from mechanical buttons in your em-
bedded application using an MCU.

Microcontroller Page 9
3 Basic techniques for reading from port pins

3.1 The need for pull-up resistors

Hình 1.1: Connecting a button to an MCU

Figure 1.1 shows a way to connect a button to an MCU. This hardware operates as
follows:

• When the switch is open, it has no impact on the port pin. An internal resistor
on the port “pulls up" the pin to the supply voltage of the MCU (typically 3.3V
for STM32F103). If we read the pin, we will see the value ‘1’.

• When the switch is closed (pressed), the pin voltage will be 0V. If we read the
pin, we will see the value ‘0’.

However, if the MCU does not have a pull-up resistor inside, when the button is
pressed, the read value will be ‘0’, but even we release the button, the read value is
still ‘0’ as shown in Figure 1.2.
So a reliable way to connect a button/switch to an MCU is that we explicitly use an
external pull-up resistor as shown in Figure 1.3.

3.2 Dealing with switch bounces

In practice, all mechanical switch contacts bounce (that is, turn on and off, re-
peatedly, for short period of time) after the switch is closed or opened as shown in
Figure 1.4.
Every system that uses any kind of mechanical switch must deal with the issue of
debouncing. The key task is to make sure that one mechanical switch or button
action is only read as one action by the MCU, even though the MCU will typically
be fast enough to detect the unwanted switch bounces and treat them as separate
events. Bouncing can be eliminated by special ICs or by RC circuitry, but in most
cases debouncing is done in software because software is “free".
As far as the MCU concerns, each “bounce" is equivalent to one press and release
of an “ideal” switch. Without appropriate software design, this can give several
problems:

Microcontroller Page 10
Hình 1.2: The need of pull up resistors

Hình 1.3: A reliable way to connect a button to an MCU

Hình 1.4: Switch bounces

Microcontroller Page 11
• Rather than reading ‘A’ from a keypad, we may read ‘AAAAA’

• Counting the number of times that a switch is pressed becomes extremely


difficult

• If a switch is depressed once, and then released some time later, the ‘bounce’
may make it appear as if the switch has been pressed again (at the time of
release).

The key to debouncing is to establish a minimum criterion for a valid button push,
one that can be implemented in software. This criterion must involve differences
in time - two button presses in 20ms must be treated as one button event, while
two button presses in 2 seconds must be treated as two button events. So what are
the relevant times we need to consider? They are these:

• Bounce time: most buttons seem to stop bouncing within 10ms

• Button press time: the shortest time a user can press and release a button
seems to be between 50 and 100ms

• Response time: a user notices if the system response is 100ms after the button
press, but not if it is 50ms after

Combining all of these times, we can set a few goals

• Ignore all bouncing within 10ms

• Provide a response within 50ms of detecting a button push (or release)

• Be able to detect a 50ms push and a 50ms release

The simplest debouncing method is to examine the keys (or buttons or switches)
every N milliseconds, where N > 10ms (our specified button bounce upper limit)
and N <= 50ms (our specified response time). We then have three possible out-
comes every time we read a button:

• We read the button in the solid ‘0’ state

• We read the button in the solid ‘1’ state

• We read the button while it is bouncing (so we will get either a ‘0’ or a ‘1’)

Outcomes 1 and 2 pose no problems, as they are what we would always like to
happen. Outcome 3 also poses no problem because during a bounce either state
is acceptable. If we have just pressed an active-low button and we read a ’1’ as it
bounces, the next time through we are guaranteed to read a ’0’ (remember, the
next time through all bouncing will have ceased), so we will just detect the button
push a bit later. Otherwise, if we read a ’0’ as the button bounces, it will still be ’0’
the next time after all bouncing has stopped, so we are just detecting the button
push a bit earlier. The same applies to releasing a button. Reading a single bounce
(with all bouncing over by the time of the next read) will never give us an invalid
button state. It’s only reading multiple bounces (multiple reads while bouncing is

Microcontroller Page 12
occurring) that can give invalid button states such as repeated push signals from
one physical push.
So if we guarantee that all bouncing is done by the time we next read the button,
we’re good. Well, almost good, if we’re lucky...
MCUs often live among high-energy beasts, and often control the beasts. High en-
ergy devices make electrical noise, sometimes great amounts of electrical noise.
This noise can, at the worst possible moment, get into your delicate button-and-
high-value-pullup circuit and act like a real button push. Oops, missile launched,
sorry!
If the noise is too intense we cannot filter it out using only software, but will need
hardware of some sort (or even a redesign). But if the noise is only occasional,
we can filter it out in software without too much bother. The trick is that instead
of regarding a single button ‘make’ or ‘break’ as valid, we insist on N contiguous
makes or breaks to mark a valid button event. N will be a factor of your button
scanning rate and the amount of filtering you want to add. Bigger N gives more
filtering. The simplest filter (but still a big improvement over no filtering) is just an
N of 2, which means compare the current button state with the last button state,
and only if both are the same is the output valid.
Note that now we have not two but three button states: active (or pressed), inac-
tive (or released), and indeterminate or invalid (in the middle of filtering, not yet
filtered). In most cases we can treat the invalid state the same as the inactive state,
since we care in most cases only about when we go active (from whatever state)
and when we cease being active (to inactive or invalid). With that simplification
we can look at simple N = 2 filtering reading a button wired to STM32 MCU:
1 void button_reading ( void ) {
2 static unsigned char last_button ;
3 unsigned char raw_button ;
4 unsigned char filtered_button ;
5 last_button = raw_button ;
6 raw_button = HAL_GPIO_ReadPin ( BUTTON_1_GPIO_Port ,
BUTTON_1_Pin ) ;
7 if ( last_button == raw_button ) {
8 filtered_button = raw_button ;
9 }
10 }
Program 1.1: Read port pin and deboucing

The function button_reading() must be called no more often than our debounce
time (10ms).
To expand to greater filtering (larger N), keep in mind that the filtering technique
essentially involves reading the current button state and then either counting or
reseting the counter. We count if the current button state is the same as the last
button state, and if our count reaches N we then report a valid new button state.
We reset the counter if the current button state is different than the last button
state, and we then save the current button state as the new button state to com-
pare against the next time. Also note that the larger our value of N the more often
our filtering routine must be called, so that we get a filtered response within our

Microcontroller Page 13
specified 50ms deadline. So for example with an N of 8 we should be calling our
filtering routine every 2 - 5ms, giving a response time of 16 - 40ms (>10ms and
<50ms).

Microcontroller Page 14
4 Reading switch input (basic code) using STM32

To demonstrate the use of buttons/switches in STM32, we use an example which


requires to write a program that

• Has a timer which has an interrupt in every 10 milliseconds.

• Reads values of button PB0 every 10 milliseconds.

• Increases the value of LEDs connected to PORTA by one unit when the button
PB0 is pressed.

• Increases the value of PORTA automatically in every 0.5 second, if the button
PB0 is pressed in more than 1 second.

4.1 Input Output Processing Patterns

For both input and output processing, we have a similar pattern to work with. Nor-
mally, we have a module named driver which works directly to the hardware. We
also have a buffer to store temporarily values. In the case of input processing, the
driver will store the value of the hardware status to the buffer for further process-
ing. In the case of output processing, the driver uses the buffer data to output to
the hardware.

Hình 1.5: Input Output Processing Patterns

Figure 1.5 shows that we should have an input_reading module to processing the
buttons, then store the processed data to the buffer. Then a module of input_output_processin
will process the input data, and update the output buffer. The output driver gets
the value from the output buffer to transfer to the hardware.

Microcontroller Page 15
4.2 Setting up

4.2.1 Create a project

Please follow the instruction in Labs 1 and 2 to create a project that includes:

• PB0 as an input port pin,

• PA0-PA7 as output port pins, and

• Timer 2 10ms interrupt

4.2.2 Create a file C source file and header file for input reading

We are expected to have files for button processing and led display as shown in
Figure 1.6.

Hình 1.6: File Organization

Steps 1 (Figure 1.7): Right click to the folder Src, select New, then select Source
File. There will be a pop-up. Please type the file name, then click Finish.
Step 2 (Figure 1.8): Do the same for the C header file in the folder Inc.

Microcontroller Page 16
Hình 1.7 : Step 1: Create a C source file for input reading

Hình 1.8: Step 2: Create a C header file for input processing

Microcontroller Page 17
4.3 Code For Read Port Pin and Debouncing

4.3.1 The code in the input_reading.c file

1 # include " main . h "


2 // we aim to work with more than one buttons
3 # define N0_OF_BUTTONS 1
4 // timer interrupt duration is 10 ms , so to pass 1 second ,
5 // we need to jump to the interrupt service routine 100 time
6 # define DURATION_FOR_AUTO_INCREASING 100
7 # define BUTTON_IS_PRESSED GPIO_PIN_RESET
8 # define BUTTON_IS_RELEASED GPIO_PIN_SET
9 // the buffer that the final result is stored after
10 // debouncing
11 static GPIO_PinState buttonBuffer [ N0_OF_BUTTONS ];
12 // we define two buffers for debouncing
13 static GPIO_PinState debounceButtonBuffer1 [ N0_OF_BUTTONS ];
14 static GPIO_PinState debounceButtonBuffer2 [ N0_OF_BUTTONS ];
15 // we define a flag for a button pressed more than 1 second .
16 static uint8_t flagForButtonPress1s [ N0_OF_BUTTONS ];
17 // we define counter for automatically increasing the value
18 // after the button is pressed more than 1 second .
19 static uint16_t counterForButtonPress1s [ N0_OF_BUTTONS ];
20 void button_reading ( void ) {
21 for ( char i = 0; i < N0_OF_BUTTONS ; i ++) {
22 debounceButtonBuffer2 [ i ] = debounceButtonBuffer1 [ i ];
23 debounceButtonBuffer1 [ i ] = HAL_GPIO_ReadPin (
BUTTON_1_GPIO_Port , BUTTON_1_Pin ) ;
24 if ( debounceButtonBuffer1 [ i ] == debounceButtonBuffer2 [ i
])
25 buttonBuffer [ i ] = debounceButtonBuffer1 [ i ];
26 if ( buttonBuffer [ i ] == BUTTON_IS_PRESSED ) {
27 // if a button is pressed , we start counting
28 if ( counterForButtonPress1s [ i ] <
DURATION_FOR_AUTO_INCREASING ) {
29 counterForButtonPress1s [ i ]++;
30 } else {
31 // the flag is turned on when 1 second has passed
32 // since the button is pressed .
33 flagForButtonPress1s [ i ] = 1;
34 // todo
35 }
36 } else {
37 counterForButtonPress1s [ i ] = 0;
38 flagForButtonPress1s [ i ] = 0;
39 }
40 }
41 }
Program 1.2: Define constants buffers and button_reading function

Microcontroller Page 18
1 unsigned char is_button_pressed ( uint8_t index ) {
2 if ( index >= N0_OF_BUTTONS ) return 0;
3 return ( buttonBuffer [ index ] == BUTTON_IS_PRESSED ) ;
4 }
Program 1.3: Checking a button is pressed or not

1 unsigned char is_button_pressed_1s ( unsigned char index ) {


2 if ( index >= N0_OF_BUTTONS ) return 0 xff ;
3 return ( flagForButtonPress1s [ index ] == 1) ;
4 }
Program 1.4: Checking a button is pressed more than a second or not

4.3.2 The code in the input_reading.h file

1 # ifndef INC_INPUT_READING_H_
2 # define INC_INPUT_READING_H_
3 void button_reading ( void ) ;
4 unsigned char is_button_pressed ( unsigned char index ) ;
5 unsigned char is_button_pressed_1s ( unsigned char index ) ;
6 # endif /* INC_INPUT_READING_H_ */
Program 1.5: Prototype in input_reading.h file

4.3.3 The code in the timer.c file

1 # include " main . h "


2 # include " input_reading . h "
3

4 void HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef * htim )


5 {
6 if ( htim - > Instance == TIM2 ) {
7 button_reading () ;
8 }
9 }
Program 1.6: Timer interrupt callback function

Microcontroller Page 19
4.4 Button State Processing

4.4.1 Finite State Machine

To solve the example problem, we define 3 states as follows:

• State 0: The button is released or the button is in the initial state.

• State 1: When the button is pressed, the FSM will change to State 1 that is
increasing the values of PORTA by one value. If the button is released, the
FSM goes back to State 0.

• State 2: while the FSM is in State 1, the button is kept pressing more than 1
second, the state of FSM will change from 1 to 2. In this state, if the button
is kept pressing, the value of PORTA will be increased automatically in every
500ms. If the button is released, the FSM goes back to State 0.

Hình 1.9: An FSM for processing a button

Microcontroller Page 20
4.4.2 The code for the FSM in the input_processing.c file

Please note that fsm_for_input_processing function should be called inside the su-
per loop of the main functin.
1 # include " main . h "
2 # include " input_reading . h "
3

4 enum ButtonState { BUTTON_RELEASED , BUTTON_PRESSED ,


B UTTON_PRESSED_MORE_THAN_1_SECOND } ;
5 enum ButtonState buttonState = BUTTON_RELEASED ;
6 void fsm_for_input_processing ( void ) {
7 switch ( buttonState ) {
8 case BUTTON_RELEASED :
9 if ( is_button_pressed (0) ) {
10 buttonState = BUTTON_PRESSED ;
11 // INCREASE VALUE OF PORT A BY ONE UNIT
12 }
13 break ;
14 case BUTTON_PRESSED :
15 if (! is_button_pressed (0) ) {
16 buttonState = BUTTON_RELEASED ;
17 } else {
18 if ( is_button_pressed_1s (0) ) {
19 buttonState = BUTTON_PRESSED_MORE_THAN_1_SECOND ;
20 }
21 }
22 break ;
23 case BUTTON_PRESSED_MORE_THAN_1_SECOND :
24 if (! is_button_pressed (0) ) {
25 buttonState = BUTTON_RELEASED ;
26 }
27 // todo
28 break ;
29 }
30 }
Program 1.7: The code in the input_processing.c file

4.4.3 The code in the input_processing.h

1 # ifndef INC_INPUT_PROCESSING_H_
2 # define INC_INPUT_PROCESSING_H_
3

4 void fsm_for_input_processing ( void ) ;


5

6 # endif /* INC_INPUT_PROCESSING_H_ */
Program 1.8: Code in the input_processing.h file

Microcontroller Page 21
4.4.4 The code in the main.c file

1 # include " main . h "


2 # include " input_processing . h "
3 // don ’t modify this part
4 int main ( void ) {
5 HAL_Init () ;
6 /* Configure the system clock */
7 SystemClock_Config () ;
8 /* Initialize all configured peripherals */
9 MX_GPIO_Init () ;
10 MX_TIM2_Init () ;
11 while (1)
12 {
13 // you only need to add the fsm function here
14 fsm_for_input_processing () ;
15 }
16 }
Program 1.9: The code in the main.c file

Microcontroller Page 22
5 Exercises and Report

5.1 Specifications

You are required to build an application of a traffic light in a cross road which in-
cludes some features as described below:

• The application has 12 LEDs including 4 red LEDs, 4 amber LEDs, 4 green
LEDs.

• The application has 4 seven segment LEDs to display time with 2 for each
road. The 2 seven segment LEDs will show time for each color LED corre-
sponding to each road.

• The application has three buttons which are used


- to select modes,
- to modify the time for each color led on the fly, and
- to set the chosen value.

• The application has at least 4 modes which is controlled by the first button.
Mode 1 is a normal mode, while modes 2 3 4 are modification modes. You
can press the first button to change the mode. Modes will change from 1 to 4
and back to 1 again.
Mode 1 - Normal mode:
- The traffic light application is running normally.
Mode 2 - Modify time duration for the red LEDs: This mode allows you to
change the time duration of the red LED in the main road. The expected be-
haviours of this mode include:
- All single red LEDs are blinking in 2 Hz.
- Use two seven-segment LEDs to display the value.
- Use the other two seven-segment LEDs to display the mode.
- The second button is used to increase the time duration value for the
red LEDs.
- The value of time duration is in a range of 1 - 99.
- The third button is used to set the value.
Mode 3 - Modify time duration for the amber LEDs: Similar for the red LEDs
described above with the amber LEDs.
Mode 4 - Modify time duration for the green LEDs: Similar for the red LEDs
described above with the green LEDs.

Microcontroller Page 23
5.2 Exercise 1: Sketch an FSM

Your task in this exercise is to sketch an FSM that describes your idea of how to
solve the problem.

Microcontroller Page 24
5.3 Exercise 2: Proteus Schematic

Your task in this exercise is to draw a Proteus schematic for the problem above.

Hình 1.10: Schematic design

5.4 Exercise 3: Create STM32 Project

Your task in this exercise is to create a project that has pin corresponding to the
Proteus schematic that you draw in previous section. You need to set up your timer
interrupt is about 10ms.
Please add your report here.

Microcontroller Page 25
Hình 1.11: Cài đặt timer_interupt là 10ms

Hình 1.12: Cài đặt chân (pin) cho project

Microcontroller Page 26
5.5 Exercise 4: Modify Timer Parameters

Your task in this exercise is to modify the timer settings so that when we want
to change the time duration of the timer interrupt, we change it the least and it
will not affect the overall system. For example, the current system we have imple-
mented is that it can blink an LED in 2 Hz, with the timer interrupt duration is
10ms. However, when we want to change the timer interrupt duration to 1ms or
100ms, it will not affect the 2Hz blinking LED.
Please add your report here.
1 # define TIMER_CYCLE 10;
Program 1.10: define TIMER_CYCLE in software_timer.h

1 void setBlinkLedTimer ( int duration ) {


2 blink_counter = duration / TIMER_CYCLE ;
3 blink_flag = 0;
4 }
Program 1.11: Function setBlinkLedTimer in software_timer.c

Giá trị TIMER_CYCLE được gán bằng timer interrupt của TIM2 là 10(ms). Trong
trường hợp nếu có thay đổi giá trị interupt thay đổi thì chỉ cần thay đổi giá trị của
TIMER_CYCLE.

5.6 Exercise 5: Adding code for button debouncing

Following the example of button reading and debouncing in the previous section,
your tasks in this exercise are:

• To add new files for input reading and output display,

• To add code for button debouncing,

• To add code for increasing mode when the first button is pressed.

Please add your report here.

5.6.1 The code in the input_reading.h file

1 # ifndef INC_INPUT_READING_H_
2 # define INC_INPUT_READING_H_
3

4 void button_reading_Init ( void ) ;


5 void button_reading ( void ) ;
6 unsigned char is_button_pressed ( unsigned char index ) ;
7

8 # endif /* INC_INPUT_READING_H_ */
Program 1.12: Khai báo prototype trong file input_reading.h

Microcontroller Page 27
• Hàm button_reading_Init được gọi trước khi vào hàm main để set các button
ở trạng thái RELEASED.

• Hàm button_reading để đọc trạng thái của nút nhấn và gán vào buttonBuffer
để sử dụng cho máy trạng thái.

• Hàm is_button_pressed để kiểm tra xem nút nhấn tại vị trí index có được
nhấn hay không.

5.6.2 The code for button debouncing and reading button in the input_reading.c
file

1 # include " main . h "


2 # include " input_reading . h "
3 // we aim to work with 3 buttons
4 # define N0_OF_BUTTONS 3
5 # define BUTTON_IS_PRESSED GPIO_PIN_RESET
6 # define BUTTON_IS_RELEASED GPIO_PIN_SET
7

8 // the buffer that the final result is stored after


debouncing
9 static GPIO_PinState buttonBuffer [ N0_OF_BUTTONS ];
10

11 // we define two buffers for debouncing


12 static GPIO_PinState debounceButtonBuffer1 [ N0_OF_BUTTONS ];
13 static GPIO_PinState debounceButtonBuffer2 [ N0_OF_BUTTONS ];
14

15 // we define an array to store 3 buttons pin


16 static uint16_t buttonPin [ N0_OF_BUTTONS ] = { BUTTON_0_Pin ,
BUTTON_1_Pin , BUTTON_2_Pin };
17

18 // we define function to SET all buffers to RELEASED


19 void button_reading_Init ( void ) {
20 for ( int i = 0; i < N0_OF_BUTTONS ; i ++) {
21 debounceButtonBuffer1 [ i ] = BUTTON_IS_RELEASED ;
22 debounceButtonBuffer2 [ i ] = BUTTON_IS_RELEASED ;
23 buttonBuffer [ i ] = BUTTON_IS_RELEASED ;
24 }
25 }
26

27 void button_reading ( void ) {


28 for ( int i = 0; i < N0_OF_BUTTONS ; i ++) {
29 debounceButtonBuffer2 [ i ] = debounceButtonBuffer1 [ i ];
30 debounceButtonBuffer1 [ i ] = HAL_GPIO_ReadPin ( GPIOB ,
buttonPin [ i ]) ;
31 if ( debounceButtonBuffer1 [ i ] == debounceButtonBuffer2 [ i
]) {
32 buttonBuffer [ i ] = debounceButtonBuffer1 [ i ];
33 }

Microcontroller Page 28
34 }
35 }
36

37 unsigned char is_button_pressed ( uint8_t index ) {


38 if ( index >= N0_OF_BUTTONS ) return 0;
39 if ( buttonBuffer [ index ] == BUTTON_IS_PRESSED ) {
40 return 1;
41 }
42 else return 0;
43 }
Program 1.13: Hiện thực hàm trong file input_reading.c

1 void HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef * htim )


2 {
3 button_reading () ;
4 timer_run () ;
5 }
Program 1.14: Gọi hàm đọc nút nhấn mỗi 10ms trong hàm ngắt

1 while (1)
2 {
3 fsm_for_output_processing () ;
4 }
Program 1.15: Máy trạng thái được gọi trong while(1)

Máy trạng thái sẽ liên tục được gọi trong while(1). Còn giá trị của nút nhấn sẽ được
cập nhật mỗi 10ms khi hàm ngắt được gọi.

5.6.3 Code for change mode when press first button in the ouptut_processing.c
file

1 # include " output_processing . h "


2

3 enum MODE { MODE_1 , MODE_2 , MODE_3 , MODE_4 } ;


4 // MODE_1 is default
5 enum MODE Mode = MODE_1 ;
6

7 // buttonflag0 is used to check button press and release ,


avoid change mode randomly
8 static uint8_t buttonflag0 ;
9

10 // FSM_MODEL is call in main ( while )


11 void fsm_for_output_processing ( void ) {
12 switch ( Mode ) {
13 case MODE_1 :
14 // BUTTON_0 PRESS
15 if ( is_button_pressed (0) == 1) {
16 if ( buttonflag0 == 0) {

Microcontroller Page 29
17 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
18 Mode = MODE_2 ;
19 counter_mode2 = 0;
20 LED_TRAFFIC_INIT () ;
21 setTimer (1000) ;
22 }
23 } else {
24 buttonflag0 = 0; // update buttonflag0 when
button0 is realeased
25 }
26 // SET_TIMER 1 S IF DON ’T PRESS
27 if ( timer0_flag == 1) {
28 setTimer (1000) ;
29 }
30 break ;
31 case MODE_2 :
32 // BUTTON_0 PRESS
33 if ( is_button_pressed (0) ) {
34 if ( buttonflag0 == 0) {
35 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
36 Mode = MODE_3 ;
37 counter_mode3 = 0;
38 LED_TRAFFIC_INIT () ;
39 setTimer (1000) ;
40 }
41 } else {
42 buttonflag0 = 0; // update buttonflag0 when button0
is realeased
43 }
44 // SET_TIMER 1 S IF DON ’T PRESS
45 if ( timer0_flag == 1) {
46 setTimer (1000) ;
47 }
48 break ;
49 case MODE_3 :
50 // BUTTON_0 PRESS
51 if ( is_button_pressed (0) ) {
52 if ( buttonflag0 == 0) {
53 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
54 Mode = MODE_4 ;
55 counter_mode4 = 0;
56 LED_TRAFFIC_INIT () ;
57 setTimer (1000) ;
58 }
59 } else {
60 buttonflag0 = 0; // update buttonflag0 when button0

Microcontroller Page 30
is realeased
61 }
62 // SET_TIMER 1 S IF DON ’T PRESS
63 if ( timer0_flag == 1) {
64 setTimer (1000) ;
65 }
66 break ;
67 case MODE_4 :
68 // BUTTON_0 PRESS
69 if ( is_button_pressed (0) ) {
70 if ( buttonflag0 == 0) {
71 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
72 Mode = MODE_1 ;
73 LED_TRAFFIC_LOAD_BUFFER () ;
74 LED_TRAFFIC_INIT () ;
75 setTimer (1000) ;
76 }
77 } else {
78 buttonflag0 = 0; // update buttonflag0 when button0
is realeased
79 }
80 // SET_TIMER 1 S IF DON ’T PRESS
81 if ( timer0_flag == 1) {
82 setTimer (1000) ;
83 }
84 break ;
85 default :
86 Mode = MODE_1 ;
87 }
88 }
Program 1.16: Code for change mode in the output_processing.c file

• Với câu lệnh gán enum MODE Mode = MODE_1 thì mặc định Mode sẽ là
MODE_1 khi máy trạng thái được gọi lần đầu.

• Cờ buttonflag0 được dùng để tránh trường hợp mode bị nhảy cóc sai ý muốn
mỗi khi người dùng nhấn nút. Qui ước khi buttonflag0 bằng 0 thì khi nhấn
mới có tác dụng và ngay sao đó sẽ set buttonflag0 lên 1. Chỉ khi nào người
dùng nhả nút nhấn ra thì cờ mới được cập nhật về 0 cho lần nhấn kế tiếp. Ở
đây chưa xét trường hợp nhấn đè.

• Khi nhấn button_0 hệ thống sẽ kiểm tra xem cờ của nút nhấn đã sẽ chuyển
qua Mode kế tiếp đồng thời set thời gian cho trạng thái kế tiếp là 1s. Ngoài
ra khi chuyển trạng thái thì các đèn sẽ được khởi động lại thông qua hàm
LED_TRAFFIC_INIT được khai báo và sử dụng trọng file led_traffic.c.

Microcontroller Page 31
5.7 Exercise 6: Adding code for displaying modes

Your tasks in this exercise are:

• To add code for display mode on seven-segment LEDs, and

• To add code for blinking LEDs depending on the mode that is selected.

Please add your report here.

5.7.1 Code for display mode on 7-SEG in led_display.h file

1 # ifndef INC_LED_DISPLAY_H_
2 # define INC_LED_DISPLAY_H_
3

4 void clearAllLED7 ( void ) ;


5 void update_LED7_driver ( uint8_t index ) ;
6 void displayLED7 ( uint8_t index ) ;
7 void update_all_clock_buffer ( uint8_t time1 , uint8_t time2 ) ;
8 void update_horizontal_clock_buffer ( uint8_t time ) ;
9 void update_vertical_clock_buffer ( uint8_t time ) ;
10

11 # endif /* INC_LED_DISPLAY_H_ */
Program 1.17: Khai báo prototype trong file led_display.h

• Hàm clearALLLED7: dùng để tắt tất cả các LED7

• Hàm update_all_clock_buffer: dùng để cập nhật lại buffer khi thay đổi thời
gian ở các mode khi nhấn Button_3

• Hàm update_horizontal_clock_buffer: dùng để cập nhật lại buffer0 và buffer1


để hiển thị thời gian người dùng muốn chỉnh sửa cho chiều ngang.

• Hàm update_vertical_clock_buffer: dùng để cập nhật lại buffer2 và buffer3


để hiển thị thời gian người dùng muốn chỉnh sửa cho chiều dọc

• Hàm update_7SEG_driver: dùng để quét từng LED trước khi hiển thị

• Hàm displayLED7: dùng để set các chân LED7 hiển thị ra màn hình

5.7.2 Code for display mode on 7-SEG in led_display.c file

1 # include " main . h "


2 # include " led_display . h "
3

4 # define NUMBER_OF_7_SEG_LED 4
5

6 static uint8_t LED7Conversion [10]={


7 0 x3f , // 0

Microcontroller Page 32
8 0 x06 , // 1
9 0 x5b , // 2
10 0 x4f , // 3
11 0 x66 , // 4
12 0 x6d , // 5
13 0 x7d , // 6
14 0 x07 , // 7
15 0 x7f , // 8
16 0 x67 // 9
17 };
18

19 // Buffer to store number after update LED7 time


20 static uint8_t numBuffer [ NUMBER_OF_7_SEG_LED ];
21

22 // Buffer to store value of LED7 conversion


23 static uint8_t buffer [ NUMBER_OF_7_SEG_LED ];
24

25 // Turn off all LED7


26 void clearAllLED7 ( void ) {
27 HAL_GPIO_WritePin ( EN0_GPIO_Port , EN0_Pin , SET ) ;
28 HAL_GPIO_WritePin ( EN1_GPIO_Port , EN1_Pin , SET ) ;
29 HAL_GPIO_WritePin ( EN2_GPIO_Port , EN2_Pin , SET ) ;
30 HAL_GPIO_WritePin ( EN2_GPIO_Port , EN3_Pin , SET ) ;
31 }
32

33 // Update all buffers when in modify time


34 void update_all_clock_buffer ( uint8_t time1 , uint8_t time2 ) {
35 numBuffer [0] = time1 /10;
36 numBuffer [1] = time1 %10;
37 numBuffer [2] = time2 /10;
38 numBuffer [3] = time2 %10;
39 }
40

41 // Update buffer0 and buffer1 when modify time in


horizontal
42 void update_horizontal_clock_buffer ( uint8_t time ) {
43 numBuffer [0] = time /10;
44 numBuffer [1] = time %10;
45 }
46

47 // Update buffer2 and buffer3 when modify time in vertical


48 void update_vertical_clock_buffer ( uint8_t time ) {
49 numBuffer [2] = time /10;
50 numBuffer [3] = time %10;
51 }
52

53 // Scan LED7 before display


54 void update_LED7_driver ( uint8_t index ) {
55 clearAllLED7 () ;

Microcontroller Page 33
56 switch ( index ) {
57 case 0:
58 buffer [0]= LED7Conversion [ numBuffer [0]];
59 displayLED7 (0) ;
60 HAL_GPIO_WritePin ( EN0_GPIO_Port , EN0_Pin ,0) ;
61 break ;
62 case 1:
63 buffer [1]= LED7Conversion [ numBuffer [1]];
64 displayLED7 (1) ;
65 HAL_GPIO_WritePin ( EN1_GPIO_Port , EN1_Pin ,0) ;
66 break ;
67 case 2:
68 buffer [2]= LED7Conversion [ numBuffer [2]];
69 displayLED7 (2) ;
70 HAL_GPIO_WritePin ( EN2_GPIO_Port , EN2_Pin ,0) ;
71 break ;
72 case 3:
73 buffer [3]= LED7Conversion [ numBuffer [3]];
74 displayLED7 (3) ;
75 HAL_GPIO_WritePin ( EN3_GPIO_Port , EN3_Pin ,0) ;
76 break ;
77 }
78 }
79

80 // Display LED7
81 void displayLED7 ( uint8_t index ) {
82 HAL_GPIO_WritePin ( SEG_A_GPIO_Port , SEG_A_Pin , !(( buffer [
index ] > >0) &0 x01 ) ) ;
83 HAL_GPIO_WritePin ( SEG_B_GPIO_Port , SEG_B_Pin , !(( buffer [
index ] > >1) &0 x01 ) ) ;
84 HAL_GPIO_WritePin ( SEG_C_GPIO_Port , SEG_C_Pin , !(( buffer [
index ] > >2) &0 x01 ) ) ;
85 HAL_GPIO_WritePin ( SEG_D_GPIO_Port , SEG_D_Pin , !(( buffer [
index ] > >3) &0 x01 ) ) ;
86 HAL_GPIO_WritePin ( SEG_E_GPIO_Port , SEG_E_Pin , !(( buffer [
index ] > >4) &0 x01 ) ) ;
87 HAL_GPIO_WritePin ( SEG_F_GPIO_Port , SEG_F_Pin , !(( buffer [
index ] > >5) &0 x01 ) ) ;
88 HAL_GPIO_WritePin ( SEG_G_GPIO_Port , SEG_G_Pin , !(( buffer [
index ] > >6) &0 x01 ) ) ;
89 }
Program 1.18: Hiện thực hàm trong file led_display.c

5.7.3 The code for display 7SEG and led blinky in the output_processing.c file

1 // variable init to check INIT_TRAFFIC_LED when we start


simulation
2 int init = 0 , index_led7 = 0;

Microcontroller Page 34
3

4 // FSM_MODEL is call in main ( while )


5 void fsm_for_output_processing ( void ) {
6 switch ( Mode ) {
7 case MODE_1 :
8 // UPADTE AND DISPLAY LED7
9 if ( led_7_flag ) {
10 update_LED7_driver ( index_led7 ) ;
11 index_led7 ++;
12 if ( index_led7 == 4) index_led7 = 0;
13 setLED7Timer (250) ;
14 }
15 // BUTTON_0 PRESS
16 if ( is_button_pressed (0) == 1) {
17 if ( buttonflag0 == 0) {
18 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
19 Mode = MODE_2 ;
20 counter_mode2 = 0;
21 LED_TRAFFIC_INIT () ;
22 setTimer (1000) ;
23 }
24 } else {
25 buttonflag0 = 0; // update buttonflag0 when
button0 is realeased
26 }
27 // SET_TIMER 1 S IF DONT PRESS AND INIT LED_TRAFFIC
28 if ( timer0_flag == 1) {
29 if ( init == 0) {
30 LED_TRAFFIC_INIT () ;
31 init = 1;
32 }
33 LED_TRAFFIC_RUN () ;
34 setTimer (1000) ;
35 }
36 break ;
37 case MODE_2 :
38 // UPDATE AND DISPLAY LED7
39 update_all_clock_buffer ( counter_mode2 , 2) ;
40 if ( led_7_flag ) {
41 update_LED7_driver ( index_led7 ) ;
42 index_led7 ++;
43 if ( index_led7 == 4) index_led7 = 0;
44 setLED7Timer (250) ;
45 }
46 // BLINK ALL LED RED 2 HZ
47 if ( blink_flag ) {
48 HAL_GPIO_TogglePin ( LED_RED1_GPIO_Port , LED_RED1_Pin ) ;
49 HAL_GPIO_TogglePin ( LED_RED2_GPIO_Port , LED_RED2_Pin ) ;

Microcontroller Page 35
50 setBlinkLedTimer (250) ;
51 }
52 break ;
53 case MODE_3 :
54 // UPDATE AND DISPLAY LED7
55 update_all_clock_buffer ( counter_mode3 , 3) ;
56 if ( led_7_flag ) {
57 update_LED7_driver ( index_led7 ) ;
58 index_led7 ++;
59 if ( index_led7 == 4) index_led7 = 0;
60 setLED7Timer (250) ;
61 }
62 // BLINK ALL LED AMBER 2 HZ
63 if ( blink_flag ) {
64 HAL_GPIO_TogglePin ( LED_AMBER1_GPIO_Port ,
LED_AMBER1_Pin ) ;
65 HAL_GPIO_TogglePin ( LED_AMBER2_GPIO_Port ,
LED_AMBER2_Pin ) ;
66 setBlinkLedTimer (250) ;
67 }
68 break ;
69 case MODE_4 :
70 // UPDATE AND DISPLAY LED7
71 update_all_clock_buffer ( counter_mode4 , 4) ;
72 if ( led_7_flag ) {
73 update_LED7_driver ( index_led7 ) ;
74 index_led7 ++;
75 if ( index_led7 == 4) index_led7 = 0;
76 setLED7Timer (250) ;
77 }
78 // BLINK ALL LED GREEN 2 HZ
79 if ( blink_flag ) {
80 HAL_GPIO_TogglePin ( LED_GREEN1_GPIO_Port ,
LED_GREEN1_Pin ) ;
81 HAL_GPIO_TogglePin ( LED_GREEN2_GPIO_Port ,
LED_GREEN2_Pin ) ;
82 setBlinkLedTimer (250) ;
83 }
84 break ;
85 default :
86 Mode = MODE_1 ;
87 }
88 }
Program 1.19: The code for display 7SEG and led blinky in output_processing.c file

• Ban đầu các tên đèn sẽ được định nghĩa lại bởi các con số tương ứng RED(2),
AMBER(3), GREEN(4) và các biến counter_mode2, counter_mode3, counter_mode4
sẽ đại diện cho thời gian của từng loại đèn để thuận tiện cho quá trình điều
chỉnh.

Microcontroller Page 36
• Khi ở MODE_1 hệ thống sẽ hiển thị trên các led 7 đoạn mặc định Đỏ (5s),
Amber (2s), Green (3s). Giá trị khởi tạo này được load vào buffer trong hàm
main trước khi vòng while được gọi. Và khi cờ led_7_flag bằng 1 thì sẽ dùng
phương pháp quét led để hiện thị các số lên LED7.

• Khi ở MODE_2 việc đầu tiên chúng ta cần làm là update lại giá trị counter cho
đèn đỏ. Trong quá trình update hệ thống sẽ hiển thị counter lên LED7, đồng
thời các led đỏ đơn sẽ liên tục nhấp nháy với tần số 2HZ khi cờ blink_flag lên
1.

• Tương tự đối với MODE_3 và MODE_4 ứng với LED AMBER và LED GREEN.

5.7.4 The code for traffic led in traffic_led.c file

1 # include " main . h "


2 # include " traffic_led . h "
3 # include " led_display . h "
4

5 # define N0_OF_LED 3
6

7 # define RED 0
8 # define AMBER 1
9 # define GREEN 2
10

11 // we define the buffer to store time_of_led


12 static uint8_t bufferTimerForLED [ N0_OF_LED ];
13

14 // we define some sub - variable counter for each led


15 static uint8_t counterRED1 , counterAMBER1 , counterGREEN1 ,
counterRED2 , counterAMBER2 , counterGREEN2 ;
16

17 // we define variable timer to save time each led


18 static uint8_t timeRED , timeAMBER , timeGREEN ;
19

20 // Function to turn off all led


21 void LED_TRAFFIC_INIT ( void ) {
22 HAL_GPIO_WritePin ( LED_RED1_GPIO_Port , LED_RED1_Pin , SET ) ;
23 HAL_GPIO_WritePin ( LED_RED2_GPIO_Port , LED_RED2_Pin , SET ) ;
24 HAL_GPIO_WritePin ( LED_AMBER1_GPIO_Port , LED_AMBER1_Pin ,
SET ) ;
25 HAL_GPIO_WritePin ( LED_AMBER2_GPIO_Port , LED_AMBER2_Pin ,
SET ) ;
26 HAL_GPIO_WritePin ( LED_GREEN1_GPIO_Port , LED_GREEN1_Pin ,
SET ) ;
27 HAL_GPIO_WritePin ( LED_GREEN2_GPIO_Port , LED_GREEN2_Pin ,
SET ) ;
28 }
29

Microcontroller Page 37
30 // Function to load value are saved in buffer to counter
and time of each led
31 // to use for display in 7 SEG
32 void LED_TRAFFIC_LOAD_BUFFER ( void ) {
33 counterRED1 = bufferTimerForLED [ RED ];
34 counterAMBER1 = bufferTimerForLED [ AMBER ];
35 counterGREEN1 = bufferTimerForLED [ GREEN ];
36 counterRED2 = bufferTimerForLED [ RED ];
37 counterAMBER2 = bufferTimerForLED [ AMBER ];
38 counterGREEN2 = bufferTimerForLED [ GREEN ];
39 timeRED = bufferTimerForLED [ RED ];
40 timeAMBER = bufferTimerForLED [ AMBER ];
41 timeGREEN = bufferTimerForLED [ GREEN ];
42 }
43

44 // Function to store value in buffer


45 void LED_TRAFFIC_STORE_BUFFER ( uint8_t time , uint8_t index ) {
46 bufferTimerForLED [ index ] = time ;
47 }
48

49 // Function to setting led in vertical


50 void LED_VERTICAL_RUN ( void ) {
51 // GREEN1 - ON
52 if ( counterGREEN2 > 0) {
53 update_vertical_clock_buffer ( counterGREEN2 ) ;
54 HAL_GPIO_WritePin ( LED_RED1_GPIO_Port , LED_RED1_Pin , SET
);
55 HAL_GPIO_WritePin ( LED_AMBER1_GPIO_Port , LED_AMBER1_Pin ,
SET ) ;
56 HAL_GPIO_WritePin ( LED_GREEN1_GPIO_Port , LED_GREEN1_Pin ,
RESET ) ;
57 counterGREEN2 - -;
58

59 }
60 // AMBER1 - ON
61 else if ( counterAMBER2 > 0) {
62 update_vertical_clock_buffer ( counterAMBER2 ) ;
63 HAL_GPIO_WritePin ( LED_RED1_GPIO_Port , LED_RED1_Pin , SET
);
64 HAL_GPIO_WritePin ( LED_AMBER1_GPIO_Port , LED_AMBER1_Pin ,
RESET ) ;
65 HAL_GPIO_WritePin ( LED_GREEN1_GPIO_Port , LED_GREEN1_Pin ,
SET ) ;
66 counterAMBER2 - -;
67 }
68 // RED1 - ON
69 else if ( counterRED2 > 0) {
70 update_vertical_clock_buffer ( counterRED2 ) ;
71 HAL_GPIO_WritePin ( LED_RED1_GPIO_Port , LED_RED1_Pin ,

Microcontroller Page 38
RESET ) ;
72 HAL_GPIO_WritePin ( LED_AMBER1_GPIO_Port , LED_AMBER1_Pin ,
SET ) ;
73 HAL_GPIO_WritePin ( LED_GREEN1_GPIO_Port , LED_GREEN1_Pin ,
SET ) ;
74 counterRED2 - -;
75 }
76 if ( counterRED2 == 0) {
77 counterRED2 = timeRED ;
78 counterAMBER2 = timeAMBER ;
79 counterGREEN2 = timeGREEN ;
80 }
81 }
82

83 // Function to setting led in horizontal


84 void LED_HORIZONTAL_RUN ( void ) {
85 // RED2 - ON
86 if ( counterRED1 > 0) {
87 update_horizontal_clock_buffer ( counterRED1 ) ;
88 HAL_GPIO_WritePin ( LED_RED2_GPIO_Port , LED_RED2_Pin ,
RESET ) ;
89 HAL_GPIO_WritePin ( LED_AMBER2_GPIO_Port , LED_AMBER2_Pin ,
SET ) ;
90 HAL_GPIO_WritePin ( LED_GREEN2_GPIO_Port , LED_GREEN2_Pin ,
SET ) ;
91 counterRED1 - -;
92 }
93 // AMBER2 - ON
94 else if ( counterAMBER1 > 0) {
95 update_horizontal_clock_buffer ( counterAMBER1 ) ;
96 HAL_GPIO_WritePin ( LED_RED2_GPIO_Port , LED_RED2_Pin , SET
);
97 HAL_GPIO_WritePin ( LED_AMBER2_GPIO_Port , LED_AMBER2_Pin ,
RESET ) ;
98 HAL_GPIO_WritePin ( LED_GREEN2_GPIO_Port , LED_GREEN2_Pin ,
SET ) ;
99 counterAMBER1 - -;
100 }
101 // GREEN2 - ON
102 else if ( counterGREEN1 > 0) {
103 update_horizontal_clock_buffer ( counterGREEN1 ) ;
104 HAL_GPIO_WritePin ( LED_RED2_GPIO_Port , LED_RED2_Pin , SET
);
105 HAL_GPIO_WritePin ( LED_AMBER2_GPIO_Port , LED_AMBER2_Pin ,
SET ) ;
106 HAL_GPIO_WritePin ( LED_GREEN2_GPIO_Port , LED_GREEN2_Pin ,
RESET ) ;
107 counterGREEN1 - -;
108 }

Microcontroller Page 39
109 if ( counterGREEN1 == 0) {
110 counterRED1 = timeRED ;
111 counterAMBER1 = timeAMBER ;
112 counterGREEN1 = timeGREEN ;
113 }
114 }
115

116 // Funtion is call when we want to display led in each mode


117 void LED_TRAFFIC_RUN ( void ) {
118 LED_HORIZONTAL_RUN () ;
119 LED_VERTICAL_RUN () ;
120 }
Program 1.20: The code for traffic led in traffic_led.c file

• Hàm LED_TRAFFIC_LOAD_BUFFER này sẽ được gọi trong hàm main trước


khi hàm while(1) được chạy để set các giá trị ban đầu cho từng đèn. Và ở các
Mode mỗi khi chúng ta muốn lấy các giá trị cho counter ra dùng thì chỉ cần
gọi hàm này.

• Hàm LED_TRAFFIC_STORE_BUFFER được sử dụng để cập nhật lại giá trị


buffer của led tương ứng và nó sẽ được gọi khi người dùng thay đổi giá trị
counter.

5.8 Exercise 7: Adding code for increasing time duration value for
the red LEDs

Your tasks in this exercise are:

• to use the second button to increase the time duration value of the red LEDs

• to use the third button to set the value for the red LEDs.

Please add your report here.


1

2 // counter_mode2 , counter_mode3 , counter_mode4 to save time


of led_traffic
3 static uint8_t counter_mode2 , counter_mode3 , counter_mode4 ;
4

5 // buttonflag0 , buttonflag1 , buttonflag2 to check button


press and release , avoid change mode randomly
6 static uint8_t buttonflag0 , buttonflag1 , buttonflag2 ;
7

8 // variable init to check INIT_TRAFFIC_LED when we start


simulation
9 int init = 0 , index_led7 = 0;
10

11 // FSM_MODEL is call in main ( while )

Microcontroller Page 40
12 void fsm_for_output_processing ( void ) {
13 switch ( Mode ) {
14 case MODE_1 :
15 // UPADTE AND DISPLAY LED7
16 if ( led_7_flag ) {
17 update_LED7_driver ( index_led7 ) ;
18 index_led7 ++;
19 if ( index_led7 == 4) index_led7 = 0;
20 setLED7Timer (250) ;
21 }
22 // BUTTON_0 PRESS
23 if ( is_button_pressed (0) == 1) {
24 if ( buttonflag0 == 0) {
25 buttonflag0 = 1; // update buttonflag0 to avoid
change mode randomly
26 Mode = MODE_2 ;
27 counter_mode2 = 0;
28 LED_TRAFFIC_INIT () ;
29 setTimer (1000) ;
30 }
31 } else {
32 buttonflag0 = 0; // update buttonflag0 when
button0 is realeased
33 }
34 // SET_TIMER 1 S IF DONT PRESS AND INIT LED_TRAFFIC
35 if ( timer0_flag == 1) {
36 if ( init == 0) {
37 LED_TRAFFIC_INIT () ;
38 init = 1;
39 }
40 LED_TRAFFIC_RUN () ;
41 setTimer (1000) ;
42 }
43 break ;
44 case MODE_2 :
45 // BUTTON_1 PRESS
46 if ( is_button_pressed (1) ) {
47 if ( buttonflag1 == 0) {
48 buttonflag1 = 1; // update buttonflag1 to avoid
change mode randomly
49 counter_mode2 = ( counter_mode2 + 1) % 99;
50 }
51 } else buttonflag1 = 0; // update buttonflag1 when
button1 is realeased
52 // BUTTON_2 PRESS
53 if ( is_button_pressed (2) ) {
54 if ( buttonflag2 == 0) {
55 buttonflag2 = 1; // update buttonflag2 to avoid
change mode randomly

Microcontroller Page 41
56 LED_TRAFFIC_STORE_BUFFER ( counter_mode2 , RED ) ;
57 }
58 } else {
59 buttonflag2 = 0; // update buttonflag2 when button2
is realeased
60 }
61 // SET_TIMER 1 S IF DONT PRESS
62 if ( timer0_flag == 1) {
63 setTimer (1000) ;
64 }
65 break ;
66 default :
67 Mode = MODE_1 ;
68 }
69 }
Program 1.21: Code for second and third button in ouput_processing.c with red
led

• Ở bài tập này chúng ta sử dụng các cở button1flag và button2flag có tác dụng
tương tự như button0flag ở câu trên.

• Khi trạng thái ở MODE_1 thì chúng ta sẽ không xét đến trường hợp nhấn
button1 hoặc button2

• Khi ở các Mode còn lại mỗi khi button1 được nhấn thì giá trị counter sẽ tăng
lên như yêu cầu của đề bài. Khi button2 được nhấn thì hàm LED_TRAFFIC_-
STORE_BUFFER được sử dụng để cập nhật lại counter cho led tương ứng ở
Mode đó.

5.9 Exercise 8: Adding code for increasing time duration value for
the amber LEDs

Your tasks in this exercise are:

• to use the second button to increase the time duration value of the amber
LEDs

• to use the third button to set the value for the amber LEDs.

Please add your report here.


1 void fsm_for_output_processing ( void ) {
2 switch ( Mode ) {
3 // ...
4 case MODE_3 :
5 // BUTTON_1 PRESS
6 if ( is_button_pressed (1) ) {
7 if ( buttonflag1 == 0) {

Microcontroller Page 42
8 buttonflag1 = 1; // update buttonflag1 to avoid
change mode randomly
9 counter_mode3 = ( counter_mode3 + 1) % 99;
10 }
11 } else {
12 buttonflag1 = 0; // update buttonflag1 when button1
is realeased
13 }
14 // BUTTON_2 PRESS
15 if ( is_button_pressed (2) ) {
16 if ( buttonflag2 == 0) {
17 buttonflag2 = 1; // update buttonflag2 to avoid
change mode randomly
18 LED_TRAFFIC_STORE_BUFFER ( counter_mode3 , AMBER ) ;
19 }
20 } else {
21 buttonflag2 = 0; // update buttonflag2 when button2
is realeased
22 }
23 // SET_TIMER 1 S IF DONT PRESS
24 if ( timer0_flag == 1) {
25 setTimer (1000) ;
26 }
27 break ;
28 default :
29 Mode = MODE_1 ;
30 }
31 }
Program 1.22: Code for second and third button in ouput_processing.c with amber
led

Mọi điều chỉnh ở bài này sẽ tương tự như ở Exercise 7.

5.10 Exercise 9: Adding code for increasing time duration value


for the green LEDs

Your tasks in this exercise are:

• to use the second button to increase the time duration value of the green
LEDs

• to use the third button to set the value for the green LEDs.

Please add your report here.


1 void fsm_for_output_processing ( void ) {
2 switch ( Mode ) {
3 // ...
4 case MODE_4 :

Microcontroller Page 43
5 // BUTTON_1 PRESS
6 if ( is_button_pressed (1) ) {
7 if ( buttonflag1 == 0) {
8 buttonflag1 = 1; // update buttonflag1 to avoid
change mode randomly
9 counter_mode4 = ( counter_mode4 + 1) % 99;
10 }
11 } else {
12 buttonflag1 = 0; // update buttonflag1 when button1
is realeased
13 }
14 // BUTTON_2 PRESS
15 if ( is_button_pressed (2) ) {
16 if ( buttonflag2 == 0) {
17 buttonflag2 = 1; // update buttonflag2 to avoid
change mode randomly
18 LED_TRAFFIC_STORE_BUFFER ( counter_mode4 , GREEN ) ;
19 }
20 } else {
21 buttonflag2 = 0; // update buttonflag2 when button2
is realeased
22 }
23 // SET_TIMER 1 S IF DONT PRESS
24 if ( timer0_flag == 1) {
25 setTimer (1000) ;
26 }
27 break ;
28 default :
29 Mode = MODE_1 ;
30 }
31 }
Program 1.23: Code for second and third button in ouput_processing.c with green
led

Mọi điều chỉnh ở bài này sẽ tương tự như ở Exercise 7.

5.11 Exercise 10: To finish the project

Link github: https://github.com/Pill50/MCU-LAB3


Link video:
https://drive.google.com/file/d/1_T4A8qnPYO57wkLo-4NpkpVLM_SKKT8I/view?usp=shari

Microcontroller Page 44

You might also like