Interfacing the Soil Sensor with the STM32-F103RB Nucleo Board
Introduction
We will utilize the ADC (Analog-to-Digital Converter) feature of the STM32-F103RB microcontroller to read the analog output of the soil moisture sensor. By converting the analog value to a digital representation, we can obtain accurate soil moisture readings.
Problem Statement
Requirements
Follow the circuit diagram below to properly connect the soil moisture sensor to the STM32-F103RB :
- Nucleo-F103RB board
- 16 x 2 LCD
- Potentiometer (10K Ohms)
- lSensor
- Jumper wires
- Breadboard
Circuit Diagram
Follow the circuit diagram below to connect the LED to the Nucleo board:
- Connect the RS (Register Select) pin of the LCD to GPIO 4 (D4) of the board.
- Connect the EN (Enable) pin of the LCD to GPIO 5 (D5) of the board.
- Connect the D4 pin of the LCD to GPIO 18 (D18) of the board.
- Connect the D5 pin of the LCD to GPIO 19 (D19) of the board.
- Connect the D6 pin of the LCD to GPIO 21 (D21) of the board.
- And connect the D7 pin of the LCD to GPIO 22 (Pin 22) of the board.
- Also connect the A0 pin from the sensor to the PA1 Pin of the board, and other power pins from the sensor to the nucleo board.

Project Configuration
Follow these steps to configure the .IOC file and set up GPIOs and Clock :
Open the STM32 Cube IDE and start by creating a new STM32 project. Click on the board selector tab in the target selection window.
Enter "NUCLEO-F103RB" as the commercial part number and click on "Next" after selecting the board.

- Enter the Project Name "soil_moisture" and click on "Finish". After that, click on "Yes" to initialize all the peripherals in default mode.

Pinout & Configuration: In the Pinout & Configuration menu, select "TIM1" from the Timers section. This will configure Timer 1 for generating delay.
Clock Source: Choose "Internal Clock" as the Clock Source to utilize the internal clock of the STM32-F103RB Nucleo Board.
Timer Configuration: In the Configuration part of the Timers section, set the prescaler value as "72-1". The prescaler determines the frequency of the timer clock. Here, we divide the timer clock frequency by 72.
Next, specify the Counter Period as "65535". The counter period defines the overall period of the timer, this will be useful in writing a delay function in LCD.
To set up PA1 as ADC Input, Open the Pinout and Configuration menu in the STM32 Cube IDE. Select ADC1 from the available options.
In the ADC1 Mode tab, locate the IN1 option and click on it to enable it. This will configure PA1 as the ADC input. Keep the parameter settings in the config tab to their default values, as they are suitable for most applications.

To configure the GPIO pins for output, click on the GPIO pin in the Pinout & Configuration tab. Select the "GPIO_Output" option from the available options. To add a user label, right-click on the GPIO pin and select the "User Label" option and enter the desired name for the label.
Configure the GPIO pins highlighted in the 4th and 5th boxes in the image above as output, and rename them as shown below. These labels are predefined in the provided library.
Finally, configure the PA1 as GPIO_Input, keeping all the other configuration for the pin to default settings.

After finishing the Pinout Configuration, go to the Clock Configuration menu. In the HCLK field, enter "72 MHz" as the desired frequency for the HCLK (system clock). The Integrated Development Environment (IDE) will automatically search for the necessary clock sources and prescalers based on this configuration.
Next, locate the gear-like icon on the toolbar and click on it. This will add the configuration settings we did in the GUI to the code.

Code
Now, let's proceed to understand and write the C code to interface the LCD. Follow the steps below:
Open the main.c file, which is automatically opened by the Device Configuration Tool.
Include the necessary header file for the LCD module. Include the source file for the LCD module.
Download the "lcd_1602.c" and "lcd_1602.h" file from this link and add it to your project. Ensure that the project structure includes the added header and source files. And your project structure should look as below:

After adding the header and source file, copy the below code into your main.c file.
Note: You can download the full project code from the provided link.
#include "main.h"
/* USER CODE BEGIN Includes */
#include "lcd_1602.h"
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim1;
UART_HandleTypeDef huart2;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM1_Init(void);
int main(void)
{
/* UsER CODE BEGIN 1 */
int ADC_VAL;
char val[20];
double moisture;
/* USER CODE END 1 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_ADC1_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim1);
lcd_init();
lcd_send_string("INTIALISING>>>>>");
HAL_Delay(1000);
lcd_clear();
/* USER CODE END 2 */
while (1)
{
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
ADC_VAL = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
moisture = 100 - (ADC_VAL / 4095) * 100;
sprintf(val, "%.2f", moisture);
lcd_put_cur(0, 0);
lcd_send_string("value:=");
lcd_put_cur(8, 0);
lcd_send_string(val);
HAL_Delay(1000);
lcd_clear();
}
/* USER CODE END 3 */
}
After pasting the above code, ensure that you have connected your STM32-F103RB Nucleo Board to your PC/Laptop using a USB cable.
Next, click on the "Run and Debug" icon in the toolbar menu of the IDE (Refer to image below). This will initiate the build process for your project. The IDE will compile the code. Once the build process is successful, the IDE will start flashing the compiled project to the STM32-F103RB Nucleo Board.

Output
Upon successful execution of the project, the STM32-F103RB Nucleo Board will continuously monitor the soil moisture levels using the interfaced soil sensor. The board will read the moisture content of the soil and display it on the connected LCD screen in a user-friendly format. To verify the accuracy of the readings, you can perform a simple test by dipping the sensor into moist or dry soil.
Conclusion
By following this guide, you have successfully learned how to interface an Soil Moisture sensor In conclusion, this guide has demonstrated the successful interfacing of a soil sensor with the STM32-F103RB Nucleo Board. By utilizing the board's ADC module, we were able to accurately measure the moisture level in the soil. This information is crucial for effective plant care and automated irrigation systems. You have understood the hardware connections, library installation, ADC working and code implementation necessary for displaying information on the LCD.