Raspberry_i2c_display_dht11_libxml2

Желание сделать что-нибудь полезное с Raspberry Pi 2 model B и набором Upgraded Arduino Starter Kit RFID Master With Motor Relay LCD Servo AVR привело к созданию информера, отображающего данные в виде температуры и влажности с сенсора DHT11 и курса доллара на текущий момент вот на такой дисплей.

Использовать Python для этого не хотелось. Потому что примеров реализации отдельных проектов достаточно, например взаимодействия с сенсором DHT11 раз, два. Хотел реализовать все это дело на C/C++. Попался замечательный пример, который я взял за основу.

Но прежде чем что-то программировать необходимо правильно скоммутировать сенсор, экран и raspberry pi, да еще так, чтобы это все богатство не закоротило и не сгорело. Вот схема распиновки GPIO Raspberry Pi 2 Model B. Оно идентично распиновке модели B+.

Raspberry Pi 2 Model B GPIO pinout

Нашел еще один полезный ресурс с интерактивной схемой, которая изменяется в зависимости от того, что нужно подключить. Отображается к каким пинам надо подключать.

Подключаем DHT11: S к GPIO 4, + к 3.3V pin1 на raspberry, — к 9 pin.

Подключаем дисплей: GND к Ground pin 6, VCC к +5.5V pin2, SDA к pin3, SCL к pin5.

Выглядит все это вот так.

Raspberry i2c dht11

Приступим к программированию. Пример работы с DHT11 найден. Осталось разобраться как работать с дисплеем. Люди уже подсуетились и написали библиотеку на C. Благодарность ее автору wargio.

Для того чтобы получать курс валют воспользуемся сайтом центрального банка. Он выдает документ в формате XML на специальной странице. Цель получить значение Value вот из этого куска документа.

<Valute ID="R01235">
<NumCode>840</NumCode>
<CharCode>USD</CharCode>
<Nominal>1</Nominal>
<Name>Доллар США</Name>
<Value>60,0341</Value>
</Valute>

Существует большое количество способов обработать документ XML. Я выбрал кросс платформенную библиотеку lixml2. Установим ее на raspberry

sudo apt-get install libxml2-dev
sudo ldconfig

По-умолчанию в Raspberry отключены модули ядра i2c и spi. Включить их можно в raspi-config в разделе Advanced options. Собрав все воедино получился вот такой код.
dht_lcd.c

#include 

#include 
#include 
#include 
#define MAXTIMINGS 85
#define DHTPIN     7
int dht11_dat[5] = { 0, 0, 0, 0, 0 };

#include 
#include "i2c.h"
#include "lcd.h"
#include 
#include 

static void print_element_names(xmlNode * a_node);

#define I2C_FILE_NAME "/dev/i2c-1"

char frow[16];
char srow[16];

static void
print_element_names(xmlNode * a_node)
{
    xmlNode *cur_node = NULL;
    xmlNode   *child = NULL;

    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
        if (cur_node->type == XML_ELEMENT_NODE) {

            if (!xmlStrcmp((const xmlChar *)"R01235", xmlGetProp(cur_node, (const xmlChar *)"ID"))) {
                //нашли ветку с нужным id

                for (child = cur_node->children; child; child = child->next) {

                    if(!xmlStrcmp(child->name, (const xmlChar *)"Value")) {
                        //нашли целевое значение, печатаем
                        sprintf(srow, "USD: %s", xmlNodeGetContent(child));
                    }
                }
            }
        }
        print_element_names(cur_node->children);
    }
}

void read_dht11_dat()
{
    uint8_t laststate   = HIGH;
    uint8_t counter     = 0;
    uint8_t j       = 0, i;

    dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

    /* pull pin down for 18 milliseconds */
    pinMode( DHTPIN, OUTPUT );
    digitalWrite( DHTPIN, LOW );
    delay( 18 );
    /* then pull it up for 40 microseconds */
    digitalWrite( DHTPIN, HIGH );
    delayMicroseconds( 40 );
    /* prepare to read the pin */
    pinMode( DHTPIN, INPUT );

    /* detect change and read data */
    for ( i = 0; i < MAXTIMINGS; i++ )
    {
        counter = 0;
        while ( digitalRead( DHTPIN ) == laststate )
        {
            counter++;
            delayMicroseconds( 1 );
            if ( counter == 255 )
            {
                break;
            }
        }
        laststate = digitalRead( DHTPIN );

        if ( counter == 255 )
            break;

        /* ignore first 3 transitions */
        if ( (i >= 4) && (i % 2 == 0) )
        {
            /* shove each bit into the storage bytes */
            dht11_dat[j / 8] <<= 1;
            if ( counter > 16 )
                dht11_dat[j / 8] |= 1;
            j++;
        }
    }

    /*
     * check we read 40 bits (8bit x 5 ) + verify checksum in the last byte
     * print it out if data is good
     */
    if ( (j >= 40) &&
            (dht11_dat[4] == ( (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF) ) )
    {
        sprintf(frow, "H: %d.%d*C %d.%d%%", dht11_dat[2], dht11_dat[3], dht11_dat[0], dht11_dat[1]);


    }
    //else  {
    //printf( "Data not good, skip\n" );
    //}
}



int main( void )
{

    xmlDoc         *doc = NULL;
    xmlNode        *root_element = NULL;

    doc = xmlReadFile("http://www.cbr.ru/scripts/XML_daily.asp", NULL, 0);

    if (doc == NULL)
    {
        printf("error: could not parse file \n");
    }
    else
    {
        root_element = xmlDocGetRootElement(doc);
        print_element_names(root_element);
        xmlFreeDoc(doc);
    }
    xmlCleanupParser();

    if ( wiringPiSetup() == -1 )
        exit( 1 );


    int i2c_dev;
    lcd lcd0;
    // 0x27 is the address of the i2c device
    i2c_dev = open_i2c(I2C_FILE_NAME, 0x27);
    if(i2c_dev <0) {
        printf("Error: %d\n", i2c_dev);
        return 1;
    }
    lcd_init(&lcd0, i2c_dev);



    while ( 1 )
    {
        read_dht11_dat();

        lcd_clear(&lcd0);
        lcd_print(&lcd0, frow, strlen(frow), 0);
        lcd_print(&lcd0, srow, strlen(srow), 1);

        delay( 3000 ); /* wait 1sec to refresh */
    }

    close_i2c(i2c_dev);
    return(0);
}
FILES   =       i2c lcd
EXAMPLES=       dht_lcd
DEPS    =       Makefile i2c.h lcd.h

AR      =       ar
CC  =   gcc
CFLAGS  =   -g -O2 -Wall -W -ggdb -lwiringPi `xml2-config --cflags` `xml2-config --libs`
LDLIBS  =   
LIBNAME =       liblcm1602

LIBAR   =       $(addsuffix .a, $(LIBNAME))
LIBOBJS =       $(addsuffix .o, $(FILES))
OBJS    =       $(addsuffix .o, $(EXAMPLES))

all: $(LIBOBJS) $(OBJS) $(LIBAR) $(EXAMPLES)
    @echo "done"

$(EXAMPLES): %: %.o $(DEPS) $(LIBAR)
    $(CC) $(CFLAGS) -o $@ $< $(LIBAR) $(LDLIBS)

$(LIBAR):
    $(AR) rcs $(LIBAR) $(LIBOBJS)

$(LIBOBJS): %.o: %.c $(DEPS)
    $(CC) $(CFLAGS) -c -o $@ $<

$(OBJS): %.o: %.c $(DEPS)
    $(CC) $(CFLAGS) -c -o $@ $<

clean:
    rm -rf $(LIBAR) $(OBJS) $(LIBOBJS) $(EXAMPLES)


Собираем и запускаем командой

make && sudo ./dht_lcd

Как обычно демострация.

Raspberry_i2c_display_dht11_libxml2

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.