Noval Saputra
Published © MIT

“UART Based Temperature Monitoring with STM32F401C and LM35”

Temperature monitoring simulation using Keil uVision and Proteus 8 Professional with STM32

BeginnerFull instructions provided2 hours250
“UART Based Temperature Monitoring with STM32F401C and LM35”

Things used in this project

Hardware components

LM35
1
×1
STM32F401CB
1
×1
Virtual Terminal
1
×1
SparkFun Breadboard Power Supply 5V/3.3V
SparkFun Breadboard Power Supply 5V/3.3V
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Proteus 8 Professionals
Keil uVision5

Hand tools and fabrication machines

Breadboard, 400 Pin
Breadboard, 400 Pin
Mastech MS8217 Autorange Digital Multimeter
Digilent Mastech MS8217 Autorange Digital Multimeter

Story

Read more

Schematics

Schmatic wiring

Code

Code for temperature sensor

C/C++
#include "stm32f4xx.h"         // CMSIS header for STM32F4 - gives access to all peripheral registers
#include <stdint.h>            // For standard integer types like uint16_t
#include <stdio.h>             // For sprintf() to format strings (must enable float support if using with float)

// Constant for delay (approx. 1 second for a 16 MHz clock)
#define DELAY_1S 400000U

// ==== Function Prototypes ====
void delay(volatile uint32_t time);          // Simple delay function using a busy loop
void GPIO_Init(void);                        // Initializes GPIOA for PA0 (ADC) and PA2 (UART TX)
void USART2_Init(void);                      // Initializes USART2 peripheral
void ADC1_Init(void);                        // Initializes ADC1 for channel 0 (PA0)
uint16_t Read_ADC(void);                     // Reads raw ADC value from channel 0
void USART2_Write(char c);                   // Sends one character over UART
void USART2_Print(char *str);                // Sends a string over UART
float Read_Temperature(void);                // Converts ADC reading to temperature in °C

// ==== Delay Function ====
void delay(volatile uint32_t time) {
    while (time--);                          // Simple loop to introduce delay (not accurate)
}

// ==== GPIO Initialization ====
void GPIO_Init(void) {
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;     // Enable clock for GPIOA

    GPIOA->MODER |= (3 << 0);                // Set PA0 to analog mode (ADC input)

    GPIOA->MODER &= ~(3 << (2 * 2));         // Clear mode bits for PA2
    GPIOA->MODER |=  (2 << (2 * 2));         // Set PA2 to alternate function mode

    GPIOA->AFR[0] |= (7 << (4 * 2));         // Set alternate function for PA2 to AF7 (USART2_TX)
}

// ==== USART2 Initialization ====
void USART2_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_USART2EN;    // Enable clock for USART2

    USART2->BRR = 0x0683;                    // Set baud rate to 9600 for 16 MHz system clock
    USART2->CR1 = USART_CR1_TE | USART_CR1_UE; // Enable transmitter and USART
}

// ==== Send a single character via UART ====
void USART2_Write(char c) {
    while (!(USART2->SR & USART_SR_TXE));    // Wait until transmit data register is empty
    USART2->DR = c;                          // Send the character
}

// ==== Send a string via UART ====
void USART2_Print(char *str) {
    while (*str) {
        USART2_Write(*str++);                // Send each character one by one
    }
}

// ==== ADC1 Initialization for channel 0 (PA0) ====
void ADC1_Init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;      // Enable clock for ADC1

    ADC1->SQR3 = 0;                          // Select channel 0 (PA0) for conversion
    ADC1->SMPR2 |= (7 << 0);                 // Set maximum sample time for accuracy
    ADC1->CR2 |= ADC_CR2_ADON;               // Turn on the ADC
}

// ==== Read value from ADC1 ====
uint16_t Read_ADC(void) {
    ADC1->CR2 |= ADC_CR2_SWSTART;            // Start conversion
    while (!(ADC1->SR & ADC_SR_EOC));        // Wait for conversion to complete
    return ADC1->DR;                         // Return converted value
}

// ==== Convert ADC value to Temperature in Celsius ====
float Read_Temperature(void) {
    uint16_t adc = Read_ADC();               // Read raw ADC value
    float voltage = (adc * 3.3f) / 4095.0f;   // Convert to voltage (assuming 3.3V reference)
    return voltage * 100.0f;                 // LM35 gives 10mV per °C → multiply by 100
}

// ==== Main Program Loop ====
int main(void) {
    char buffer[50];                         // Buffer to store formatted string
    float temp;                              // Variable to hold temperature value

    GPIO_Init();                             // Initialize GPIO for analog and UART
    USART2_Init();                           // Initialize UART for output
    ADC1_Init();                             // Initialize ADC for temperature sensor

    while (1) {
        temp = Read_Temperature();           // Read current temperature
        sprintf(buffer, "Temp: %.2f C\r\n", temp); // Format string with temperature
        USART2_Print(buffer);                // Send formatted string over UART
        delay(DELAY_1S);                     // Wait approx. 1 second
    }
}

Credits

Noval Saputra
1 project • 2 followers

Comments