Query the two cities inSTATIONwith the shortest and longestCITYnames, as well as their respective lengths (i.e.: number of characters in the name). If there is more than one smallest or largest city, choose the one that comes first when ordered alphabetically. TheSTATIONtable is described as follows:
CITY 이름중에 가장 짧은 것과 가장 긴 것을 각각 찾고, 길이가 같은 것이 있을 경우 알파벳 순으로 가장 빠른 것을 찾는 문제
Find the difference between the total number ofCITYentries in the table and the number of distinctCITYentries in the table. TheSTATIONtable is described as follows:
Polling방식에서는 데이터가 들어올 때까지 대기하는 시간 동안은 버튼을 눌러도 동작하지 않는 경우가 있었다. (HAL_UART_Receive의 timeout 시간을 길게 하면 확실히 볼 수 있다.)
Uart Interrupt를 이용하여 이를 해결해보자
먼저 Uart Interrput 기능을 설정하기 위해 PinOut & Configuration에서 사용하는 Uart를 선택하고 NVIC Settings 메뉴에서 Interrupt를 Enable 시킨 후, CodeGeneration을 한다.
이제 Uart Interrupt 기능을 사용할 수 있게 되었다.
먼저 메인 함수의 MX_USART1_UART_Init()을 한 후, HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)를 호출한다.(*pData 는 수신받을 변수, size는 수신받을 데이터 크기)HAL_UART_Receive_IT는 수신 인터럽트를 Enable 하고 수신 대기 상태로 만든다.인터럽트가 발생하면 HAL_UART_IRQHandler 가 호출된다. HAL_UART_IRQHandler에서 자동으로 인터럽트를 처리한 후 Callback 함수를 호출한다.
여러 Callback 함수들이 있지만 수신과 관련된 RxCpltCallback을 사용한다.
HAL_UART_RxCpltCallback은 수신을 완료했을때 Callback이 되며 __weak함수이므로 해당 weak 함수를 수정하지 말고 직접 따로 구현을 해주면 된다.
먼저 구현한 HAL_UART_RxCpltCallback은 다음과 같다.
uart1로 인터럽트가 수신이 되면 데이터를 저장하는 data_arr에 수신받은 데이터를 넣는다.
수신받은 데이터를 HAL_UART_Transmit_IT로 송신하여 콘솔 창에 출력한다.
그 후, HAL_UART_Receive_IT를 호출하여 다시 수신 대기상태로 만든다.
(HAL_UART_Receive_IT의 경우 1회용이라고 생각하고 한번 수신을 한 후, 계속 수신을 하려면 반복하여 호출해야 한다. )
이제 메인 함수의 루프에서 data_arr을 체크하여 LED를 동작시키면 된다.
기존의 on/off 에서 LED1이면 LED on / LED0 이면 LED off가 되도록하였다.
1. RxCpltCallback에서 수신을 받은 후 idx++을 하기에 메인 루프에서는 idx-1을 하여 '\r' 또는 '\n'을 찾는다.
2. 해당 조건에 들어가면 '\0'을 넣어 문자열의 끝을 알린다.
3. 문자열을 비교하여 LED를 On/Off 한다.
해당 코드로 기능들은 잘 동작한다.
하지만 뭔가 찝찝하다.
일단 메인 루프에 버튼 조작까지 주르륵 늘어있어서 가독성이 별로인 것 같다.
버튼 조작 부분을 함수로 만들어 버리자
push_btn과 push_tick은 저장된 값을 알고 있어야 하므로 포인터 매개변수로 넘겨주자
콘솔을 입력하는 부분도 함수로 만들자
data_arr 배열의 경우 RxCallback에도 호출되기 때문에 전역 변수로 사용하였다.
메인의 소스가 훨씬 깔끔해진것 같다.
하지만 그래도 찝찝하다.
지금의 RxCpltCallback에서 데이터를 처리하는 방식으로는 문제가 발생할 것 같은 느낌적인 느낌이 난다.
만약 메인 루프의 use_console을 처리하는 중에 인터럽트가 발생하여 데이터를 수신한다면 idx가 변경되면서 문제가 생길 수 있지 않을까?
예를 들어 LED0을 수신받고 use_console의 루틴으로 들어갔는데 바로 LED1을 수신 받으면 data_arr[idx]='\0'을 처리할 때 idx가 바뀌어 다음 LED1이 동작이 안되지 않을까?