Ответить
  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 19 ноября 2014 16:39
    Drosha:

    art100, Misha_03, http://alex-avr2.livejournal.com/9250.html

    Cпасибо. Понял. С фольгой травить. Как народ только не развлекается. :) Может когда-нибудь тоже поразвлекаюсь :)

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Drosha Senior Member
    офлайн
    Drosha Senior Member

    1966

    18 лет на сайте
    пользователь #86205

    Профиль
    Написать сообщение

    1966
    # 19 ноября 2014 20:00

    тут в руки попал экран Innolux AT043TN24, можно его как то к ардуино подключить малой кровью, или лучше не заморачиваться ?

  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 20 ноября 2014 05:36 Редактировалось art100, 16 раз(а).
    Drosha:

    тут в руки попал экран Innolux AT043TN24, можно его как то к ардуино подключить малой кровью, или лучше не заморачиваться ?

    1 надо узнать его чип
    2 почитать даташит если паралельные шины теоретически 8 бит - arduino uno, 16 - бит arduino mega чисто теоретически, I2C в идеале, но отлаживать значительно сложней.
    3 поискать комбинацию чипа и arduino например ST7781 Arduino и читаем мои посты веселье http://forum.arduino.cc/index.php?topic=223769.0
    4 поняв что ближе попытатся готовую библиотеку подправить под себя
    5 надо понимать что с ростом точек резко надо увеличивать скорость контроллера
    6.официальная 180x180 и на 16 мегагерцах и последовательной шинке летает. Тут вероятность успеха 99%.
    Экран 1.77" по диагонали, с 160 x 128 пикселей. TFT библиотека взаимодействует с экрана контроллера через SPI при использовании TFT библиотека.

    Я развлекался веселился 320x240 https://yadi.sk/d/EPYljwnIKAWUT мне как-бы скорости хватало одну точку обрабатывать, но дальнейшая 8 битовая скорострельность ST7781 напрягала. Не нашел видео где регулятор уровня стерео писал. Прикручивают 7 дюймовые к многоножкам mega но вероятность успеха 5% и как меню статичное еще ничего 16 мегагерц хватает.
    7.Cудя по черным точкам на шлейфе, думаю там выбран режим чипа, явно не на 8 проводков. Для переключения режимов 1 4 8 16 как вы дымаете сколько резисторов хватит? Может сначала надо понять под какой чип этот экранчик разрабатывался, и вы увидите что там небось графикозаточенный типа Intel Graphics на 1 гигагерц. А вы пытаетесь чип, которому кнопочку/лампочку поморгать, заставить тысячи точек моргать.
    "А arduin-ке головушка не бобо"
    Для таких фанатов выпустили 3-ех вольтовую 32 битную многоножку. Китайцы ее уже дешево за 16$ паяют.

    Но народ ее еще пока обкатывает. Да. В основном на экранчиках за 2-ух кратное ускорение по результату.
    Разрядность в 4 раза увеличили а скорость всего в 2 раза поднялась.


    Вероятность успеха 5%
    Прикрутить-то можно все к ардуинкам, а результат вам видней.
    Пробуйте. Нам расскажите.

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • maxxlife Member
    офлайн
    maxxlife Member

    230

    15 лет на сайте
    пользователь #325167

    Профиль
    Написать сообщение

    230
    # 21 ноября 2014 13:54 Редактировалось maxxlife, 11 раз(а).

    Всем привет. Решил поделиться своей серьезной разработкой на данном форуме. Думаю, вас заинтересует.
    Кратко, это многоцелевой колесный робот.
    Способен автономно двигаться в замкнутом пространстве, имеется управление роботом при помощи смартфона, а видеокамера спереди способна распознавать цветные объекты и следовать за ними. А БК мотор способен разогнать данного малыша до 60 км/ч!
    Пишите в личку, скину страницу проекта.
    Там документация, подробное описание робота, что он умеет и для чего он. Я вижу, что без команды мой проект загнется, поэтому если есть интерес развивать данное направление, стучите в личку.
    Сейчас я работаю над машинным зрением, но не на Arduino, а на более серьзных платах.
    Кратко: Ищу единомышленников! Работать в команде всегда интереснее, чем одному!

  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 23 ноября 2014 19:12 Редактировалось art100, 4 раз(а).

    maxxlife Сколько? 500 железо ? Может ссылки где заказывать?
    arduino due? stm32? не видно

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Misha_03 Senior Member
    офлайн
    Misha_03 Senior Member

    847

    16 лет на сайте
    пользователь #167409

    Профиль
    Написать сообщение

    847
    # 24 ноября 2014 16:56

    У кого есть нормальная библиотека и программа для опроса АМ 2302 DHT22 датчика.

    #include <DHT.h>

    dht DHT;

    #define DHT22_PIN 6

    void setup()
    {
    Serial.begin(115200);
    Serial.println("DHT TEST PROGRAM ");
    Serial.print("LIBRARY VERSION: ");
    Serial.println(DHT_LIB_VERSION);
    Serial.println();
    Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
    }

    void loop()
    {
    // READ DATA
    Serial.print("DHT22, \t");
    int chk = DHT.read22(DHT22_PIN);
    switch (chk)
    {
    case DHTLIB_OK:
    Serial.print("OK,\t");
    break;
    case DHTLIB_ERROR_CHECKSUM:
    Serial.print("Checksum error,\t");
    break;
    case DHTLIB_ERROR_TIMEOUT:
    Serial.print("Time out error,\t");
    break;
    default:
    Serial.print("Unknown error,\t");
    break;
    }
    // DISPLAY DATA
    Serial.print(DHT.humidity, 1);
    Serial.print(",\t\t");
    Serial.println(DHT.temperature, 1);

    delay(2000);
    }

  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 28 ноября 2014 06:02 Редактировалось art100, 3 раз(а).

    Вчера на день рождения сотруднику подарили arduino uno r3. :shuffle:

    Нас ардуинщиков оказалось 2-ое. :D Мы в двоем подсаживаем его 3-его на этот наркотик. :) За вчера мы ему выдрали из системника кнопки и светодиоды. :znaika: Подопытным blink fade и button были пройдены, под наши пинки ногами. :znaika: Восторженный взгляд в его глазах был замечен. :ura: Мы поняли наркотик подействовал. :jump: Начинает донимать вопросами не пролистав "примеры". :idea: Был послан на пердварительную оплату 100$ за разьяснение на С. Посмотрим, денежная стимуляция заставила его пролистать и прочитать примеры? :100500: Ваш покорный слуга превратился в arduino-наркодилера в составе организованной преступной группы. Ардуино-ОПГ в действии. :trollface:

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Ded140 Senior Member
    офлайн
    Ded140 Senior Member

    771

    14 лет на сайте
    пользователь #451748

    Профиль
    Написать сообщение

    771
    # 28 ноября 2014 20:02
    <p>Стараний мало для достижения цели.</p>
  • МиГ Senior Member
    офлайн
    МиГ Senior Member

    2168

    19 лет на сайте
    пользователь #53792

    Профиль
    Написать сообщение

    2168
    # 28 ноября 2014 21:45 Редактировалось МиГ, 2 раз(а).
    art100:

    Вчера на день рождения сотруднику подарили arduino uno r3. :shuffle:

    Нас ардуинщиков оказалось 2-ое. :D Мы вдвоем подсаживаем его 3-его на этот наркотик. :) За вчера мы ему выдрали из системника кнопки и светодиоды. :znaika: Подопытным blink fade и button были пройдены, под наши пинки ногами. :znaika: Восторженный взгляд в его глазах был замечен.

    Самое интересное, что вчера, тот самый сотрудник т.е. видимо я, допоздна сидел и читал эту ветку форума, скачал себе PDF для начинающих. И было большое желание пообщаться и позадавать вопросики art100, а как оказалось, я уже видимо его знаю, правда 100$ это многовато, видимо придется разбираться самому :D, пока до сих пор балуюсь с fademount, хочу по прежнему попробовать прикрутить пьезодинамик, попробовать побибикать. Короче буду пытаться как-то развиваться. Народ примите новичка в свою группу.
    art100 будем знакомы :beer:
    P.S. Жена идею подкинула, говорит мол, сделай робот пылесос со своей "ар дуринки", а что интересная идея, правда для меня пока невыполнимая

  • Protez1999 Senior MemberАвтор темы
    офлайн
    Protez1999 Senior Member Автор темы

    9978

    18 лет на сайте
    пользователь #113845

    Профиль
    Написать сообщение

    9978
    # 29 ноября 2014 15:57
    Ded140:

    Может кто помочь?

    через регистр будет все работать??? на ардуине на все ведь не хватит выходов

  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 29 ноября 2014 18:01 Редактировалось art100, 2 раз(а).
    Ded140:

    asm+c>>>>нечто

    У меня времени как всегда нет. Но выложи схему и код. Среди советов не в тему бывает проскальзывает в тему. spoiler -ом прикройте содержимое. Начните с чего-нибудь.

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Ded140 Senior Member
    офлайн
    Ded140 Senior Member

    771

    14 лет на сайте
    пользователь #451748

    Профиль
    Написать сообщение

    771
    # 29 ноября 2014 20:26

    код для цифр, только он не хочет работать...

    #include <avr/io.h>
    #include <avr/interrupt.h>

    //выводим на сегмент с общим КАТОДОМ (1-сегмент горит, 0 - не горит)
    // 0 1 2 3 4 5 6 7 8 9

    const unsigned char codes1[10]={0b00111100,0b00011000,0b00101100,0b00111100,0b00011000,0b00110100,0b00110100,0b00011100,0b00111100,0b00111100};
    const unsigned char codes2[10]={0b00000011,0b00000000,0b00000101,0b00000100,0b00000110,0b00000110,0b00000111,0b00000000,0b00000111,0b00000110};

    unsigned char data[2]={0x00,0x00};
    unsigned char data2[2]={0x00,0x00};
    unsigned char counter=0;

    void pause (unsigned int a)
    { unsigned int i;

    for (i=a;i>0;i--)
    ;
    }

    void init_timer (void)
    {
    TIMSK=(1<<TOIE0); //Enable timer overflow interrupt
    TCCR0=(0<<CS00)|(1<<CS01)|(0<<CS02); //Prescaller = 8

    TCCR1A=0;
    TCCR1B=_BV(ICNC1) | _BV(CS12) | _BV(CS11) | _BV(CS10); // Вход T1
    }

    void convert_data (unsigned int x)
    {
    unsigned int temp,res;
    temp=x;
    res=temp/1000; //Calculate 1000-s
    data[1]=codes1[res];
    data2[1]=codes2[res];
    temp=temp-res*1000;

    res=temp/100; //Calculate 100-s
    data[0]=codes1[res];
    data2[0]=codes2[res];
    }

    ISR (TIMER0_OVF_vect)
    {
    //PORTB=0xff;
    //PORTC=0xff;
    PORTC=~_BV(counter); //Enable digit
    PORTB=~data[counter]; //Write code
    PORTC=~data2[counter]; //Write code
    counter=(counter+1)%4; //Increment digit counter

    //TCNT0=0x00; //Clear timer
    }

    int main(void)
    {
    uint16_t x=0;
    DDRD =0b11011111;
    PORTD =0b11011111;
    DDRB =0b11111111;
    PORTB =0b11111111;
    DDRC =0b11111111;
    PORTC =0b11111111;

    pause(1000); //Settle pause

    init_timer(); //Init timer

    sei(); //Interrupt enable

    while(1)
    {
    convert_data(x); //Conver data to codes
    if (x<9999) x=x+1; //Increment data
    else x=0;
    pause(30000);
    };

    return 1;
    }
    не выводит совсем ничего, только если немного закаротить +5 и землю... выдод на сегменты: A - PB2, B - PB3, C - PB4, D - PB5, E - PC0, F - PC1, G - PC2, 1DP - PC3, 2DP - PC4.

    <p>Стараний мало для достижения цели.</p>
  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 29 ноября 2014 23:54 Редактировалось art100, 3 раз(а).
    Ded140:

    код ....

    а схема плата фото к чему это?
    если бездумно компилировать для arduino uno
    видим что код нерабочий
    вдумываться что за глупости там с таймерами лень

    код выделить все

    sketch_nov29b.ino: In function 'void init_timer()':
    sketch_nov29b:17: error: 'TIMSK' was not declared in this scope
    sketch_nov29b:18: error: 'TCCR0' was not declared in this scope

    выкинуть и взять для нужной схемы рабочий код

    из сегодняшнего http://art1.by/0arduino/video/BH1750.wmv

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Protez1999 Senior MemberАвтор темы
    офлайн
    Protez1999 Senior Member Автор темы

    9978

    18 лет на сайте
    пользователь #113845

    Профиль
    Написать сообщение

    9978
    # 30 ноября 2014 09:32

    Делал часы могу скинуть код. думаю с ненужных букв как нибудь наколупаите на диоды тахометра

  • Ded140 Senior Member
    офлайн
    Ded140 Senior Member

    771

    14 лет на сайте
    пользователь #451748

    Профиль
    Написать сообщение

    771
    # 30 ноября 2014 16:11
    Protez1999:

    Делал часы могу скинуть код. думаю с ненужных букв как нибудь наколупаите на диоды тахометра

    скинь. посмотрим что можно сделать)))

    <p>Стараний мало для достижения цели.</p>
  • art100 Клуб Самоделкиных
    офлайн
    art100 Клуб Самоделкиных

    5114

    14 лет на сайте
    пользователь #397580

    Профиль
    Написать сообщение

    5114
    # 30 ноября 2014 20:44 Редактировалось art100, 3 раз(а).
    Ded140:

    ..скинь. посмотрим что можно сделать)))

    А схему скинуть слабо?
    Кода для ardu-инки хочется? Да пожалуйсто. Для индикаторчика:

    код выделить все

    #include &quot;temperature.h&quot;
    #include &quot;ultralcd.h&quot;
    #ifdef ULTRA_LCD
    #include &quot;Marlin.h&quot;
    #include &quot;language.h&quot;
    #include &quot;cardreader.h&quot;
    #include &quot;temperature.h&quot;
    #include &quot;stepper.h&quot;
    #include &quot;ConfigurationStore.h&quot;

    int8_t encoderDiff; /* encoderDiff is updated from interrupt context and added to encoderPosition every LCD update */

    /* Configuration settings */
    int plaPreheatHotendTemp;
    int plaPreheatHPBTemp;
    int plaPreheatFanSpeed;

    int absPreheatHotendTemp;
    int absPreheatHPBTemp;
    int absPreheatFanSpeed;

    #ifdef ULTIPANEL
    static float manual_feedrate[] = MANUAL_FEEDRATE;
    #endif // ULTIPANEL

    /* !Configuration settings */

    //Function pointer to menu functions.
    typedef void (*menuFunc_t)();

    uint8_t lcd_status_message_level;
    char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG;

    #ifdef DOGLCD
    #include "dogm_lcd_implementation.h"
    #else
    #include "ultralcd_implementation_hitachi_HD44780.h"
    #endif

    /** forward declarations **/

    void copy_and_scalePID_i();
    void copy_and_scalePID_d();

    /* Different menus */
    static void lcd_status_screen();
    #ifdef ULTIPANEL
    extern bool powersupply;
    static void lcd_main_menu();
    static void lcd_tune_menu();
    static void lcd_prepare_menu();
    static void lcd_move_menu();
    static void lcd_control_menu();
    static void lcd_control_temperature_menu();
    static void lcd_control_temperature_preheat_pla_settings_menu();
    static void lcd_control_temperature_preheat_abs_settings_menu();
    static void lcd_control_motion_menu();
    #ifdef DOGLCD
    static void lcd_set_contrast();
    #endif
    static void lcd_control_retract_menu();
    static void lcd_sdcard_menu();

    static void lcd_quick_feedback();//Cause an LCD refresh, and give the user visual or audible feedback that something has happened

    /* Different types of actions that can be used in menu items. */
    static void menu_action_back(menuFunc_t data);
    static void menu_action_submenu(menuFunc_t data);
    static void menu_action_gcode(const char* pgcode);
    static void menu_action_function(menuFunc_t data);
    static void menu_action_sdfile(const char* filename, char* longFilename);
    static void menu_action_sddirectory(const char* filename, char* longFilename);
    static void menu_action_setting_edit_bool(const char* pstr, bool* ptr);
    static void menu_action_setting_edit_int3(const char* pstr, int* ptr, int minValue, int maxValue);
    static void menu_action_setting_edit_float3(const char* pstr, float* ptr, float minValue, float maxValue);
    static void menu_action_setting_edit_float32(const char* pstr, float* ptr, float minValue, float maxValue);
    static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float minValue, float maxValue);
    static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue);
    static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue);
    static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue);
    static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_float32(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_float5(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
    static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc);

    #define ENCODER_FEEDRATE_DEADZONE 10

    #if !defined(LCD_I2C_VIKI)
    #ifndef ENCODER_STEPS_PER_MENU_ITEM
    #define ENCODER_STEPS_PER_MENU_ITEM 5
    #endif
    #ifndef ENCODER_PULSES_PER_STEP
    #define ENCODER_PULSES_PER_STEP 1
    #endif
    #else
    #ifndef ENCODER_STEPS_PER_MENU_ITEM
    #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation
    #endif
    #ifndef ENCODER_PULSES_PER_STEP
    #define ENCODER_PULSES_PER_STEP 1
    #endif
    #endif

    /* Helper macros for menus */
    #define START_MENU() do { \
    if (encoderPosition > 0x8000) encoderPosition = 0; \
    if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\
    uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \
    bool wasClicked = LCD_CLICKED;\
    for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \
    _menuItemNr = 0;
    #define MENU_ITEM(type, label, args...) do { \
    if (_menuItemNr == _lineNr) { \
    if (lcdDrawUpdate) { \
    const char* _label_pstr = PSTR(label); \
    if ((encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) { \
    lcd_implementation_drawmenu_ ## type ## _selected (_drawLineNr, _label_pstr , ## args ); \
    }else{\
    lcd_implementation_drawmenu_ ## type (_drawLineNr, _label_pstr , ## args ); \
    }\
    }\
    if (wasClicked && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\
    lcd_quick_feedback(); \
    menu_action_ ## type ( args ); \
    return;\
    }\
    }\
    _menuItemNr++;\
    } while(0)
    #define MENU_ITEM_DUMMY() do { _menuItemNr++; } while(0)
    #define MENU_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label) , ## args )
    #define MENU_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label) , ## args )
    #define END_MENU() \
    if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM >= _menuItemNr) encoderPosition = _menuItemNr * ENCODER_STEPS_PER_MENU_ITEM - 1; \
    if ((uint8_t)(encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) >= currentMenuViewOffset + LCD_HEIGHT) { currentMenuViewOffset = (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) - LCD_HEIGHT + 1; lcdDrawUpdate = 1; _lineNr = currentMenuViewOffset - 1; _drawLineNr = -1; } \
    } } while(0)

    /** Used variables to keep track of the menu */
    #ifndef REPRAPWORLD_KEYPAD
    volatile uint8_t buttons;//Contains the bits of the currently pressed buttons.
    #else
    volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shift register values
    #endif
    #ifdef LCD_HAS_SLOW_BUTTONS
    volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons.
    #endif
    uint8_t currentMenuViewOffset; /* scroll offset in the current menu */
    uint32_t blocking_enc;
    uint8_t lastEncoderBits;
    uint32_t encoderPosition;
    #if (SDCARDDETECT > 0)
    bool lcd_oldcardstatus;
    #endif
    #endif//ULTIPANEL

    menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */
    uint32_t lcd_next_update_millis;
    uint8_t lcd_status_update_delay;
    uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial) */

    //prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
    menuFunc_t prevMenu = NULL;
    uint16_t prevEncoderPosition;
    //Variables used when editing values.
    const char* editLabel;
    void* editValue;
    int32_t minEditValue, maxEditValue;
    menuFunc_t callbackFunc;

    // place-holders for Ki and Kd edits
    float raw_Ki, raw_Kd;

    /* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependent */
    static void lcd_status_screen()
    {
    if (lcd_status_update_delay)
    lcd_status_update_delay--;
    else
    lcdDrawUpdate = 1;
    if (lcdDrawUpdate)
    {
    lcd_implementation_status_screen();
    lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
    }
    #ifdef ULTIPANEL
    if (LCD_CLICKED)
    {
    currentMenu = lcd_main_menu;
    encoderPosition = 0;
    lcd_quick_feedback();
    }

    // Dead zone at 100% feedrate
    if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
    (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
    {
    encoderPosition = 0;
    feedmultiply = 100;
    }

    if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
    {
    feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
    encoderPosition = 0;
    }
    else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
    {
    feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
    encoderPosition = 0;
    }
    else if (feedmultiply != 100)
    {
    feedmultiply += int(encoderPosition);
    encoderPosition = 0;
    }

    if (feedmultiply < 10)
    feedmultiply = 10;
    if (feedmultiply > 999)
    feedmultiply = 999;
    #endif//ULTIPANEL
    }

    #ifdef ULTIPANEL
    static void lcd_return_to_status()
    {
    encoderPosition = 0;
    currentMenu = lcd_status_screen;
    }

    static void lcd_sdcard_pause()
    {
    card.pauseSDPrint();
    }
    static void lcd_sdcard_resume()
    {
    card.startFileprint();
    }

    static void lcd_sdcard_stop()
    {
    card.sdprinting = false;
    card.closefile();
    quickStop();
    if(SD_FINISHED_STEPPERRELEASE)
    {
    enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND));
    }
    autotempShutdown();
    }

    /* Menu implementation */
    static void lcd_main_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_WATCH, lcd_status_screen);
    if (movesplanned() || IS_SD_PRINTING)
    {
    MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu);
    }else{
    MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu);
    }
    MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu);
    #ifdef SDSUPPORT
    if (card.cardOK)
    {
    if (card.isFileOpen())
    {
    if (card.sdprinting)
    MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
    else
    MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
    MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
    }else{
    MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
    #if SDCARDDETECT < 1
    MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user
    #endif
    }
    }else{
    MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu);
    #if SDCARDDETECT < 1
    MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface
    #endif
    }
    #endif
    END_MENU();
    }

    #ifdef SDSUPPORT
    static void lcd_autostart_sd()
    {
    card.lastnr=0;
    card.setroot();
    card.checkautostart(true);
    }
    #endif

    void lcd_preheat_pla()
    {
    setTargetHotend0(plaPreheatHotendTemp);
    setTargetHotend1(plaPreheatHotendTemp);
    setTargetHotend2(plaPreheatHotendTemp);
    setTargetBed(plaPreheatHPBTemp);
    fanSpeed = plaPreheatFanSpeed;
    lcd_return_to_status();
    setWatch(); // heater sanity check timer
    }

    void lcd_preheat_abs()
    {
    setTargetHotend0(absPreheatHotendTemp);
    setTargetHotend1(absPreheatHotendTemp);
    setTargetHotend2(absPreheatHotendTemp);
    setTargetBed(absPreheatHPBTemp);
    fanSpeed = absPreheatFanSpeed;
    lcd_return_to_status();
    setWatch(); // heater sanity check timer
    }

    static void lcd_cooldown()
    {
    setTargetHotend0(0);
    setTargetHotend1(0);
    setTargetHotend2(0);
    setTargetBed(0);
    lcd_return_to_status();
    }

    #ifdef BABYSTEPPING
    static void lcd_babystep_x()
    {
    if (encoderPosition != 0)
    {
    babystepsTodo[X_AXIS]+=(int)encoderPosition;
    encoderPosition=0;
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_X),"");
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_tune_menu;
    encoderPosition = 0;
    }
    }

    static void lcd_babystep_y()
    {
    if (encoderPosition != 0)
    {
    babystepsTodo[Y_AXIS]+=(int)encoderPosition;
    encoderPosition=0;
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_Y),"");
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_tune_menu;
    encoderPosition = 0;
    }
    }

    static void lcd_babystep_z()
    {
    if (encoderPosition != 0)
    {
    babystepsTodo[Z_AXIS]+=BABYSTEP_Z_MULTIPLICATOR*(int)encoderPosition;
    encoderPosition=0;
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_Z),"");
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_tune_menu;
    encoderPosition = 0;
    }
    }
    #endif //BABYSTEPPING

    static void lcd_tune_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
    MENU_ITEM_EDIT(int3, MSG_SPEED, &feedmultiply, 10, 999);
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15);
    #if TEMP_SENSOR_1 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15);
    #endif
    #if TEMP_SENSOR_2 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15);
    #endif
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15);
    #endif
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);
    MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999);

    #ifdef BABYSTEPPING
    #ifdef BABYSTEP_XY
    MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x);
    MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y);
    #endif //BABYSTEP_XY
    MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
    #endif
    #ifdef FILAMENTCHANGEENABLE
    MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600"));
    #endif
    END_MENU();
    }

    static void lcd_prepare_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
    #ifdef SDSUPPORT
    #ifdef MENU_ADDAUTOSTART
    MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd);
    #endif
    #endif
    MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
    MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
    //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0"));
    MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla);
    MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs);
    MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);
    #if PS_ON_PIN > -1
    if (powersupply)
    {
    MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81"));
    }else{
    MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80"));
    }
    #endif
    MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu);
    END_MENU();
    }

    float move_menu_scale;
    static void lcd_move_menu_axis();

    static void lcd_move_x()
    {
    if (encoderPosition != 0)
    {
    refresh_cmd_timeout();
    current_position[X_AXIS] += float((int)encoderPosition) * move_menu_scale;
    if (min_software_endstops && current_position[X_AXIS] < X_MIN_POS)
    current_position[X_AXIS] = X_MIN_POS;
    if (max_software_endstops && current_position[X_AXIS] > X_MAX_POS)
    current_position[X_AXIS] = X_MAX_POS;
    encoderPosition = 0;
    #ifdef DELTA
    calculate_delta(current_position);
    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder);
    #else
    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder);
    #endif
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR("X"), ftostr31(current_position[X_AXIS]));
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_move_menu_axis;
    encoderPosition = 0;
    }
    }
    static void lcd_move_y()
    {
    if (encoderPosition != 0)
    {
    refresh_cmd_timeout();
    current_position[Y_AXIS] += float((int)encoderPosition) * move_menu_scale;
    if (min_software_endstops && current_position[Y_AXIS] < Y_MIN_POS)
    current_position[Y_AXIS] = Y_MIN_POS;
    if (max_software_endstops && current_position[Y_AXIS] > Y_MAX_POS)
    current_position[Y_AXIS] = Y_MAX_POS;
    encoderPosition = 0;
    #ifdef DELTA
    calculate_delta(current_position);
    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder);
    #else
    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder);
    #endif
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR("Y"), ftostr31(current_position[Y_AXIS]));
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_move_menu_axis;
    encoderPosition = 0;
    }
    }
    static void lcd_move_z()
    {
    if (encoderPosition != 0)
    {
    refresh_cmd_timeout();
    current_position[Z_AXIS] += float((int)encoderPosition) * move_menu_scale;
    if (min_software_endstops && current_position[Z_AXIS] < Z_MIN_POS)
    current_position[Z_AXIS] = Z_MIN_POS;
    if (max_software_endstops && current_position[Z_AXIS] > Z_MAX_POS)
    current_position[Z_AXIS] = Z_MAX_POS;
    encoderPosition = 0;
    #ifdef DELTA
    calculate_delta(current_position);
    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder);
    #else
    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder);
    #endif
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR("Z"), ftostr31(current_position[Z_AXIS]));
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_move_menu_axis;
    encoderPosition = 0;
    }
    }
    static void lcd_move_e()
    {
    if (encoderPosition != 0)
    {
    current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale;
    encoderPosition = 0;
    #ifdef DELTA
    calculate_delta(current_position);
    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder);
    #else
    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder);
    #endif
    lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR("Extruder"), ftostr31(current_position[E_AXIS]));
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_move_menu_axis;
    encoderPosition = 0;
    }
    }

    static void lcd_move_menu_axis()
    {
    START_MENU();
    MENU_ITEM(back, MSG_MOVE_AXIS, lcd_move_menu);
    MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
    MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
    if (move_menu_scale < 10.0)
    {
    MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
    MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
    }
    END_MENU();
    }

    static void lcd_move_menu_10mm()
    {
    move_menu_scale = 10.0;
    lcd_move_menu_axis();
    }
    static void lcd_move_menu_1mm()
    {
    move_menu_scale = 1.0;
    lcd_move_menu_axis();
    }
    static void lcd_move_menu_01mm()
    {
    move_menu_scale = 0.1;
    lcd_move_menu_axis();
    }

    static void lcd_move_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu);
    MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm);
    MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm);
    MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm);
    //TODO:X,Y,Z,E
    END_MENU();
    }

    static void lcd_control_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
    MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu);
    #ifdef DOGLCD
    // MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63);
    MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast);
    #endif
    #ifdef FWRETRACT
    MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu);
    #endif
    #ifdef EEPROM_SETTINGS
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    MENU_ITEM(function, MSG_LOAD_EPROM, Config_RetrieveSettings);
    #endif
    MENU_ITEM(function, MSG_RESTORE_FAILSAFE, Config_ResetDefault);
    END_MENU();
    }

    static void lcd_control_temperature_menu()
    {
    #ifdef PIDTEMP
    // set up temp variables - undo the default scaling
    raw_Ki = unscalePID_i(Ki);
    raw_Kd = unscalePID_d(Kd);
    #endif

    START_MENU();
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15);
    #if TEMP_SENSOR_1 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15);
    #endif
    #if TEMP_SENSOR_2 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15);
    #endif
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15);
    #endif
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);
    #ifdef AUTOTEMP
    MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled);
    MENU_ITEM_EDIT(float3, MSG_MIN, &autotemp_min, 0, HEATER_0_MAXTEMP - 15);
    MENU_ITEM_EDIT(float3, MSG_MAX, &autotemp_max, 0, HEATER_0_MAXTEMP - 15);
    MENU_ITEM_EDIT(float32, MSG_FACTOR, &autotemp_factor, 0.0, 1.0);
    #endif
    #ifdef PIDTEMP
    MENU_ITEM_EDIT(float52, MSG_PID_P, &Kp, 1, 9990);
    // i is typically a small value so allows values below 1
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i);
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d);
    # ifdef PID_ADD_EXTRUSION_RATE
    MENU_ITEM_EDIT(float3, MSG_PID_C, &Kc, 1, 9990);
    # endif//PID_ADD_EXTRUSION_RATE
    #endif//PIDTEMP
    MENU_ITEM(submenu, MSG_PREHEAT_PLA_SETTINGS, lcd_control_temperature_preheat_pla_settings_menu);
    MENU_ITEM(submenu, MSG_PREHEAT_ABS_SETTINGS, lcd_control_temperature_preheat_abs_settings_menu);
    END_MENU();
    }

    static void lcd_control_temperature_preheat_pla_settings_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &plaPreheatFanSpeed, 0, 255);
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &plaPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15);
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &plaPreheatHPBTemp, 0, BED_MAXTEMP - 15);
    #endif
    #ifdef EEPROM_SETTINGS
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    #endif
    END_MENU();
    }

    static void lcd_control_temperature_preheat_abs_settings_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &absPreheatFanSpeed, 0, 255);
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &absPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15);
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &absPreheatHPBTemp, 0, BED_MAXTEMP - 15);
    #endif
    #ifdef EEPROM_SETTINGS
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    #endif
    END_MENU();
    }

    static void lcd_control_motion_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
    #ifdef ENABLE_AUTO_BED_LEVELING
    MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50);
    #endif
    MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 99000);
    MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990);
    MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &max_z_jerk, 0.1, 990);
    MENU_ITEM_EDIT(float3, MSG_VE_JERK, &max_e_jerk, 1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &max_feedrate[X_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &max_feedrate[Y_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &max_feedrate[Z_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &max_feedrate[E_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMIN, &minimumfeedrate, 0, 999);
    MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &mintravelfeedrate, 0, 999);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT(float5, MSG_A_RETRACT, &retract_acceleration, 100, 99000);
    MENU_ITEM_EDIT(float52, MSG_XSTEPS, &axis_steps_per_unit[X_AXIS], 5, 9999);
    MENU_ITEM_EDIT(float52, MSG_YSTEPS, &axis_steps_per_unit[Y_AXIS], 5, 9999);
    MENU_ITEM_EDIT(float51, MSG_ZSTEPS, &axis_steps_per_unit[Z_AXIS], 5, 9999);
    MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999);
    #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
    MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &abort_on_endstop_hit);
    #endif
    END_MENU();
    }

    #ifdef DOGLCD
    static void lcd_set_contrast()
    {
    if (encoderPosition != 0)
    {
    lcd_contrast -= encoderPosition;
    if (lcd_contrast < 0) lcd_contrast = 0;
    else if (lcd_contrast > 63) lcd_contrast = 63;
    encoderPosition = 0;
    lcdDrawUpdate = 1;
    u8g.setContrast(lcd_contrast);
    }
    if (lcdDrawUpdate)
    {
    lcd_implementation_drawedit(PSTR(MSG_CONTRAST), itostr2(lcd_contrast));
    }
    if (LCD_CLICKED)
    {
    lcd_quick_feedback();
    currentMenu = lcd_control_menu;
    encoderPosition = 0;
    }
    }
    #endif

    #ifdef FWRETRACT
    static void lcd_control_retract_menu()
    {
    START_MENU();
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
    MENU_ITEM_EDIT(bool, MSG_AUTORETRACT, &autoretract_enabled);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT, &retract_length, 0, 100);
    MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &retract_feedrate, 1, 999);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_ZLIFT, &retract_zlift, 0, 999);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER, &retract_recover_length, 0, 100);
    MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate, 1, 999);
    END_MENU();
    }
    #endif

    #if SDCARDDETECT == -1
    static void lcd_sd_refresh()
    {
    card.initsd();
    currentMenuViewOffset = 0;
    }
    #endif
    static void lcd_sd_updir()
    {
    card.updir();
    currentMenuViewOffset = 0;
    }

    void lcd_sdcard_menu()
    {
    if (lcdDrawUpdate == 0 && LCD_CLICKED == 0)
    return; // nothing to do (so don't thrash the SD card)
    uint16_t fileCnt = card.getnrfilenames();
    START_MENU();
    MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
    card.getWorkDirName();
    if(card.filename[0]=='/')
    {
    #if SDCARDDETECT == -1
    MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
    #endif
    }else{
    MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
    }

    for(uint16_t i=0;i<fileCnt;i++)
    {
    if (_menuItemNr == _lineNr)
    {
    #ifndef SDCARD_RATHERRECENTFIRST
    card.getfilename(i);
    #else
    card.getfilename(fileCnt-1-i);
    #endif
    if (card.filenameIsDir)
    {
    MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
    }else{
    MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
    }
    }else{
    MENU_ITEM_DUMMY();
    }
    }
    END_MENU();
    }

    #define menu_edit_type(_type, _name, _strFunc, scale) \
    void menu_edit_ ## _name () \
    { \
    if ((int32_t)encoderPosition < minEditValue) \
    encoderPosition = minEditValue; \
    if ((int32_t)encoderPosition > maxEditValue) \
    encoderPosition = maxEditValue; \
    if (lcdDrawUpdate) \
    lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \
    if (LCD_CLICKED) \
    { \
    *((_type*)editValue) = ((_type)encoderPosition) / scale; \
    lcd_quick_feedback(); \
    currentMenu = prevMenu; \
    encoderPosition = prevEncoderPosition; \
    } \
    } \
    void menu_edit_callback_ ## _name () \
    { \
    if ((int32_t)encoderPosition < minEditValue) \
    encoderPosition = minEditValue; \
    if ((int32_t)encoderPosition > maxEditValue) \
    encoderPosition = maxEditValue; \
    if (lcdDrawUpdate) \
    lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \
    if (LCD_CLICKED) \
    { \
    *((_type*)editValue) = ((_type)encoderPosition) / scale; \
    lcd_quick_feedback(); \
    currentMenu = prevMenu; \
    encoderPosition = prevEncoderPosition; \
    (*callbackFunc)();\
    } \
    } \
    static void menu_action_setting_edit_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) \
    { \
    prevMenu = currentMenu; \
    prevEncoderPosition = encoderPosition; \
    \
    lcdDrawUpdate = 2; \
    currentMenu = menu_edit_ ## _name; \
    \
    editLabel = pstr; \
    editValue = ptr; \
    minEditValue = minValue * scale; \
    maxEditValue = maxValue * scale; \
    encoderPosition = (*ptr) * scale; \
    }\
    static void menu_action_setting_edit_callback_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) \
    { \
    prevMenu = currentMenu; \
    prevEncoderPosition = encoderPosition; \
    \
    lcdDrawUpdate = 2; \
    currentMenu = menu_edit_callback_ ## _name; \
    \
    editLabel = pstr; \
    editValue = ptr; \
    minEditValue = minValue * scale; \
    maxEditValue = maxValue * scale; \
    encoderPosition = (*ptr) * scale; \
    callbackFunc = callback;\
    }
    menu_edit_type(int, int3, itostr3, 1)
    menu_edit_type(float, float3, ftostr3, 1)
    menu_edit_type(float, float32, ftostr32, 100)
    menu_edit_type(float, float5, ftostr5, 0.01)
    menu_edit_type(float, float51, ftostr51, 10)
    menu_edit_type(float, float52, ftostr52, 100)
    menu_edit_type(unsigned long, long5, ftostr5, 0.01)

    #ifdef REPRAPWORLD_KEYPAD
    static void reprapworld_keypad_move_z_up() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_z();
    }
    static void reprapworld_keypad_move_z_down() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_z();
    }
    static void reprapworld_keypad_move_x_left() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_x();
    }
    static void reprapworld_keypad_move_x_right() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_x();
    }
    static void reprapworld_keypad_move_y_down() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_y();
    }
    static void reprapworld_keypad_move_y_up() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_y();
    }
    static void reprapworld_keypad_move_home() {
    enquecommand_P((PSTR("G28"))); // move all axis home
    }
    #endif

    /** End of menus **/

    static void lcd_quick_feedback()
    {
    lcdDrawUpdate = 2;
    blocking_enc = millis() + 500;
    lcd_implementation_quick_feedback();
    }

    /** Menu action functions **/
    static void menu_action_back(menuFunc_t data)
    {
    currentMenu = data;
    encoderPosition = 0;
    }
    static void menu_action_submenu(menuFunc_t data)
    {
    currentMenu = data;
    encoderPosition = 0;
    }
    static void menu_action_gcode(const char* pgcode)
    {
    enquecommand_P(pgcode);
    }
    static void menu_action_function(menuFunc_t data)
    {
    (*data)();
    }
    static void menu_action_sdfile(const char* filename, char* longFilename)
    {
    char cmd[30];
    char* c;
    sprintf_P(cmd, PSTR("M23 %s"), filename);
    for(c = &cmd[4]; *c; c++)
    *c = tolower(*c);
    enquecommand(cmd);
    enquecommand_P(PSTR("M24"));
    lcd_return_to_status();
    }
    static void menu_action_sddirectory(const char* filename, char* longFilename)
    {
    card.chdir(filename);
    encoderPosition = 0;
    }
    static void menu_action_setting_edit_bool(const char* pstr, bool* ptr)
    {
    *ptr = !(*ptr);
    }
    #endif//ULTIPANEL

    /** LCD API **/
    void lcd_init()
    {
    lcd_implementation_init();

    #ifdef NEWPANEL
    pinMode(BTN_EN1,INPUT);
    pinMode(BTN_EN2,INPUT);
    WRITE(BTN_EN1,HIGH);
    WRITE(BTN_EN2,HIGH);
    #if BTN_ENC > 0
    pinMode(BTN_ENC,INPUT);
    WRITE(BTN_ENC,HIGH);
    #endif
    #ifdef REPRAPWORLD_KEYPAD
    pinMode(SHIFT_CLK,OUTPUT);
    pinMode(SHIFT_LD,OUTPUT);
    pinMode(SHIFT_OUT,INPUT);
    WRITE(SHIFT_OUT,HIGH);
    WRITE(SHIFT_LD,HIGH);
    #endif
    #else // Not NEWPANEL
    #ifdef SR_LCD_2W_NL // Non latching 2 wire shift register
    pinMode (SR_DATA_PIN, OUTPUT);
    pinMode (SR_CLK_PIN, OUTPUT);
    #elif defined(SHIFT_CLK)
    pinMode(SHIFT_CLK,OUTPUT);
    pinMode(SHIFT_LD,OUTPUT);
    pinMode(SHIFT_EN,OUTPUT);
    pinMode(SHIFT_OUT,INPUT);
    WRITE(SHIFT_OUT,HIGH);
    WRITE(SHIFT_LD,HIGH);
    WRITE(SHIFT_EN,LOW);
    #else
    #ifdef ULTIPANEL
    #error ULTIPANEL requires an encoder
    #endif
    #endif // SR_LCD_2W_NL
    #endif//!NEWPANEL

    #if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0)
    pinMode(SDCARDDETECT,INPUT);
    WRITE(SDCARDDETECT, HIGH);
    lcd_oldcardstatus = IS_SD_INSERTED;
    #endif//(SDCARDDETECT > 0)
    #ifdef LCD_HAS_SLOW_BUTTONS
    slow_buttons = 0;
    #endif
    lcd_buttons_update();
    #ifdef ULTIPANEL
    encoderDiff = 0;
    #endif
    }

    void lcd_update()
    {
    static unsigned long timeoutToStatus = 0;

    #ifdef LCD_HAS_SLOW_BUTTONS
    slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context
    #endif

    lcd_buttons_update();

    #if (SDCARDDETECT > 0)
    if((IS_SD_INSERTED != lcd_oldcardstatus))
    {
    lcdDrawUpdate = 2;
    lcd_oldcardstatus = IS_SD_INSERTED;
    lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it.

    if(lcd_oldcardstatus)
    {
    card.initsd();
    LCD_MESSAGEPGM(MSG_SD_INSERTED);
    }
    else
    {
    card.release();
    LCD_MESSAGEPGM(MSG_SD_REMOVED);
    }
    }
    #endif//CARDINSERTED

    if (lcd_next_update_millis < millis())
    {
    #ifdef ULTIPANEL
    #ifdef REPRAPWORLD_KEYPAD
    if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) {
    reprapworld_keypad_move_z_up();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) {
    reprapworld_keypad_move_z_down();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) {
    reprapworld_keypad_move_x_left();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) {
    reprapworld_keypad_move_x_right();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) {
    reprapworld_keypad_move_y_down();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) {
    reprapworld_keypad_move_y_up();
    }
    if (REPRAPWORLD_KEYPAD_MOVE_HOME) {
    reprapworld_keypad_move_home();
    }
    #endif
    if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP)
    {
    lcdDrawUpdate = 1;
    encoderPosition += encoderDiff / ENCODER_PULSES_PER_STEP;
    encoderDiff = 0;
    timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
    }
    if (LCD_CLICKED)
    timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
    #endif//ULTIPANEL

    #ifdef DOGLCD // Changes due to different driver architecture of the DOGM display
    blink++; // Variable for fan animation and alive dot
    u8g.firstPage();
    do
    {
    u8g.setFont(u8g_font_6x10_marlin);
    u8g.setPrintPos(125,0);
    if (blink % 2) u8g.setColorIndex(1); else u8g.setColorIndex(0); // Set color for the alive dot
    u8g.drawPixel(127,63); // draw alive dot
    u8g.setColorIndex(1); // black on white
    (*currentMenu)();
    if (!lcdDrawUpdate) break; // Terminate display update, when nothing new to draw. This must be done before the last dogm.next()
    } while( u8g.nextPage() );
    #else
    (*currentMenu)();
    #endif

    #ifdef LCD_HAS_STATUS_INDICATORS
    lcd_implementation_update_indicators();
    #endif

    #ifdef ULTIPANEL
    if(timeoutToStatus < millis() && currentMenu != lcd_status_screen)
    {
    lcd_return_to_status();
    lcdDrawUpdate = 2;
    }
    #endif//ULTIPANEL
    if (lcdDrawUpdate == 2)
    lcd_implementation_clear();
    if (lcdDrawUpdate)
    lcdDrawUpdate--;
    lcd_next_update_millis = millis() + 100;
    }
    }

    void lcd_setstatus(const char* message)
    {
    if (lcd_status_message_level > 0)
    return;
    strncpy(lcd_status_message, message, LCD_WIDTH);
    lcdDrawUpdate = 2;
    }
    void lcd_setstatuspgm(const char* message)
    {
    if (lcd_status_message_level > 0)
    return;
    strncpy_P(lcd_status_message, message, LCD_WIDTH);
    lcdDrawUpdate = 2;
    }
    void lcd_setalertstatuspgm(const char* message)
    {
    lcd_setstatuspgm(message);
    lcd_status_message_level = 1;
    #ifdef ULTIPANEL
    lcd_return_to_status();
    #endif//ULTIPANEL
    }
    void lcd_reset_alert_level()
    {
    lcd_status_message_level = 0;
    }

    #ifdef DOGLCD
    void lcd_setcontrast(uint8_t value)
    {
    lcd_contrast = value & 63;
    u8g.setContrast(lcd_contrast);
    }
    #endif

    #ifdef ULTIPANEL
    /* Warning: This function is called from interrupt context */
    void lcd_buttons_update()
    {
    #ifdef NEWPANEL
    uint8_t newbutton=0;
    if(READ(BTN_EN1)==0) newbutton|=EN_A;
    if(READ(BTN_EN2)==0) newbutton|=EN_B;
    #if BTN_ENC > 0
    if((blocking_enc<millis()) && (READ(BTN_ENC)==0))
    newbutton |= EN_C;
    #endif
    buttons = newbutton;
    #ifdef LCD_HAS_SLOW_BUTTONS
    buttons |= slow_buttons;
    #endif
    #ifdef REPRAPWORLD_KEYPAD
    // for the reprapworld_keypad
    uint8_t newbutton_reprapworld_keypad=0;
    WRITE(SHIFT_LD,LOW);
    WRITE(SHIFT_LD,HIGH);
    for(int8_t i=0;i<8;i++) {
    newbutton_reprapworld_keypad = newbutton_reprapworld_keypad>>1;
    if(READ(SHIFT_OUT))
    newbutton_reprapworld_keypad|=(1<<7);
    WRITE(SHIFT_CLK,HIGH);
    WRITE(SHIFT_CLK,LOW);
    }
    buttons_reprapworld_keypad=~newbutton_reprapworld_keypad; //invert it, because a pressed switch produces a logical 0
    #endif
    #else //read it from the shift register
    uint8_t newbutton=0;
    WRITE(SHIFT_LD,LOW);
    WRITE(SHIFT_LD,HIGH);
    unsigned char tmp_buttons=0;
    for(int8_t i=0;i<8;i++)
    {
    newbutton = newbutton>>1;
    if(READ(SHIFT_OUT))
    newbutton|=(1<<7);
    WRITE(SHIFT_CLK,HIGH);
    WRITE(SHIFT_CLK,LOW);
    }
    buttons=~newbutton; //invert it, because a pressed switch produces a logical 0
    #endif//!NEWPANEL

    //manage encoder rotation
    uint8_t enc=0;
    if(buttons&EN_A)
    enc|=(1<<0);
    if(buttons&EN_B)
    enc|=(1<<1);
    if(enc != lastEncoderBits)
    {
    switch(enc)
    {
    case encrot0:
    if(lastEncoderBits==encrot3)
    encoderDiff++;
    else if(lastEncoderBits==encrot1)
    encoderDiff--;
    break;
    case encrot1:
    if(lastEncoderBits==encrot0)
    encoderDiff++;
    else if(lastEncoderBits==encrot2)
    encoderDiff--;
    break;
    case encrot2:
    if(lastEncoderBits==encrot1)
    encoderDiff++;
    else if(lastEncoderBits==encrot3)
    encoderDiff--;
    break;
    case encrot3:
    if(lastEncoderBits==encrot2)
    encoderDiff++;
    else if(lastEncoderBits==encrot0)
    encoderDiff--;
    break;
    }
    }
    lastEncoderBits = enc;
    }

    void lcd_buzz(long duration, uint16_t freq)
    {
    #ifdef LCD_USE_I2C_BUZZER
    lcd.buzz(duration,freq);
    #endif
    }

    bool lcd_clicked()
    {
    return LCD_CLICKED;
    }
    #endif//ULTIPANEL

    /********************************/
    /** Float conversion utilities **/
    /********************************/
    // convert float to string with +123.4 format
    char conv[8];
    char *ftostr3(const float &x)
    {
    return itostr3((int)x);
    }

    char *itostr2(const uint8_t &x)
    {
    //sprintf(conv,"%5.1f",x);
    int xx=x;
    conv[0]=(xx/10)%10+'0';
    conv[1]=(xx)%10+'0';
    conv[2]=0;
    return conv;
    }

    // convert float to string with +123.4 format
    char *ftostr31(const float &x)
    {
    int xx=x*10;
    conv[0]=(xx>=0)?'+':'-';
    xx=abs(xx);
    conv[1]=(xx/1000)%10+'0';
    conv[2]=(xx/100)%10+'0';
    conv[3]=(xx/10)%10+'0';
    conv[4]='.';
    conv[5]=(xx)%10+'0';
    conv[6]=0;
    return conv;
    }

    // convert float to string with 123.4 format
    char *ftostr31ns(const float &x)
    {
    int xx=x*10;
    //conv[0]=(xx>=0)?'+':'-';
    xx=abs(xx);
    conv[0]=(xx/1000)%10+'0';
    conv[1]=(xx/100)%10+'0';
    conv[2]=(xx/10)%10+'0';
    conv[3]='.';
    conv[4]=(xx)%10+'0';
    conv[5]=0;
    return conv;
    }

    char *ftostr32(const float &x)
    {
    long xx=x*100;
    if (xx >= 0)
    conv[0]=(xx/10000)%10+'0';
    else
    conv[0]='-';
    xx=abs(xx);
    conv[1]=(xx/1000)%10+'0';
    conv[2]=(xx/100)%10+'0';
    conv[3]='.';
    conv[4]=(xx/10)%10+'0';
    conv[5]=(xx)%10+'0';
    conv[6]=0;
    return conv;
    }

    char *itostr31(const int &xx)
    {
    conv[0]=(xx>=0)?'+':'-';
    conv[1]=(xx/1000)%10+'0';
    conv[2]=(xx/100)%10+'0';
    conv[3]=(xx/10)%10+'0';
    conv[4]='.';
    conv[5]=(xx)%10+'0';
    conv[6]=0;
    return conv;
    }

    char *itostr3(const int &xx)
    {
    if (xx >= 100)
    conv[0]=(xx/100)%10+'0';
    else
    conv[0]=' ';
    if (xx >= 10)
    conv[1]=(xx/10)%10+'0';
    else
    conv[1]=' ';
    conv[2]=(xx)%10+'0';
    conv[3]=0;
    return conv;
    }

    char *itostr3left(const int &xx)
    {
    if (xx >= 100)
    {
    conv[0]=(xx/100)%10+'0';
    conv[1]=(xx/10)%10+'0';
    conv[2]=(xx)%10+'0';
    conv[3]=0;
    }
    else if (xx >= 10)
    {
    conv[0]=(xx/10)%10+'0';
    conv[1]=(xx)%10+'0';
    conv[2]=0;
    }
    else
    {
    conv[0]=(xx)%10+'0';
    conv[1]=0;
    }
    return conv;
    }

    char *itostr4(const int &xx)
    {
    if (xx >= 1000)
    conv[0]=(xx/1000)%10+'0';
    else
    conv[0]=' ';
    if (xx >= 100)
    conv[1]=(xx/100)%10+'0';
    else
    conv[1]=' ';
    if (xx >= 10)
    conv[2]=(xx/10)%10+'0';
    else
    conv[2]=' ';
    conv[3]=(xx)%10+'0';
    conv[4]=0;
    return conv;
    }

    // convert float to string with 12345 format
    char *ftostr5(const float &x)
    {
    long xx=abs(x);
    if (xx >= 10000)
    conv[0]=(xx/10000)%10+'0';
    else
    conv[0]=' ';
    if (xx >= 1000)
    conv[1]=(xx/1000)%10+'0';
    else
    conv[1]=' ';
    if (xx >= 100)
    conv[2]=(xx/100)%10+'0';
    else
    conv[2]=' ';
    if (xx >= 10)
    conv[3]=(xx/10)%10+'0';
    else
    conv[3]=' ';
    conv[4]=(xx)%10+'0';
    conv[5]=0;
    return conv;
    }

    // convert float to string with +1234.5 format
    char *ftostr51(const float &x)
    {
    long xx=x*10;
    conv[0]=(xx>=0)?'+':'-';
    xx=abs(xx);
    conv[1]=(xx/10000)%10+'0';
    conv[2]=(xx/1000)%10+'0';
    conv[3]=(xx/100)%10+'0';
    conv[4]=(xx/10)%10+'0';
    conv[5]='.';
    conv[6]=(xx)%10+'0';
    conv[7]=0;
    return conv;
    }

    // convert float to string with +123.45 format
    char *ftostr52(const float &x)
    {
    long xx=x*100;
    conv[0]=(xx>=0)?'+':'-';
    xx=abs(xx);
    conv[1]=(xx/10000)%10+'0';
    conv[2]=(xx/1000)%10+'0';
    conv[3]=(xx/100)%10+'0';
    conv[4]='.';
    conv[5]=(xx/10)%10+'0';
    conv[6]=(xx)%10+'0';
    conv[7]=0;
    return conv;
    }

    // Callback for after editing PID i value
    // grab the PID i value out of the temp variable; scale it; then update the PID driver
    void copy_and_scalePID_i()
    {
    #ifdef PIDTEMP
    Ki = scalePID_i(raw_Ki);
    updatePID();
    #endif
    }

    // Callback for after editing PID d value
    // grab the PID d value out of the temp variable; scale it; then update the PID driver
    void copy_and_scalePID_d()
    {
    #ifdef PIDTEMP
    Kd = scalePID_d(raw_Kd);
    updatePID();
    #endif
    }

    #endif //ULTRA_LCD

    код выделить все
    #ifndef ULTRALCD_H
    #define ULTRALCD_H

    #include &quot;Marlin.h&quot;

    #ifdef ULTRA_LCD

    void lcd_update();
    void lcd_init();
    void lcd_setstatus(const char* message);
    void lcd_setstatuspgm(const char* message);
    void lcd_setalertstatuspgm(const char* message);
    void lcd_reset_alert_level();

    #ifdef DOGLCD
    extern int lcd_contrast;
    void lcd_setcontrast(uint8_t value);
    #endif

    static unsigned char blink = 0; // Variable for visualization of fan rotation in GLCD

    #define LCD_MESSAGEPGM(x) lcd_setstatuspgm(PSTR(x))
    #define LCD_ALERTMESSAGEPGM(x) lcd_setalertstatuspgm(PSTR(x))

    #define LCD_UPDATE_INTERVAL 100
    #define LCD_TIMEOUT_TO_STATUS 15000

    #ifdef ULTIPANEL
    void lcd_buttons_update();
    extern volatile uint8_t buttons; //the last checked buttons in a bit array.
    #ifdef REPRAPWORLD_KEYPAD
    extern volatile uint8_t buttons_reprapworld_keypad; // to store the keypad shift register values
    #endif
    #else
    FORCE_INLINE void lcd_buttons_update() {}
    #endif

    extern int plaPreheatHotendTemp;
    extern int plaPreheatHPBTemp;
    extern int plaPreheatFanSpeed;

    extern int absPreheatHotendTemp;
    extern int absPreheatHPBTemp;
    extern int absPreheatFanSpeed;

    void lcd_buzz(long duration,uint16_t freq);
    bool lcd_clicked();

    #ifdef NEWPANEL
    #define EN_C (1&lt;&lt;BLEN_C)
    #define EN_B (1&lt;&lt;BLEN_B)
    #define EN_A (1&lt;&lt;BLEN_A)

    #define LCD_CLICKED (buttons&amp;EN_C)
    #ifdef REPRAPWORLD_KEYPAD
    #define EN_REPRAPWORLD_KEYPAD_F3 (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_F3)
    #define EN_REPRAPWORLD_KEYPAD_F2 (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_F2)
    #define EN_REPRAPWORLD_KEYPAD_F1 (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_F1)
    #define EN_REPRAPWORLD_KEYPAD_UP (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_UP)
    #define EN_REPRAPWORLD_KEYPAD_RIGHT (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_RIGHT)
    #define EN_REPRAPWORLD_KEYPAD_MIDDLE (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_MIDDLE)
    #define EN_REPRAPWORLD_KEYPAD_DOWN (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_DOWN)
    #define EN_REPRAPWORLD_KEYPAD_LEFT (1&lt;&lt;BLEN_REPRAPWORLD_KEYPAD_LEFT)

    #define LCD_CLICKED ((buttons&amp;EN_C) || (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_F1))
    #define REPRAPWORLD_KEYPAD_MOVE_Z_UP (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_F2)
    #define REPRAPWORLD_KEYPAD_MOVE_Z_DOWN (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_F3)
    #define REPRAPWORLD_KEYPAD_MOVE_X_LEFT (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_LEFT)
    #define REPRAPWORLD_KEYPAD_MOVE_X_RIGHT (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_RIGHT)
    #define REPRAPWORLD_KEYPAD_MOVE_Y_DOWN (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_DOWN)
    #define REPRAPWORLD_KEYPAD_MOVE_Y_UP (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_UP)
    #define REPRAPWORLD_KEYPAD_MOVE_HOME (buttons_reprapworld_keypad&amp;EN_REPRAPWORLD_KEYPAD_MIDDLE)
    #endif //REPRAPWORLD_KEYPAD
    #else
    //atomic, do not change
    #define B_LE (1&lt;&lt;BL_LE)
    #define B_UP (1&lt;&lt;BL_UP)
    #define B_MI (1&lt;&lt;BL_MI)
    #define B_DW (1&lt;&lt;BL_DW)
    #define B_RI (1&lt;&lt;BL_RI)
    #define B_ST (1&lt;&lt;BL_ST)
    #define EN_B (1&lt;&lt;BLEN_B)
    #define EN_A (1&lt;&lt;BLEN_A)

    #define LCD_CLICKED ((buttons&amp;B_MI)||(buttons&amp;B_ST))
    #endif//NEWPANEL

    #else //no LCD
    FORCE_INLINE void lcd_update() {}
    FORCE_INLINE void lcd_init() {}
    FORCE_INLINE void lcd_setstatus(const char* message) {}
    FORCE_INLINE void lcd_buttons_update() {}
    FORCE_INLINE void lcd_reset_alert_level() {}
    FORCE_INLINE void lcd_buzz(long duration,uint16_t freq) {}

    #define LCD_MESSAGEPGM(x)
    #define LCD_ALERTMESSAGEPGM(x)
    #endif

    char *itostr2(const uint8_t &amp;x);
    char *itostr31(const int &amp;xx);
    char *itostr3(const int &amp;xx);
    char *itostr3left(const int &amp;xx);
    char *itostr4(const int &amp;xx);

    char *ftostr3(const float &amp;x);
    char *ftostr31ns(const float &amp;x); // float to string without sign character
    char *ftostr31(const float &amp;x);
    char *ftostr32(const float &amp;x);
    char *ftostr5(const float &amp;x);
    char *ftostr51(const float &amp;x);
    char *ftostr52(const float &amp;x);

    #endif //ULTRALCD

    Для тахомерчика выкладывать?
    Ну скажем

    код выделить все

    #define RPMpin 2 // катушка зажигания
    volatile long rpm = 0;

    void setup()
    {
    Serial.begin(9600);
    attachInterrupt(0, RPM, FALLING);
    }

    void loop()
    {
    Serial.println(rpm, DEC); // об/мин
    delay(100);
    }

    void RPM ()
    {
    static unsigned long micros_prev;
    rpm = (1000000.0/(micros() - micros_prev))*60/2;
    micros_prev = micros();
    }

    Круиз-контроль 88 км/ч. Радость никакая печаль.
  • Drosha Senior Member
    офлайн
    Drosha Senior Member

    1966

    18 лет на сайте
    пользователь #86205

    Профиль
    Написать сообщение

    1966
    # 30 ноября 2014 21:26

    немного не в тему но может кто знает где в Минске можно найти такие разъемы https://www.sparkfun.com/products/570 ?

  • Ded140 Senior Member
    офлайн
    Ded140 Senior Member

    771

    14 лет на сайте
    пользователь #451748

    Профиль
    Написать сообщение

    771
    # 1 декабря 2014 12:44

    код для тахометра интересный, только вот у меня 7-ми сегментный двух разрядный индикатор

    <p>Стараний мало для достижения цели.</p>
  • МиГ Senior Member
    офлайн
    МиГ Senior Member

    2168

    19 лет на сайте
    пользователь #53792

    Профиль
    Написать сообщение

    2168
    # 1 декабря 2014 18:54 Редактировалось МиГ, 1 раз.

    Народ, и сразу же появился вопрос. Пробовал вчера побаловаться с дисплейчиком от nokia 5110. Целый день провозился, а он собака так и не заработал, попробовал подключить на работе к ноуту и блин, никаких проблем, запустилось все с первого раза. Причем ставил туже самую библиотеку и загружал тот же скетч. Опять пришел проверить дома, и опять какая-то хрень.
    Выскочила ошибка

    Arduino: 1.5.8 ( Windows 8 ), Board: "Arduino Uno"

    sketch_dec01a.ino:11:38: error: variable 'logoBmp' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
    Ошибка компиляции.

    This report would have more information with
    "Show verbose output during compilation"
    enabled in File > Preferences.

    А это собственно сам скетч

    #include <Adafruit_GFX.h>
    #include <Adafruit_PCD8544.h>

    // pin 3 - Serial clock out (SCLK)
    // pin 4 - Serial data out (DIN)
    // pin 5 - Data/Command select (D/C)
    // pin 7 - LCD chip select (CS)
    // pin 6 - LCD reset (RST)
    Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6);

    static unsigned char PROGMEM logoBmp[] =
    {
    B11111111, B11111111, B10000000,
    B11111111, B11111111, B10000000,
    B11111111, B11111111, B10000000,
    B11111100, B00000011, B10000000,
    B11111000, B00000001, B10000000,
    B11111100, B00000011, B10000000,
    B11111111, B11000011, B10000000,
    B11111111, B10000111, B10000000,
    B11111111, B10001111, B10000000,
    B11111111, B00001111, B10000000,
    B11111110, B00011111, B10000000,
    B11111110, B00011111, B10000000,
    B11111100, B00111111, B10000000,
    B11111100, B01111111, B10000000,
    B11111000, B00000011, B10000000,
    B11111000, B00000001, B10000000
    };

    void setup() {
    Serial.begin(9600);

    // Инициализация дисплея
    display.begin();

    // Очищаем дисплей
    display.clearDisplay();
    display.display();

    // Устанавливаем контраст
    display.setContrast(50);
    delay(1000);
    }

    void loop()
    {
    // Рисуем заранее подготовленное лого
    // Подготовлен массив из 16 пар байтов
    // каждый байт состоит из 8 битов, соответсвенно
    // получаем матрицу 16х16 битов, 1-черный цвет, 0-белый цвет
    display.drawBitmap(LCDWIDTH/2-8, LCDHEIGHT/2-8, logoBmp, 24, 16, BLACK); // x, y, logo, w, h, color
    display.display();
    delay(10000);
    // Рисуем несколько пикселей (точек)
    display.drawPixel(0, 0, BLACK);
    display.drawPixel(1, 1, BLACK);
    display.drawPixel(2, 2, WHITE); // Посередине белый пиксель
    display.drawPixel(3, 3, BLACK);
    display.drawPixel(4, 4, BLACK);
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем диагональ
    display.drawLine(0, LCDHEIGHT-1, LCDWIDTH, 0, BLACK); // x0, y0, x1, y1, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Для рисования вертикальных и горизонтальных линий лучше использовать
    // более быстрые функции
    display.drawFastVLine(LCDWIDTH/2, 0, LCDHEIGHT, BLACK); // x, y, h, color
    display.drawFastHLine(0, LCDHEIGHT/2, LCDWIDTH, BLACK); //x, y, w, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем прямоугольник
    display.drawRect(LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, LCDHEIGHT/2, BLACK); // x, y, w, h, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем закрашенный прямоугольник
    display.fillRect(LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, LCDHEIGHT/2, BLACK); // x, y, w, h, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Закрашиваем весь дисплей
    display.fillScreen(BLACK);
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем окружность
    display.drawCircle(LCDWIDTH/2, LCDHEIGHT/2, LCDHEIGHT/2, BLACK); // x, y, r, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем закрашенную окружность
    display.fillCircle(LCDWIDTH/2, LCDHEIGHT/2, LCDHEIGHT/2, BLACK); // x, y, r, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем треугольник
    display.drawTriangle(LCDWIDTH/4, LCDHEIGHT/4, 3*LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, 3*LCDHEIGHT/4, BLACK); // x0, y0, x1, y1, x2, y2, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем закрашенный треугольник
    display.fillTriangle(LCDWIDTH/4, LCDHEIGHT/4, 3*LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, 3*LCDHEIGHT/4, BLACK); // x0, y0, x1, y1, x2, y2, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем прямоугольник с закругленными углами
    display.drawRoundRect(LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, LCDHEIGHT/2, 10, BLACK); // x, y, w, h, r, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем закрашенный прямоугольник с закругленными углами
    display.fillRoundRect(LCDWIDTH/4, LCDHEIGHT/4, LCDWIDTH/2, LCDHEIGHT/2, 10, BLACK); // x, y, w, h, r, colordisplay.display();
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Рисуем заранее подготовленное лого
    // Подготовлен массив из 16 пар байтов
    // каждый байт состоит из 8 битов, соответсвенно
    // получаем матрицу 16х16 битов, 1-черный цвет, 0-белый цвет
    display.drawBitmap(LCDWIDTH/2-8, LCDHEIGHT/2-8, logoBmp, 24, 16, BLACK); // x, y, logo, w, h, color
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);

    // Выведем текст
    // Устанавливаем курсор
    display.setCursor(0, 0);
    // Устанавливаем цвет текста
    display.setTextColor(BLACK);
    // Устанавливаем размер текста
    display.setTextSize(1);
    // Выводим текст
    display.write('Z');
    display.write('e');
    display.write('l');
    display.write('e');
    display.write('c');
    display.write('t');
    display.write('r');
    display.write('o');
    display.display();
    delay(1000);

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    delay(1000);
    }

    Что не так, помогите кто плиз.

  • Drosha Senior Member
    офлайн
    Drosha Senior Member

    1966

    18 лет на сайте
    пользователь #86205

    Профиль
    Написать сообщение

    1966
    # 1 декабря 2014 19:08

    попробуйте

    код выделить все
    static unsigned char PROGMEM

    поменять на

    код выделить все
    const unsigned char PROGMEM