Часы на светодиодных матрицах с драйверами MAX7219
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Ну кто ж вам запретит?
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Вроде разобрался как сделать. Не знаю правильно или нет, но работает.
В файле bmp180.c сделал изменения. Калибровочная величина записывается в 0x19 байт eeprom. Можно уходить в обе стороны.
Выкладываю код. Может кому пригодится и автор покритикует...
В файле 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;
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Немножко покритикую.
1. Лучше в eeprom.h добавить макрос, по аналогии с другими ячейками.
2. Коррекцию проводить не в драйвере bmp180, а непосредственно при выводе на экран. Т.е., в функции loadTempString(), там где вызывается bmp180GetPressure().
3. К коррекции лучше добавить +1. Тогда значение ячейки eeprom по умолчанию (0xFF = -1) будет как бы нулём и не будет влиять на показания.
1. Лучше в eeprom.h добавить макрос, по аналогии с другими ячейками.
2. Коррекцию проводить не в драйвере bmp180, а непосредственно при выводе на экран. Т.е., в функции loadTempString(), там где вызывается bmp180GetPressure().
3. К коррекции лучше добавить +1. Тогда значение ячейки eeprom по умолчанию (0xFF = -1) будет как бы нулём и не будет влиять на показания.
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Спасибо за критику. По поводу eeprom.h сразу хотел так сделать. Но не смог реализовать, так как не хватает знаний и опыта в программировании. Потихоньку изучаю...
Добавил в eeprom.h строку #define EEPROM_BMP180CORR 0x19. Теперь разбираюсь как извлечь для подстановки сюда -> eeprom_read_byte((uint8_t*)0x19);
Добавил в eeprom.h строку #define EEPROM_BMP180CORR 0x19. Теперь разбираюсь как извлечь для подстановки сюда -> eeprom_read_byte((uint8_t*)0x19);
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Ну вот вместо 0x19 и вставлять.
Вчера попробовал собрать код более новыми версиями компилятора - не получается влезть в 8 килобайт. Надо бы сесть и немного оптимизацией заняться...
Вчера попробовал собрать код более новыми версиями компилятора - не получается влезть в 8 килобайт. Надо бы сесть и немного оптимизацией заняться...
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Чудеса
раньше так делал и не получалось, а теперь после подсказки все собралось. Наверное допустил синтаксическую ошибку. Спасибо, WiseLord, за подсказку!
Тоже пробовал собирать avr-gcc-5.4.0 - не влезает. Сейчас в VirtualBox Debian 9 avr-gcc-4.9.2 и пока помещаюсь - ровно 8192.
Код: Выделить всё
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.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Попробовал немного оптимизировать код - вроде как с сотню байт удалось выжать. Залил исходники на Github
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Да, реально уменьшился код. Спасибо!
А можно еще вопрос? Хочу изменить ширину пробела до 2-х символов (0x00, 0x00, VOID, VOID, VOID). Но во всех настройках портится первый символ и бегущая строка раньше обрывается. Не подскажете где копать?
Код: Выделить всё
AVR Memory Usage:
Program: 8122 bytes (.text + .data)
Data: 591 bytes (.data + .bss)- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
При выводе цифр есть фишка - все они должны быть одной ширины, такой же как и пробел - чтобы было проще реализовать разного рода мигания и скроллинги. Поэтому простым способом, наверное, не получится сделать.
Хотя можете попробовать.
В коде есть несколько вызовов типа 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).
Хотя можете попробовать.
В коде есть несколько вызовов типа 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).
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Спасибо за подробные разъяснения
На выходных будет чем заняться.
На выходных будет чем заняться.
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
[uquote="WiseLord",url="/forum/viewtopic.php?p=3835223#p3835223"]В общем, идея следующая. Найти по коду эти вызовы, там где они вызываются с пробелом. Вместо пробела подставить другой символ, например 0xBE. Сейчас он не используется (в font-cp1251-08.c), и там идёт сплошная заливка знакоместа, если вдруг такой символ встретится.
Нужно отрисовать этот символ в пробел (0x00, 0x00, 0x00, 0x00, VOID), и вызывать теперь mkNumberString(value, 2, 0xBE); Тогда все статичные цифры будут отображаться как раньше, без сдвигов. А уже основной пробел можно обрезать до двух-трёх пикселов.[/uquote]
Сделал все следуя Вашим разъяснениям. Считаю, получилось
Но немного по-другому...
Вместо пробела и в коде (там где он используется), и в надписях использовал символ "]" 0x5D. Так проще писать когда нужно в редакторе eeprom использовать "короткий пробел".
Благодарю!
Нужно отрисовать этот символ в пробел (0x00, 0x00, 0x00, 0x00, VOID), и вызывать теперь mkNumberString(value, 2, 0xBE); Тогда все статичные цифры будут отображаться как раньше, без сдвигов. А уже основной пробел можно обрезать до двух-трёх пикселов.[/uquote]
Сделал все следуя Вашим разъяснениям. Считаю, получилось
Вместо пробела и в коде (там где он используется), и в надписях использовал символ "]" 0x5D. Так проще писать когда нужно в редакторе eeprom использовать "короткий пробел".
Благодарю!
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
WiseLord, пожалуйста, подскажите как реализована функция записи и чтения байта?
Например, записать в устройство 0x76, адрес 0xF5, значение 0xA0.
Например, записать в устройство 0x76, адрес 0xF5, значение 0xA0.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Про какие устройства и адреса речь?
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Датчик BME280 его ID на шине 0x76. Записать по адресу 0xF5 значение 0xA0.
Есть желание попробовать написать драйвер для него...
Есть желание попробовать написать драйвер для него...
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Код: Выделить всё
I2CswStart(0x76);
I2CswWriteByte(0xF5);
I2CswWriteByte(0xA0);
I2CswStop();- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Спасибо. Буду заниматься...
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Нужно извлечь последовательность из 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);Так должно работать?
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Да. Если у bme280 именно такая адресация на чтение.
Разве что вторым параметром я бы uint8_t *buff сделал, а не массив.
Разве что вторым параметром я бы 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();
}- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Как пример использую этот исходник - https://github.com/Yenya/avr-bmp280/blo ... 0/bmp280.c
- dark
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Ср июн 04, 2008 00:22:30
- Откуда: Украина, Ковель
- Контактная информация:
Re: Часы на светодиодных матрицах с драйверами MAX7219
Пока написал только температуру и давление. Сначала не мог понять почему не инициализировался датчик. Потом посмотрел как сделано чтение в rtc.c и поменял местами команды I2C_ACK, I2C_NOACK. Заработало.
Формула расчета очень громоздкая. А если ее привести требуемым значениям, то вовсе не влазит в 8kb.
bme280.c
bme280.h
Формула расчета очень громоздкая. А если ее привести требуемым значениям, то вовсе не влазит в 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