Professional Documents
Culture Documents
Report
Report
Report
TỔNG HỢP
Mục lục
1 Chapter 1: LED Animations 2
1.1 Bài tập 1: Chuyển đổi led 2 led . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Bài tập 2: Đèn giao thông . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Bài tập 3: Ngã tư đèn giao thông . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Bài tập 4: Led 7 đoạn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Bài tập 5: Tổng hợp 4 bài trước . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.6 Bài tập 6, 7, 8, 9: Ma trận led . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.7 Bài tập 10: Ma trận led và đồng hồ . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2 Chapter 2: Timer 16
2.1 Bài tập 1: Làm quen với timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Bài tập 2: Làm quen với timer (tt) . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3 Bài tập 3: Hàm update7SEG và Callback . . . . . . . . . . . . . . . . . . . . . . . 19
2.4 Bài tập 4: Thay đổi tần số bằng Callback . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 Bài tập 5: Hàm updateClockBuffer . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.6 Bài tập 6: Internal Timer và trả lời câu hỏi . . . . . . . . . . . . . . . . . . . . . . 20
2.7 Bài tập 7 + 8: Đồng hồ với timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.8 Bài tập 9: Timer và ma trận led: chữ A . . . . . . . . . . . . . . . . . . . . . . . . 22
2.9 Bài tập 10: Timer và chữ A di chuyển . . . . . . . . . . . . . . . . . . . . . . . . . 25
Hình 1: Schematic.
Hình 3: Schematic.
Hình 5: Schematic.
19 HAL_Delay ( 3 0 0 0 ) ;
20 HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_7) ;
21 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
22 HAL_Delay ( 2 0 0 0 ) ;
23 }
Hình 7: Schematic.
Hình 9: Schematic.
Hàm while
1 while (1)
2 {
3 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 1 ) ; // RED
4 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_2, 1 ) ; // YELLOW
5 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_3, 0 ) ; // GREEN
6 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ; // RED
7 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 1 ) ; // YELLOW
8 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 1 ) ; // GREEN
9
10 display (3 ,5) ;
11 HAL_Delay ( 1 0 0 0 ) ;
12
13 display (2 ,4) ;
14 HAL_Delay ( 1 0 0 0 ) ;
15
16 display (1 ,3) ;
17 HAL_Delay ( 1 0 0 0 ) ;
18
22 display (2 ,2) ;
23 HAL_Delay ( 1 0 0 0 ) ;
24
25 display (1 ,1) ;
26 HAL_Delay ( 1 0 0 0 ) ;
27
33 display (5 ,3) ;
34 HAL_Delay ( 1 0 0 0 ) ;
35
36 display (4 ,2) ;
37 HAL_Delay ( 1 0 0 0 ) ;
38
39 display (3 ,1) ;
40 HAL_Delay ( 1 0 0 0 ) ;
41
45 display (2 ,2) ;
46 HAL_Delay ( 1 0 0 0 ) ;
47
48 display (1 ,1) ;
49 HAL_Delay ( 1 0 0 0 ) ;
50 }
Câu 2: Hàm setNumberOnClock(int num): Nguyên lý: bật/tắt thật nhanh chân điều
khiển cột để có thể hiển thị các led đồng thời.
1 v o i d setNumberOnClock ( i n t num) {
2 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_15 , 1 ) ;
3 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_9, 1 ) ;
4 s w i t c h (num) {
5 case 0:
6 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 0 ) ;
7 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 1 ) ;
8 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
9 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
10 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
11 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_10 , 0 ) ;
12 HAL_Delay ( 1 ) ;
13 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_10 , 1 ) ;
14 break ;
15 case 1:
16 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 0 ) ;
17 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ;
18 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 1 ) ;
19 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
20 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
21 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_10 , 0 ) ;
22 HAL_Delay ( 1 ) ;
23 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_10 , 1 ) ;
24 break ;
25 case 2:
26 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 0 ) ;
27 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ;
28 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
85 case 8:
86 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 0 ) ;
87 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 1 ) ;
88 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
89 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
90 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
91 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_14 , 0 ) ;
92 HAL_Delay ( 1 ) ;
93 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_14 , 1 ) ;
94 break ;
95 case 9:
96 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 1 ) ;
97 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ;
98 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
99 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
100 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
101 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_13 , 0 ) ;
102 HAL_Delay ( 1 ) ;
103 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_13 , 1 ) ;
104 break ;
105 case 10:
106 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 1 ) ;
107 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ;
108 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
109 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
110 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
111 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_12 , 0 ) ;
112 HAL_Delay ( 1 ) ;
113 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_12 , 1 ) ;
114 break ;
115 case 11:
116 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_4, 1 ) ;
117 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 0 ) ;
118 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, 0 ) ;
119 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_7, 0 ) ;
120 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, 0 ) ;
121 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_11 , 0 ) ;
122 HAL_Delay ( 1 ) ;
123 HAL_GPIO_WritePin (GPIOA, GPIO_PIN_11 , 1 ) ;
124 break ;
125 }
126 }
Câu 5: Tổng hợp sẽ dùng các nút để điều khiển tắt sáng 12 Led đồng hồ.
Hàm xử lý nút
1 v o i d h a n d l e ( i n t num) {
2 num = num%12;
3 i f ( l e d _ f l a g [ num ] == 1 ) setNumberOnClock (num) ;
4 e l s e l e d _ f l a g [ num ] == 0 ;
5 i f (HAL_GPIO_ReadPin(GPIOB, 1 << num) == 1 && f l a g _ c l e a r == 0 ) l e d _ f l a g [ num ] = 1 ;
6 e l s e l e d _ f l a g [ num ] = 0 ;
7 }
Hàm while
1 while (1) {
2 h a n d l e ( i ++) ;
3 }
Câu 2: Code
1 v o i d c a s e _ c l o c k ( i n t time ) {
2 s w i t c h ( time ) {
3 case 11:
4 setNumberOnClock ( 0 ) ;
5 break ;
6 case 12:
7 setNumberOnClock ( 1 ) ;
8 break ;
9 default :
10 setNumberOnClock ( time +1) ;
11 break ;
12 }
13 }
14 v o i d c l o c k ( i n t hour , i n t minute , i n t s e c o n d ) {
15 clearAllClock () ;
16 c a s e _ c l o c k ( hour ) ;
17 c a s e _ c l o c k ( minute / 5 ) ;
18 case_clock ( second /5) ;
19 }
Hàm while
1 i n t hour = 0 , min = 0 , s e c = 0 ;
2 while (1)
3 {
4 s e c ++;
5 i f ( s e c == 5 9 ) {
6 sec = 0;
7 min++;
8 }
9 i f ( min == 5 9 ) {
10 min = 0 ;
11 hour++;
12 }
13 i f ( hour == 1 2 ) {
14 hour = 0 ;
15 }
16 c l o c k ( hour , min , s e c ) ;
17 }
2 Chapter 2: Timer
16 display = 50;
17 }
18 }
Câu 2: Điều gì xảy ra khi đổi "setTimer0(1000)" thành "setTimer0(1)": Led sẽ không
sáng vì lúc này "timer0_counter" sẽ luôn bằng 0 do đó (timer0_counter > 0) sẽ trả về
false nên "timer0_flag" sẽ luôn bằng 0.
Câu 3: Điều gì xảy ra khi đổi "setTimer0(1000)" thành "setTimer0(10)": Đèn sẽ sáng
vì "timer0_counter" bằng 1 nên "timer0_flag" sẽ được set bằng 1.
Ý tưởng cơ bản
• Khi cờ của timer0 được set sau mỗi 1s thì second sẽ được tăng thêm 1. Code sẽ giải quyết
việc chuyển đổi minute và hour
• Khi cờ của timer1 được set sau mỗi 250ms thì sẽ có đèn sáng ở vị trí được sáng theo thứ tự.
Câu 1: Biểu diễn source code trong hàm main và các hàm thành phần.
Hàm main
1 i n t main ( v o i d )
2 {
3 HAL_Init ( ) ;
4 SystemClock_Config ( ) ;
5 MX_GPIO_Init ( ) ;
6 MX_TIM2_Init ( ) ;
Ý tưởng: matrix_buffer[8] sẽ chứa giá trị Led sáng theo từng hàng từ 1 tới 8. Led từng
hàng sáng cùng lúc khi thời gian chuyển giữa các chân điều khiển theo hàng ngắn thì sẽ nhìn như
chúng đang sáng cùng lúc.
Hình 18: FSM chuyển Led từng hàng trong khoảng thời gian ngắn
Câu hỏi 2: Biểu diễn source code trong hàm updateLEDMatrix(int index)
1 c o n s t i n t MAX_LED_MATRIX = 8 ;
2 i n t index_led_matrix = 0 ;
3 u i n t 8 _ t m a t r i x _ b u f f e r [ 8 ] = {0 x11 , 0 x11 , 0 x11 , 0 x11 , 0 x11 , 0 x11 , 0 x11 , 0 x11 } ;
4 u i n t 8 _ t m a t r i x _ s o u r c e [ 8 ] = {0 x18 , 0 x3c , 0 x66 , 0 x66 , 0 x7e , 0 x7e , 0 x66 , 0 x66 } ;
5 v o i d updateLEDMatrix ( i n t i n d e x ) {
6 i n d e x = i n d e x %8;
7 GPIOA−>ODR = ~m a t r i x _ s o u r c e [ i n d e x ] ;
8 switch ( index ) {
9 case 0:
10 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_0, 0 ) ;
11 HAL_Delay ( 1 ) ;
12 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_0, 1 ) ;
13 break ;
14 case 1:
15 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_1, 0 ) ;
16 HAL_Delay ( 1 ) ;
17 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_1, 1 ) ;
18 break ;
19 case 2:
20 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_2, 0 ) ;
21 HAL_Delay ( 1 ) ;
22 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_2, 1 ) ;
23 break ;
24 case 3:
25 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_3, 0 ) ;
26 HAL_Delay ( 1 ) ;
27 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_3, 1 ) ;
28 break ;
29 case 4:
30 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_4, 0 ) ;
31 HAL_Delay ( 1 ) ;
32 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_4, 1 ) ;
33 break ;
34 case 5:
35 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_5, 0 ) ;
36 HAL_Delay ( 1 ) ;
37 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_5, 1 ) ;
38 break ;
39 case 6:
40 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_6, 0 ) ;
41 HAL_Delay ( 1 ) ;
42 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_6, 1 ) ;
43 break ;
44 case 7:
45 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_7, 0 ) ;
46 HAL_Delay ( 1 ) ;
47 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_7, 1 ) ;
48 break ;
49 default :
50 break ;
51 }
52 }
Ý tưởng: Sau khi hiện thực hàm hiện LED updateLEDMatrix(int index), giờ ta thiết kế
máy trạng thái để chữ A chạy từ trái sang phải vì LED có 8 cột và chữ A được biểu diễn có chiều
ngang là 6 bit nên sẽ dung máy trạng thái có 14 trạng thái để biểu diễn.
21 case 0:
22 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 7 ) ;
23 break ;
24 case 1:
25 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 6 ) ;
26 break ;
27 case 2:
28 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 5 ) ;
29 break ;
30 case 3:
31 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 4 ) ;
32 break ;
33 case 4:
34 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 3 ) ;
35 break ;
36 case 5:
37 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 2 ) ;
38 break ;
39 case 6:
40 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] >> 1 ) ;
41 break ;
42 case 7:
43 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = m a t r i x _ s o u r c e [ i ] ;
44 break ;
45 case 8:
46 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 1 ) ;
47 break ;
48 case 9:
49 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 2 ) ;
50 break ;
51 case 10:
52 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 3 ) ;
53 break ;
54 case 11:
55 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 4 ) ;
56 break ;
57 case 12:
58 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 5 ) ;
59 break ;
60 case 13:
61 for ( int i = 0 ; i < 8 ; i ++) m a t r i x _ b u f f e r [ i ] = ( m a t r i x _ s o u r c e [ i ] << 6 ) ;
62 break ;
63 default :
64 break ;
65 }
66 }
67 v o i d updateLEDMatrix ( i n t i n d e x ) {
68 i n d e x = i n d e x %8;
69 GPIOA−>ODR = ~ m a t r i x _ b u f f e r [ i n d e x ] ;
70 switch ( index ) {
71 case 0:
72 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_0, 0 ) ;
73 HAL_Delay ( 1 ) ;
74 HAL_GPIO_WritePin (GPIOB, GPIO_PIN_0, 1 ) ;
75 break ;
76 case 1:
124 setTimer0 ( 1 ) ;
125 i n t led_run = 0 ;
126
133 }
134 }
135 }
• Ứng dụng có 12 đèn LED bao gồm 4 đèn LED đỏ, 4 đèn LED màu vàng, 4 đèn LED xanh .
• Ứng dụng có 4 đèn LED bảy đoạn để hiển thị thời gian với 2 đèn cho mỗi con đường. Có 2
LED bảy đoạn sẽ hiển thị thời gian cho từng LED màu tương ứng với từng đường.
– để sửa đổi thời gian cho từng đèn led màu một cách nhanh chóng
• Ứng dụng có ít nhất 4 chế độ được điều khiển bằng nút đầu tiên. Chế độ 1 là chế độ bình
thường, trong khi chế độ 2 3 4 là chế độ sửa đổi. Bạn có thể nhấn nút đầu tiên để thay đổi
chế độ. Các chế độ sẽ thay đổi từ 1 thành 4 và trở lại 1 lần nữa.
• Tất cả các đèn LED đơn màu đỏ đang nhấp nháy ở tần số 2 Hz.
• Sử dụng hai đèn LED bảy đoạn để hiển thị giá trị.
• Sử dụng hai đèn LED bảy đoạn còn lại để hiển thị chế độ.
• Nút thứ hai được sử dụng để tăng giá trị thời lượng cho các đèn LED màu đỏ.
• Giá trị của khoảng thời gian nằm trong khoảng 1 - 99.
Chế độ 3 - Sửa đổi khoảng thời gian đối với đèn LED màu vàng: Tương tự đối với đèn
LED màu đỏ được mô tả ở trên với đèn LED màu hổ phách.
Chế độ 4 - Sửa đổi khoảng thời gian cho các đèn LED màu xanh: Tương tự cho các đèn
LED màu đỏ được mô tả ở trên với các đèn LED màu xanh lá cây.
1 s t a t i c v o i d MX_TIM2_Init ( v o i d )
2 {
3
8 TIM_ClockConfigTypeDef s C l o c k S o u r c e C o n f i g = { 0 } ;
9 TIM_MasterConfigTypeDef s M a s t e r C o n f i g = { 0 } ;
10
34 }
35 /∗ USER CODE BEGIN TIM2_Init 2 ∗/
36
39 }
3 #d e f i n e NO_OF_BUTTONS 3
4
6 #d e f i n e DURATION_FOR_AUTO_INCREASING 100
7 #d e f i n e BUTTON_IS_PRESSED GPIO_PIN_RESET
8 #d e f i n e BUTTON_IS_RELEASED GPIO_PIN_SET
9
10
11 s t a t i c GPIO_PinState b u t t o n B u f f e r [NO_OF_BUTTONS] ;
12
13 s t a t i c GPIO_PinState d e b o u n c e B u t t o n B u f f e r 1 [NO_OF_BUTTONS ] ;
14 s t a t i c GPIO_PinState d e b o u n c e B u t t o n B u f f e r 2 [NO_OF_BUTTONS ] ;
15
16 s t a t i c uint8_t f l a g F o r B u t t o n P r e s s 1 s [NO_OF_BUTTONS] ;
17
18
19 s t a t i c u i n t 1 6 _ t c o u n t e r F o r B u t t o n P r e s s 1 s [NO_OF_BUTTONS ] ;
20 void button_reading ( void ) {
21 f o r ( c h a r i = 0 ; i < NO_OF_BUTTONS; i ++){
22 debounceButtonBuffer2 [ i ] = debounceButtonBuffer1 [ i ] ;
23 d e b o u n c e B u t t o n B u f f e r 1 [ i ] = HAL_GPIO_ReadPin(GPIOA, ( 1 << (8+ i ) ) ) ;
24 \\3 b u t t o n s a s s i g n f o r p i n 8 , 9 , 10
25 i f ( d e b o u n c e B u t t o n B u f f e r 1 [ i ] == d e b o u n c e B u t t o n B u f f e r 2 [ i ] )
26 buttonBuffer [ i ] = debounceButtonBuffer1 [ i ] ;
27 i f ( b u t t o n B u f f e r [ i ] == BUTTON_IS_PRESSED) {
28 i f ( c o u n t e r F o r B u t t o n P r e s s 1 s [ i ] < DURATION_FOR_AUTO_INCREASING) {
29 c o u n t e r F o r B u t t o n P r e s s 1 s [ i ]++;
30 }
31 else {
32 flagForButtonPress1s [ i ] = 1;
33 }
34 }
35 else {
36 counterForButtonPress1s [ i ] = 0;
37 flagForButtonPress1s [ i ] = 0;
38 }
39 }
40 }
41 unsigned char is_button_pressed ( uint8_t index ) {
42 i f ( i n d e x >= NO_OF_BUTTONS) r e t u r n 0 ;
43 r e t u r n ( b u t t o n B u f f e r [ i n d e x ] == BUTTON_IS_PRESSED) ;
44 }
45
Code thay đổi Chế độ mỗi lần nhấn nút thứ nhất.
1 enum B u t t o n S t a t e {BUTTON_RELEASED, BUTTON_PRESSED,
BUTTON_PRESSED_MORE_THAN_1_SECOND} ;
2 enum B u t t o n S t a t e b u t t o n S t a t e = BUTTON_RELEASED;
3
17 else {
18 i f ( is_button_pressed_1s ( 0 ) ) {
19 b u t t o n S t a t e = BUTTON_PRESSED_MORE_THAN_1_SECOND;
20 }
21 }
22 break ;
23 c a s e BUTTON_PRESSED_MORE_THAN_1_SECOND:
24 i f ( ! is_button_pressed (0) ) {
25 b u t t o n S t a t e = BUTTON_RELEASED;
26 }
27 // TODO
28 break ;
29 }
30 }
33 b u t t o n S t a t e 1 = BUTTON_PRESSED_MORE_THAN_1_SECOND;
34 }
35 }
36 break ;
37 c a s e BUTTON_PRESSED_MORE_THAN_1_SECOND:
38 i f ( ! is_button_pressed (1) ) {
39 b u t t o n S t a t e 1 = BUTTON_RELEASED;
40 }
41 // TODO
42 i f ( t i m e r 2 _ f l a g == 1 ) {
43 led_light_red_new = led_light_red_new +5;
44 s e t L e d b u f f e r ( led_light_red_new , 1 ) ;
45 setTimer2 (1000) ;
46 }
47 break ;
48 }
49 i f ( is_button_pressed (2) ) {
50 // b u t t o n S t a t e 1 = BUTTON_PRESSED;
51 l e d _ l i g h t _ t i m e [ 0 ] = led_light_red_new ;
52 led_light_time [ 2 ] = led_light_time [ 0 ] − led_light_time [ 1 ] ;
53 // s e t L e d b u f f e r ( led_light_red_new , 1 ) ;
54 }
55 }
1 v o i d mode0 ( ) {
2 i f ( t i m e r 0 _ f l a g == 1 ) {
3 i n d e x = i n d e x %4;
4 update7SEG_1 ( i n d e x ) ;
5 // update7SEG_2 ( i n d e x ) ;
6 i n d e x ++;
7 setTimer0 ( 3 ) ;
8 }
9
10 i f ( t i m e r 1 _ f l a g ==1){
11 switch ( t r a f f i c 1 ) {
12 case red :
13 i f ( count_less < led_light_time [ 2 ] ) {
14 t u r n _ l ed _ l i g h t _ 1 (OFF, OFF, ON) ;
15 t u r n _ l ed _ l i g h t _ 2 (ON, OFF, OFF) ;
16 s e t L e d b u f f e r ( led_light_time [ 0 ] − count_less , led_light_time [2] − count_less
);
17 }
18 else {
19 t u r n _ l ed _ l i g h t _ 1 (OFF, ON, OFF) ;
20 t u r n _ l ed _ l i g h t _ 2 (ON, OFF, OFF) ;
21 s e t L e d b u f f e r ( led_light_time [ 0 ] − count_less , led_light_time [0] − count_less
);
22 }
23 c o u n t _ l e s s ++;
24 i f ( c o u n t _ l e s s >= l e d _ l i g h t _ t i m e [ 0 ] ) { t r a f f i c 1 = g r e e n ; c o u n t _ l e s s = 0 ; }
25 break ;
26 case green :
27 t u r n _ l e d _l i g h t _ 1 (ON, OFF, OFF) ;
28 t u r n _ l e d _l i g h t _ 2 (OFF, OFF, ON) ;
29 s e t L e d b u f f e r ( led_light_time [ 2 ] − count_less , led_light_time [ 0 ] − count_less
);
30 c o u n t _ l e s s ++;
31 i f ( c o u n t _ l e s s >= l e d _ l i g h t _ t i m e [ 2 ] ) { t r a f f i c 1 = amber ; c o u n t _ l e s s = 0 ; }
32 break ;
33 c a s e amber :
34 t u r n _ l e d _l i g h t _ 1 (ON, OFF, OFF) ;
35 t u r n _ l e d _l i g h t _ 2 (OFF, ON, OFF) ;
36 s e t L e d b u f f e r ( led_light_time [ 1 ] − count_less , led_light_time [ 1 ] − count_less
);
37 c o u n t _ l e s s ++;
38 i f ( c o u n t _ l e s s >= l e d _ l i g h t _ t i m e [ 1 ] ) { t r a f f i c 1 = r e d ; c o u n t _ l e s s = 0 ; }
39 break ;
40 default :
41 break ;
42 }
43 setTimer1 (1111) ;
44 }
45 }
• void SCH_Update(void)
• void SCH_Dispatch_Tasks(void)
Ý tưởng gốc: Hàm này sẽ cập nhật giá trị Delay được điều khiển bởi timer interupt, từ đó
cập nhập lại giá trị RunMe để xác định được task nào sẽ được thực thi theo thứ tự TaskID.
1 v o i d SCH_Update ( v o i d ) {
2 u n s i g n e d c h a r Index ;
3 f o r ( Index = 0 ; Index < SCH_MAX_TASKS; Index++) {
4 i f ( SCH_tasks_G [ Index ] . pTask ) {
5 i f ( SCH_tasks_G [ Index ] . Delay == 0 ) {
6 SCH_tasks_G [ Index ] . RunMe += 1 ;
7 i f ( SCH_tasks_G [ Index ] . P e r i o d ) {
8 SCH_tasks_G [ Index ] . Delay = SCH_tasks_G [ Index ] . P e r i o d ;
9 }
10 }
11 else {
12 SCH_tasks_G [ Index ] . Delay −= 10 ;
13 }
14 }
15 }
16 }
Ý tưởng 2: Sau khi cập nhập lại giá trị của Delay của Task vừa được thực thi ta sẽ kiểm tra
lại Task nào đang giữ giá trị Delay thấp nhất, rồi set RunMe của nó lên. Từ đó ta có thể thay đổi
độ phức tạp của hàm update từ O(n) mỗi lần gọi thành O(1) khi được gọi bình thường và O(n)
khi cập nhập lại giá trị Delay của Task vừa được thực thi.
1 unsigned char index = 0 ;
2 i n t time = 0 ;
3 v o i d SCH_Update ( v o i d ) {
4 i f ( SCH_tasks_G [ i n d e x ] . Delay == time ) {
5 SCH_tasks_G [ i n d e x ] . RunMe += 1 ;
6 i f ( SCH_tasks_G [ i n d e x ] . P e r i o d ) {
7 SCH_tasks_G [ i n d e x ] . Delay += SCH_tasks_G [ i n d e x ] . P e r i o d ;
8 }
9 i n d e x = ( i n d e x +1)%SCH_MAX_TASKS;
10 i n t min = SCH_tasks_G [ i n d e x ] . Delay ;
11 f o r ( i n t i = 0 ; i < SCH_MAX_TASKS; i ++){
12 i f ( SCH_tasks_G [ i ] . pTask ) {
13 i f ( min >= SCH_tasks_G [ i ] . Delay ) {
14 min = SCH_tasks_G [ i ] . Delay ;
15 index = i ;
16 }
17 }
18 else {
19 break ;
20 }
21 }
22 }
23 time += 1 0 ;
24
25 }
Ý tưởng: Hàm này sẽ kiểm tra lần lượt các task đang có, và sẽ thực thi nếu chúng đủ điều
kiện RunMe > 0 và có con trỏ hàm, đồng thời sẽ xóa hàm nào không có Period (chu kỳ gọi). Đây
là hàm xử lý chính của hệ thống, được gọi trong vòng while(1).
1 v o i d SCH_Dispatch_Tasks ( v o i d ) {
2 u n s i g n e d c h a r Index ;
3 f o r ( Index = 0 ; Index < SCH_MAX_TASKS; Index++) {
4 i f ( SCH_tasks_G [ Index ] . pTask ) {
5 i f ( SCH_tasks_G [ Index ] . RunMe > 0 ) {
6 ( ∗ SCH_tasks_G [ Index ] . pTask ) ( ) ;
7 i f ( SCH_tasks_G [ Index ] . P e r i o d == 0 ) {
8 SCH_Delete_Task ( Index ) ;
9 }
10 }
11 }
12 }
13 }
Ý tưởng: Hàm này sẽ truyền vào địa chỉ con trỏ hàm cần thêm pFunction, thời gian Delay,
chu kỳ gọi Period. Các dữ liệu trên sẽ được cập nhập vào biến mảng kiểu sTask ở trên. Có giá
trị trả về số thứ tự của Task đã thêm vào mảng.
1 u n s i g n e d c h a r SCH_Add_Task( v o i d ( ∗ pFunction ) ( ) , u n s i g n e d i n t DELAY, u n s i g n e d i n t
PERIOD) {
2 u n s i g n e d c h a r Index = 0 ;
3 w h i l e ( ( SCH_tasks_G [ Index ] . pTask != 0 ) && ( Index < SCH_MAX_TASKS) ) {
4 Index++;
5 }
6 i f ( Index == SCH_MAX_TASKS) {
7 Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
8 r e t u r n SCH_MAX_TASKS;
9 }
10 SCH_tasks_G [ Index ] . pTask = pFunction ;
11 SCH_tasks_G [ Index ] . Delay = DELAY;
12 SCH_tasks_G [ Index ] . P e r i o d = PERIOD ;
13 SCH_tasks_G [ Index ] . RunMe = 0 ;
14 r e t u r n Index ;
15 }
Ý tưởng: Hàm này sẽ xóa dữ liệu của Task ở vi trí TaskID. Còn được gọi khi khởi tạo
Scheduler. Có dữ liệu trả về để xác định Task được xóa hay có lỗi.
1 u n s i g n e d c h a r SCH_Add_Task( v o i d ( ∗ pFunction ) ( ) , u n s i g n e d i n t DELAY, u n s i g n e d i n t
PERIOD) {
2 u n s i g n e d c h a r Index = 0 ;
3 w h i l e ( ( SCH_tasks_G [ Index ] . pTask != 0 ) && ( Index < SCH_MAX_TASKS) ) {
4 Index++;
5 }
6 i f ( Index == SCH_MAX_TASKS) {
7 Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
8 r e t u r n SCH_MAX_TASKS;
9 }
10 SCH_tasks_G [ Index ] . pTask = pFunction ;
11 SCH_tasks_G [ Index ] . Delay = DELAY;
12 SCH_tasks_G [ Index ] . P e r i o d = PERIOD ;
13 SCH_tasks_G [ Index ] . RunMe = 0 ;
14 r e t u r n Index ;
15 }
Ý tưởng: Hàm này sẽ khởi tạo Scheduler bằng cách xóa hết các Task trước đó. Hàm này sẽ
được gọi trước vòng while.
1 v o i d SCH_Init ( v o i d ) {
2 unsigned char i ;
3 f o r ( i = 0 ; i < SCH_MAX_TASKS; i ++) {
4 SCH_Delete_Task ( i ) ;
5 }
6 }
Ý tưởng: Đây là hàm điều khiển các timer c̈ứng.̈ Ở đây timer 2 với tần số 100Hz (chu kỳ
10ms) sẽ điều khiển hàm void SCH_update() và cập nhập biến time_duration để xác định
thời gian làm việc của các Task - sẽ được trình bày sau.
1 i n t time_duration ;
2 v o i d HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef ∗ htim ) {
3 i f ( htim −> I n s t a n c e == TIM2 ) {
4 SCH_Update ( ) ;
5 t i m e _ d u r a t i o n −= 1 0 ;
6 }
7 }
Ý tưởng: Task có thời gian thục thi được xác định bởi biến time_duration và vòng
while(time_duration > 0), biến này được cập nhập bởi timer 2 mỗi 10ms. Các task có cấu
trúc giống nhau, chỉ khác các giá trị được in ra Terminal để biết được Task nào đang được thực
thi và thời gian bắt đầu thực thi sẽ được tính bởi hàm HAL_GetTick() việc chia cho 10 rồi
nhân 10 là để có thể loại bỏ giá trị hàng milisecond để dễ theo dõi kết quả. Đây là ví dụ cho void
taskA().
1 v o i d taskA ( ) {
2 u i n t 8 _ t t x B u f f e r [ ] = { "A " };
3 HAL_UART_Transmit(& huart1 , t x B u f f e r , s t r l e n ( t x B u f f e r ) , 1 0 0 ) ;
4 i n t time = HAL_GetTick ( ) /10∗10 −20;
5 char b u f f e r [ 1 6 ] ;
6 HAL_UART_Transmit(& huart1 , ( u i n t 8 _ t ∗ ) b u f f e r , s p r i n t f ( b u f f e r , "%d" , time ) , 5 0 0 ) ;
7 HAL_UART_Transmit(& huart1 , ( u i n t 8 _ t ∗ ) " \ r " , 2 , 5 0 0 ) ;
8 time_duration = 5 0 ;
9 while ( time_duration > 0) {
10 }
11 }
4.4 Demonstration
Mô phỏng protues.
Giả sử ta có 5 task với thời gian thực thi 50ms, và chu kỳ thực thi lần lượt là 0.5s, 1s, 1.5s,
2s, 2.5s. Các task này được thêm vào bằng hàm SCH_Add_Task trước vòng while(1). Thì
các Task.Delay lần lượt là 0, 50, 100, 150, 200 để chắc chắn rằng các thứ tự thực thi của chúng
không bị đảo lộn.
1 SCH_Add_Task( taskA , 0 , 500) ;
2 SCH_Add_Task( taskB , 50 , 1000) ;
3 SCH_Add_Task( taskC , 100 , 1500) ;
4 SCH_Add_Task( taskD , 150 , 2000) ;
5 SCH_Add_Task( taskE , 200 , 2500) ;
Với giả thuyết như trên, theo lý thuyết ta sẽ có thời gian biểu thực thi của các Task như sau:
Để có thể