- Overview of GPIO Input Modes
1.1 Button Basics
Mechanical buttons are common digital input devices that close a circuit when pressed and open it when released. Due to the physical nature of their internal spring contacts, they exhibit bounce—a series of rapid on/off transitions during state changes. This requires software or hardware debouncing for reliable detection.
1.2 Sensor Modules
Sensor modules often use variable-resistance components like photoresistors (light-dependent resistors), thermistors, or infrared receivers. Their resistance changes with environmental conditions (e.g., light intensity or temperature). By placing them in a voltage divider with a fixed resistor, an analog voltage is produced. A built-in comparator then converts this into a clean digital output (DO), while the analog signal may also be available via AO for ADC sampling.
- Photoresistor: Resistence decreases as light intensity increases.
- Thermistor (NTC): Resistance decreases as temperature rises.
- Through-beam IR sensor: Receiver resistance drops with stronger IR exposure.
- Reflective IR sensor: Detects reflected IR from nearby objects.
A small filter capacitor is typically added near the sensor output to suppress electrical noise and stabilize readings.
1.3 Common Hardware Configurations
Pull-down wiring (most common):
- Button connects GPIO to GND when pressed.
- GPIO must be configured as
Input with Pull-upso it reads HIGH when open and LOW when pressed. - Without pull-up, the pin floats when unpressed, leading to unpredictable readings.
Pull-up wiring:
- Button connects GPIO to VCC (e.g., 3.3V) when pressed.
- Requires
Input with Pull-downmode (if supported) to read LOW when open and HIGH when pressed. - Note: Some MCUs (like certain STM32 variants) lack internal pull-down resistors on all pins.
In both cases, the active state (pressed) can be either logic LOW or HIGH depending on wiring. Most designs favor active-LOW with internal pull-up for simplicity and lower power.
- Buton-Controlled LED Example
2.1 Circuit Setup
Two buttons connected to PB1 and PB11 using pull-up configuration (active-LOW). Two LEDs on PA1 and PA2, driven in active-LOW mode (LED turns on when pin is LOW).
2.2 Modular Code Implementation
LED Driver (LED.c):
#include "stm32f10x.h"
void LED_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef cfg;
cfg.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
cfg.GPIO_Mode = GPIO_Mode_Out_PP;
cfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &cfg);
// Turn off LEDs initially (set HIGH for active-LOW)
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
void LED1_Toggle(void) {
GPIO_WriteBit(GPIOA, GPIO_Pin_1,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)));
}
void LED2_Toggle(void) {
GPIO_WriteBit(GPIOA, GPIO_Pin_2,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2)));
}
Button Driver (KEY.c):
#include "stm32f10x.h"
#include "Delay.h"
void KEY_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef cfg;
cfg.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
cfg.GPIO_Mode = GPIO_Mode_IPU; // Internal pull-up
GPIO_Init(GPIOB, &cfg);
}
uint8_t KEY_GetState(void) {
static uint8_t last_key = 0;
uint8_t key = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET) {
Delay_ms(20);
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET) {
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET);
key = 1;
}
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == RESET) {
Delay_ms(20);
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == RESET) {
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == RESET);
key = 2;
}
}
return key;
}
2.3 Main Application
#include "stm32f10x.h"
#include "LED.h"
#include "KEY.h"
#include "Delay.h"
int main(void) {
LED_Init();
KEY_Init();
while (1) {
uint8_t key = KEY_GetState();
if (key == 1) LED1_Toggle();
if (key == 2) LED2_Toggle();
Delay_ms(10); // Small delay to reduce CPU load
}
}
- Light Sensor Controllling Buzzer
3.1 Sensor Behavior
The digital output (DO) of the light sensor module is LOW under bright light and HIGH in darkness (due to internal comparator threshold). This signal drives a buzzer via GPIO.
3.2 Driver Implementation
Buzzer Driver (Buzzer.c):
#include "stm32f10x.h"
void Buzzer_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef cfg;
cfg.GPIO_Pin = GPIO_Pin_12;
cfg.GPIO_Mode = GPIO_Mode_Out_PP;
cfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &cfg);
Buzzer_Off(); // Start silent
}
void Buzzer_On(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_12); }
void Buzzer_Off(void) { GPIO_SetBits(GPIOB, GPIO_Pin_12); }
Light Sensor Interface (LightSensor.c):
#include "stm32f10x.h"
void LightSensor_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef cfg;
cfg.GPIO_Pin = GPIO_Pin_13;
cfg.GPIO_Mode = GPIO_Mode_IPU; // Use pull-up if sensor is open-drain
GPIO_Init(GPIOB, &cfg);
}
uint8_t LightSensor_Read(void) {
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}
3.3 Main Logic
#include "stm32f10x.h"
#include "Buzzer.h"
#include "LightSensor.h"
int main(void) {
Buzzer_Init();
LightSensor_Init();
while (1) {
if (LightSensor_Read() == SET) { // Dark condition
Buzzer_On();
} else { // Bright condition
Buzzer_Off();
}
}
}
This results in the buzzer sounding only when ambient light is low.