71. UART-Based LEDs Control

Back To All Submissions
Previous Submission
Next Submission

Solving Approach

How do you plan to solve it?

LED-Brightness-and-Toggle-control-Via-UART

 

Code

#define LED_Pin     6
#define Button_Pin  5 

uint8_t toggle    = 0;
int buttonRead[2] = { 0 };

void setup() {
  Serial.begin(9600);
  pinMode(LED_Pin, OUTPUT);
  pinMode(Button_Pin, INPUT_PULLUP);
}

int buttonPressed()
{
  buttonRead[0] = digitalRead(Button_Pin);
  delay(150);
  buttonRead[1] = digitalRead(Button_Pin);

  //Serial.println(buttonRead[0]);
  //Serial.println(buttonRead[1]);

  if(buttonRead[0] == 0 && buttonRead[1] == 0)
    return 1;
  else
    return 0;
}

void loop() {
  if(buttonPressed())
  {
    toggle ^= 1;
    Serial.write(toggle);
  }

  if(Serial.available() > 0)
  {
    char receivedChar = Serial.read();
    analogWrite(LED_Pin, (uint8_t)receivedChar);
  }
}
/*
 * my_main.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */

#include "my_main.h"

UART_HandleTypeDef usart2, usart3;
ADC_HandleTypeDef adc1;
uint8_t rcvd_byte, trans_value;
char led_status[10] = { 0 };
uint32_t adc_value;
float conv_value;

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;

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

	// Configure the ADC module
	if( ADC_Config(&adc1, ADC1, ADC_CHANNEL_1) != Execution_Succesfull )
		return Execution_Failed;

	// Configure the LED Pin
	if ( LED_Config() != Execution_Succesfull )
		return Execution_Failed;

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

	for(;;)
	{
		if( HAL_ADC_Start(&adc1) != HAL_OK )
			return Execution_Failed;

		if( HAL_ADC_PollForConversion(&adc1, HAL_MAX_DELAY) == HAL_OK )
		{
			adc_value = HAL_ADC_GetValue(&adc1);
			conv_value = ((float)adc_value * 255.0) / 4096.0;
			trans_value = (uint8_t)conv_value;
		}

		if( HAL_ADC_Stop(&adc1) != HAL_OK )
			return Execution_Failed;

		if( HAL_UART_Transmit(&usart2, &trans_value, 1, HAL_MAX_DELAY) != 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;

}

ReturnStatus ADC_Config(ADC_HandleTypeDef *adc_handle, ADC_TypeDef *Instance, uint32_t channel)
{
	memset(adc_handle, 0, sizeof(*adc_handle));

	adc_handle->Instance = Instance;
	adc_handle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	adc_handle->Init.Resolution = ADC_RESOLUTION_12B;
	adc_handle->Init.ScanConvMode = DISABLE;
	adc_handle->Init.ContinuousConvMode = DISABLE;
	adc_handle->Init.DiscontinuousConvMode = DISABLE;
	adc_handle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	adc_handle->Init.ExternalTrigConv = ADC_SOFTWARE_START;
	adc_handle->Init.DataAlign = ADC_DATAALIGN_RIGHT;
	adc_handle->Init.NbrOfConversion = 1;
	adc_handle->Init.DMAContinuousRequests = DISABLE;
	adc_handle->Init.EOCSelection = ADC_EOC_SINGLE_CONV;

	if (HAL_ADC_Init(adc_handle) != HAL_OK)
		return Execution_Failed;

	ADC_ChannelConfTypeDef sConfig = { 0 };
	sConfig.Channel = channel;
	sConfig.Rank = 1;
	sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;

	if (HAL_ADC_ConfigChannel(adc_handle, &sConfig) != HAL_OK)
		return Execution_Failed;

	return Execution_Succesfull;
}

ReturnStatus LED_Config(void)
{
	GPIO_InitTypeDef led_gpio = { 0 };

	// Enable the clock for the GPIO
	__HAL_RCC_GPIOA_CLK_ENABLE();

	led_gpio.Pin = GPIO_PIN_4;
	led_gpio.Speed = GPIO_SPEED_FREQ_LOW;
	led_gpio.Pull = GPIO_NOPULL;
	led_gpio.Mode = GPIO_MODE_OUTPUT_PP;

	HAL_GPIO_Init(GPIOA, &led_gpio);

	return Execution_Succesfull;
}

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)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, rcvd_byte);
		if(rcvd_byte == 0)
			sprintf(led_status, "LED OFF\r\n");
		else if(rcvd_byte == 1)
			sprintf(led_status, "LED ON\r\n");

		if( HAL_UART_Transmit(&usart3, (uint8_t *)led_status, sizeof(led_status), HAL_MAX_DELAY) != HAL_OK )
			for(;;);

		memset(led_status, 0, sizeof(led_status));

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

	}
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART2)
	{

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

#ifndef INC_MY_MAIN_H_
#define INC_MY_MAIN_H_

#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include "stm32f4xx_hal.h"

/*
 *	@brief	This is a custom enumeration for the return status
 */

// If no PLL clock available set this to 1.
#define NO_PLL	( 1 )

typedef enum
{
	Execution_Succesfull 	= 0,
	Execution_Failed 		= 1
} ReturnStatus;

/*
 * @brief This is the enumeration type for the supported clocks.
 */
typedef enum
{
	HSI_16	=	0,
	HSI_8	=	1,
	HSE_4	=	2,
	HSE_2	=	3,
	PLL_84	=	4,
	PLL_42	=	5,
} Clock_Source_t;

/*
 * @brief This function sets the appropriate clock source for our circuit.
 */
ReturnStatus SystemClock_Config(Clock_Source_t clk);

/*
 * @brief This function configures the USART1 module.
 */
ReturnStatus USART_Config(UART_HandleTypeDef *uart_handle, USART_TypeDef *Instance);

/*
 * brief This function configures the ADC module.
 */
ReturnStatus ADC_Config(ADC_HandleTypeDef *adc_handle, ADC_TypeDef *Instance, uint32_t channel);

/*
 * @brief This function configures the GPIO LED Pin.
 */
ReturnStatus LED_Config(void);

/*
 * @brief This function implements delay in ms with the DWT module(Debugging and profiling feature in Arm Cortex-M processors, measures CPU cycles).
 */
void Delay(uint32_t ms);

#endif /* INC_MY_MAIN_H_ */
/*
 * 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, gpio_uart3;

	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);
	}

	if(huart->Instance == USART3)
	{
		memset(&gpio_uart3, 0, sizeof(gpio_uart3));

		// Enable the UART and GPIO PORTA clock.
		__HAL_RCC_USART3_CLK_ENABLE();
		__HAL_RCC_GPIOB_CLK_ENABLE();

		gpio_uart3.Pin = GPIO_PIN_10 | GPIO_PIN_11;
		gpio_uart3.Speed = GPIO_SPEED_FREQ_LOW;
		gpio_uart3.Mode = GPIO_MODE_AF_PP;
		gpio_uart3.Alternate = GPIO_AF7_USART3;
		gpio_uart3.Pull = GPIO_PULLUP;

		HAL_GPIO_Init(GPIOB, &gpio_uart3);

		HAL_NVIC_SetPriority(USART3_IRQn, 8, 0);
		HAL_NVIC_EnableIRQ(USART3_IRQn);
	}
}

void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{

	if(hadc->Instance == ADC1)
	{
		GPIO_InitTypeDef gpio_adc = { 0 };

		// Enable the clocks for the ADC module and the relative GPIO port.
		__HAL_RCC_ADC1_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();

		gpio_adc.Pin = GPIO_PIN_1;
		gpio_adc.Mode = GPIO_MODE_ANALOG;
		gpio_adc.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOA, &gpio_adc);
	}
}
/*
 * it.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */
#include "my_main.h"

extern UART_HandleTypeDef usart2, usart3;

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

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

void USART3_IRQHandler(void)
{
	HAL_UART_IRQHandler(&usart3);
}

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 

Add a Screenshot of the serial terminal showing the output.


 

Was this helpful?
Upvote
Downvote