طراحی منو های تو در توی گرافیکی

  • نویسنده موضوع Alma
  • تاریخ شروع

Alma

مدیر
پرسنل مدیریت
مهمترین نکته این کار مشترک سازی منو های هست
یعنی بیاییم نقاط مشترک و مهمی که توی همه منوها نیازه رو جدا کنیم و طبق اونها یک یا چنتا جدول بسازیم یا اگر نیست نزدیک به همشون بکنیم
برای مثال توی همه منو ها مقدار مینیمم ،ماکزیمم ، مقدار پیشفرض ، واحد ، محدوده متغییر ، رشته ، و ... مشترک هستند یعنی همشون این موارد رو باید داشته باشن

من در این روش منو ها رو به سه قسمت اصلی تقرسیم کردم

1 - منو های بدون مقدار

منو های بدون مقدار به منوهایی میگم که یه تعداد منوی دیگه توش هست یعنی صرفا یه رشته هست که یه تعداد منوی دیگه رو از هم جدا میکنه برای طبقه بندی و مرتب کردن منو ها از هم استفاده میشه مثل منوی File توی اکثر نرم افزار ها که چنتا زیرذ منو رو توی هودش طبقه بندی کرده
نکته های مشترک این قسمت میتونه ادیکس رشته هر منو ، ادرس اولین رشته داخل منو ، تعداد منوی داخلی ئ و .. باشه

2 - منو های با مقدار یا زیر منو با موارد مشترک

زیر منو یا منو های مقدار دار مشترک به منوهایی میگم که یک متغیر باهاش ارتباط داره و با انتخاب اون میتونیم مقدار متغیر رو تغییر بدیم خود این زیر منو میتونه کلی شرایط خاص داشته باشه که ما اون نکته های مشترکی که بین همشون ثابت هستند رو پیدا و جدول بندی میکنیم

3 - منو های خاص بدون موارد مشترک که نیاز به فراخوانی تابع خاص دارند

منوهای خاص منوهایی هستند که شرایط مشترکی ندارند و برای مقدار دهی اونها نیاز به تابعی مخصوص دارد برای مثال قراره چند متغییر مقدار دهی بشه


برای مثال به جدول زیر توجه کنید

upload_2020-5-9_18-50-42.png


در حالت کلی من دوتا تابع اصلی دارم یکی برای نمایش و پیمایش بین منوها که مربوط میشه به مورد 1 و دومی برای مقدار دهی و فراخوانی توابع در صورت لزوم که مربوط میشه به مورد های دوم و سوم

اما جدول ها و رشته های مورد نیاز
معمولا به صورت کلی سه تا رشته دارم

1 - اسم منو ها و زیر منو ها
2 - واحد ها
3 - رشته منو های رشته ای

مورد اول و دوم که مشخصه در مورد سومی توضیح میدم
بعضی وقتا منوهایی نیازه که به جای مقدار عددی قراره یه رشته نمایش داده بشه برای مثال وقتی قراره بازر فعال و غیر فعال بشه هم میشه 0 یا 1 نمایش داد هم اینکه خود رشته فعال و غیرفعال رو نمایش بدیم که طبیعتا خوشگل تر خواهد بود مورد سوم همین رشته ها هستند

یک جدول اصلی هم نیاز هست که تصویر فوق بخشی از اون رو نمایش میده و کلیه موارد و مقادریر هر منو و زیر منو رو در خودش جای میده

معمولا چنتا هم یونیون دارم که نوع متغیر ها ، واحد و شناسه تابع رو مشخص میکنه و برای مقدار دهی راحت تر جدول استفاده میشه

برای راحتی کار یه رشته عددی از نوع علامت دار 16 بیت int16_t دارم که مقدار همه منو ها توی اون هست ابتدای برنامه حافظه ثابت رو کلا میخونم و در این رشته قرار میدم و نهایتا در صورتی که کاربر وارد منو ها بشه و مقداری رو تغییر بده مقدار همین متغیر و حافظه اصلی که در فلش یا eeprom هست تغییر میکنه

یکم وارد جزئیات میشیم
همونطوری که قبلا عرض شد دوتا تابع اصلی داریم که اولی برای پیمایش در منو ها هست این تابع یه ورودی داره که استارت منویی هایی هست که قراره نمایش بده
کد:
void Menu (int16_t Index);
وقتی کاربر کلید منو رو میزنه این تابع با مقدار 0 فراخوانی میشه و مقدار اولین عضو جدول خونده میشه همونطوری که در تصویر مشخصه هر عضو 6 تا مقدار داره اولین عضو ادرس استارت اولین عضو منو رو در همین جدول رو بهمون میگه برای مثال اولین مقدار اولین عضو ما 1 هست دومی 9 یعنی از ادرس 1 باید 9 منوی جدول نمایش داده بشه
اگر اولین عضو هر منو در جدول مقدارش بیشتر از صفر باشه یعنی این منو از نوع 1 هست و با انتخاب اون دوباره تابع منو فراخوانی خواهد شد اما این بار ورودی تابع همین مقدار استارت خواهد بود
توی این کد من یه نوع Access در نظر گرفتم که با وارد شدن کاربر با هرکدوم از این Access ها یع تعداد خاصی از منو ها برای کاربر دردسترش خواهد بود برای مثال برای اولین منو که SETTING هست در صورتی که کار بر با Access یک یا دو وارد بشه 9 منو دیده خواهد شد ولی اگر با Access سه وارد بشه فقط 4 تا منو دیده خواهد شد
عضو پنجم VT_NULL هست که نوع Variable Type رو مشخص میکنه که اینجا کاربردی نداره
عضو ششم هم ادرس String Index هست که مقدار ادرس رشته رو از لیست رشته های منو هارو بهمون میده
نوع منوها
کد:
typedef enum {     //VARIABLE_TYPE
    VT_NULL=0,
    VT_VOID=100,
    VT_BIT,
    VT_U08,
    VT_S08,
    VT_U16,
    VT_S16,
    VT_U32,
    VT_S32,
    VT_F01,
    VT_F02,
    VT_F03,
    VT_F04,
    VT_STR 
}VARIABLE_TYPE;
واحد منوها
کد:
typedef enum {    //VARIABLE_UNIT
    VU_NULL=0,
    VU_MSEC,
    VU_SEC,
    VU_MIN,
    VU_HUR,
    VU_DAY,
    VU_MON,
    VU_YEAR,
    VU_MM,
    VU_M,
    VU_V,
    VU_A,
    VU_W,
    VU_KG,
    VU_N
}VARIABLE_UNIT;

منتظر ادامه اموزش در پست بعدی باشید!!!
 

Alma

مدیر
پرسنل مدیریت
برای دسترسی راحت تر به رشته ها من معمولا یه تابع مینویسم که با دادن اندیس رشته ادرس رشته رو برمیگردونه
توی این روش دیکه اندازه رشته ها میتونه متغیر هست و باعث میشه حجم فلش خیلی کمتر بشه
اینجا سه تا تابع مهعمشو میزارم تا با روش کار اشنا بشید

برای رشته واحدها
کد:
const char *put_Unit_Strs (int16_t index){
    const char *Unit_Strs={
        "\0"            //        VU_NULL
        "mS\0"            //0        VU_MSEC
        "Sec\0"            //1        VU_SEC
        "Min\0"            //2        VU_MIN
        "Hour\0"        //3        VU_HUR
        "Day\0"            //4        VU_DAY
        "Month\0"        //5        VU_MON
        "Year\0"        //6        VU_YEAR
        "mm\0"            //7        VU_MM
        "M\0"            //8        VU_M
        "V\0"            //9        VU_V
        "A\0"            //10    VU_A
        "W\0"            //11    VU_W
        "Kg\0"            //12    VU_KG
        "Person\0"        //13    VU_N
        "Number\0"        //14    VU_NUM
    };
    const char *p;
    for(p = Unit_Strs; index; p++)if(!*p)index--;
    return p;
}
برای متغیر های رشته ای "با توجه به توضیحات پست قبل"
کد:
const char *put_Value_Strs (u8 index){
    const char *Value_Strs={
        //-------------------------
        "غير فعال\0"            //0
        "فعال\0"                //1
        "بسته\0"                //2
        "باز\0"                //3
        "خاموش\0"            //4
        "روشن\0"                //5
        "بازسازي\0"            //6
        "نرمال\0"                //7
        "دستي\0"                //8
        "اتوماتيک\0"            //9
        "بالا\0"                //10
        "پايين\0"                //11
        "راست\0"                //12
        "چپ\0"                //13
        "جلو\0"                //14
        "عقب\0"                //15
        "کم\0"                //16
        "زياد\0"                //17
        "کمتر\0"                //18
        "بيشتر\0"                //19
        "فارسي\0"                //20
        "English\0"            //21
        "\0"                //22
        };
    const char *p;
    for(p = Value_Strs; index; p++)if(!*p)index--;
    return p;
}
دلیل بهم ریختن نمایش کد ترکیب حروف فارسی و انگلیسی هست
در ادیتور محیط کامپایلر به این صورت نمایش داده میشه

upload_2020-5-10_1-55-30.png

برای خود منو ها
چون منو ها هنوز کامل نشده و کار داره یه تعدادیشون هنوز خالی هستن و مقداری ندارن
کد:
const char *put_Menu_Strs (u8 index){
    const char *Menu_Strs={
        "\0"                        //0
        "منوي اصلي\0"                    //1
        "تنظبمات\0"                    //2        *
        "گزارشها\0"                    //3        #
        "ارتباط با ما\0"                    //4        #
        "\0"                        //5
        "\0"                        //6
        "\0"                        //7
        "\0"                        //8
//-------------------------------------------تنظيمات--------------------------------------------
        "تنظيمات عمومي\0"                //9        *
        "تنظيمات سريع\0"                //10    *
        "تنظيمات کنترلي\0"                //11    *
        "تنظيمات پيش فرض\0"                //12    #
        "\0"                        //13
        "\0"                        //14
        "\0"                        //15
        "\0"                        //16
//------------------------------------------تنظيمات عمومي----------------------------------------------
        "ساعت و تاريخ\0"                //17    #
        "بازر\0"                        //18    %
        "صفحه نمايش\0"                    //19    %
        "زبان سيستم\0"                    //20    %
        "تغيير رمز عبور\0"                //21    #
        "\0"                        //22
        "\0"                        //23
        "\0"                        //24
//------------------------------------------تنظيمات کنترلي----------------------------------------------
        "تنظيمات آب\0"                    //25    *
        "تنظيمات هوا\0"                    //26    *
        "تنظيمات روشنايي\0"                //27    *
        "تنظيمات تغذيه\0"                //28    *
        "تنظيمات ورودي و خروجي\0"        //29    *
        "تنظيمات سنسورها\0"                //30    *
        "تنظيمات شبکه\0"                //31    *
        "\0"                        //32
//------------------------------------------تنظيمات آب----------------------------------------------
        "توان نامي بخاري\0"                //33    %
        "دماي آب\0"                    //34    %
        "کمينه دماي آب\0"                //35    %
        "بيشينه دماي آب\0"                //36    %
        "اخطار دماي بالا\0"                //37    %
        "اخطار دماي پايين\0"                //38    %
        "روش کنترل دما\0"                //39    %
        "بيشينه زمان روشن بودن\0"            //40    %
        "بيشينه زمان خاموش بودن\0"        //41    %
        "تنظيم مقدار P\0"                //42    %
        "تنظيم مقدار I\0"                //43    %
        "تنظيم مقدار D\0"                //44    %
        "کنترل سطح آب\0"                //46    %
        "\0"                        //47
        "\0"                        //45
        "\0"                        //48
    };

    const char *p;
    for(p = Menu_Strs; index; p++)if(!*p)index--;
    return p;
}


این منو ها برای یه سیستم کنترل حوضچه تکثیر ماهی یا اکواریوم هست

ادامه مطلب در پست بعدی
 
آخرین ویرایش:

Alma

مدیر
پرسنل مدیریت
در این پست قراره تابع اولمون یعنی تابع پیمایش منو ها رو بنویسیم و در موردش توضیحاتی ارائه کنیم
حتما وقتی قراره اقدام کنیم برای نوشتن منو ،قبلا lcd یا نمایشگرمون درایو شده و توابع اون در دسترش هست پس طبق نمایشگر خودتونو باید توابع کار با lcd رو جایگزین توابعی که بنده استفاده کردم بکنید
از طرفی توابعی برای خوندن eeprom یا فلش که دیتا متغیر های متصل به منو ها در اونجا ذخیره میشه هم قبلا نوشته شده و به کد اضافه شده

اولین کاری که باید در تابع انجام بشه ورود به محیط دریافت رمز ورود هست و چک کردن لول Access به این صورت که اگر بزرگتر از صفر باشه تابع رو ادامه میدیم در غیر این صورت از تابع خارج میشیم
حالا در صورتی که رمز ورودی درست باشه بر طبق رمزی که وارد شده یکی از لول های Access انتخاب میشه و وارد تابع میشیم

با استفاده از تابع مربطه اطلاعات منو ها که قبلا ذخیره شده رو میخونیم و در متغیر قرار میدیم
تعداد منو هایی که میتونیم در این پیج نمایش بدیم رو از جدولی که نوشتیم میخونیم و در متغیری به اسم Scroll_Max میریزیم به این صورت
کد:
Menu_Lengths[Index][User_Access_Level]
نمایشگر رو پاک میکنیم
فونت مورد نظر رو انتخاب میکنیم
دوباره از جدول ادرس رشته اسم منو رو میخونیم و با استفاده از تابع put_Menu_Strs رشته مربوطه این پیج رو در سربرگ صفحه جاری مینیوسیم به این صورت
کد:
LCDFarsiText(put_Menu_Strs(Menu_Lengths[Index][STR_INDEX]),24,0,128,0,1);
وارد یک حلقه while بینهایت میشیم
قبل از ورود به کیس با استفاده از دستور if فشرده شدن یکی از کلید هارو چک میکنیم در صورتی که کلیدی فشرده شده باشه
متغیری به نام Access_Timer رو مقدار دهی میکنیم با استفاده از این متغیر قراره اگر تا یه زمان مشخصی به کلید ها دست نزنیم از تابع خارج بشیم و لول Access رو صفر کنیم
بعد یه متغیر دیگه رو به اسم f_reload صفر میکنیماین متغیر قراره اگر کیلیدی فشرده شده باشه اطلاعات نمایشگر رو از نو بنویسه
اینجا باید کلید های پنل رو چک کنیم پس براش یه سویچ کیس مینویسیم که کیس هاش اسم کلید هاست

طبق نیاز پروژه در این کد برای پیمایش به دوتا کلید نیازه یعنی بالا و پایین لذا برای این دو کلید به این صورت کدنویسی میکنیم
توجه داشته باشید که اینجا برای اسکرول به دو تا متغییر نیاز دارم حالا چرا دوتا ؟؟؟
حتما دیدین که وقتی وارد صفحه ای میشیم اولین مورد به صورت پیش فرض انتخاب شده و فرض کنید توی هر فحه میشه فقط 5 تا منو نمایش داده بشه اما اگر تعداد منو های ما بیشتر از 5 تا باشه بعد از اینکه اسکرول به اخرین مورد صفحه میشه یعنی پنجمین مورد اگر باز هم پایینتری بیاییم همه منو ها یه مورد به بالا شیفت پیدا میکنه پس یه متغیر برای اسکرول نیازه که فقط تا 5 قراره افزایش پیدا کنه و ممتغییر دوم شیفت هست که حد اگثر مقدارش میشه 5 منهای همه منوهای قابل مایش در صفحه جاری
پس یه کدی مشابه کد زیر مینویسیم

کد:
            case UP_KEY:
                if(Scroll_Index)
                    Scroll_Index--;
                else if(Scroll_Shift)
                    Scroll_Shift--;
                break;
            case DOWN_KEY:
                if(Scroll_Index < 4)
                {
                    if(Scroll_Index < Scroll_Max - 1) Scroll_Index++;
                } else {
                    if(Scroll_Index + Scroll_Shift < Scroll_Max-1) Scroll_Shift++;
                }

                break;

اما نیاز دو تا کلید دیگه هم داریم یعنی ورودی یا اینتر و خروج
تکلیف کلید خروج که مشخصه فقط کافیه از دستور return استفاده کرده و از تابع خارج بشیم
اما برای کلید اینتر باید چک کنیم ببینیم منویی که انتخاب شده قابل مقدار دهی هست یا لیستی از منو های دیگه
این کار رو باز با استفاده از جدولمون به این صورت انجام میدیم

کد:
temp = Menu_Lengths[Index][START_INDEX] + Scroll_Shift + Scroll_Index;
                if(Menu_Lengths[temp][START_INDEX])
                {
                    Menu(temp);
                } else {
                    Set_menu_Value(temp);
                }
یعنی اگر اولین مقدار عضو انتخاب شده جدولمون که اسمشو گذاشتم START_INDEX مقدار داشته باشه یعنی لیستی از منو های دیگه رو خواهیم داشت پس دوباره همین تابع رو صدا میزنیم اما این بار با مقدار جدیدی که ازجدول خوندبم
ولی اگر صفر باشه یعنی میشه مقدار دهی کرد پس تابع دوممون رو که قراره بعدا توضیح داده بشه رو صدا میکنیم

بعد از کد بالا کد رو به این ورت ادامه میدیم
اینجایی جایی هست که بعد از خروج از توابع فراخوانی شده دوباره به همین تابع برمیگردیم
باید دوباره نمایشگر رو پاک میکنیم
فونت رو انتخاب میکنیم
و رشته سربرگ رو بالای صفحه مینیویسیم و از کیس خارج میشیم

حالا فقط میمونه نمایش منو ها و هایلایت کردن منویی که انتخاب شده

برای این کار با دستور if متغیر صفر بودن متغیر f_reload رو چک میکنیم در صورت صفر بودن مقدارشو 1 میکنیم
فونت رو انتخاب میکنیم
یه حلقه for برای نمایش رشته هایی که باید نمایش داده بشه مینویسیم باز با استفاده از جدولمون ادرس رشته هر عضو رو پیدا میکنیم و با استفاده از تابع put_Menu_Strs در موقعیت خودش نمایش میدیم
توی این حلقه باز با استفاده از دستور if منوی انتخاب شده و دیگر مینو هارو جدا میکنیم
توابع نمایش گر من طوری هست که دو ورودی اخر تابع رنگ پس زمینه و رنگ فونت رو مشخص میکنه پس برای منویی که انتخاب شده مقدار یک برای پس زمینه و مقدار صفر برای رنگ خود فونت ارسال میشه و برای رشته های دیگه که انتخاب نشدن برعکس خواهد بود

بعد از حلقه خارج شده و ایکون کلید هایی که امکان عملکرد دارن در جای خودشون نمایش داده میشه
چون کلید های ورود و خروج محدودیتی ندارن همیشه روشن هستن ولی برای کلید های بالا برای اولین منو و کلید اخر برای اخرین منو محدودیت ایجاد میکنیم

کد:
        if(!f_reload) {
            f_reload = 1;
            SetFont(Farsi);

            for(i = 0; i < Scroll_Max && i < 5; i++) {
                temp = Menu_Lengths[i + Menu_Lengths[Index][START_INDEX] + Scroll_Shift][STR_INDEX];
                if(i == Scroll_Index)
                    LCDFarsiText(put_Menu_Strs(temp), 0, i * 9 + 9, 128, 0, 1);
                else
                    LCDFarsiText(put_Menu_Strs(temp), 0, i * 9 + 9, 128, 1, 0);
            }

            symbol = _BV(KS_S) | _BV(KS_E);
            if(Scroll_Index + Scroll_Shift)sbi(symbol,KS_U);
            if(Scroll_Max > Scroll_Index + Scroll_Shift + 1)sbi(symbol,KS_D);
            Key_Symbol(0 ,56 ,symbol ,1 ,0);
        }

در اخر متغیر Access_Timer رو چک میکنیم تا اگر مقدارش صفر شده باشه از تابع خارج بشیم
مقدار این متغیر در تابع تایمر هر 100 میلی ثانیه یک واحد کم میشه

نهایتا تابعی به این صورت خواهیم داشت


کد:
void         Menu(uint8_t Index){

    uint8_t Scroll_Index=0;
    uint8_t Scroll_Max=0;
    uint8_t Scroll_Shift=0;
    uint8_t symbol=0;
    uint8_t f_reload=0;
    uint16_t i,temp;

    if(!User_Access_Level)
    {
        User_Access_Level = Set_Password(0);
        if(!User_Access_Level) return;
    }
  

    reload_eeprom_data();

    Scroll_Max = Menu_Lengths[Index][User_Access_Level];

    GRAM_clear();
    SetFont(Farsi);
    LCDFarsiText("<",0,0,128,0,1);
    LCDFarsiText(put_Menu_Strs(Menu_Lengths[Index][STR_INDEX]),24,0,128,0,1);

    while(1) {
        if(!f_key)
        {
            if(KEY != NO_KEY)
            {
                Access_Timer = Access_Timer_var;
                f_reload = 0;
            }
            switch(KEY)
            {
            case UP_KEY:
                if(Scroll_Index)
                    Scroll_Index--;
                else if(Scroll_Shift)
                    Scroll_Shift--;
                break;
            case DOWN_KEY:
                if(Scroll_Index < 4)
                {
                    if(Scroll_Index < Scroll_Max - 1) Scroll_Index++;
                } else {
                    if(Scroll_Index + Scroll_Shift < Scroll_Max-1) Scroll_Shift++;
                }

                break;
            case ENTER_KEY:
                f_key = 1;
                temp = Menu_Lengths[Index][START_INDEX] + Scroll_Shift + Scroll_Index;
                if(Menu_Lengths[temp][START_INDEX])
                {
                    Menu(temp);
                } else {
                    Set_menu_Value(temp);
                }
                GRAM_clear();
                SetFont(Farsi);
                LCDFarsiText("<",0,0,128,0,1);
                LCDFarsiText(put_Menu_Strs(Menu_Lengths[Index][STR_INDEX]),24,0,128,0,1);
                break;
            case ESC_KEY:
                f_key = 1;
                return;
                break;
            }
            KEY = NO_KEY;
        }
        if(!f_reload) {
            f_reload = 1;
            SetFont(Farsi);

            for(i = 0; i < Scroll_Max && i < 5; i++) {
                temp = Menu_Lengths[i + Menu_Lengths[Index][START_INDEX] + Scroll_Shift][STR_INDEX];
                if(i == Scroll_Index)
                    LCDFarsiText(put_Menu_Strs(temp), 0, i * 9 + 9, 128, 0, 1);
                else
                    LCDFarsiText(put_Menu_Strs(temp), 0, i * 9 + 9, 128, 1, 0);
            }

            symbol = _BV(KS_S) | _BV(KS_E);
            if(Scroll_Index + Scroll_Shift)sbi(symbol,KS_U);
            if(Scroll_Max > Scroll_Index + Scroll_Shift + 1)sbi(symbol,KS_D);
            Key_Symbol(0 ,56 ,symbol ,1 ,0);
        }

        if(!Access_Timer) return;
    }
}
همونطوری که مشاهده میکنید در کمتر از 100 خط کد نمایش منو ها و کار پیمایش بین اونها انجام میشه

در صورتی که مفید باشه بنده رو از دعای خیرتون بی نصیب نفرمایید
 
  • Like
واکنش‌ها[ی پسندها]: ali

Alma

مدیر
پرسنل مدیریت
تابع دوم مقدار دهی منو ها که من اسمشو گذاشتم Set_Menu_Value
اگر در تابع پست قبل منویی انتخاب بشه که اولین عضو جدول مقداری نداشته باشه یعنی میشه به این منو مقدار داد که در این صورت این تابع رو صدا میزنیم
بعد از ورود به تابع یه قسمتی از نمایشگرمون که قراره پنجره نمایش داده بشه رو پاک میکنیم و و دورش یه خط میکشیم این کارو من اینجا با دو خط زریر انجام میدیم
کد:
    FillRect(6, 6, 116, 52, 0);
    DrawRect(7, 7, 114, 50, 1);
البته این کار برای زیبایی کار هست شما میتونید کل صفحه رو پاک کرده و به صورت فول اسکرین این کار رو انجام بدین
بعد متن منو رو در سربرگ پنجره مینویسیم
بعد با استفاده از دستور if از نوع تابع بودن منو مون رو طبق توضیحاتی که در پست قبل داده شد چک میکیم این کار رو با چک کردن عضو VAR_TYPE هر منو انجام میدیم که ایا از نوع VT_VOID هست یا نه
در ضورتی که منو از نوع VT_VOID باشه یعنی این منو از نوع منو های خاص هست و باید یه تابع مخصوص بهش نصبت داده بشه برای مثال به این صورت

کد:
    if(Menu_Lengths[Index][VAR_TYPE] == VT_VOID){
        switch (Menu_Lengths[Index][FANC_TYPE]){
        case FT_SFL:        //گزارشها
            Show_Logs_Fault();
            break;
        case FT_SEL:        //گزارشها
            Show_Logs_Event();
            break;
        case FT_CFL:        //گزارشها
            Clear_Logs_Fault();
            break;
        case FT_CEL:        //گزارشها
            Clear_Logs_Event();
            break;
        case FT_AU:            //ارتباط با ما
            About_Us();
            break;
        case FT_SS:            //Save Settings
            Save_Settings();
            break;
        case FT_LS:            //Load Settings
            load_Settings();
            break;
        case FT_LD:            //Load Defaults
            Load_Defaults();
            break;
        case FT_SDT:        //ساعت و تاريخ
            Set_Date_Time();
            break;
        case FT_SP:            //رمز عبور
            Set_Password(1);
            break;
        case FT_SAI:
            Set_Analog_Input_Value(Index);
            break;
        }
    }

اما در صورتی که از نوع VT_VOID نباشه در ادامه برنامه مقدار منوی مورد نظر رو از eeprom میخونیم
و با مقدار مینیمم و ماکزیمم جدوملمون مقایسه میکنیم که در صورتی که از این مقادیر بزرگتر یا کوچکتر باشه مقدار متغیر رو برابر مینیمم مقدار مجاز میکنیم
بعد با نوجه به مقدار VAR_UNIT از جدول واحد متغیر رو در جای مناسب نمایش میدیم
بعد وارد یه حلقه while بینهایت میشیم و تا مقدار توسط کاربر اعمال بشه
توی این حلقه باید کلید هارو اسکن کنیم و طبق سلیقه خودمون با کلیدهایی که داریم مقدار رو شیفت بدیم یا کم و زیاد کنیم و البته کلیدی برای تایید و خروج هم خواهیم داشت که با کلید تایید بعد تغییر با این کلید مقدار ذخیره میشه و با کلید خروج بدون تغییر از منو خارج شده و به تابع قبلی برمیگردیم

کد:
if(!f_key)
            {
                if(KEY != NO_KEY)f_reload = 0;
                switch(KEY)
                {
                case UP_KEY:
                    if(++var > max_var)var = min_var;
                    break;
                case DOWN_KEY:
                    if(--var > max_var || var < min_var)var = max_var;
                    break;
                case UP_KEY | DOWN_KEY:
                    DEBUG = DEBUG ? 0 : 1;
                    break;
                case SET_KEY:
                    f_key = 1;
                    EE_Buffer_Menu[VAR_INDEX] = var;
                    SOFT_I2C_WriteWord( 0xA0, Buffer_Menu_Start_Adress + (VAR_INDEX * Buffer_Menu_datasize), var);

                    FillRect(8, 16, 112, 32, 0);
                    DrawRect(16, 26, 96, 8, 1);
                    for(i=0;i<96;i++)
                    {
                        DrawYLineLen(26, 8, i+16, 1);
                        rt_thread_delay(DELAY_MAIN/2);
                    }
                    SetFont(English);
                    LCDSoftText(put_Value_Strs("Accepted Setting"),16,38,0,1,0);
                    rt_thread_delay(DELAY_1_SEC);
                    return;

                    break;
                case ESC_KEY:
                    f_key = 1;
                    return;
                }
                KEY = NO_KEY;
            }
در انتهای حلقه نقدار متغیر رو باید نمایش بدیم این کار رو میشه مدارم انجام داد یا میشه مثل کدی که من نوشتم فقط در صورت فشار کلید ها انجام داد
در این قسمت هم موردی که مهمه نوع متغیر هست که نسبت به نوع روش نمایش رو تغییر میدیم
برای مثال چک میکنیم که VAR_TYPE منوی مورد نظر از چه نوع است اگر از نوع VT_STR یا رشته ای باشد مقدار رشته مورد نظر رو نمایش داده میشه و اگر از نوع VT_F01 باشد به صورت شناور و در غیر این صورت به صورت عدد ثابت نمایش داده میشه

کد:
if(!f_reload)
            {
                f_reload = 1;
                if(Menu_Lengths[Index][VAR_TYPE] == VT_STR)
                {
                    SetFont(English);
                    LCDSoftText(put_Value_Strs(var),24,32,120,1,0);
                }
                else
                {
                    SetFont(f16x8a);
                    if(Menu_Lengths[Index][VAR_TYPE] == VT_F01)
                        sprintf(str,"%3u.%u",var/10, var%10);
                    else
                        sprintf(str,"%5i",var);
                    LCDSoftText(str,32,29,64,1,0);
                    if(VAR_INDEX == 115)LCD_Contrast = 42 + (var / 5);
                }
                Key_Symbol(88 ,48 ,0x3F ,1 ,0);
            }
 
آخرین ویرایش:

Alma

مدیر
پرسنل مدیریت
نهایتا کل تابع به این صورت خواهد بود

کد:
void Set_Menu_Value (int16_t Index){

    int16_t var = 0;
    int8_t i,symbol=0;
    int8_t f_reload=0;
    int16_t VAR_INDEX = Menu_Lengths[Index][STR_INDEX];
    int16_t max_var, min_var;
    char str[40];

    FillRect(6, 6, 116, 52, 0);
    DrawRect(7, 7, 114, 50, 1);

    SetFont(English);
    LCDSoftText(put_Menu_Strs(VAR_INDEX),8,8,120,0,1);

    if(Menu_Lengths[Index][VAR_TYPE] == VT_VOID){
        switch (Menu_Lengths[Index][FANC_TYPE]){
        case FT_SFL:        //گزارشها
            Show_Logs_Fault();
            break;
        case FT_SEL:        //گزارشها
            Show_Logs_Event();
            break;
        case FT_CFL:        //گزارشها
            Clear_Logs_Fault();
            break;
        case FT_CEL:        //گزارشها
            Clear_Logs_Event();
            break;
        case FT_AU:            //ارتباط با ما
            About_Us();
            break;
        case FT_SS:            //Save Settings
            Save_Settings();
            break;
        case FT_LS:            //Load Settings
            load_Settings();
            break;
        case FT_LD:            //Load Defaults
            Load_Defaults();
            break;
        case FT_SDT:        //ساعت و تاريخ
            Set_Date_Time();
            break;
        case FT_SP:            //رمز عبور
            Set_Password(1);
            break;
        case FT_SAI:
            Set_Analog_Input_Value(Index);
            break;
        }
    }else{
        SOFT_I2C_ReadWord( 0xA0, Buffer_Menu_Start_Adress + (VAR_INDEX * Buffer_Menu_datasize), &var);
        max_var = Menu_Lengths[Index][VAR_MAX];
        min_var = Menu_Lengths[Index][VAR_MIN];
        if(var > max_var || var < min_var)var = min_var;

        SetFont(English);
        if(Menu_Lengths[Index][VAR_UNIT])
        {
            if(Menu_Lengths[Index][VAR_UNIT] == VU_BAR)
            {
                if(PRESSURE_UNIT == BAR)
                {
                    LCDSoftText(put_Unit_Strs(VU_BAR),80,34,120,1,0);
                }
                else if(PRESSURE_UNIT == PSI)
                {
                    LCDSoftText(put_Unit_Strs(VU_PSI),80,34,120,1,0);
                    var *= PSI_FACTOR;
                    max_var *= PSI_FACTOR;
                    min_var *= PSI_FACTOR;
                }
            }
            else if(Menu_Lengths[Index][VAR_UNIT] == VU_CEL)
            {
                if(TEMPREATURE_UNIT == CELSIUS)
                {
                    LCDSoftText(put_Unit_Strs(VU_CEL),80,34,120,1,0);
                }
                else if(TEMPREATURE_UNIT == FAHRENHEIT)
                {
                    LCDSoftText(put_Unit_Strs(VU_FAR),80,34,120,1,0);
                    var *= FAHRENHEIT_FACTOR;
                    max_var *= FAHRENHEIT_FACTOR;
                    min_var *= FAHRENHEIT_FACTOR;
                }
            }
            else
            {
                LCDSoftText(put_Unit_Strs(Menu_Lengths[Index][VAR_UNIT]),80,34,120,1,0);
            }
        }

        while(1)
        {
            if(!f_key)
            {
                if(KEY != NO_KEY)f_reload = 0;
                switch(KEY)
                {
                case UP_KEY:
                    if(++var > max_var)var = min_var;
                    break;
                case DOWN_KEY:
                    if(--var > max_var || var < min_var)var = max_var;
                    break;
                case UP_KEY | DOWN_KEY:
                    DEBUG = DEBUG ? 0 : 1;
                    break;
                case SET_KEY:
                    f_key = 1;
                    EE_Buffer_Menu[VAR_INDEX] = var;
                    SOFT_I2C_WriteWord( 0xA0, Buffer_Menu_Start_Adress + (VAR_INDEX * Buffer_Menu_datasize), var);

                    FillRect(8, 16, 112, 32, 0);
                    DrawRect(16, 26, 96, 8, 1);
                    for(i=0;i<96;i++)
                    {
                        DrawYLineLen(26, 8, i+16, 1);
                        rt_thread_delay(DELAY_MAIN/2);
                    }
                    SetFont(English);
                    LCDSoftText(put_Value_Strs("Accepted Setting"),16,38,0,1,0);
                    rt_thread_delay(DELAY_1_SEC);
                    return;

                    break;
                case ESC_KEY:
                    f_key = 1;
                    return;
                }
                KEY = NO_KEY;
            }
            if(!f_reload)
            {
                f_reload = 1;
                if(Menu_Lengths[Index][VAR_TYPE] == VT_STR)
                {
                    SetFont(English);
                    LCDSoftText(put_Value_Strs(var),24,32,120,1,0);
                }
                else
                {
                    SetFont(f16x8a);
                    if(Menu_Lengths[Index][VAR_TYPE] == VT_F01)
                        sprintf(str,"%3u.%u",var/10, var%10);
                    else
                        sprintf(str,"%5i",var);
                    LCDSoftText(str,32,29,64,1,0);
                    if(VAR_INDEX == 115)LCD_Contrast = 42 + (var / 5);
                }
                Key_Symbol(88 ,48 ,0x3F ,1 ,0);
            }
        }
    }
}
 

Alma

مدیر
پرسنل مدیریت
تصاویری از نمایش منو ها طبق توضیحات پست های قبل

upload_2020-6-7_22-30-55.png

upload_2020-6-7_22-31-5.png

تصاویری از پنجره مقدار دهی منو ها

upload_2020-6-7_22-35-33.png

upload_2020-6-7_22-35-44.png

upload_2020-6-7_22-32-1.png

upload_2020-6-7_22-32-8.png

تصویری از منو های خاص

upload_2020-6-7_22-32-41.png

upload_2020-6-7_22-35-20.png
 
بالا پایین