Poslední vylepšená verze měření teploty pomocí interního termistoru a ADC na Raspberry Pi Pico. Teploměr je ocejchovaný podle přesnějšího teploměru. Naměřená hodnota je zobrazena na OLED displeji s čipem SDD1306.

Konstrukce

Teploměr ver. 8

IMG 20250301 205237

Program

main.c
/* Cejchovaný teploměr main.c
 * (c) Jirka Chráska 2025; <jirka@lixis.cz>
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/adc.h"

#include "ssd1306.h"
#include "font_spleen_8x5.h"
#include "font_spleen_16x8a.h"

// definice dipleje
const uint8_t num_chars_per_disp[]={20,20,20,20,20};
const uint8_t *fonts[2]= {font_spleen_8x5, font_spleen_16x8a};

#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 32
#define I2C_ADDRESS 0x3C
#define I2C_FREQ 50000
#define SLEEPTIME 55

void setup_gpios(void);
void animation(void);



// nastavení I2C  i2c0
// SDA pin GP4
// SCL pin GP5
// https://i.sstatic.net/P4Mkp.jpg
// https://raspberrypi.stackexchange.com/questions/106482/rpi3b-ssd1306-oled-i2c-interface-problem

void setup_i2c_gpios(void) {
    // nelze používat i2c_default, je tam zajímavá chyba kdy aplikace běží bez problémů po nahrání,
    // ale po restartu Pica se displej neinicializuje a je temný
    i2c_init(i2c0, I2C_FREQ);
    gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
    // gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN); // pull up rezistory jsou na displeji
    // gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
}

// vraci prumernou hotnotu ADC interniho termistoru * 10
uint32_t cteni_teploty(void)
{
uint32_t sum = 0;
uint32_t avg = 0;
uint16_t h[64] = {0};

    for(int i=0; i<64; i++) {
        h[i] = adc_read();
        sum += h[i];
    }
    avg = sum*10/64;
return avg;
}

void teplota(void) {

    // inicializace ADC
    // nastavení PWM měniče na malý šum
    gpio_set_function( 23, GPIO_FUNC_SIO );
    gpio_set_dir( 23, true );
    gpio_put(23, 1);

    gpio_set_function( 25, GPIO_FUNC_SIO );
    gpio_set_dir( 25, true );
    sleep_ms(200);

    adc_init();
    adc_set_temp_sensor_enabled(true);
    adc_select_input(4);


    // inicializace dipleje
    ssd1306_t disp;
    char buf[128];
    gpio_put(25,1);
    disp.external_vcc = false;
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, i2c0);
    ssd1306_poweron(&disp);
    ssd1306_clear(&disp);

    sprintf(buf,"%s","(c) Jiří Chráska 2025");
    ssd1306_draw_string_with_font(&disp, 0, 1, 1, font_spleen_8x5, buf);
    ssd1306_draw_line(&disp, 0, 13, 127, 13);
    sprintf(buf,"%s","jirka@lixis.cz");
    ssd1306_draw_string_with_font(&disp, 0, 15, 1, font_spleen_8x5, buf);
    ssd1306_show(&disp);
    sleep_ms(4000);
    gpio_put(25,0);

    uint32_t raw=0, rawold=0;
    float temp=0, tempold=0;

    for(;;) {
        rawold = raw;
        tempold = temp;
        raw = cteni_teploty();
        // spočítané hodnoty konverze podle etalonového teploměru
        temp = -0.036824*raw + 348.5;
        sprintf(buf, "%5u; %2.1f C", raw, temp);
        printf("%4u; %2.1f C\n", raw, temp);
        ssd1306_clear(&disp);
        ssd1306_draw_string_with_font(&disp, 0,  0, 1, font_spleen_16x8a, buf);
        sprintf(buf, "%5u; %2.1f C", rawold, tempold);
        ssd1306_draw_string_with_font(&disp, 0, 16, 1, font_spleen_16x8a, buf);
        ssd1306_show(&disp);
        gpio_put(25,1);
        sleep_ms(2000);
        gpio_put(25,0);
    }
}

int main() {
    stdio_init_all();

    printf("Konfigurace pinů dipleje...\n");
    setup_i2c_gpios();

    printf("Jedeme měřit teplotu...\n");
    teplota();

    return 0;
}