Меньше точно не бывает! Делаем вольтметр на ATTINY10

В продолжение к прошлой статье решил пощупать и Attiny10. Ну меньше уже точно ничего нет. Если и есть такое извращение с менее чем 6 ногами, я о нем не знаю, точнее не нашел.

.Тут у нас полноценный МК, в корпусе SOT-23–6! И задачи на нем решать можно вполне серьезные. Собрав схему на макетке с МК на адаптере и модулем дисплея я было обрадовался, но готовая плата работать отказалась…

А как, а что…

Маааленький!Маааленький!

Attiny10 самый маленький МК, из AVR точно (не пугайтесь картинке, Microchip купила Atmel). Но характеристики у него вполне серьезные. Частота до 12МГц, 1кБ флэш и 32 байта оперативной памяти. Для корпуса SOT-23–6 это, согласитесь, не мало. Но самым главным плюсом наряду с размерами является энергопотребление, которое составляет всего 2.7–4 мА при 8МГц и 5В питания, или всего 0.2–0.4 мА при 1МГц и питании 1.8В.

4886111543511214ca2e7c56f7c56f4c.png

Есть даже АЦП и ШИМ. Все характеристики вы можете посмотреть в даташите. Есть у тини10 и младшие братья ATTINY4, 5 и 9. У 4 и 9 нет АЦП, у 4 и 5 к тому же всего 512 байт флэш.

b1580efe8cc293fc952acc7993b7d14f.png

Программирование

Программируются эти малыши по интерфейсу TPI- Tiny Programming Interface. Но как бы страшно это не звучало, этот интерфейс поддерживается программатором USBasp, естественно он должен быть прошит последней версией по ссылке выше. Подключение:

8080674ebf125ee69ea678e85b95660b.gif

Программирование поддерживается при питании 5В, так что не забудьте переключить программатор в этот режим.

ПО я писал и заливал в среде Ardiono IDE. Для самых маленьких аттини есть ядро. Правда про библиотеки думаю можно забыть, тут только хардкор поместится.

Возможные траблы

98681ee35bf660cbf06eb9e592290c07.jpeg

Сначала я собрал схему на макетке, чтобы отладить прошивку. Разъема для программирования на плате я не предусмотрел, да и дисплей наверное не пережил бы питания в 5В. Тут из проблем встречалось только то что где-то после 20й прошивки начались с этой самой прошивкой проблемы, которая прошивалась только на 2–3–4 раз. Вероятно это связано с моим железом.

После сборки платы вроде все заработало, но при втором включении я уже увидел шум на дисплее вместо данных. В первую очередь я заменил всю обвязку дисплея, но это не помогло. Программные ухищрения тоже. Еще раз прогуглив варианты обвязки- заметил что часто встречается аппаратная задержка на RESET дисплея. Ее добавление и решило проблему.

Схема

3700b5e2d9e97b8d2201d100e986e26a.png

По больше части схема повторяет прошлую. Тут только добавлен С2 и защита от превышения напряжений. Так если по питанию придет больше 12В, на которые рассчитан MCP1703- некоторый диапазон отработает параметрический стабилизатор R3 D3, а при дальнейшем превышении R3 сгорит как предохранитель. Так-же в линию АЦП добавлен стабилитрон D1.

Делитель с плечем 3.5 позволяет измерить до 3.5×3.3=11.55В. При раздельном питании и измеряемом напряжении диапазон получается 0–11.55В. Если объединить питание и вход диапазон 4–12В. Это обусловлено тем что опорное напряжение ATTINY10 берет равным линии питания, которая здесь 3.3В плюс падение на стабилизаторе. Итого шаг на значение АЦП 11.55/255=0.045В.

Плата

16d35aff6ee7ab5b34053b214acd4c99.png

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

Собранная платаСобранная плата

Дисплей просто приклеил на двусторонний скотч.

e3d84b9bc3cb8de789e0c149bae68bb9.jpeg

Программа

ПО по большей части позаимствовано здесь и здесь. Итого ПО занимает всего 912 байт.

Код


uint8_t AD;
uint16_t VOLT;

const uint8_t Init[24] = {
  0xAE,         // Display OFF
  0xA8, 0x1F,   // set multiplex (HEIGHT-1): 0x1F for 128x32, 0x3F for 128x64
  0x22, 0x00, 0x03, // Page min to max
  0x20, 0x01,   // Memory addressing mode 0x00 Horizontal 0x01 Vertical
  0xDA, 0x02,   // Set COM Pins hardware configuration to sequential
  0x8D, 0x14,   // Charge pump enabled
  0xD3, 0x00,   // Display offset to 0
  0x81, 0xFF,   // Set contrast
  0xD9, 0xF1,   // Set pre-charge period
  0xDB, 0x40,   // Set vcom detect
  0x21, 0x00, 0x7F, // Column min to max
  0xAF,  // Display on

};

#define PI2C_SDA    PB0
#define PI2C_SCL    PB1

#define OUT_REG PORTB


#define SDA_ON (OUT_REG |= (1<< PI2C_SDA))
#define SDA_OFF (OUT_REG &= ~(1<< PI2C_SDA))
#define SCL_ON (OUT_REG |= (1<< PI2C_SCL))
#define SCL_OFF (OUT_REG &= ~(1<< PI2C_SCL))

#define SDA_READ (PINB & (1<

Шрифт и отрисовка

const uint8_t OLED_FONT[] PROGMEM = {
  0x7F, 0x41, 0x7F, // 0  0
  0x00, 0x00, 0x7F, // 1  1
  0x79, 0x49, 0x4F, // 2  2
  0x41, 0x49, 0x7F, // 3  3
  0x0F, 0x08, 0x7E, // 4  4
  0x4F, 0x49, 0x79, // 5  5
  0x7F, 0x49, 0x79, // 6  6
  0x03, 0x01, 0x7F, // 7  7
  0x7F, 0x49, 0x7F, // 8  8
  0x4F, 0x49, 0x7F, // 9  9
  0x00, 0x60, 0x00, // .  10
  0x1F, 0x78, 0x1F, // V  11
  0x00, 0x00, 0x00, // -  12
  
};



void OLED_printB(uint8_t *buffer) {
  start();
  Tx(ADDR);
  Tx(0x40);
  for (uint8_t i = 0; i < 8; i++) OLED_printD(buffer[i]); // print buffer
  stop();                          // stop transmission
  
}



uint8_t OLED_stretch(uint8_t b) {
  b  = ((b & 2) << 3) | (b & 1);          // split 2 LSB into the nibbles
  b |= b << 1;                            // double the bits
  b |= b << 2;                            // double them again = 4 times
  return b;                               // return the value
}


void OLED_printD(uint8_t ch) {
  uint8_t i, j, k, b;                     // loop variables
  uint8_t sb[4];                          // stretched character bytes
  ch += ch << 1;                          // calculate position of character in font array
  for (i = 8; i; i--) Tx(0x00);    // print spacing between characters
  for (i = 3; i; i--) {                   // font has 3 bytes per character
    b = OLED_FONT[ch++]; // read character byte
    for (j = 0; j < 4; j++, b >>= 2) sb[j] = OLED_stretch(b); // stretch 4 times
    j = 4; if (i == 2) j = 6;             // calculate x-stretch value
    while (j--) {                      // write several times (x-direction)
      for (k = 0; k < 4; k++) Tx(sb[k]); // the 4 stretched bytes (y-direction)
    }
  }
}

Работа с I2C


/*  i2c start sequence */
void start() {
  SDA_ON;
  dly();
  SCL_ON;
  dly();
  SDA_OFF;
  dly();
  SCL_OFF;
  dly();
}


/*  i2c stop sequence */
void stop() {
  SDA_OFF;
  dly();
  SCL_ON;
  dly();
  SDA_ON;
  dly();
}

/* Transmit 8 bit data to slave */
bool Tx(uint8_t dat) {
  for (uint8_t i = 0; i < 8; i++) {
    (dat & 0x80) ? SDA_ON : SDA_OFF;
    dat <<= 1;
    dly();
    SCL_ON;
    dly();
    SCL_OFF;
    
  }

  SDA_ON;
  SCL_ON;
  dly();
  bool ack = !SDA_READ;    // Acknowledge bit
  SCL_OFF;
  return ack;
}

Файлы

Файлы на гитхаб https://github.com/ENGIN33RRR/Attiny10_VoltMeter

Схема и ПП в диптрейс, прошивка в Arduino IDE.

© Habrahabr.ru