Официальный сайт компании Arduino по адресу arduino.cc
Миниатюрный комнатный термометр на Attiny85 c OLED
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Пт, 01/12/2017 - 17:13
Просто маленький термометр/барометр/гигрометр на BME280 и Attiny85
Питается от батареек CR2032, в спящем режиме потребление 7 мкА, в режиме отображения <10мА
Отображение включается кнопкой, и поочередно сменяются значения в течении 38 секунд
#include <TinyOzOLED.h> #include <TinyWireM.h> #include <avr/sleep.h> #define BME280_ADDRESS 0x76 unsigned long int hum_raw, temp_raw, pres_raw; signed long int t_fine; 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; int8_t dig_H1; int16_t dig_H2; int8_t dig_H3; int16_t dig_H4; int16_t dig_H5; int8_t dig_H6; #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // PB0 pin 5 - SDA #define PB0_OUT sbi(DDRB,PB0) #define PB0_IN cbi(DDRB,PB0) #define PB0_HIGH sbi(PORTB,PB0) #define PB0_LOW cbi(PORTB,PB0) // PB1 pin 6 #define PB1_OUT sbi(DDRB,PB1) #define PB1_IN cbi(DDRB,PB1) #define PB1_HIGH sbi(PORTB,PB1) #define PB1_LOW cbi(PORTB,PB1) // PB2 pin 7 - SCL #define PB2_OUT sbi(DDRB,PB2) #define PB2_IN cbi(DDRB,PB2) #define PB2_HIGH sbi(PORTB,PB2) #define PB2_LOW cbi(PORTB,PB2) // PB3 pin 2 - WakeUp KEY #define PB3_OUT sbi(DDRB,PB3) #define PB3_IN cbi(DDRB,PB3) #define PB3_HIGH sbi(PORTB,PB3) #define PB3_LOW cbi(PORTB,PB3) #define PB3_READ bitRead(PINB,PB3) // PB4 pin 3 #define PB4_OUT sbi(DDRB,PB4) #define PB4_IN cbi(DDRB,PB4) #define PB4_HIGH sbi(PORTB,PB4) #define PB4_LOW cbi(PORTB,PB4) boolean firstStart; unsigned long showTimer; unsigned long wakeUpTimer; byte showMode; // 0-temp 1-pres 2-hum boolean changeMode; void writeReg(uint8_t reg_address, uint8_t data) { TinyWireM.beginTransmission(BME280_ADDRESS); TinyWireM.write(reg_address); TinyWireM.write(data); TinyWireM.endTransmission(); } void initBME280() { TinyWireM.begin(); uint8_t osrs_t = 1; //Temperature oversampling x 1 uint8_t osrs_p = 1; //Pressure oversampling x 1 uint8_t osrs_h = 2; //Humidity oversampling x 1 uint8_t mode = 3; //Normal mode uint8_t t_sb = 5; //Tstandby 1000ms uint8_t filter = 0; //Filter off uint8_t spi3w_en = 0; //3-wire SPI Disable uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode; uint8_t config_reg = (t_sb << 5) | (filter << 2) | spi3w_en; uint8_t ctrl_hum_reg = osrs_h; writeReg(0xF2, ctrl_hum_reg); writeReg(0xF4, ctrl_meas_reg); writeReg(0xF5, config_reg); readTrim(); } void resetBME280() { writeReg(0xE0, 0xB6); } signed long int calibration_T(signed long int adc_T) { signed long int var1, var2, T; var1 = ((((adc_T >> 3) - ((signed long int)dig_T1 << 1))) * ((signed long int)dig_T2)) >> 11; var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T >> 4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14; t_fine = var1 + var2; T = (t_fine * 5 + 128) >> 8; return T; } void readTrim() { uint8_t data[32], i = 0; TinyWireM.beginTransmission(BME280_ADDRESS); TinyWireM.write(0x88); TinyWireM.endTransmission(); TinyWireM.requestFrom(BME280_ADDRESS, 24); while (TinyWireM.available()) { data[i] = TinyWireM.read(); i++; } TinyWireM.beginTransmission(BME280_ADDRESS); TinyWireM.write(0xA1); TinyWireM.endTransmission(); TinyWireM.requestFrom(BME280_ADDRESS, 1); data[i] = TinyWireM.read(); i++; TinyWireM.beginTransmission(BME280_ADDRESS); TinyWireM.write(0xE1); TinyWireM.endTransmission(); TinyWireM.requestFrom(BME280_ADDRESS, 7); while (TinyWireM.available()) { data[i] = TinyWireM.read(); i++; } dig_T1 = (data[1] << 8) | data[0]; dig_T2 = (data[3] << 8) | data[2]; dig_T3 = (data[5] << 8) | data[4]; dig_P1 = (data[7] << 8) | data[6]; dig_P2 = (data[9] << 8) | data[8]; dig_P3 = (data[11] << 8) | data[10]; dig_P4 = (data[13] << 8) | data[12]; dig_P5 = (data[15] << 8) | data[14]; dig_P6 = (data[17] << 8) | data[16]; dig_P7 = (data[19] << 8) | data[18]; dig_P8 = (data[21] << 8) | data[20]; dig_P9 = (data[23] << 8) | data[22]; dig_H1 = data[24]; dig_H2 = (data[26] << 8) | data[25]; dig_H3 = data[27]; dig_H4 = (data[28] << 4) | (0x0F & data[29]); dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); dig_H6 = data[31]; } ISR(PCINT0_vect) { if (PB3_READ == 0) { // LOW level KEY sleep_disable(); cbi(GIMSK, PCIE); cbi(PCMSK, PCINT3); } } void toSleep() { // pins mode PB0_IN; PB0_LOW; PB1_OUT; PB1_LOW; PB2_IN; PB2_LOW; PB3_IN; PB3_HIGH; // LOW = OFF res, if HIGH level KEY PB4_OUT; PB4_LOW; // sleep cbi(ADCSRA, ADEN); set_sleep_mode (SLEEP_MODE_PWR_DOWN); sleep_enable(); sbi(GIMSK, PCIE); sbi(PCMSK, PCINT3); sleep_mode(); } void setup () { firstStart = true; } void readData() { int i = 0; uint32_t data[8]; TinyWireM.beginTransmission(BME280_ADDRESS); TinyWireM.write(0xF7); TinyWireM.endTransmission(); TinyWireM.requestFrom(BME280_ADDRESS, 8); while (TinyWireM.available()) { data[i] = TinyWireM.read(); i++; } pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); hum_raw = (data[6] << 8) | data[7]; temp_raw = calibration_T(temp_raw); pres_raw = (calibration_P(pres_raw) / 133.32) - 5; hum_raw = calibration_H(hum_raw) / 1024; } void loop () { unsigned long curr_millis = millis(); if (firstStart) { toSleep(); firstStart = false; wakeUpTimer = curr_millis; showMode = 0; showTimer = curr_millis; changeMode = true; // get data from BME280 initBME280(); readData(); resetBME280(); OzOled.init(); //инициализация дисплей OzOled.setNormalDisplay(); //нормальный режим OzOled.setPageMode(); //адресация страничная OzOled.sendCommand(0xA1); //выбор ориентации сверху - вниз OzOled.sendCommand(0xC8); //слева - направо } // work if ((curr_millis - showTimer) >= 4000UL) { // change disp every 4 sec showTimer = curr_millis; changeMode = true; ++showMode; if (showMode > 2) { showMode = 0; } } if (changeMode) { OzOled.clearDisplay(); //очистка дисплея switch (showMode) { case 1: { char str[4] = ""; str[0] = (pres_raw / 100) + 0x30; str[1] = (pres_raw % 100) / 10 + 0x30; str[2] = (pres_raw % 100) % 10 + 0x30; str[3] = 0x00; OzOled.printBigNumber(str, 3, 0); break; } case 2: { /*char str[6] = ""; str[0] = (hum_raw / 10000) + 0x30; str[1] = (hum_raw % 10000)/1000 + 0x30; str[2] = ((hum_raw % 10000)%1000)/100 + 0x30; str[3] = (((hum_raw % 10000)%1000)%100)/10 + 0x30; str[4] = (((hum_raw % 10000)%1000)%100)%10 + 0x30; str[5] = 0x00;*/ char str[3] = ""; str[0] = hum_raw / 10 + 0x30; str[1] = hum_raw % 10 + 0x30; str[2] = 0x00; OzOled.printBigNumber(str, 6, 0); break; } default: { // show temp char str[6] = ""; str[0] = (temp_raw / 1000) + 0x30; str[1] = (temp_raw % 1000) / 100 + 0x30; str[2] = '.'; str[3] = ((temp_raw % 1000) % 100) / 10 + 0x30; str[4] = ((temp_raw % 1000) % 100) % 10 + 0x30; str[5] = 0x00; OzOled.printBigNumber(str, 0, 0); } } changeMode = false; } // OFF show data if ((curr_millis - wakeUpTimer) >= 39000UL) { // show 39 sec firstStart = true; // OFF display OzOled.setPowerOff(); // OFF BME } } unsigned long int calibration_P(signed long int adc_P) { signed long int var1, var2; unsigned long int P; var1 = (((signed long int)t_fine) >> 1) - (signed long int)64000; var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((signed long int)dig_P6); var2 = var2 + ((var1 * ((signed long int)dig_P5)) << 1); var2 = (var2 >> 2) + (((signed long int)dig_P4) << 16); var1 = (((dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + ((((signed long int)dig_P2) * var1) >> 1)) >> 18; var1 = ((((32768 + var1)) * ((signed long int)dig_P1)) >> 15); if (var1 == 0) { return 0; } P = (((unsigned long int)(((signed long int)1048576) - adc_P) - (var2 >> 12))) * 3125; if (P < 0x80000000) { P = (P << 1) / ((unsigned long int) var1); } else { P = (P / (unsigned long int)var1) * 2; } var1 = (((signed long int)dig_P9) * ((signed long int)(((P >> 3) * (P >> 3)) >> 13))) >> 12; var2 = (((signed long int)(P >> 2)) * ((signed long int)dig_P8)) >> 13; P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4)); return P; } unsigned long int calibration_H(signed long int adc_H) { signed long int v_x1; v_x1 = (t_fine - ((signed long int)76800)); v_x1 = (((((adc_H << 14) - (((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) + ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) * (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) * ((signed long int) dig_H2) + 8192) >> 14)); v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4)); v_x1 = (v_x1 < 0 ? 0 : v_x1); v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1); return (unsigned long int)(v_x1 >> 12); }
Классный проект, нужный. У мня такой жэ, маленько проще, на 27 строчек кода. И тока мой на улице валяеца. С баторейкой на 9 Вольт. И жена пилит, когда я буквы побольше сделаю. А мне лень. :)
дома тупо термометра и барометра нет - вот и собрал из того что было, осталось в спичесный коробок засунуть
поторопился я выкладывать :( - нашел серъезную ошибку, исправленый текст ниже.
влажность показывает странную - 33...34% но мне она не нужна , потому не разбирался.
также с моим OLED дисплеем из Китая не заработала стандартная библиотека TinyOzOLED - пришлось ее корректировать - если кого заинтересует - выложу.
Надо попробовать повторить :) а какую плату вы выбираете в иде?
ATtiny85 @ 1 MHz (internal oscillator; BOD disabled)
Понятно ... что-то с библиотеками ... буду разбираться
Понятно ... что-то с библиотеками ... буду разбираться
в смысле? там все просто - распаковывайте архив с tiny библиотеками в hardware и все, поищите поиском Arduino as ISP для ATtiny
Микроконтроллер я уже установил, ругается на бибилиотеку для барометра, возможно я не самую свежую скачал
Микроконтроллер я уже установил, ругается на бибилиотеку для барометра, возможно я не самую свежую скачал
Текст ошибки чтоль показали бы....
это ошибка библиотеки барометра? вы собираетесь барометр BME280 из библиотеки использовать? не хочу вас расстраивать - ничего не получиться - памяти МК не хватит - только напрямую командами - на ГитХабе масса примеров, мой скетч в основном отттуда.
ЗЫ. хотел добавить мелкий текст - тпа градусов цельсия или мм рт столба - не влезло, сейчас занимает 94 % памяти контроллера.
Так как вы тогда компилировали то, что выложили? Ладно, спасибо, разберемся ... еще индикатор нужно заказать в китае ... просто на будущее
Так как вы тогда компилировали то, что выложили? Ладно, спасибо, разберемся ... еще индикатор нужно заказать в китае ... просто на будущее
не понял вопроса, так и компилировал - в ардуино ИДЕ выбрал меню загрузить через программатор - он загрузил в Attiny85
Если при компиляции возникают ошибки, как же можно загрузить в мк?
Если при компиляции возникают ошибки, как же можно загрузить в мк?
у меня не было ошибок :)
итак по пунктам:
1 скачиваете с гитраб библиотеку Tinywirem - устанавливаете
2. аналогично TinyOzOled
3. выбираете плату Attiny85
все должно скомпилироваться, если нет - как то не правильно все поставили
Все, обновил бибилиотеку, скомпилировалось без ошибок ....
91% программная память
91% программная память
у меня TinyOzOled библиотека исправлена, потому и размер другой, если с вашим дисплеем (128*32) будет аналогичная проблема как у меня (знаки сплюснуты были) - тогда скину исправленную.
Ок ... ну осталось дело за малым, чтобы по коду не рисовать схему, возможно позволите на нее взглянуть :)
а у меня нет схемы :)
и с стоках 034..058 все же написано, там тупо три контакта МК только использовано
я так и думал ... :) ладно, нарисую сам
Здравствуйте!
Не подскажете, как полусенные Вами измерения отправить на RF передатчик 433Мгц ?
Для экономии памяти тиньки можно было бы отправить *_raw данные, а на стороне приемника их уже причесать.
Спасибо!
http://arduino.ru/forum/ishchu-ispolnitelya/proshu-pomoshchi-s-kodom-dly...
Спасибо огромное!
http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-displeya-128kh64-s-kirillitsei-utf-8
Не?
http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-displeya-128kh64-s-kirillitsei-utf-8
Не?
Куча ошибок при загрузке в 85
Не Digispark