Вопросы и замечания по статьям и схемам, представленным на нашем сайте

При поддержке РадиоКОТструктор.ру


Ответить

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт апр 21, 2020 10:01:23

Ну кто ж вам запретит?

Re: Часы на светодиодных матрицах с драйверами MAX7219

Чт апр 30, 2020 22:24:50

Вроде разобрался как сделать. Не знаю правильно или нет, но работает.
В файле bmp180.c сделал изменения. Калибровочная величина записывается в 0x19 байт eeprom. Можно уходить в обе стороны.
Выкладываю код. Может кому пригодится и автор покритикует... :)
Код:
void bmp180Convert (void)
{
    int8_t pcor;
    pcor = eeprom_read_byte((uint8_t*)0x19);


    pressure = (p + ((x1 + x2 + 3791) >> 4)) * 3 / 40 + pcor;

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 00:00:04

Немножко покритикую.

1. Лучше в eeprom.h добавить макрос, по аналогии с другими ячейками.
2. Коррекцию проводить не в драйвере bmp180, а непосредственно при выводе на экран. Т.е., в функции loadTempString(), там где вызывается bmp180GetPressure().
3. К коррекции лучше добавить +1. Тогда значение ячейки eeprom по умолчанию (0xFF = -1) будет как бы нулём и не будет влиять на показания.

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 09:08:34

Спасибо за критику. По поводу eeprom.h сразу хотел так сделать. Но не смог реализовать, так как не хватает знаний и опыта в программировании. Потихоньку изучаю...
Добавил в eeprom.h строку #define EEPROM_BMP180CORR 0x19. Теперь разбираюсь как извлечь для подстановки сюда -> eeprom_read_byte((uint8_t*)0x19);

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 09:54:16

Ну вот вместо 0x19 и вставлять.

Вчера попробовал собрать код более новыми версиями компилятора - не получается влезть в 8 килобайт. Надо бы сесть и немного оптимизацией заняться...

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 10:22:47

Чудеса :shock: раньше так делал и не получалось, а теперь после подсказки все собралось. Наверное допустил синтаксическую ошибку. Спасибо, WiseLord, за подсказку!
Код:
static void loadTempString(void)
{
    uint8_t i;
    uint8_t sm = eep.sensMask;
    int8_t pcor;
    pcor = eeprom_read_byte((uint8_t*)EEPROM_BMP180CORR);


    if (bmp180HaveSensor() && (sm & SENS_MASK_BMP_PRES)) {
        loadPlaceString(LABEL_PRESSURE);
        matrixScrollAddString(" ");
        loadSensorString(bmp180GetPressure() + pcor + 1, LABEL_MMHG);


Тоже пробовал собирать avr-gcc-5.4.0 - не влезает. Сейчас в VirtualBox Debian 9 avr-gcc-4.9.2 и пока помещаюсь - ровно 8192.

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 12:44:51

Попробовал немного оптимизировать код - вроде как с сотню байт удалось выжать. Залил исходники на Github

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 14:54:11

Да, реально уменьшился код. Спасибо!
Код:
AVR Memory Usage:

Program:  8122 bytes (.text + .data)
Data:     591 bytes (.data + .bss)
А можно еще вопрос? Хочу изменить ширину пробела до 2-х символов (0x00, 0x00, VOID, VOID, VOID). Но во всех настройках портится первый символ и бегущая строка раньше обрывается. Не подскажете где копать?

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 15:58:24

При выводе цифр есть фишка - все они должны быть одной ширины, такой же как и пробел - чтобы было проще реализовать разного рода мигания и скроллинги. Поэтому простым способом, наверное, не получится сделать.

Хотя можете попробовать.

В коде есть несколько вызовов типа mkNumberString(value, 2, ' '). Это формирование строчки из некоторого числа value. двойка - это ширина (в символах) на выходе, ' ' - это пробел, которым будут заполнены нулевые символы в начале. То есть, для числа 34 сформируется строка "34", а для числа 2 - строка " 2". А если вызывать как mkNumberString(value, 2, '0') - то соотвестсвенно сформировались бы "23" и "02".

В общем, идея следующая. Найти по коду эти вызовы, там где они вызываются с пробелом. Вместо пробела подставить другой символ, например 0xBE. Сейчас он не используется (в font-cp1251-08.c), и там идёт сплошная заливка знакоместа, если вдруг такой символ встретится.

Нужно отрисовать этот символ в пробел (0x00, 0x00, 0x00, 0x00, VOID), и вызывать теперь mkNumberString(value, 2, 0xBE); Тогда все статичные цифры будут отображаться как раньше, без сдвигов. А уже основной пробел можно обрезать до двух-трёх пикселов.

Или взять не 0xBE, а какой-нибудь другой символ, из таблицы CP1251, наименее нужный (типа 0xAC).

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пт май 01, 2020 17:46:18

Спасибо за подробные разъяснения :beer:
На выходных будет чем заняться.

Re: Часы на светодиодных матрицах с драйверами MAX7219

Пн май 04, 2020 20:57:02

В общем, идея следующая. Найти по коду эти вызовы, там где они вызываются с пробелом. Вместо пробела подставить другой символ, например 0xBE. Сейчас он не используется (в font-cp1251-08.c), и там идёт сплошная заливка знакоместа, если вдруг такой символ встретится.

Нужно отрисовать этот символ в пробел (0x00, 0x00, 0x00, 0x00, VOID), и вызывать теперь mkNumberString(value, 2, 0xBE); Тогда все статичные цифры будут отображаться как раньше, без сдвигов. А уже основной пробел можно обрезать до двух-трёх пикселов.

Сделал все следуя Вашим разъяснениям. Считаю, получилось :-) Но немного по-другому...
Вместо пробела и в коде (там где он используется), и в надписях использовал символ "]" 0x5D. Так проще писать когда нужно в редакторе eeprom использовать "короткий пробел".
Благодарю!

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 10:01:51

WiseLord, пожалуйста, подскажите как реализована функция записи и чтения байта?
Например, записать в устройство 0x76, адрес 0xF5, значение 0xA0.

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 10:16:30

Про какие устройства и адреса речь?

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 10:27:45

Датчик BME280 его ID на шине 0x76. Записать по адресу 0xF5 значение 0xA0.
Есть желание попробовать написать драйвер для него...

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 10:33:05

Код:
I2CswStart(0x76);
I2CswWriteByte(0xF5);
I2CswWriteByte(0xA0);
I2CswStop();
Можно для примера смотреть на код bmp180, dht22, rtc.

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 10:35:35

Спасибо. Буду заниматься...

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 22:10:59

Нужно извлечь последовательность из n-го количества байт. Задаю начальный адрес(start), буфер промежуточного хранения(buff[]) и длину последовательности(bytes).
Код:
void bme280ReadMem(uint8_t start, uint8_t buff[], uint8_t bytes)
{
    uint8_t i = 0;
    I2CswStart(BME280_ADDR);
    I2CswWriteByte(start);
    I2CswStart(BME280_ADDR | I2C_READ);
   for(i=0; i<bytes; i++) {
      if(i==bytes-1)
         buff[i] = I2CswReadByte(I2C_ACK);
      else
         buff[i] = I2CswReadByte(I2C_NOACK);
   }
    I2CswStop();
}

Затем
Код:
bme280ReadMem(BME280_ADC_DATA_START, data, BME280_ADC_DATA_BYTES);

Так должно работать?

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 22:43:14

Да. Если у bme280 именно такая адресация на чтение.

Разве что вторым параметром я бы uint8_t *buff сделал, а не массив.

Код:
void bme280ReadMem(uint8_t start, uint8_t *buff, uint8_t bytes)
{
    I2CswStart(BME280_ADDR);
    I2CswWriteByte(start);
    I2CswStart(BME280_ADDR | I2C_READ);
    for(uint8_t i = 0; i < bytes; i++) {
        buff[i] = I2CswReadByte(i == bytes - 1 ? I2C_ACK : I2C_NOACK);
    }
    I2CswStop();
}

Re: Часы на светодиодных матрицах с драйверами MAX7219

Вт май 19, 2020 22:54:12

Как пример использую этот исходник - https://github.com/Yenya/avr-bmp280/blo ... 0/bmp280.c

Re: Часы на светодиодных матрицах с драйверами MAX7219

Чт май 21, 2020 10:51:41

Пока написал только температуру и давление. Сначала не мог понять почему не инициализировался датчик. Потом посмотрел как сделано чтение в rtc.c и поменял местами команды I2C_ACK, I2C_NOACK. Заработало.
Формула расчета очень громоздкая. А если ее привести требуемым значениям, то вовсе не влазит в 8kb.

bme280.c
Спойлер
Код:
#include <string.h>
#include <util/delay.h>

#include "bme280.h"
#include "i2csw.h"

static int16_t  temperature = 0;
static int16_t pressure = 0;

static uint8_t bme280Sensor = 0;

void bme280ReadMem(uint8_t start, uint8_t *buff, uint8_t bytes)
{
    I2CswStart(BME280_ADDR);
    I2CswWriteByte(start);
    I2CswStart(BME280_ADDR | I2C_READ);
    for(uint8_t i = 0; i < bytes; i++) {
        buff[i] = I2CswReadByte(i == bytes - 1 ? I2C_NOACK : I2C_ACK);
    }
    I2CswStop();
}

static void bme280WriteMem(uint8_t reg, uint8_t value)
{
    I2CswStart(BME280_ADDR);
    I2CswWriteByte(reg);
    I2CswWriteByte(value);
    I2CswStop();
}

static union _bme280cal_union {
    uint8_t bytes[BME280_CAL_DATA_SIZE];
    struct {
        uint16_t dig_t1;
        int16_t  dig_t2;
        int16_t  dig_t3;
        uint16_t dig_p1;
        int16_t  dig_p2;
        int16_t  dig_p3;
        int16_t  dig_p4;
        int16_t  dig_p5;
        int16_t  dig_p6;
        int16_t  dig_p7;
        int16_t  dig_p8;
        int16_t  dig_p9;
    }
} bme280cal;

static void bme280GetCal(void)
{
    memset(bme280cal.bytes, 0, sizeof(bme280cal));
    bme280ReadMem(BME280_CAL_REG_FIRST, bme280cal.bytes, BME280_CAL_DATA_SIZE);
}

void bme280Init(void)
{
    uint8_t buffer[1];
    buffer[0] = 0;
    bme280ReadMem(BME280_ID_REG, buffer, 1);
    if (buffer[0] != BME280_ID_VAL) {
        bme280Sensor = 0;
        return;
    }

    bme280Sensor = 1;
    bme280GetCal();
    bme280WriteMem(BME280_CTRL_MEAS, 0x27);
    bme280WriteMem(BME280_CTRL_CONFIG, 0xA0);

    _delay_ms(BME280_CONV_TIME);

}

uint8_t bme280HaveSensor(void)
{
    return bme280Sensor;
}


#define bme280_20bit_reg(b1, b2, b3)    ( \
        ((int32_t)(b1) << 12) \
        | ((int32_t)(b2) << 4) \
        | ((int32_t)(b3) >> 4) \
)

void bme280Convert(void)
{
        uint8_t data[BME280_ADC_RAWDATA_BYTES];
        int32_t temp_raw, pres_raw,
        var1, var2, t_fine;

        // read the raw ADC data from the I2C registers
        bme280ReadMem(BME280_ADC_DATA_START, data, BME280_ADC_RAWDATA_BYTES);
        pres_raw = bme280_20bit_reg(data[0], data[1], data[2]);
        temp_raw = bme280_20bit_reg(data[3], data[4], data[5]);

        // compute the temperature
        var1 = ((((temp_raw >> 3) - ((int32_t)bme280cal.dig_t1 << 1)))
                * ((int32_t)bme280cal.dig_t2)) >> 11;
        var2 = (((((temp_raw >> 4) - ((int32_t)bme280cal.dig_t1))
                * ((temp_raw >> 4) - ((int32_t)bme280cal.dig_t1))) >> 12)
                * ((int32_t)bme280cal.dig_t3)) >> 14;
        t_fine = var1 + var2;
        temperature = ((t_fine * 5 + 128) >> 8);

        // compute the pressure
        var1 = (((int32_t)t_fine) >> 1) - (int32_t)64000;
        var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bme280cal.dig_p6);
        var2 = var2 + ((var1 * ((int32_t)bme280cal.dig_p5)) << 1);
        var2 = (var2 >> 2) + (((int32_t)bme280cal.dig_p4) << 16);
        var1 = (((bme280cal.dig_p3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3)
                + ((((int32_t)bme280cal.dig_p2) * var1) >> 1)) >> 18;
        var1 = ((((32768 + var1)) * ((int32_t)bme280cal.dig_p1)) >> 15);

        if (var1 == 0) {
                pressure = 0;
        } else {
                pressure = (((uint32_t)(((int32_t)1048576)-pres_raw)
                        - (var2 >> 12))) * 3125;
                if (pressure < 0x80000000) {
                        pressure = (pressure << 1) / ((uint32_t)var1);
                } else {
                        pressure = (pressure / (uint32_t)var1) * 2;
                }
                var1 = (((int32_t)bme280cal.dig_p9) * ((int32_t)(((pressure>>3) * (pressure >> 3)) >> 13))) >> 12;
                var2 = (((int32_t)(pressure >> 2)) * ((int32_t)bme280cal.dig_p8)) >> 13;
                pressure = (uint32_t)((int32_t)pressure + ((var1 + var2 + bme280cal.dig_p7) >> 4));
        }
}

int16_t bme280GetTemp(void)
{
    return temperature;
}

int16_t bme280GetPressure(void)
{
    return pressure;
}


bme280.h
Спойлер
Код:
#ifndef BME280_H
#define BME280_H

#include <inttypes.h>

#define BME280_ADDR                 0xEC
#define BME280_ID_REG               0xD0
#define BME280_ID_VAL               0x60

// EEPROM calibration addresses
#define BME280_CAL_REG_FIRST        0x88
#define BME280_CAL_REG_LAST         0x9F
#define BME280_CAL_DATA_SIZE        (BME280_CAL_REG_LAST+1 - BME280_CAL_REG_FIRST)

// BME280 registers
#define BME280_CTRL_MEAS            0xF4
#define BME280_CTRL_CONFIG          0xF5

#define BME280_ADC_DATA_START       0xF7
#define BME280_ADC_RAWDATA_BYTES    6    // 3 bytes pressure, 3 bytes temperature

#define BME280_CONV_TIME            50

void bme280Init(void);
uint8_t bme280HaveSensor(void);

void bme280Convert(void);

int16_t bme280GetTemp(void);
int16_t bme280GetPressure(void);
int16_t bme280GetHumidity(void);

#endif // BME280_H
Ответить