V tomto článku se naučíme automaticky zapínat a vypínat světla podle okolního osvětlení.
Princip spočívá v tom, že měříme napětí pomocí ADC na děliči s fotorezistorem a současně měříme napětí na proměnném referenčním děliči napětí. Odpor fotorezistoru závisí na vnějším osvětlení. Osvětlený fotorezistor má malý odpor (stovky Ohmů), fotorezistor ve tmě má odpor okolo 15 kiloOhmů. Referenční dělič nám umožňuje nastavit hranici mezi světlem a tmou.
Spínání světel je pomocí reléového modulu.
Schéma zapojení
Schéma zapojení

Prototyp

Program
/* Měření na fotoodporu
* svetlo.c
* (c) Jirka Chráska 2026, <jirka@lixis.cz>
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/adc.h"
// pro OLED displej
#include "ssd1306.h"
#include "font_spleen_8x5.h"
#include "font_spleen_16x8a.h"
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 32
#define I2C_ADDRESS 0x3C
#define I2C_FREQ 400000
#define SLEEPTIME 55
#define SDA_PIN 4
#define SDC_PIN 5
#define I2C i2c0
ssd1306_t disp;
// nastavení I2C sběrnice
void setup_i2c(void)
{
// nelze použít i2c_default -- aplikace bude chodit nekorektně (zajímavá chyba)
i2c_init(I2C, I2C_FREQ);
gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
// Pull-up rezistory jsou v displeji, netřeba nastavovat
}
void zapnuti_displeje( void )
{
ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C); // inicializace
ssd1306_poweron(&disp); // zapnutí displeje
ssd1306_clear(&disp); // vymazání displeje
ssd1306_contrast(&disp,0x50);
ssd1306_draw_string_with_font(&disp, 0, 0, 1, font_spleen_16x8a, "Osv" "\xec" "tlen" "\xed" ".");
ssd1306_show(&disp); // zobrazíme písmenka na displeji
}
#define MERENI_PIN 26
#define REFERENCE_PIN 27
#define ADC_INPUT 0
#define REFERENCE_INPUT 1
#define TEMNO 1.3
#define REF_VOLTAGE 3.25f
int main()
{
char buffer[128];
uint16_t raw;
const float conversion_factor = 3.3f / (1<<12);
float reference = 0.0;
float napeti = 0.0;
memset(buffer,'\0',128);
gpio_init(22);
gpio_set_dir(22,GPIO_OUT);
gpio_put(22,1);
// debugování přes USB
stdio_init_all();
sleep_ms(1200);
// inicializace a konfigurace 0LED displeje
// nastavení displeje SSD1306
setup_i2c();
zapnuti_displeje();
sleep_ms(10);
// nastavení ADC
adc_init();
adc_gpio_init(MERENI_PIN);
adc_gpio_init(REFERENCE_PIN);
printf("\nMěření napětí na fotorezistoru.\n");
// měření osvetleni
while(1) {
memset(buffer,'\0',128);
adc_select_input(ADC_INPUT);
napeti = adc_read() * REF_VOLTAGE / (1<<12);
adc_select_input(REFERENCE_INPUT);
reference = adc_read() * REF_VOLTAGE / (1<<12);
ssd1306_clear(&disp);
sprintf(buffer,"S:%5.2fV %s", napeti, napeti > reference ? "temno" : "sv\xectlo");
ssd1306_draw_string_with_font(&disp,0,0,1, font_spleen_16x8a, buffer);
sprintf(buffer,"R:%5.2fV",reference);
ssd1306_draw_string_with_font(&disp,0,16,1, font_spleen_16x8a, buffer);
ssd1306_show(&disp);
printf("Napětí fotoodpor: %5.3f V, referenční napětí: %5.3f\n",napeti,reference);
if( napeti > reference ) {
gpio_put(22,0);
} else {
gpio_put(22,1);
}
sleep_ms(500);
}
return 0;
}
cmake_minimum_required(VERSION 3.13)
# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(osvetleni)
set(CMAKE_C_STANDARD 11)
# initialize the Raspberry Pi Pico SDK
pico_sdk_init()
# rest of your project
add_executable(osvetleni
svetlo.c
disp/ssd1306.c
)
target_include_directories(osvetleni
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/disp
)
target_link_libraries(osvetleni
pico_stdlib
hardware_i2c
hardware_adc
)
pico_enable_stdio_usb(osvetleni 1)
pico_enable_stdio_uart(osvetleni 0)
# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(osvetleni)