[STM32#04] HAL_UART_Transmit(), HAL_UART_Receive() 함수를 이용해서 USART2 시리얼통신 계속 해보기!(녹칸다 내맘대로 STM32)
프로그래밍/STM32 2025. 10. 22. 00:47
https://youtube.com/live/2mMDL1DBVEM
[STM32#04] HAL_UART_Transmit(), HAL_UART_Receive() 함수를 이용해서 USART2 시리얼통신 계속 해보기!(녹칸다 내맘대로 STM32)
심심한녹칸다의 내맘대로 STM32시리즈이다!
STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g39b3b733ade_1_225#slide=id.g39b3b733ade_1_225
기본 송수신은 되었고, 가변길이에 대한 송수신과 LED와 버튼을 제어해보는 예제를 만들어보도록 하자!
1.STM32의 PB1에 연결된 버튼을 누르면 usart2통신으로 PC에게 “PB1 PRESSED!!”라는 문자열이 버튼 누를때마다 전송되도록 하시오!

/* USER CODE BEGIN 2 */
char *msg = "PB1 PRESSED!!\n";
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PB1을 눌렀다!
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
//usart2로 메시지를 전송한다!
HAL_UART_Transmit(&huart2, msg, strlen(msg), 100);
HAL_Delay(200); //채터링 방지를 위한 소량의 딜레이
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
2.10초간격으로 STM32가 PC쪽으로 “NOCKANDA!!”라는 문자열을 전송한다! 그리고 이때 PB1버튼을 누르면 “PB1 PRESSED!!”라는 문자열이 이전 조건과는 별개로 전송된다!(HAL_Delay를 사용하지 마십시요!)

/* USER CODE BEGIN 2 */
char *msg1 = "PB1 PRESSED!!\n";
char *msg2 = "NOCKANDA\n";
uint32_t t = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PB1을 눌렀다!
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
//usart2로 메시지를 전송한다!
HAL_UART_Transmit(&huart2, msg1, strlen(msg1), 100);
HAL_Delay(200); //채터링 방지를 위한 소량의 딜레이
}
//10000이라는 값을 인터벌로해서 인터벌마다 한번씩 걸리는 조건문!
if(HAL_GetTick() - t >= 10000){
t = HAL_GetTick();
//지정된 메시지를 10초간격으로 전송한다!
HAL_UART_Transmit(&huart2, msg2, strlen(msg2), 100);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
3.조건문의 재미난 특성에 대해서 간략한 예시를 구현하시오!(깨알지식)
/* USER CODE BEGIN 2 */
char *msg1 = "condition1 print!!\n";
char *msg2 = "condition2 print!!\n";
char *msg3 = "condition3 print!!\n";
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//if는 괄호안에 들어가는 조건식이 참이면 중괄호 부분을 실행한다!
//조건식은 흔히 yes와 no같은 맞다 아니다로 해석하는데, 내부적으로는 참이 1이고 거짓이 0이다!
//참은 0이 아닌 숫자는 참으로 처리한다!
if(0){
HAL_UART_Transmit(&huart2, msg1, strlen(msg1), 100);
}
if(1){
HAL_UART_Transmit(&huart2, msg2, strlen(msg2), 100);
}
if(2){
HAL_UART_Transmit(&huart2, msg3, strlen(msg3), 100);
}
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
4.가변길이를 가지는 문자열 데이터를 PC에서 STM32로 전송했을때 수신을 하는 예시를 보이시오!(타임아웃을 기반으로 처리하기 버전1)

/* USER CODE BEGIN 2 */
char recv;
char buff[100]; //수신메모리
int pos = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 보낸 데이터가 있는가? 있다면 읽기 시작한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//보낸 데이터가 있다면 1바이트씩 읽는다!
buff[0] = recv;
pos = 1;
while(1){
//만약 PC에서 데이터를 연속으로 보내다가 흐름이 0.5초정도 끊어지면 읽기를 종료한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//계속 데이터가 우체통에 있고~
buff[pos] = recv;
pos++;
}else{
//0.5초 기다려도 없네? 타임아웃이네?
//이 지점이 문자열의 끝지점인것을 의미한다!
buff[pos] = '\0';
//ECHO
HAL_UART_Transmit(&huart2, buff, pos, 100);
break;
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
5.가변길이를 가지는 문자열 데이터를 PC에서 STM32로 전송했을때 수신을 하는 예시를 보이시오!(타임아웃을 기반으로 처리하기 버전2)

/* USER CODE BEGIN 2 */
char recv;
char buff[100]; //수신메모리
int pos = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 뭔가 데이터를 보내면 while루프는 동작한다!
pos = 0;
while(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
buff[pos] = recv;
pos++;
}
buff[pos] = '\0';
//pos가 0이면 PC에서 온 데이터가 없고 0보다 크다면 있는것이다!
if(pos > 0){
//받은 데이터를 ECHO한다!
HAL_UART_Transmit(&huart2, buff, pos, 100);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
6.이번에는 PC하고 STM32하고 종료문자를 라인피더(‘\n’)로 설정했을때 STM32에서 1개씩 데이터를 빼오다가 라인피더가 확인되면 거기까지를 한덩어리로 해서 PC쪽으로 반환하시오!(보내는 쪽에서 무조건 종료문자를 붙힌다) putty의 설정이 \n이 아니라 캐리지리턴인 \r로 되어있어서 수정함!

/* USER CODE BEGIN 2 */
char recv;
char buff[100]; //수신메모리
int pos = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 보낸 데이터가 있는가? 있다면 읽기 시작한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//보낸 데이터가 있다면 1바이트씩 읽는다!
buff[0] = recv;
pos = 1;
while(1){
//만약 PC에서 데이터를 연속으로 보내다가 흐름이 0.5초정도 끊어지면 읽기를 종료한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//지금 읽은 데이터가 종료문자이냐? 이면 끝이고 아니면 계속 읽는다!
if(recv == '\r'){
buff[pos] = '\0';
HAL_UART_Transmit(&huart2, buff, pos, 100);
break;
}else{
buff[pos] = recv;
pos++;
}
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
7.녹칸다가 “LED ON”이라고 전송하면 PB3에 연결된 LED가 켜지고, “LED OFF”라고 전송하면 LED가 꺼지도록 하시오!
/* USER CODE BEGIN 2 */
char recv;
char buff[100]; //수신메모리
int pos = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 보낸 데이터가 있는가? 있다면 읽기 시작한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//보낸 데이터가 있다면 1바이트씩 읽는다!
buff[0] = recv;
pos = 1;
while(1){
//만약 PC에서 데이터를 연속으로 보내다가 흐름이 0.5초정도 끊어지면 읽기를 종료한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//지금 읽은 데이터가 종료문자이냐? 이면 끝이고 아니면 계속 읽는다!
if(recv == '\r'){
buff[pos] = '\0';
//LED ON이면 LED를 켜고 LED OFF면 끈다
if(strcmp(buff,"LED ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
}else if(strcmp(buff,"LED OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
}
break;
}else{
buff[pos] = recv;
pos++;
}
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
8.STM32실습보드에 LED가 총 8개 연결되어있는데, LED다음에 번호를 1~8까지 붙히고 ON이면 켜지고 OFF면 꺼지도록 하시오! 예를들면 LED5 ON이라고 하면 다섯번째 LED가 켜지는 것이다!(LED가 만약 10개 이상이라면 숫자가 2자리가 되어서 복잡한데 지금은 한자리만 해석하면 되니까 간단!)
/* USER CODE BEGIN 2 */
char recv;
char buff[100]; //수신메모리
int pos = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 보낸 데이터가 있는가? 있다면 읽기 시작한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//보낸 데이터가 있다면 1바이트씩 읽는다!
buff[0] = recv;
pos = 1;
while(1){
//만약 PC에서 데이터를 연속으로 보내다가 흐름이 0.5초정도 끊어지면 읽기를 종료한다!
if(HAL_UART_Receive(&huart2, &recv, 1, 500) == HAL_OK){
//지금 읽은 데이터가 종료문자이냐? 이면 끝이고 아니면 계속 읽는다!
if(recv == '\r'){
buff[pos] = '\0';
//LED ON이면 LED를 켜고 LED OFF면 끈다
if(strcmp(buff,"LED1 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
}else if(strcmp(buff,"LED1 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED2 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
}else if(strcmp(buff,"LED2 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED3 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
}else if(strcmp(buff,"LED3 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED4 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
}else if(strcmp(buff,"LED4 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED5 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
}else if(strcmp(buff,"LED5 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED6 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
}else if(strcmp(buff,"LED6 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED7 ON") == 0){
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET);
}else if(strcmp(buff,"LED7 OFF") == 0){
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET);
}else if(strcmp(buff,"LED8 ON") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
}else if(strcmp(buff,"LED8 OFF") == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
}
break;
}else{
buff[pos] = recv;
pos++;
}
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
9.녹칸다가 LED1번부터 8번까지의 상태를 2진수로 전송한다! 0이면 OFF고 1이면 ON이다! 예를들어 11110000이라고 보내면 LED1~4까지는 ON이고 5~8까지는 OFF하라는 의미이다!(데이터가 고정길이다)
/* USER CODE BEGIN 2 */
char buff[100]; //수신메모리
GPIO_TypeDef *mygpio[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PC에서 보낸 데이터가 있는가? 있다면 읽기 시작한다!
if(HAL_UART_Receive(&huart2, buff, 8, 500) == HAL_OK){
//buff에 0~7까지 LED의 상태가 문자 '0'또는 '1'로 지정되어서 데이터가 왔다!
//buff를 반복문으로 0~7까지 하나씩 순회하면서 문자로 해석한다!
for(int i = 0;i < 8;i++){
if(buff[i] == '0'){
//i번째 LED가 OFF이다!
HAL_GPIO_WritePin(mygpio[i], mypin[i], GPIO_PIN_RESET);
}else if(buff[i] == '1'){
//i번째 LED가 ON이다!
HAL_GPIO_WritePin(mygpio[i], mypin[i], GPIO_PIN_SET);
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
10.예제1번에서 연결해놓은 PB1버튼을 2초동안 누르면 길게눌렀다고 PC로 전송하고, 2초이내로 짧게 누르면 짧게 눌렀다고 전송하시오!
/* USER CODE BEGIN 2 */
char *msg1 = "LONG CLICK!!\n";
char *msg2 = "SHORT CLICK!!\n";
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PB1을 눌렀다!
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
//눌렀던 버튼을 뗄때까지 무한루프를 돌려버린다
//루프가 작동한 시간을 측정한다!
uint32_t t = HAL_GetTick(); //while루프에 진입하기 직전의 시간!
uint8_t is_longclick = 0;
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
if(HAL_GetTick() - t > 2000){
//버튼을 2초이상 눌렀다!
is_longclick = 1;
break;
}
}
if(is_longclick){
//길게 눌러서 while루프가 강제종료된 경우
HAL_UART_Transmit(&huart2, msg1, strlen(msg1), 100);
//버튼 뗄때까지 무한대기
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET);
//버튼 뗀다음에 오류를 방지하기 위한 소량의 지연시간
HAL_Delay(200);
}else{
//2초 이내에 눌렀다가 떼서 자연스럽게 종료된경우
HAL_UART_Transmit(&huart2, msg2, strlen(msg2), 100);
HAL_Delay(200);
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
11.PB1버튼을 짧게누르면 모든 LED를 ON한다! PB1을 길게 누르면 모든 LED를 OFF한다!(예제10번내용 포함)
/* USER CODE BEGIN 2 */
char *msg1 = "LONG CLICK!!\n";
char *msg2 = "SHORT CLICK!!\n";
GPIO_TypeDef *mygpio[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//PB1을 눌렀다!
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
//눌렀던 버튼을 뗄때까지 무한루프를 돌려버린다
//루프가 작동한 시간을 측정한다!
uint32_t t = HAL_GetTick(); //while루프에 진입하기 직전의 시간!
uint8_t is_longclick = 0;
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET){
if(HAL_GetTick() - t > 2000){
//버튼을 2초이상 눌렀다!
is_longclick = 1;
break;
}
}
if(is_longclick){
//길게 눌러서 while루프가 강제종료된 경우
HAL_UART_Transmit(&huart2, msg1, strlen(msg1), 100);
//LED컨트롤
for(int i = 0;i<8;i++){
HAL_GPIO_WritePin(mygpio[i], mypin[i], GPIO_PIN_RESET);
}
//버튼 뗄때까지 무한대기
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET);
//버튼 뗀다음에 오류를 방지하기 위한 소량의 지연시간
HAL_Delay(200);
}else{
//2초 이내에 눌렀다가 떼서 자연스럽게 종료된경우
HAL_UART_Transmit(&huart2, msg2, strlen(msg2), 100);
for(int i = 0;i<8;i++){
HAL_GPIO_WritePin(mygpio[i], mypin[i], GPIO_PIN_SET);
}
HAL_Delay(200);
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}






