본문 바로가기
DSP, MCU/STM32 (ARM Cortex-M)

STM32 ] 어플과 STM32간 블루투스 통신을 통한 데이터 송수신 - 프로젝트 준비과정 (5)

by eteo 2022. 7. 19.

 

 

어플 화면

 

 

SCAN 버튼을 눌러 블루투스 페어링 합니다.

Control을 누르면 아래 버튼을 사용해 수동제어를 할 수 있고, Waypoint 버튼을 누른 뒤 어플 지도상의 파란색 마커(Waypoint)를 찍으면 해당 위치로 자율주행을 시작합니다.

 

 

bluetooth.c 중 일부

void BT_Init()
{
	HAL_UART_Receive_IT(&huart7, &rx7_data, sizeof(rx7_data));
}
void transmit_To_Phone(){
	
	char buf[GPSBUFSIZE] = {0,};
	sprintf(buf, "A,%.13f\n\r", GPS.dec_latitude);
	//HAL_UART_Transmit(&huart3, (unsigned char *)buf, strlen(buf), 10);
	HAL_UART_Transmit(&huart7, (unsigned char *)buf, strlen(buf), 10);
	sprintf(buf, "O,%.13f\n\r", GPS.dec_longitude);
	//HAL_UART_Transmit(&huart3, (unsigned char *)buf, strlen(buf), 10);
	HAL_UART_Transmit(&huart7, (unsigned char *)buf, strlen(buf), 10);
	sprintf(buf, "C,%.13f\n\r", headingDegrees);	
	//HAL_UART_Transmit(&huart3, (unsigned char *)buf, strlen(buf), 10);
	HAL_UART_Transmit(&huart7, (unsigned char *)buf, strlen(buf), 10);
	
}

 

STM32에서 스마트폰으로 송신하는 부분. GPS 모듈로 수신된 위도, 경도와 지자기센서로 알아낸 방위각을 송신하다. 어플에서 파싱할 수 있게 A, O, C, 로 시작하는 구분자와 함께 데이터를 보내고 라인피드와 캐리지리턴으로 끝난다.

 

 

void Phone_UART_CallBack(){

	// AUTO_MODE_SIGNAL == 'A'
	if((Mode_Flag == CONTROL_MODE || Mode_Flag == WAYPOINT_MODE) && rx7_data==AUTO_MODE_SIGNAL){
		memset(rx7_buffer, 0, sizeof(rx7_buffer));
		Mode_Flag=AUTO_MODE;

	// WAYPOINT_MODE_SIGNAL == 'W'
	}else if((Mode_Flag == AUTO_MODE || Mode_Flag == CONTROL_MODE) && rx7_data==WAYPOINT_MODE_SIGNAL){
		memset(rx7_buffer, 0, sizeof(rx7_buffer));
		Mode_Flag=WAYPOINT_MODE;

	// CONTROL_MODE_SIGNAL == 'C'
	}else if((Mode_Flag == AUTO_MODE || Mode_Flag == WAYPOINT_MODE) && rx7_data==CONTROL_MODE_SIGNAL){
		memset(rx7_buffer, 0, sizeof(rx7_buffer));
		Mode_Flag=CONTROL_MODE;
	}


	if(Mode_Flag==CONTROL_MODE){
		if (rx7_data != '\n' && rx7_index < sizeof(rx7_buffer)) {
			rx7_buffer[rx7_index++] = rx7_data;
		} else {
			rx7_buffer[rx7_index]=0;
			rx7_index = 0;
			sscanf((const char*)(rx7_buffer+2), "%d", &controlCMD);
		}

	}else if(Mode_Flag==WAYPOINT_MODE){
		if (rx7_data != '\n' && rx7_index < sizeof(rx7_buffer)) {
			rx7_buffer[rx7_index++] = rx7_data;
		} else {
			rx7_buffer[rx7_index]=0;
			rx7_index = 0;
			sscanf((const char*)(rx7_buffer+1), "%f,%f", &phoneGPS.latitude, &phoneGPS.longitude);
			if(phoneGPS.latitude > 34 && phoneGPS.latitude< 38 && phoneGPS.longitude > 126 && phoneGPS.longitude < 130){
				waypointGPS.latitude=phoneGPS.latitude;
				waypointGPS.longitude=phoneGPS.longitude;
			}
		}

	}else if(Mode_Flag==AUTO_MODE){
		if (rx7_data != '\n' && rx7_index < sizeof(rx7_buffer)) {
			rx7_buffer[rx7_index++] = rx7_data;
		} else {
			rx7_buffer[rx7_index]=0;
			rx7_index = 0;
			sscanf((const char*)(rx7_buffer+1), "%f,%f", &phoneGPS.latitude, &phoneGPS.longitude);
		}
	}

	HAL_UART_Transmit(&huart3, &rx7_data, sizeof(rx7_data), 10);
	HAL_UART_Receive_IT(&huart7, &rx7_data, sizeof(rx7_data));
}

 

스마트폰으로부터 들어온 데이터를 파싱하는 부분. main.c의 HAL_UART_RxCpltCallback() 을 거쳐 들어온다.

 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart2) GPS_UART_CallBack();
	if(huart->Instance == UART7) Phone_UART_CallBack();

}

 

Mode_Flag는 다음 3개의 값을 가질 수 있는데 AUTO_MODE는 아직 구현된 부분이 아니다.

enum{
	CONTROL_MODE,
	WAYPOINT_MODE,
	AUTO_MODE
};

 

CONTROL_MODE 는 시작비트인 C와 제어신호를 뜻하는 ASCII 코드 한바이트가 들어오는데 짧아서 그런지 오류가 없다.

 

WAYPOINT_MODE 는 시작비트인 W와 이어서 위도, 경도가 콤마로 구분되어 들어오는데 아무래도 길어서인지 가끔 이상한 값이 들어올 때가 있다. 일단은 어플에서 WaPpoint 마커가 새로운 곳에 찍혔을 때 한번이 아니라 계속 위도, 경도를 보내게끔해서 정상범위의 값만 받게끔 했는데 이 부분은 추후 수정될 수도 있다.

 

 

 

그리고 현재의 main.c 의 while 문은 이렇게 작성했다.

  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  current_tick = HAL_GetTick();
	  if(current_tick - start_tick >= 70){
		  calculateHeading();
		  start_tick = current_tick;
	  }

	  if(Mode_Flag==CONTROL_MODE){
		  Move(controlCMD);

	  }else if(Mode_Flag==WAYPOINT_MODE){
		  if(waypointGPS.latitude!=0 && waypointGPS.latitude!=0){
			  SelfDriving();
		  }

	  }else if(Mode_Flag==AUTO_MODE){

	  }
	  
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

 

 

 

 

아래는 동료의 자료 입니다.