Uart Interrupt로 LED를 On/Off 할 수 있게 되었다. 

https://pilimage.tistory.com/20

 

[C/STM32] 5. LED ON/OFF - Uart Interrupt제어

Uart Polling으로 LED를 On/Off 할 수 있게 되었다. https://pilimage.tistory.com/19 [C/STM32] 4. LED ON/OFF - Uart Polling 제어 LED를 버튼으로도 제어를 할 수 있게 되었다. https://pilimage.tistory.com/1..

pilimage.tistory.com

 

이제 ring buffer를 이용하여 인터럽트를 수신해보자

https://pilimage.tistory.com/21

 

[C] Ring Buffer / 링버퍼 구현

링 버퍼란? 고정된 크기의 큐의 양 끝을 이어 원형 모양처럼 사용하는 버퍼 데이터를 넣었다가 빼는 역할을 할 수 있다 구현은 다음과 같이 하였다. ring_buffer.h #include #include typedef struct{ uint8_t *bu.

pilimage.tistory.com

 

ring_buffer.h를 Core의 Inc 폴더에 ring_buffer.c를 Core의 Src폴더에 넣고 main에 ring_buffer.h를 include 한다.

ring_buffer를 이용하여 데이터를 수신할 rx_buffer와 수신 받은 데이터를 pop하여 저장하는 rx_frame을 만든다. 

(전역 변수로 선언)

그 후 메인에 ring_buf를 초기화 시킨다.

이제 준비는 모두 끝났다. 

HAL_UART_RxCpltCallback 함수를 위와 같이 수정하였다.

PC와 연결된 uart1번으로 데이터가 수신되면 받은 데이터를 ring_buf에 push 한다. 

PC 콘솔에 입력한 데이터를 출력하기 위해서 HAL_UART_Transmit을 하였고,

HAL_UART_Receive_IT를 통해 다음 데이터 수신을 대기한다.

 

그리고 메인 함수의 루프에서 동작하다 use_console함수를 다음과 같이 수정하였다.

메인 루프에서 반복적으로 ring_buffer에 데이터가 있으면 pop하여 rx_frame에 넣는다. 

데이터의 끝을 알리는 \r나 \n이 아니면 rx_frame의 idx를 증가시키며 ring_buffer에서 꺼낸 데이터를 넣는다. 

데이터의 끝을 알리는 \r나 \n을 만나면 데이터에 맞게 LED를 On / Off 시키도록 수정하였다. 

 

이제 LED를 Uart를 이용하여 On/Off 할 수 있게 되었다...

 

단순히 LED를 On/Off 하는 것 말고도 LED를 서서히 밝아지고 서서히 어두워지게 할 수 있을까?

LED Dimming  / LED Dimmer 라고 하는 기능을 구현해보자

 

언제 ? 

다음글에... 

 

반응형

Uart Polling으로 LED를 On/Off 할 수 있게 되었다. 

https://pilimage.tistory.com/19

 

[C/STM32] 4. LED ON/OFF - Uart Polling 제어

LED를 버튼으로도 제어를 할 수 있게 되었다. https://pilimage.tistory.com/17 [C/STM32] 3. LED ON/Off - 버튼 채터링 추가 버튼을 누르고 있으면 LED가 On되고 버튼을 떼면 LED가 Off되는 것은 이제 쉽다. http..

pilimage.tistory.com

 

Polling방식에서는 데이터가 들어올 때까지 대기하는 시간 동안은 버튼을 눌러도 동작하지 않는 경우가 있었다.  (HAL_UART_Receive의 timeout 시간을 길게 하면 확실히 볼 수 있다.)

 

Uart Interrupt를 이용하여 이를 해결해보자 

 

먼저 Uart Interrput 기능을 설정하기 위해 PinOut & Configuration에서 사용하는 Uart를 선택하고 NVIC Settings  메뉴에서 Interrupt를 Enable 시킨 후, Code Generation을 한다. 

 

이제 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이 동작이 안되지 않을까?

 

수신 데이터를 처리하는데 있어서 싸늘하다....불안한다...

이를 좀 더 보완하고자 링 버퍼(Ring Buffer)를 이용한 인터럽트를 사용해보자

언제? 

다음글에서 ....

 

반응형

+ Recent posts