72. PathFinder Compass

Back To All Submissions
Previous Submission
Next Submission

Solving Approach

How do you plan to solve it?

 

 

Code

/*
 * my_main.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */

#include "my_main.h"

#define CAMP_LATITUDE 		18.556283  // Camp Latitude (destination)
#define CAMP_LONGITUDE	 	73.955067  // Camp Longitude (destination)

#define R 					6371  	   // Earth's radius in kilometers

UART_HandleTypeDef usart2;
int new_coordinates = 0;
uint8_t received_byte, usart2_index = 0;
uint8_t integers1 = 0, found_num_of_integers1 = 0, integers2 = 0, found_num_of_integers2 = 0, found_komma = 0;
uint32_t decimals1 = 10, decimals2 = 10;
char usart2_buffer[60] = { 0 };
double lat1 = 0.0, lon1 = 0.0, a, c, d, theta;
char directions[2] = { 0 };

int main(void)
{

	/* Initializes low level hardware at the processor level */
	HAL_Init();

	// Sets other clock sources besides HSI
	if( SystemClock_Config(HSI_16) != Execution_Succesfull)
		return Execution_Failed;

	// Configure the USART2 module
	if( USART_Config(&usart2, USART2) != Execution_Succesfull )
		return Execution_Failed;

	if( HAL_UART_Receive_IT(&usart2, &received_byte, 1) != HAL_OK )
		for(;;);

	for(;;)
	{

		if(new_coordinates == 1)
		{
			new_coordinates = 0;

			// Find the number of integers before '.' and the number of decimals after '.'
			for(uint8_t i=0; i<usart2_index; i++)
			{
				if(usart2_buffer[i] == '.')
				{
					if(found_komma)
						found_num_of_integers2 = 1;
					else
						found_num_of_integers1 = 1;
				}
				else if(usart2_buffer[i] >= '0' && usart2_buffer[i] <= '9')
				{
					if(found_komma)
					{
						if(!found_num_of_integers2)
							integers2++;
					}
					else
					{
						if(!found_num_of_integers1)
							integers1++;
					}
				}
				else if(usart2_buffer[i] == ',')
					found_komma = 1;
			}

			found_num_of_integers1 = 0;
			found_num_of_integers2 = 0;
			found_komma = 0;

			// Calculate floats
			for(uint8_t i=0; i<usart2_index; i++)
			{
				if(usart2_buffer[i] == '.')
				{
					if(found_komma)
						found_num_of_integers2 = 1;
					else
						found_num_of_integers1 = 1;
				}
				else if(usart2_buffer[i] >= '0' && usart2_buffer[i] <= '9')
				{
					if(found_komma)
					{
						if(found_num_of_integers2)
						{
							lon1 += (double)(usart2_buffer[i] - '0') / (double)decimals2;
							decimals2 *= 10;
						}
						else
						{
							lon1 += ((double)(usart2_buffer[i] - '0') * pow(10.0, ((double)integers2-1)));
							integers2--;
						}
					}
					else
					{
						if(found_num_of_integers1)
						{
							lat1 += (double)(usart2_buffer[i] - '0') / (double)decimals1;
							decimals1 *= 10;
						}
						else
						{
							lat1 += ((double)(usart2_buffer[i] - '0') * pow(10.0, ((double)integers1-1)));
							integers1--;
						}
					}
				}
				else if(usart2_buffer[i] == ',')
					found_komma = 1;
			}

			memset(usart2_buffer, 0, sizeof(usart2_buffer));

			// Calculate Haversine Formula
			a = sin((to_radians(CAMP_LATITUDE) - to_radians(lat1))/2) * sin((to_radians(CAMP_LATITUDE) - to_radians(lat1))/2) + cos(to_radians(lat1)) * cos(to_radians(CAMP_LATITUDE)) * sin((to_radians(CAMP_LONGITUDE) - to_radians(lon1))/2) * sin((to_radians(CAMP_LONGITUDE) - to_radians(lon1))/2);
			c = 2.0 * atan2(sqrt(a), sqrt(1-a));
			d = R * c;

			// Calculate Bearing Formula
			theta = atan2(sin(to_radians(CAMP_LONGITUDE) - to_radians(lon1)) * cos(to_radians(CAMP_LATITUDE)), cos(to_radians(lat1)) * sin(to_radians(CAMP_LATITUDE)) - sin(to_radians(lat1)) * cos(to_radians(CAMP_LATITUDE)) * cos(to_radians(CAMP_LONGITUDE) - to_radians(lon1)));
			theta = to_degrees(theta);
			if(theta < 0.0)
				theta += 360.0;

			// Calculate Direction
			if((theta >= 337.5 && theta < 360) || (theta >= 0 && theta < 22.5))
			{
				directions[0] = 'N';
				directions[1] = ' ';
			}
			else if(theta >= 22.5 && theta < 67.5)
			{
				directions[0] = 'N';
				directions[1] = 'E';
			}
			else if(theta >= 67.5 && theta < 112.5)
			{
				directions[0] = 'E';
				directions[1] = ' ';
			}
			else if(theta >= 112.5 && theta < 157.5)
			{
				directions[0] = 'S';
				directions[1] = 'E';
			}
			else if(theta >= 157.5 && theta < 202.5)
			{
				directions[0] = 'S';
				directions[1] = ' ';
			}
			else if(theta >= 202.5 && theta < 247.5)
			{
				directions[0] = 'S';
				directions[1] = 'W';
			}
			else if(theta >= 247.5 && theta < 292.5)
			{
				directions[0] = 'W';
				directions[1] = ' ';
			}
			else if(theta >= 292.5 && theta < 337.5)
			{
				directions[0] = 'N';
				directions[1] = 'W';
			}

			// Write the result to the usart3 buffer
			sprintf(usart2_buffer, "Distance to camp: %2.2f km\n\rDirection to camp: %c%c\r\n", d, directions[0], directions[1]);

			if( HAL_UART_Transmit_IT(&usart2, (uint8_t *)usart2_buffer, sizeof(usart2_buffer)) != HAL_OK )
				for(;;);
		}
	}

	return Execution_Succesfull;
}

ReturnStatus SystemClock_Config(Clock_Source_t clk)
{
	RCC_OscInitTypeDef osc_init;
	RCC_ClkInitTypeDef clk_init;

	memset(&osc_init, 0, sizeof(osc_init));
	memset(&clk_init, 0, sizeof(clk_init));

	switch (clk)
	{
		case HSI_16:
			break;
		case HSI_8:
			osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSI;
			osc_init.HSIState = RCC_HSI_ON;
			if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
				return Execution_Failed;

			clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
			clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
			clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
			clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
			clk_init.APB2CLKDivider = RCC_HCLK_DIV1;

			if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
				return Execution_Failed;
			break;

		case HSE_4:
			osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
			osc_init.HSEState = RCC_HSE_ON; // YOU HAVE TO CHECK ON THE SCHEMATIC WHETHER HSE IS BYPASSED OR NOT!!!
			if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
				return Execution_Failed;

			clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
			clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
			clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
			clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
			clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

			if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
				return Execution_Failed;

			__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

			break;

		case HSE_2:
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON; // YOU HAVE TO CHECK ON THE SCHEMATIC WHETHER HSE IS BYPASSED OR NOT!!!
				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV4;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;

		case PLL_84:
#if !NO_PLL
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON;

				// Enable the clock to the power ccontroller.
				__HAL_RCC_PWR_CLK_ENABLE();

				// Set regulator voltage scale as 1.
				__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

				// Turn on the over drive mode.

				osc_init.PLL.PLLState = RCC_PLL_ON;
				osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
				osc_init.PLL.PLLM = 16;
				osc_init.PLL.PLLN = 336;
				osc_init.PLL.PLLP = 2;
				osc_init.PLL.PLLQ = 7;

				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;
#endif
		case PLL_42:
#if !NO_PLL
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON;

				// Enable the clock to the power ccontroller.
				__HAL_RCC_PWR_CLK_ENABLE();

				// Set regulator voltage scale as 1.
				__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

				// Turn on the over drive mode.

				osc_init.PLL.PLLState = RCC_PLL_ON;
				osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
				osc_init.PLL.PLLM = 16;
				osc_init.PLL.PLLN = 336;
				osc_init.PLL.PLLP = 2;
				osc_init.PLL.PLLQ = 7;

				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV4;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;
#endif
		default:
	}

	return Execution_Succesfull;
}

ReturnStatus USART_Config(UART_HandleTypeDef *uart_handle, USART_TypeDef *Instance)
{
	memset(uart_handle, 0, sizeof(*uart_handle));

	uart_handle->Instance = Instance;
	uart_handle->Init.BaudRate = 9600;
	uart_handle->Init.HwFlowCtl = UART_HWCONTROL_NONE;
	uart_handle->Init.Mode = UART_MODE_TX_RX;
	uart_handle->Init.OverSampling = UART_OVERSAMPLING_16;
	uart_handle->Init.Parity = UART_PARITY_NONE;
	uart_handle->Init.StopBits = UART_STOPBITS_1;
	uart_handle->Init.WordLength = UART_WORDLENGTH_8B;

	if( HAL_UART_Init(uart_handle) != HAL_OK )
		return Execution_Failed;

	return Execution_Succesfull;

}

inline double to_radians(double degrees) {
    return M_PI * (degrees / 180.0);
}

inline double to_degrees(double radians) {
    return radians * (180.0 / M_PI);
}

void Delay(uint32_t ms)
{
	DWT->CTRL |= (1 << 0); // Enable the DTW counter of the CortexM4
	uint32_t start = DWT->CYCCNT;
	uint32_t ticks = ms * (HAL_RCC_GetHCLKFreq() / 1000);

	while ((DWT->CYCCNT - start) < ticks);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART2)
	{
		usart2_buffer[usart2_index++] = received_byte;
		if(received_byte != '\r')
		{
			if( HAL_UART_Receive_IT(&usart2, &received_byte, 1) != HAL_OK )
				for(;;);
		}
		else
			new_coordinates = 1;
	}
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART2)
	{
		integers1 = 0;
		integers2 = 0;
		decimals1 = 10;
		decimals2 = 10;
		lat1 = 0;
		lon1 = 0;
		found_komma = 0;
		found_num_of_integers1 = 0;
		found_num_of_integers2 = 0;
		memset(usart2_buffer, 0, sizeof(usart2_buffer));
		usart2_index = 0;

		if( HAL_UART_Receive_IT(&usart2, &received_byte, 1) != HAL_OK )
			for(;;);
	}
}
/*
 * msp.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */

#include "my_main.h"

void HAL_MspInit(void)
{

	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

	// Enable necessary IRQs
	HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
	HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
	HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);

	HAL_NVIC_EnableIRQ(MemoryManagement_IRQn);
	HAL_NVIC_EnableIRQ(BusFault_IRQn);
	HAL_NVIC_EnableIRQ(UsageFault_IRQn);

}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef gpio_uart2;

	if(huart->Instance == USART2)
	{
		memset(&gpio_uart2, 0, sizeof(gpio_uart2));

		// Enable the UART and GPIO PORTA clock.
		__HAL_RCC_USART2_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();

		gpio_uart2.Pin = GPIO_PIN_2 | GPIO_PIN_3;
		gpio_uart2.Speed = GPIO_SPEED_FREQ_LOW;
		gpio_uart2.Mode = GPIO_MODE_AF_PP;
		gpio_uart2.Alternate = GPIO_AF7_USART2;
		gpio_uart2.Pull = GPIO_PULLUP;

		HAL_GPIO_Init(GPIOA, &gpio_uart2);

		HAL_NVIC_SetPriority(USART2_IRQn, 8, 0);
		HAL_NVIC_EnableIRQ(USART2_IRQn);
	}
}
/*
 * it.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */
#include "my_main.h"

extern UART_HandleTypeDef usart2;

void SysTick_Handler(void)
{
	HAL_IncTick();
	HAL_SYSTICK_IRQHandler();
}

void USART2_IRQHandler(void)
{
	HAL_UART_IRQHandler(&usart2);
}

void HardFault_Handler(void)
{
	// Halt execution, when HardFault error occurs.
	for(;;);
}

void MemManage_Handler(void)
{
	// Halt execution, when MemManage error occurs.
	for(;;);
}

void BusFault_Handler(void)
{
	// Halt execution, when BusFault error occurs.
	for(;;);
}

void UsageFault_Handler(void)
{
	// Halt execution, when UsageFault error occurs.
	for(;;);
}

Output

Video

Add a video of the output (know more)

 

 

 

 

 

Photo of Output

Add a photo of your hardware showing the output.

 

 

 

 

 

Screenshot of Serial Terminal 


 

Was this helpful?
Upvote
Downvote