오늘은 USART를 인터럽트 방식과 DMA방식으로 해보자
먼저 인터럽트 방식으로 하자.
저번 폴링방식에서 인터럽트 부분을 켜주면 되는데 같이 알아가보자
NVIC에서 USART2 인터럽트를 Enable해주자
저번과 같은 프로토콜을 사용할 것이고, 코드는 아래와 같다.
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t rx_data[4];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if(huart->Instance == USART2){
if(rx_data[0] == '2' && rx_data[3] == '3' && rx_data[1] == '1'){
if(rx_data[2] == '0'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA6_D2_Pin, 1);
}else if(rx_data[2] == '1'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA6_D2_Pin, 0);
}
}else if(rx_data[0] == '2' && rx_data[3] == '3' && rx_data[1] == '2'){
if(rx_data[2] == '0'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA7_D3_Pin, 1);
}else if(rx_data[2] == '1'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA7_D3_Pin, 0);
}
}else if(rx_data[0] == '2' && rx_data[3] == '3' && rx_data[1] == '0'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA6_D2_Pin, 1);
HAL_GPIO_WritePin(GPIOA, GPIO_PA7_D3_Pin, 1);
}
HAL_UART_Transmit_IT(&huart2, rx_data, 4);
HAL_UART_Receive_IT(&huart2, rx_data, 4);
}
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart2, rx_data, 4);
/* USER CODE END 2 */
인터럽트로 동작하는거라 while에서 호출하지 않아도 된다.
다음으로 DMA에 대해 알아보자
DMA는 CPU의 개입 없이 데이터 전송을 담당하는 컨트롤러이다.
DMA가 데이터를 처리하기 위해 "버퍼 역할을 하는 메모리"를 필요로 한다.
따라서 DMA는 데이터 전송 담당, 버퍼는 데이터 저장 장소로 구분된다.
DMA를 사용하면 데이터 전송이 효율적이고 빠르며, CPU는 더 중요한 작업에 집중할 수 있다.
이전과 같이 설정해주되, 여기서 DMA Settings를 만져주자
처음에 아무것도 없어서 당황할텐데 그냥 Add 눌러서 설정하면 된다.
TX는 Normal로 냅둬도 된다.
설명 | |
Normal | 데이터 크기만큼 읽으면 전송을 종료 ( TX에서 주로 사용 ) 이후 DMA는 멈추며, 데이터를 추가로 처리하려면 다시 DMA를 설정 |
Circular | 버퍼 크기를 초과하면 다시 처음부터 덮어쓰기를 시작 ( RX에서 주로 사용 ) 수신 데이터가 계속 들어오는 경우 적합하며, 데이터를 놓치지 않고 처리 가능 |
코드를 보자
/* USER CODE BEGIN 0 */
uint8_t rx_data[4];
uint8_t data_arrived = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
data_arrived = 1;
HAL_UART_Transmit(&huart2, (uint8_t*)rx_data, 4, 100);
HAL_UART_Receive_DMA(&huart2, (uint8_t*)rx_data, 4);
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart){
HAL_GPIO_TogglePin(GPIOA, GPIO_PA6_D2_Pin);
}
.
.
.
HAL_UART_Receive_DMA(&huart2, (uint8_t*)rx_data, 4);
while(!data_arrived);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(data_arrived == 1){
if(rx_data[0] == '2' && rx_data[3] == '3' && rx_data[1] == '1'){
if(rx_data[2] == '1'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA7_D3_Pin, 0);
}else if(rx_data[2] == '0'){
HAL_GPIO_WritePin(GPIOA, GPIO_PA7_D3_Pin, 1);
}
}
data_arrived = 0;
}
HAL_Delay(500);
코드에 대한 설명을 조금 더 이해하기 쉽게 설명해보겠다.
절반 완료 시 (2바이트):데이터가 2바이트가 되면 HAL_UART_RxHalfCpltCallback 호출 ( D2번의 LED 상태 반전 )
완료 시 (4바이트):데이터가 4바이트가 되면 HAL_UART_RxCpltCallback 호출.데이터를 처리하고, 버퍼를 비우거나 새로운 데이터를 대기. ( 데이터 기반으로 D3번의 LED 상태 변경 )
https://youtube.com/shorts/otllUn4K35M?feature=share
이렇게 동작하는 것을 볼 수 있다.
'STM32' 카테고리의 다른 글
STM32F407VE - 기초 6) ADC-2 (0) | 2024.11.24 |
---|---|
STM32F407VE - 기초 5) ADC (0) | 2024.11.23 |
STM32F407VE - 기초 3) USART (0) | 2024.11.21 |
STM32F407VE - 기초 2) EXTI (0) | 2024.11.20 |
STM32F103C6T6A - 다루기 (0) | 2024.11.17 |