이미 오래 전에 Blue Pill 보드의 USART3에 ESP8266 모듈을 달아 놨습니다.
위 그림에서 Blue Pill 보드 위에 설치한 모듈이 ESP8266 모듈입니다. ESP8266-12F 버전을 사용하고 있습니다. 현재 ESP8266-12F의 1번핀(Rx)는 STM32F103C8T6의 USART3 포트인 PB10(USART3_TX)에, 2번핀(Tx)는 PB11(USART3_RX)에 연결하였습니다. 그리고 ESP8266-12F의 현재 통신 설정 환경은 다음과 같습니다.
속도 : 115200b0s
패리티 : none
데이터 : 8bit
스톱비트 : 1
STM32F103C8T6은 UART1, USART2, USART3 이렇게 3개의 USART 포트를 가지고 있습니다. 이중에서 USART1은 미세먼지 센서 SDS011에 할당하였습니다. USART2는 Rx아 Tx가 PA2, PA3 핀인데, 이 핀들은 이미 그래픽 lcd를 제어하기 위해 GPIO로 할당했습니다. USART2를 리매핑하면 PD5, PD6을 사용해야 하는데, STM32F103C8T6에는 PD5, PD6 핀이 없습니다. 따라서 USART2는 사용할 수 없는 상태입니다. 따라서 마지막 남은 USART3에 ESP8266-12F를 연결할 수 밖에 없습니다.
미세먼지 센서 SDS011 사용하기에서는 패킷의 길이가 10바이트로 고정되어 있어서 굳이 queue를 사용하지 않아도 되었습니다.
ESP8266에서 오는 패킷은 길이가 얼마가 될지 모르므로, STM32F407로 ESP8266 다루기 - 수신인터럽트 개선에서 했던 방법과 같이 queue를 이용하는 인터럽트를 사용할 필요가 있습니다. 본 글에서는 STM32F407로 ESP8266 다루기 - 수신인터럽트 개선에서 사용했던 코드를 조금 변경하여 사용하겠습니다.
1. 프로젝트 만들기
미세먼지 센서 SDS011 사용하기(개선편)에서 사용하던 STM32F103AIR.ioc를 엽니다.
[Connectivity]에서 USART3를 선택하고 오른쪽의 [Mode]를 Asyncronous로 지정합니다. [Configuration]의 [Parameter Settings]에서 Baud Rate, Word Length, Parity, Stop bits 등을 적절한 값으로 설정합니다. 필자의 경우, 115200, 8, None, 1로 맞추었습니다.
[NVIC Settings]에서 USART3 global interrupt Enable에 체크합니다.
[GENERATE CODE] 버튼을 눌러 코드를 생성합니다.
2. 코딩 하기
STM32F407로 ESP8266 다루기 - 수신 인터럽트 사용 개선에서 사용했던 방법을 사용하기로 합니다. 즉, USART 수신인터럽트가 발생했을 때에 콜백 함수인 HAL_UART_RxCpltCallback() 함수를 사용하지 않고, [Src] 폴더 내의 stm32f1xx_it.c 파일에 있는 인터럽트 핸들러 함수 USART3_IRQHandler() 함수에서 수신한 데이터를 queue에 넣고 인터럽틑 핸들러를 종료합니다. 차후에 시간적 여유가 있을 때에 queue에 있는 데이터들을 선입선출(FIFO:First In First Out) 방법으로 처리합니다.
앞의 글에 사용하던 uart.h와 uart.c를 약간 변형시켜 사용하겠습니다. 변형시키는 이유는 STM32F407로 프로그램할 때에는 Wifi 모듈 ESP8266은 USART2에, PC의 터미털 프로그램은 USART3에 각각 연결해서 사용했습니다. 따라서 queue를 다루는 함수를 호출할 때에 매개 변수로 UART_HandleTypeDef를 사용할 수 있었습니다.
본 글에서는 USART2를 사용할 수 없기 때문에 Wifi 모듈 ESP8266을 USART3에 연결하고, PC는 USB의 CDC(Communicatio Device Class)로 연결할 예정입니다. CDC는 USART가 아니라서 UART_HandleTypeDef를 사용하지 않기 때문에 queue를 다루는 함수의 매개 변수로 UART_HandleTypeDef를 사용할 수 없습니다. 대신에 각각 사용하는 queue의 포인터를 매개 변수로 전달하도록 함수를 고쳐야 합니다.
[Inc] 폴더와 [Src] 폴더 안에 uart.h 파일과 uart.c 파일을 각각 만들고 다음과 같이 입력합니다.
먼저 uart.h 파일입니다.
#ifndef UART_H_ #define UART_H_ #define QUEUE_BUFFER_LENGTH 1024 typedef struct { int head, tail, data; uint8_t Buffer[QUEUE_BUFFER_LENGTH]; }UARTQUEUE, *pUARTQUEUE; extern UART_HandleTypeDef huart3; extern UARTQUEUE WifiQueue; void InitUartQueue(pUARTQUEUE pQueue); void PutDataToUartQueue(pUARTQUEUE pQueue, uint8_t data); uint8_t GetDataFromUartQueue(pUARTQUEUE pQueue); #endif /* UART_H_ */
uart.c 파일입니다.
#include "stm32f1xx_hal.h" #include "uart.h" UARTQUEUE WifiQueue; void InitUartQueue(pUARTQUEUE pQueue) { pQueue->data = pQueue->head = pQueue->tail = 0; } void PutDataToUartQueue(pUARTQUEUE pQueue, uint8_t data) { if (pQueue->data == QUEUE_BUFFER_LENGTH) GetDataFromUartQueue(pQueue); pQueue->Buffer[pQueue->head++] = data; if (pQueue->head == QUEUE_BUFFER_LENGTH) pQueue->head = 0; pQueue->data++; } uint8_t GetDataFromUartQueue(pUARTQUEUE pQueue) { uint8_t ch; ch = pQueue->Buffer[pQueue->tail++]; if (pQueue->tail == QUEUE_BUFFER_LENGTH) pQueue->tail = 0; pQueue->data--; HAL_Delay(1); return ch; }
main.h에 매크로 WIFI를 추가합니다. 다른 코드는 입력하는 위치를 알려주기 위해 같이 보여 줍니다. 입력한 내용은 #define WIFI huart3 한 줄입니다.
/* USER CODE BEGIN Private defines */ #define WIFI huart3 #define SDS011 huart1 #define SDS011_MESSAGE_LENGTH 10
WIFI 포트 즉 USART3로 데이터가 들어오면 처리하는 루틴을 입력해야 합니다. USART3의 인터럽트 핸들러는 [Src] 폴더의 stm32f1xx_it.c 파일 안에 있는 USART3_IRQHandler()입니다. 우선 컴파일시 에러가 발생하지 않도록 uart.h를 포함시키고, USART3_IRQHandler() 함수에 다음과 같은 내용을 추가합니다. 주석문은 입력하는 위치를 파악하도록 하기 위해 같이 기술했습니다.
/* USER CODE BEGIN Includes */ #include "uart.h" /* USER CODE END Includes */ void USART3_IRQHandler(void) { /* USER CODE BEGIN USART3_IRQn 0 */ if ((__HAL_UART_GET_FLAG(&WIFI, UART_FLAG_RXNE) != RESET)) { PutDataToUartQueue(&WifiQueue, (uint8_t)(WIFI.Instance->DR & (uint8_t)0x00FF)); } __HAL_UART_CLEAR_PEFLAG(&WIFI); /* clear event flag */ return; /* USER CODE END USART3_IRQn 0 */ HAL_UART_IRQHandler(&huart3); /* USER CODE BEGIN USART3_IRQn 1 */ /* USER CODE END USART3_IRQn 1 */ }
main.c 파일 안에 다음 내용들을 추가 합니다. 실제로 추가한 행은 주석에 ① ~ ③의 번호가 붙은 3개의 행이고 나머지 코드들은 추가하는 위치를 알리기 위해 같이 올렸습니다.
/* USER CODE BEGIN Includes */ #include "M19264Display.h" #include "GlcdDisplay.h" #include "AM2302.h" #include "uart.h" // ①
/* USER CODE BEGIN 2 */ HAL_Delay(2000); intFlag = NO_INTERRUPT; HAL_TIM_Base_Start_IT(&htim2); GlcdInitialize(); InitUartQueue(&WifiQueue); // ② HAL_UART_Receive_IT(&SDS011, SDS011Msg, 1); HAL_UART_Receive_IT(&WIFI, WifiQueue.Buffer, 1); // ③
현재 이 코드는 아직 완성된 코드는 아닙니다. 왜냐하면 ESP8266 즉 USART3으로 데이터를 보내는 장치가 구현되지 않았기 때문입니다. USART3로 데이터를 보낼 수 있는 장치가 없기 때문에 현재로는 동작 여부를 알 수 없습니다. 다음 글에서 USB의 CDC 기능을 활성화 시켜서 동작하는 프로그램으로 만들 예정입니다.
'STM32F103' 카테고리의 다른 글
STM32F103으로 IR 신호 다루기(1편) (0) | 2019.11.18 |
---|---|
STM32F103 CDC 사용하기 (0) | 2018.12.28 |
미세먼지 센서 SDS011 사용하기(개선편) (0) | 2018.12.18 |
미세먼지 센서 SDS011 사용하기 (0) | 2018.12.12 |
DHT22(AM2302) 온도 습도 센서 사용하기 (2) | 2018.12.11 |