Охотно принимаю. На мой взгляд, это актуально, буду принимать участие в обсуждении. Вместе мы сможем прийти к правильному ответу.
Охотно принимаю. На мой взгляд, это актуально, буду принимать участие в обсуждении. Вместе мы сможем прийти к правильному ответу.
От ЕЖА планирую отказаться - разочаровал сложностями со шлейфом и траблами с питанием при запуске движка. Также экран ужасно слепнет на ярком солнце, что не есть гуд.
Поэтому назревает версия 3:
Заказал себе зверя teensy++ 2.0
Ссылку не буду давать, дабы не сочли за рекламу, гугл легко находит.
Оно практически как Ардуино Мега (128 K памяти для программ), но намного меньше размером и имеет встроенный АППАРАТНЫЙ USB (дает возможности подключения намного шире, чем Arduino).
Программно совместимо с Ардуино.
Также имеет РАЗДЕЛЬНЫЙ UART и USB, что позволяет отлаживать взаимодействие с UART через USB дебажную консоль.
Хочу подключить к нему Блютуз модуль (уже едет)
http://cgi.ebay.com/Wireless-Bluetoo...item1e61cf0e5d
И в резульnате получить девайс, которым можно рулить БЕЗ дров, через HID профиль из Винды (до конца не понятен этот момент),
через Serial (SPP) Bluetooth c ЛЮБОГО андроид девайса, а также локально через матрицу кнопок и ИК-пульт.
Учитывая 128 К памяти для программ и бездну ног (38) для периферии, открываются почти неограниченные возможности.
Сейчас моя буйная фантазия придумала:
1. Часы - DS1307
2. Управление климатом (винда/кнопки/андроид) - температура, скорость потока, направление потока, включение, рециркуляция - просто панель к существующему неказистому климату с крутелками (но управляемым электрическими сигналами) + серво-мотор для изменения потоков воздуха (PWM).
3. Термометр внутри салона / внешний (винда/кнопки/андроид) - 1-wire 2 x DS18B20.
4. Управление 2 подогревами сидений (винда/кнопки/андроид) - раздельное включение, регулировка температуры отключения - 1-wire 2 x DS18B20.
5. Управление радио (винда/кнопки/андроид) - настройки, поиск? - LM7001 + блок от автомагнитолы.
6. Управление предусилителем (винда/кнопки/андроид) - коммутация источников, громкость, баланс, громкость тыловых каналов, задержка включения усилителя, маппинг стерео в 4 канала - I2C - TDA7313.
7. Управление питанием андроид-устройства - ждущий/рабочий от ACC
Для автономной работы будет отдельный ЖКИ-экран через SPI или 4-битный (EADOGM162S-A ?
http://www.lcd-module.com/products/dog.html) и матрица кнопок. Также часть функций будет управляться через нарульный ИК-пульт (RC5 / Sony / NEC ?), ИК-приемник тоже подключается к teensy.
Планирую создать также Андроид-оболочку а-ля Центрифуга, но с возможностью расширения и руления ВСЕМИ функциями + возможностью запуска внешних приложений типа Навитела внутри оболочки.
Оболочка также будет иметь как минимум Lossless плеер с поддержкой внешнего HDD и чтением CUE (PowerAMP? или что-то свое), а также видеоплеер на популярные форматы.
Возможно, позже будет аналогичное что-то под Винду как отдельная апликуха или плагин к ЦФ.
Надеюсь, мощности проца хватит для поставленных задач.
Планшет будет использоваться Huawei S7. Его Снапдрагон должен быть достаточен для поставленной задачи
Как с реализацией всего перечисленного?
Что уже сделано?
в принципе, в бета версии уже почти все работает из андроида, что хотелось.
1. Часы попробовал - работают - убрал пока, так как непонятно куда их выводить.
2-6 сделано
7. Застрял на управлении питанием планшета - хочется, чтобы ACC включал-выключал планшет. С этим засада пока - загнать в сон могу, вытащить обратно - нет.
Есть управление с ИК пультов на руле - 2 шт.
Пока нет управления автономного и ЖК, так как непонятно, где их разместить на морде, но поцепить их к ардуине не проблема - ноги есть, дописать децл скетч.
Плеер играет LOSSLESS (не PowerAmp, свой), но есть проблема с автомонтированием винта при старте планшета. Навител работает нормально, только есть проблема - ругается при старте, если отключить питание насильно - нужно более умное отключение - Андроид,гад не дает это нормально сделать не системных программам. Над этим думаю сейчас.
Если интересно, могу сюда выложить наработки, может кто-то захочет присоединиться.
Сейчас идет концептуальная ломка - попробую заменить планшет на коробочку с TCC8902 (ARM11), в связи с этим часть функций уйдет с тачскрина на кнопки и ЖКИ, а экран будет несенсорный (зеркало заднего вида) с вытекающими...
Знаю, что это олдскульно, но МНЕ показалось так удобнее, чем пытаться на ходу что-то разглядеть на тачскрине, который довольно низко расположен.
Последний раз редактировалось s.m.; 12.10.2011 в 13:41.
Выкладываю последний актуальный релиз моего Autolauncher
AutoLauncher.zip
под Android 2.1+ и 800x480
Требует установленного Amarino, Andless и Navitel.
Для плеера нужен готовый плейлист /sdcard/Favorites.playlist ,
созданный при помощи Andless
Скриншоты
http://www.flickr.com/photos/6933831...7627906524675/
Последний раз редактировалось s.m.; 02.11.2011 в 04:24.
Схема проекта, фотки железа и скриншоты оболочки
http://www.flickr.com/photos/69338318@N06
Рассчитана на подключение к магнитоле, заточенной под синтезатор частоты и аудиопроцессор TDA7318, радио реализовано на LM7001
Скетч для Teensy 2.0 ++
В новой версии (в работе) Ethernet модуль заменит Bluetooth, а планшет Huawei S7 - на Android TV BOX (http://www.pandawill.com/x1-mini-and...ck-p49624.html)Код HTML:#include <IRremote.h> #include <OneWire.h> #include <DallasTemperature.h> #include <Wire.h> #include <SPI.h> #include <MeetAndroid.h> #define HEATER1 19 //#define HEATER1 6 #define HEATER2 41 #define AMP_ON 16 #define AUDIO_MUTE 17 #define AD_SELECT 20 // Data wire is plugged into pin 25 on the Arduino #define ONE_WIRE_BUS 25 const int RECV_PIN = 26; #define FAN_DIRECTION_PWM 27 #define POWER_SWITCH 38 #define AUDIO_ON 44 #define ACC 45 #define CLIMATE_POWER 42 #define CLIMATE_REC 43 #define DS1307_I2C_ADDRESS 0x68 #define TDA7318_I2C_ADDRESS 0x44 #define TDA_SW1 0x58 #define TDA_SW2 0x59 #define TDA_SW3 0x5A #define TDA_SW4 0x5B // LM pins #define LM_CE 14 //LM7001 PIN3 #define LM_CL 13 //LM7001 PIN4 #define LM_DA 12 //LM7001 PIN5 // LM delay in microsec #define LM_DELAY 2 #define RADIO_MIN_FREQUENCY 880 #define RADIO_MAX_FREQUENCY 1080 DeviceAddress intTempSensor = { 0x28, 0x44, 0x0A, 0xD8, 0x02, 0x00, 0x00, 0x58 }; DeviceAddress extTempSensor = { 0x28, 0xA8, 0xE4, 0x7D, 0x02, 0x00, 0x00, 0x5C }; DeviceAddress hlTempSensor = { 0x28, 0x7C, 0xDF, 0xD7, 0x02, 0x00, 0x00, 0x02 }; DeviceAddress hrTempSensor = { 0x28, 0xB6, 0x1A, 0x7E, 0x02, 0x00, 0x00, 0x98 }; byte climateTempMap[] = {255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,225,200, 175,150,130,105,80,60,40,0x00}; byte climateFanMap[] = {0,16,32,48,64,80,96,112,128,144, 160,176,192,208,224,255}; byte climateDirectionMap[] = {0,0,64,128,255}; byte volMap[] = {0x3F,0x3D,0x3B,0x39,0x37,0x35,0x33,0x31, 0x2F,0x2D,0x2B,0x29,0x27,0x25,0x23,0x21, 0x1F,0x1D,0x1B,0x19,0x17,0x15,0x13,0x11, 0x0F,0x0D,0x0B,0x09,0x07,0x05,0x03,0x00}; byte lfAttMap[] = {0x9F,0x9D,0x9B,0x99,0x97,0x95,0x93,0x91, 0x8F,0x8D,0x8B,0x89,0x87,0x85,0x83,0x80}; byte rfAttMap[] = {0xBF,0xBD,0xBB,0xB9,0xB7,0xB5,0xB3,0xB1, 0xAF,0xAD,0xAB,0xA9,0xA7,0xA5,0xA3,0xA0}; byte lrAttMap[] = {0xDF,0xDD,0xDB,0xD9,0xD7,0xD5,0xD3,0xD1, 0xCF,0xCD,0xCB,0xC9,0xC7,0xC5,0xC3,0xC0}; byte rrAttMap[] = {0xFF,0xFD,0xFB,0xF9,0xF7,0xF5,0xF3,0xF1, 0xEF,0xED,0xEB,0xE9,0xE7,0xE5,0xE3,0xE0}; byte bassMap[] = {0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x6F, 0x6E,0x6D,0x6C,0x6B,0x6A,0x69,0x68}; byte trebleMap[] = {0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x7F, 0x7E,0x7D,0x7C,0x7B,0x7A,0x79,0x78}; byte currentVolume = 16; byte currentHeaterOff1 = 0; byte currentHeaterOn1 = 0; byte currentHeaterOff2 = 0; byte currentHeaterOn2 = 0; int heaterTimer1 = 0; int heaterTimer2 = 0; OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); IRrecv irrecv(RECV_PIN); decode_results results; MeetAndroid meetAndroid; HardwareSerial Uart = HardwareSerial(); void setup() { Uart.begin(9600); Serial.begin(9600); setCallbacks(); initTempSensors(); initTda(); initLM(); initAd(); initHeaters(); initIR(); pinMode(CLIMATE_POWER, OUTPUT); pinMode(CLIMATE_REC, OUTPUT); pinMode(POWER_SWITCH, OUTPUT); digitalWrite(POWER_SWITCH, LOW); pinMode(FAN_DIRECTION_PWM, OUTPUT); pinMode(AMP_ON, OUTPUT); pinMode(AUDIO_ON, OUTPUT); pinMode(AUDIO_MUTE, OUTPUT); } void loop() { meetAndroid.receive(); // you need to keep this in your loop() to receive events receiveIR(); if (heaterTimer1 == 10000) { checkHeater1(); heaterTimer1 = 0; } if (heaterTimer2 == 15000) { checkHeater2(); heaterTimer2 = 0; } heaterTimer1++; heaterTimer2++; } void setCallbacks() { meetAndroid.registerFunction(getInternalTemperature, 'A'); //Internal temperature: 1 meetAndroid.registerFunction(setAudioBalance, 'B'); //Audio balance: 0-15 meetAndroid.registerFunction(setClimatePower, 'C'); //Climate power: 1-ON, 0-OFF meetAndroid.registerFunction(setClimateFanDirection, 'D'); //Climate fan direction: 1-direction 1, 2-direction 2, 3-direction 3, 4-direction 4 meetAndroid.registerFunction(getExternalTemperature, 'E'); //External temperature: 1 meetAndroid.registerFunction(setClimateFanSpeed, 'F'); //Climate fan speed: 0-15 meetAndroid.registerFunction(setHeaterOnTemperature1, 'G'); //Heater temp 1 ON: 25-ON, 0-OFF meetAndroid.registerFunction(setHeaterOnTemperature2, 'H'); //Heater temp 2 ON: 25-ON, 0-OFF meetAndroid.registerFunction(setClimateRecirculation, 'I'); //Climate internal recirculation: 1-ON, 0-OFF meetAndroid.registerFunction(setAudioBass, 'J'); //Audio bass: 0-14 meetAndroid.registerFunction(setAudioTreble, 'K'); //Audio treble: 0-14 meetAndroid.registerFunction(setAudioRearLeftVolume, 'L'); //Audio rear left volume: 0-15 meetAndroid.registerFunction(setAudioMute, 'M'); //Audio mute: 1-ON, 0-OFF meetAndroid.registerFunction(setHeaterOffTemperature1, 'N'); //Heater temp 1 OFF: 25-OFF, 0-OFF meetAndroid.registerFunction(setHeaterOffTemperature2, 'O'); //Heater temp 2 OFF: 25-OFF, 0-OFF meetAndroid.registerFunction(setPowerState, 'P'); //Power state: 1-ON, 0-OFF meetAndroid.registerFunction(setRadioFrequency, 'R'); //Radio frequency: (880-1080)-ON, 0-OFF meetAndroid.registerFunction(setAudioSource, 'S'); //Audio source: 2-radio, 3-music meetAndroid.registerFunction(setClimateTemperature, 'T'); //Climate temperature: 18-26 meetAndroid.registerFunction(getCarVoltage, 'U'); //Car voltage: 1 meetAndroid.registerFunction(setAudioVolume, 'V'); //Audio volume: 0-31 meetAndroid.registerFunction(setAudioRearRightVolume, 'X'); //Audio rear right volume: 0-15 meetAndroid.registerFunction(getHeaterTemperature1, 'Y'); //Heater 1 meetAndroid.registerFunction(getHeaterTemperature2, 'Z'); //Heater 2 } void initTempSensors() { sensors.begin(); // set the resolution to 9 bit sensors.setResolution(intTempSensor, 9); sensors.setResolution(extTempSensor, 9); sensors.setResolution(hlTempSensor, 9); sensors.setResolution(hrTempSensor, 9); } void initTda() { sendAudioMute(1); sendAudioOn(1); delay(3000); sendAmpOn(1); Wire.begin(); // join i2c bus (address optional for master) sendAudioVolume(16); sendAudioLFAttenuator(15); sendAudioRFAttenuator(15); sendAudioLRAttenuator(15); sendAudioRRAttenuator(15); sendAudioSwitch(3); sendAudioBass(7); sendAudioTreble(7); sendAudioMute(0); } void initLM() { pinMode(LM_CE, OUTPUT); pinMode(LM_CL, OUTPUT); pinMode(LM_DA, OUTPUT); } void initAd(){ pinMode(AD_SELECT, OUTPUT); SPI.begin(); } void initHeaters() { pinMode(HEATER1, OUTPUT); pinMode(HEATER2, OUTPUT); } void initIR() { irrecv.enableIRIn(); irrecv.blink13(true); } void receiveIR() { if (irrecv.decode(&results)) { char buf[50]; sprintf(buf, "IR:%u", results.value); meetAndroid.send(buf); irrecv.resume(); } } void checkHeater1() { if (currentHeaterOff1 != 0 && currentHeaterOn1 != 0) { sensors.requestTemperaturesByAddress(hlTempSensor); float tempC = sensors.getTempC(hlTempSensor); if (tempC != -127.00) { if (tempC > currentHeaterOff1) { digitalWrite(HEATER1, LOW); } if (tempC < currentHeaterOn1) { digitalWrite(HEATER1, HIGH); } } } else { digitalWrite(HEATER1, LOW); } } void checkHeater2() { if (currentHeaterOff2 != 0 && currentHeaterOn2 != 0) { sensors.requestTemperaturesByAddress(hrTempSensor); float tempC = sensors.getTempC(hrTempSensor); if (tempC != -127.00) { if (tempC > currentHeaterOff2) { digitalWrite(HEATER2, LOW); } if (tempC < currentHeaterOn2) { digitalWrite(HEATER2, HIGH); } } } else { digitalWrite(HEATER2, LOW); } } void writeI2c(byte address, byte value) { Wire.beginTransmission(address); Wire.send(value); Wire.endTransmission(); } void sendAudioMute(byte value) { digitalWrite(AUDIO_MUTE, value == 1 ? HIGH : LOW); } void sendAmpOn(byte value) { digitalWrite(AMP_ON, value == 1 ? HIGH : LOW); } void sendAudioOn(byte value) { digitalWrite(AUDIO_ON, value == 1 ? HIGH : LOW); } void sendAudioVolume(byte value) { if (value > 31) return; currentVolume = value; writeI2c(TDA7318_I2C_ADDRESS, volMap[value]); } void sendAudioLFAttenuator(byte value) { if (value > 15) return; writeI2c(TDA7318_I2C_ADDRESS, lfAttMap[value]); } void sendAudioRFAttenuator(byte value) { if (value > 15) return; writeI2c(TDA7318_I2C_ADDRESS, rfAttMap[value]); } void sendAudioLRAttenuator(byte value) { if (value > 15) return; writeI2c(TDA7318_I2C_ADDRESS, lrAttMap[value]); } void sendAudioRRAttenuator(byte value) { if (value > 15) return; writeI2c(TDA7318_I2C_ADDRESS, rrAttMap[value]); } void sendAudioBass(byte value) { if (value > 14) return; writeI2c(TDA7318_I2C_ADDRESS, bassMap[value]); } void sendAudioTreble(byte value) { if (value > 14) return; writeI2c(TDA7318_I2C_ADDRESS, trebleMap[value]); } void sendAudioSwitch(byte value) { switch (value) { case 1: writeI2c(TDA7318_I2C_ADDRESS, TDA_SW1); break; case 2: writeI2c(TDA7318_I2C_ADDRESS, TDA_SW2); break; case 3: writeI2c(TDA7318_I2C_ADDRESS, TDA_SW3); break; case 4: writeI2c(TDA7318_I2C_ADDRESS, TDA_SW4); break; } } void sendRadioFrequency(int frequency, boolean power) { frequency += 107; digitalWrite(LM_CE, HIGH); writeLM(byte(frequency)); writeLM(byte(frequency >> 8)); writeLM((power == true) ? 135 : 71); digitalWrite(LM_CE, LOW); } void writeLM(byte bytes) { int d; int d1; delayMicroseconds(LM_DELAY); for (int x=0; x <= 7; x++) { // Set DA d = bytes >> 1; d1 = d << 1; digitalWrite(LM_DA, bytes == d1 ? LOW : HIGH); // Make CL digitalWrite(LM_CL, HIGH); delayMicroseconds(LM_DELAY); digitalWrite(LM_CL, LOW); delayMicroseconds(LM_DELAY); bytes = bytes >> 1; } delayMicroseconds(LM_DELAY); } void getInternalTemperature(byte flag, byte numOfValues) { sensors.requestTemperaturesByAddress(intTempSensor); float tempC = sensors.getTempC(intTempSensor); meetAndroid.send(tempC == -127.00 ? 0 : tempC); } void setAudioBalance(byte flag, byte numOfValues) { int value = meetAndroid.getInt(); sendAudioLFAttenuator(value); sendAudioRFAttenuator(15 - value); } void setClimatePower(byte flag, byte numOfValues) { digitalWrite(CLIMATE_POWER, meetAndroid.getInt() == 1 ? HIGH : LOW); } void setClimateFanDirection(byte flag, byte numOfValues) { int value = meetAndroid.getInt(); if (value < 1 && value > 4) value = 1; analogWrite(FAN_DIRECTION_PWM, climateDirectionMap[value]); } void getExternalTemperature(byte flag, byte numOfValues) { sensors.requestTemperaturesByAddress(extTempSensor); float tempC = sensors.getTempC(extTempSensor); meetAndroid.send(tempC == -127.00 ? 0 : tempC); } void setClimateFanSpeed(byte flag, byte numOfValues) { int value = meetAndroid.getInt(); if (value < 0) value = 0; if (value > 15) value = 15; digitalPotWrite(0, climateFanMap[value]); } void getHeaterTemperature1(byte flag, byte numOfValues) { sensors.requestTemperaturesByAddress(hlTempSensor); float tempC = sensors.getTempC(hlTempSensor); meetAndroid.send(tempC == -127.00 ? 0 : tempC); } void getHeaterTemperature2(byte flag, byte numOfValues) { sensors.requestTemperaturesByAddress(hrTempSensor); float tempC = sensors.getTempC(hrTempSensor); meetAndroid.send(tempC == -127.00 ? 0 : tempC); } void setHeaterOnTemperature1(byte flag, byte numOfValues) { currentHeaterOn1 = meetAndroid.getInt(); } void setHeaterOffTemperature1(byte flag, byte numOfValues) { currentHeaterOff1 = meetAndroid.getInt(); } void setHeaterOnTemperature2(byte flag, byte numOfValues) { currentHeaterOn2 = meetAndroid.getInt(); } void setHeaterOffTemperature2(byte flag, byte numOfValues) { currentHeaterOff2 = meetAndroid.getInt(); } void setClimateRecirculation(byte flag, byte numOfValues) { digitalWrite(CLIMATE_REC, (meetAndroid.getInt() == 1) ? HIGH : LOW); } void setAudioBass(byte flag, byte numOfValues) { sendAudioBass(meetAndroid.getInt()); } void setAudioTreble(byte flag, byte numOfValues) { sendAudioTreble(meetAndroid.getInt()); } void setAudioRearLeftVolume(byte flag, byte numOfValues) { sendAudioLRAttenuator(meetAndroid.getInt()); } void setAudioMute(byte flag, byte numOfValues) { sendAudioMute(meetAndroid.getInt()); } void setPowerState(byte flag, byte numOfValues) { digitalWrite(POWER_SWITCH, (meetAndroid.getInt() == 1) ? HIGH : LOW); } void setRadioFrequency(byte flag, byte numOfValues) { int frequency = meetAndroid.getInt(); if (frequency == 0) { sendRadioFrequency(frequency, false); } else if (frequency >= RADIO_MIN_FREQUENCY && frequency <= RADIO_MAX_FREQUENCY){ sendRadioFrequency(frequency, true); } } void setAudioSource(byte flag, byte numOfValues) { sendAudioSwitch(meetAndroid.getInt()); } void setClimateTemperature(byte flag, byte numOfValues) { int value = meetAndroid.getInt(); if (value < 18) value = 0; if (value > 26) value = 27; digitalPotWrite(1, climateTempMap[value]); } void digitalPotWrite(byte address, byte value){ digitalWrite(AD_SELECT, LOW); SPI.transfer(address); SPI.transfer(value); digitalWrite(AD_SELECT, HIGH); } void getCarVoltage(byte flag, byte numOfValues) { float R1 = 9930.0; float R2 = 970.0; int value = analogRead(ACC); meetAndroid.send(((value * 5.0) / 1024.0) / (R2 / (R1 + R2))); } void setAudioVolume(byte flag, byte numOfValues) { sendAudioVolume(meetAndroid.getInt()); } void setAudioRearRightVolume(byte flag, byte numOfValues) { sendAudioRRAttenuator(meetAndroid.getInt()); }
Железо будет доработано, скетч и оболочка будут модернизированы.
Последний раз редактировалось s.m.; 30.11.2011 в 04:26.
Сделал для проекта управляемый хаб
Дано: хаб с BIC за 5.41
и 2 модуля KIS-3R33S с ебея
Задача: сделать управляемый хаб с писанием от 12В. Питание на порты подается одновременно с появлением питания на входе хаба. Ток 3А - на 3 порта и отдельно 3А - на 4 порта.
Вот фототчет
Разбираем хаб - просто снимаем часть корпуса - там типа защелок по краям и направляющих штырей по углам.
Далее, видим внутри вот это
Берем модули
Снимаем крышку сверху, отогнув защелки отверткой и видим внутри
и с другой стороны
Далее берем SMD резистор типоразмера 0805 номиналом 10К
и припаиваем в правый верхний угол. Также переносим резистор 100К в левом верхнем углу в другое место.
Готовый к установке модуль показан здесь
Такую же процедуру проделываем со вторым модулем.
Дальше просто припаиваем провода как надо - входы модулей на разъем 12В - выходы - на группы из 3 и 4 портов. Входы управления включением модулей подключаем к +5В на входном USB.
Результат показан здесь
хаб под нагрузкой
Собирается в обратном порядке и выглядит в результате точно также, как и до переделки.
Фотку в собранном виде не делал, но могу позже вывесить.
Тестирование показало незначительный нагрев модулей и стабильность выходного напряжения под нагрузкой.
Привет! А исходники программы для андроида есть? Выложишь?
И как там всё происходит программно? Можешь рассказать?
Да, прикольно. Хотел замутить подобное. Только вот в программировании для Андроида вообще не разбираюсь...
Liliput 629 GL, Intel Atom N230 1.6, HDD 200 GB, ОЗУ 2GB, Globalsat GT-100.
Кстати, как себя тинси с далласом чувствует?
Я, в свое время, был вынужден отказаться от ds18x20 из-за непредсказуемого времени чтения оного.
Эту тему просматривают: 2 (пользователей: 0 , гостей: 2)