본문 바로가기
프로그래밍/MFC (C++)

MFC ] 시리얼 통신으로 LED 제어하기 (2)

by eteo 2022. 7. 13.

 

이전 버전을 개선하였다.

 

2022.07.09 - [프로그래밍/MFC (C++)] - MFC ] 시리얼 통신으로 LED 제어하기 (1)

 

MFC ] 시리얼 통신으로 LED 제어하기 (1)

깃허브 주소: https://github.com/joeteo/LEDSerialCMD GitHub - joeteo/LEDSerialCMD Contribute to joeteo/LEDSerialCMD development by creating an account on GitHub. github.com https://github.com/joeteo/..

eteo.tistory.com

 

 

깃허브 주소:

https://github.com/joeteo/MFC_test01.git

 

GitHub - joeteo/MFC_test01

Contribute to joeteo/MFC_test01 development by creating an account on GitHub.

github.com

https://github.com/joeteo/LEDSerialCMD.git

 

GitHub - joeteo/LEDSerialCMD

Contribute to joeteo/LEDSerialCMD development by creating an account on GitHub.

github.com

 

 

 

MFC송신-STM32수신부분은 이전에 비해 많이 달라진게 없다.

버튼의 text도 STM32에서 100ms 마다 보내는 상태 신호를 읽어서 바뀌게 할 수 있는데 해당 부분은 수정하진 않았다.

 

 

그리고 다른 컴퓨터에서 깃 클론해서 실행해보려고 했더니 갑자기 통신이 안되서 원인을 찾아 헤멨는데 알고보니 Visual Studio 빌드 버전이 x64 로 바뀌어 있는 탓이었다.

 

 

 

아무튼 STM32 송신 - MFC 수신 부분을 개선했는데

 

STM32 송신부분에선 커맨드를 한번에 보내는 버전으로 바꿨다.

예를들어 2번 LED만 켜있다면

"L010\n" 이런식이다.

 

그리고 MFC 수신 부분에서는 char 타입 vector 를 멤버변수로 만들어 놓고 벡터에 담긴 값을 전부 처리하고 나가는 버전으로 바꾸었다.

STM32에선 한 바이트 단위로 수신 인터럽트가 발생하는데 MFC 에선 OnReceive 메시지가 호출 될 때 WPARAM length 와 같이 들어오고 이 length가 얼마가 될지 모르니까 벡터로 처리하는 것이 매우 효율적이다.

 

 

 

 

STM32 송신 부분

 

memset으로 초기화 후 strcpy로 뒤에 '\0' 을 넣는 형태로 카피하고 각각 LED와 연결된 GPIO Output 핀의 상태를 읽어서 strcat으로 뒷부분에 이어붙이다. 마지막으론 개행문자를 붙이고 폴링방식으로 100ms 간격마다 송신한다.

 

  char temp[5];
  /* USER CODE END 2 */
    while (1)
    {
      memset(temp, 0, sizeof(temp));
      strcpy(temp, "L");
      if(HAL_GPIO_ReadPin(LD1_GPIO_Port, LD1_Pin)){
          strcat(temp,"1");
      }else{
          strcat(temp,"0");
      }
      if(HAL_GPIO_ReadPin(LD2_GPIO_Port, LD2_Pin)){
          strcat(temp,"1");
      }else{
          strcat(temp,"0");
      }
      if(HAL_GPIO_ReadPin(LD3_GPIO_Port, LD3_Pin)){
          strcat(temp,"1");
      }else{
          strcat(temp,"0");
      }
      strcat(temp,"\n");

      HAL_UART_Transmit(&huart3, (uint8_t*)temp, sizeof(temp), 10);
      HAL_Delay(100);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }

 

 

 

 

 

 

 

MFC 수신 부분

-Dlg.h 에 시리얼 통신으로 수신된 데이터를 한 바이트씩 담아둘 char 타입 벡터를 만들어 둔다.

vector<char> rx;

 

rx 벡터에 차례대로 담고 커맨드 길이가 5라서 while(rx.size() >= 5) 으로 벡터 사이즈가 5 미만으로 남을 때까지 계속 처리하고 삭제하고를 반복한 후 빠져나간다.

첫번째 if문은 시작비트가 'L'이고 종료비트가 '\n'인 커맨드 형식에 맞게 들어왔을 때 커맨드에 따른 처리를 해주고 5개 길이만큼 삭제하고

두번째 if문은 시작비트가 'L'이 아닌경우 한 요소를 지우고

세번째 if문은 시작비트는 'L'이지만 종료비트인 '\n'이 제자리에 없는 경우를 의미하며  5개 길이만큼 삭제하고

결국에는 벡터 사이즈가 5미만이 될 때까지 이런식으로 반복 처리한다.

afx_msg LRESULT CLEDSerialCMDDlg::OnReceive(WPARAM length, LPARAM lParam)
{
	CString str;
	char* data = new char[length + 1];
	
	if (m_comm)
	{
		m_comm->Receive(data, length);	// Length 길이만큼 데이터 받음.
		//data[length] = _T('\0');

		for (int i = 0; i < length; i++)
		{			
			//str += data[i];
			rx.push_back(data[i]);
		}

		while(rx.size() >= 5)
		{
			if (rx.at(0) == 'L' && rx.at(4) == '\n')
			{

				if (rx.at(1) == '1')
				{
					m_LD1State = _T("ON");
				}
				else
				{
					m_LD1State = _T("OFF");
				}

				if (rx.at(2) == '1')
				{
					m_LD2State = _T("ON");
				}
				else
				{
					m_LD2State = _T("OFF");
				}

				if (rx.at(3) == '1')
				{
					m_LD3State = _T("ON");
				}
				else
				{
					m_LD3State = _T("OFF");
				}

				rx.erase(rx.begin(), rx.begin() + 4);

			}else if(rx.at(0) != 'L')
			{
				rx.erase(rx.begin());

			}else if (rx.at(4) != '\n')
			{
				rx.erase(rx.begin(), rx.begin() + 4);
			}

		}
        
		UpdateData(false);
		
		//str = "";
	}
	delete data;


	return 0;
}