Специальные цены   новые товары
Закрытая тема
Показано с 1 по 32 из 32

Самодельный передатчик (ver. by Nick_Shl)

Тема раздела Самодельная электроника, компьютерные программы в категории Общие вопросы; Как-то все обещался рассказать, " как надо программить ". Но с учетом какой я тяжелый на подъем... в общем придется ...

  1. #1

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344

    Самодельный передатчик (ver. by Nick_Shl)

    Как-то все обещался рассказать, "как надо программить". Но с учетом какой я тяжелый на подъем... в общем придется делать по другому.
    Напомню про свой вариант кодера. Есть еще и приемник, кому интересно, но сейчас речь не о нем.

    В этом посте я выкладываю исходный текст своего кодера. Но не просто код, а репозиторий.
    Но для его использования у меня есть условия. Их я озвучу в конце. Использование кода автоматом подтверждает принятие вами этих условий.
    Файл имеет расширение zip, но на самом деле это архиватор 7z, потому что zip давал файл 1,4 МБ, а сайт пускает не больше 1 МБ. И не пускает файлы с расширением 7z - пришлось переименовать.

    Управление версиями

    Первое что надо сделать при желании что-нибудь написать - это реализовать управление версиями. Подход типа "А зачем мне старые версии? И последней хватит!" или "Я тут основные версии себе забэкапил" - НЕ ПОДХОДЯТ. Что позволяет система контроля версий? Позволяет она многое. Но я расскажу о базовых вещах, остальное почитаете в интернете.
    Для групповой разработки лучше всего подойдет онлайновая система контроля версий, но с ней я не сталкивался, так что рассказать не смогу.
    Для небольшой группы разработчиков имеющих локальную сеть нужно поставить сервер.
    Программист одиночка может обойтись и без этого, а поможет в этом TortoiseSVN.
    Данная утилита позволяет организовать локальный репозиторий. Ее придется установить для того, что бы достать код моего кодера.
    Установив ее заходим через "Проводник" в любое удобное место, жмем правой кнопкой мыши, выбираем "SVN Checkout...", открывается окно. В поле "URL of repository:" вводим(без кавычек) "file:///<путь к файлу>" и жмем кнопочку в три точечки рядом. У меня весь путь выглядит так: "file:///D:/AVR/SVN_Rep/".
    В открывшемся окне слева кликаем на "CVProject_My", жмем ОК и видим что в "URL of repository:" и в "Checkout directory:" добавилось "CVProject_My". Жмем ОК и в этом окне и получаем сходный код моего кодера в папку "CVProject_My".
    Данная папка помечена зеленым значком - это значит, что файлы в ней не изменялись. Если вы поменяете файл, значок будет красный. Зайдя в папку такие же значки увидим на каждом файле.

    Далее если вам интересно, что же я менял, то на папке "CVProject_My" нажимаем правой кнопкой мыши, выбираем пункт "TortoiseSVN", а в открывшемся списке "Show log". Видим все мои изменения с комментариями.
    Нажав на конкретное изменение видим список измененных файлов. Дважды кликнув на файл из списка видим что же было в нем изменено. Стандартная программа сравнения мне не очень нравится, рекомендую установить Araxis Merge и настроить его в настройках TortoiseSVN как программу сравнения файлов.

    Изменив какой-либо файл он помечается красным значком. Нажав на этом файле правой кнопкой мыши и выбрав пункт "SVN Commit...", откроется окно для сохранения этого файла в репозиторий. Точно так же двойной клик на файле позволяет просмотреть что в нем было изменено. Перед заливкой обязательно вписывайте комментарий в соответствующее окошко!
    Этот же подход работает и для директории. Можно выбрать "SVN Commit...", тогда вы получите список изменённых файлов, которые будут добавлены за один коммит. Это удобно когда у вас какое-то одно изменение затрагивает несколько файлов(например при добавлении новой функциональности).

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

    Форматированрие кода

    То что творится сейчас - это ужас! Посмотрите на код, который я выложил. Каждая функция имеет "шапку" которая ее выделяет.
    Скобочки открываются и закрываются на одном уровне. Содержимое строчек внутри скобочек сдвинуто на 4 пробела, так что сразу понятно, что к чему относится.
    Почти каждая строчка прокомментирована(в основном такое не требуется, но учитывая что тут многие не очень знакомы с программированием полезно).

    Другие вопросы

    Задавайте! По мере возможности буду отвечать, консультировать и т.д.


    Условия использования:
    1) При изменении использовать управление версиями.
    2) При изменении поддерживать форматирование кода, причем такое же, как есть там сейчас.
    3) Не использовать код в коммерческих проектах без моего согласия.


    P.S. Я сейчас не занимаюсь кодером, этому есть пару причин:
    Первая - это нет летающей модели. Хотя сделать ее смог бы - есть и двигатель, и регулятор, и батарея и вроде даже сервы. Есть и пара крыльев, сделанных давным-давно.
    Вторая и основная - передатчик был сделан криво. Изначально это была модель с аналоговыми триммерами, сделано все "как смог", триммеры глючили, что-то отваливалось, потом еще детишки добавили... в общем так и валяется он теперь.
    А денег на новую игрушку в семейном бюджете не нашлось(на тот момент поглядывал на Turnigy 9X), сейчас наиболее интересный вариант Turnigy 9XR - хоть у нее и спорный дизайн, но она имеет разъем для программирования и экран 128x64, такой же как я использовал в своем кодере. То есть она не требует вмешательства в аппаратную часть.
    Впрочем, денег на нее не находится и сейчас(на ХК она продается только без модулей, в отличие от 9X, что повышает цену готовой системы). Но если кто пожелает задарить мне такую штуку - сопротивляться не буду
    Вложения

  2.  
  3. #2

    Регистрация
    30.10.2012
    Адрес
    Hochiminh,vietnam
    Возраст
    32
    Сообщений
    70
    hello Guy

    can you show some picture ? Wonderful project

  4. #3

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от minhthien1988 Посмотреть сообщение
    can you show some picture ?
    Two links in first meaage:
    http://nick_shl.at.tut.by/Work/Transmitter.htm
    http://nick_shl.at.tut.by/Work/Receiver.htm
    This articles have some pictures.

  5. #4

    Регистрация
    12.02.2011
    Адрес
    Москва
    Возраст
    51
    Сообщений
    806
    Эх уважаемый Николай. Пром-акция удалась. Но
    Цитата Сообщение от Nick_Shl Посмотреть сообщение
    это нет летающей модели
    Цитата Сообщение от Nick_Shl Посмотреть сообщение
    передатчик был сделан криво.
    Но вьетнам с китаем заинтересовались. Не продешевите.

  6.  
  7. #5

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Dinotron Посмотреть сообщение
    Пром-акция удалась.
    Это вы о чем? 5 лет он у меня просто лежала... не помню, почему именно не выложил... может быть потому, что никто так и не удосужился хотя бы "причесать" код, что бы он выглядело красиво и понятно новичкам. Все равно превратили бы в такую же "помойку" как и все остальное... наверное. Сейчас мне кажется, что надо было выложить и попробовать направить в правильное русло. В любом случае не вижу смысла, что бы он у меня лежал дальше.
    ем более, что я об этом заикался, на что Aleksey_Gorelikov резонно заметил:
    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    Да давно пора! Кчерту декларации намеряний! Сначало дело!
    Так что вот оно - дело.

    Цитата Сообщение от Dinotron Посмотреть сообщение
    Но вьетнам с китаем заинтересовались. Не продешевите.
    Так наш англоязычный друг оттуда? Ну заинтересовались и ладно... за 5 лет она довольно сильно устарела - надо добавлять поддержку протокольных передатчиков(PPM уже прошлый век наверное) и поддержку телеметрии.

  8. #6

    Регистрация
    12.02.2011
    Адрес
    Москва
    Возраст
    51
    Сообщений
    806
    Извините, не очень хочется вступать с вами в дискуссию. Был бы живой проект-шло бы обсуждение, а так.

  9. #7

    Регистрация
    04.10.2004
    Адрес
    Балашиха
    Возраст
    42
    Сообщений
    2,892
    Цитата Сообщение от Dinotron Посмотреть сообщение
    Был бы живой проект-шло бы обсуждение, а так.
    Живой проект был 10 лет назад. Когда аппаратура стоила как чугунный мост и простым пионерам приходилось копить годами на какой-нибудь хайтек-фокус4, а тот же "компьютеризированный" флешь-5 был мечтой. Ныне китайское чудо сопостовимо по цене со стоимостью недельных завтраков первоклашки, в следствии чего все самодельные проекты умирают. Исключение- общественные проекты типа ер9х под "народное" китайское железо.

    Коля критиковал код что фокуса, что мсв, я упрекнул его, что "покажи как надо личным примером!" и вот он, наконец-то делится своим опытом, примером для подражания и т.д. Вполне возможно, что кто-то присоединится именно к его проекту, ведь (наверно, я не смотрел) он более понятный. Использование контроля версий действительно значительно упрощает развитие проекта. Это же тоже плюс. Но главное, чем делится Николай - это своим опытом использования этого софта. Ведь, многие даже не понимают смысл этого и не могут найти исходники вполне себе распространненых открытых проектов. И основная идея сей ветки, как я понимаю именно в ключевых трех буквах SVN. Этому же посвещено и стартовое сообщение. Люди, пользуйтесь SVN, это удобно! Облегчите жизнь и себе и другим. Коля потратил время чтобы показать на собственном примере как это работает! Молодец, спасибо! Так держать! И... "давно пора было!"

  10.  
  11. #8

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    Живой проект был 10 лет назад. Когда аппаратура стоила как чугунный мост и простым пионерам приходилось копить годами на какой-нибудь хайтек-фокус4, а тот же "компьютеризированный" флешь-5 был мечтой. Ныне китайское чудо сопостовимо по цене со стоимостью недельных завтраков первоклашки, в следствии чего все самодельные проекты умирают. Исключение- общественные проекты типа ер9х под "народное" китайское железо.
    C этим согласен по большей части. Просто проекты из аппаратно-программных сместились больше в программную часть - зачем самому делать платы, если можно взять ту же 9XR, где даже ISP разъем для программирования выведен наружу?
    И на данный момент я не вижу никаких проблем запустить мой проект там, где запускается ер9х - если не ошибаюсь, экран там с контроллером KS108, такой же как использовал я. Если есть желание, могу попробовать найти описание что куда подключено, скомпилировать и выложить.

    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    ведь (наверно, я не смотрел) он более понятный.
    А жаль... так хочется что бы хоть кто-то оценил

    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    И основная идея сей ветки, как я понимаю именно в ключевых трех буквах SVN. Этому же посвещено и стартовое сообщение.
    Это ошибочно. Просто вылоджен-то репозиторий, и безх SVN код не достанешь. А раз так, то пришлось все рассказать. Дальше попробую описать некоторые моменты, жаль только, что теги "CODE" не позволяют менять цвет фона и букв - расцветка тоже не маловажный фактор восприятия...

    А про код пример. Вот первый попавшийся кусок от MSV:
    Код:
    //Исходные тексты клонированы от версии MSV v.1.9.
    //Отличия от базовой версии (MSV v.1.9) описаны в файле Eagle_version.txt
    //
    //В интерфейсе программатора CVAVR фузы BODEN и BODLEVEL отмечены (=запрограммированы, при чтении =0).
    //У остальных фузов отметка снята (=не запрограммированы, при чтении =1).
    //См. также файлы Notes.txt и Coder.txt
    
    //#define NoCheckThrottleOnStart //Раскомментировать, если требуется отменить проверку положения ручки газа при запуске аппы
    
    //#define AntennaCtrlUse  //Раскомментировать, если требуется управление током антенны
        #ifdef AntennaCtrlUse    
        #endif  
    
    #include <mega128.h>
    #include <delay.h>
    #include <stdio.h>
    #include <math.h>
    #include <i2c.h>
    #include "def.h"
    #include "LCD_3320.h"
    #include "menu.h"
    #include "displ.h"
    #include "coder.h"
    
    // I2C Bus functions
    #asm
       .equ __i2c_port=0x15 ;PORTC
       .equ __sda_bit=5
       .equ __scl_bit=4
    #endasm
    // Сохраняемые данные в EEPROM'е
    eeprom MODEL_SET EEPR_models[MAX_MODELS];
    eeprom unsigned char EEPR_start_model;
    eeprom unsigned char EEPR_f_sound_en;
    eeprom unsigned char EEPR_BatCntr[3];
    eeprom unsigned char EEPR_AntCntr;
    eeprom int EEPR_ADmid[5], EEPR_ADmax[5], EEPR_ADmin[5];
    eeprom unsigned char EEPR_FirstON, EEPR_Calibration;
    eeprom signed int EPPR_CalibrTemperature[2];
    //------------------------------------------------------
    signed int out_control[MAX_CONTRS];
    signed int ADmid[6];
    signed int ADmin[6];
    signed int ADmax[6];
    signed int ADcur[6];
    signed int out_ch[MAX_CHANS];
    MODEL_SET cur_model;
    unsigned char cur_model_ind;
    unsigned char cur_mode_ind;
    bit f_TCut;
    unsigned int cur_Batt;
    #ifdef AntennaCtrlUse    
        unsigned int cur_Power;
        unsigned int cur_Antenna;
    #endif    
    unsigned int cur_Temperature;
    signed int dir_Temperature;
    unsigned char wd_Temperature;
    unsigned int div_trimmer;
    unsigned char f_l;
    unsigned char g_MainMenuMode;
    extern bit f_timer_en;
    unsigned int gRPMtmp=0;
    unsigned int gRPM;
    unsigned char gRPMn;
    signed int g_pos_d[3];
    unsigned char g_keys;
    signed int gAddPropVal;
    signed int gAddPropValOld;
    bit gfca_start;
    
    #define F_SW1 1
    #define F_SW2_1 2
    #define F_SW2_2 4
    #define F_SW3 8
    #define F_DUAL1 0x10
    #define F_DUAL2 0x20
    #define F_DUAL3 0x40
    #define F_TCUT 0x80
    
    #define UNI_KEY 0x5a
    //------------------------------------------------------
    //------------------------------------------------------
    #define ADC_VREF_TYPE 0x00
    unsigned int read_adc(unsigned char adc_input)
    {
    ADMUX=adc_input|ADC_VREF_TYPE;
    delay_us(10);
    ADCSRA|=0x40; // Start the AD conversion
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10; // Stop
    return ADCW;
    }
    //------------------------------------------------------
    //------------------------------------------------------
    // (PD0-tachometr)
    interrupt [EXT_INT0] void ext_int0_isr(void)
    {
    gRPMtmp++;
    if(gRPMtmp==1024) EIMSK&=0xfe;
    }
    //------------------------------------------------------
    void TimerTachometer(void)
    { // 50Hz
    static unsigned char div;
    div++;
    if(div>=25)
      { // ~2Hz
      div=0;
      gRPM[gRPMn]=gRPMtmp;
      if(++gRPMn>=SIZE_RPM_BUFF) gRPMn=0;
      gRPMtmp=0;
      }
    }
    //------------------------------------------------------
    //------------------------------------------------------
    __flash const unsigned int notes[]= {//Note A 1-okt;
    440, 466, 494, 523,    554,  588,  612,  660,    698,  740,  784,  830,
    880, 932, 988, 1064,   1108, 1176, 1224, 1320,   1396, 1480, 1568, 1660};
    BEEP_TRACK_DEF flash *beep_track;
    unsigned int beep_length;
    unsigned char beep_cnt;
    unsigned char beep_cntn;
    unsigned char beep_rep;
    bit f_beep_timer;
    bit f_beep_EEP;
    bit f_beep_key;
    bit f_beep_trimmer;
    bit f_beep_trimmer_c;
    
    extern flash const BEEP_TRACK_DEF hello_sound[];
    //------------------------------------------------------
    void beep(BEEP_TRACK_DEF flash *note)
    {
    unsigned long ln, freq;
    unsigned int v;
    
    freq=notes[note->note];
    v=(unsigned int)((1500000L/2)/freq);
    ICR3H=(unsigned char)(v>>8);
    ICR3L=(unsigned char)v;
    ln=note->ms*freq;
    beep_length=ln/1000;
    }
    //------------------------------------------------------
    // Timer 3 output compare A interrupt service routine
    interrupt [TIM3_COMPA] void timer3_compa_isr(void)
    {
    bit f_con;
    
    if(PINE.3) return;
    if(--beep_length==0)
      {
      f_con=0;
      if(++beep_cntn<beep_cnt)  f_con=1;
      else if(beep_rep) { beep_rep--; beep_cntn=0; f_con=1; }
      if(f_con==0) { TCCR3B&=0xf8; return; }  // stop
      else beep((beep_track+beep_cntn));
      }
    }
    //------------------------------------------------------
    void beep_start(BEEP_TRACK_DEF flash *notes, unsigned char cnt, unsigned char rep)
    {
    beep_track=notes;
    beep_cnt=cnt;
    beep_cntn=0;
    beep_rep=rep;
    beep(notes);
    TCCR3B|=0x2;
    }
    //-------------------------------------------------------------
    //-------------------------------------------------------------
    //-------------------------------------------------------------
    unsigned int CHcalc (char ch_ind)
    {
    signed long ln;
    unsigned char i;
    signed char *mix;
    CHANNEL * channel;
    signed int v, val;
    
    mix=cur_model.modes[cur_mode_ind].mixer[ch_ind];
    val=0;
    for (i=0; i<MAX_CONTRS; i++)
      {
      if(mix[i])
        {
        ln=out_control[i]; ln*=mix[i]; ln/=100;
        val+=(signed int)ln;
        }
      }
    channel=&cur_model.channels[ch_ind];
    v=channel->subtrimmer; v*=5; //50*5 -> +-250
    val+=v;
    //limit
    if(val<-900) val=-900;
    if(val>900) val=900;
    //--------------------------------
    //#define EPA_MODE1
    #ifdef EPA_MODE1
    //epa 1 (Просто ограничение с обрезанием по epa)
    v=-channel->epa[0]; v*=90; v/=12;
    if(val<v) val=v;
    v=channel->epa[1]; v*=90; v/=12;
    if(val>v) val=v;
    #else
    #ifdef EPA_MODE2
    //epa 2 (масштабирование раздельно на участках epa-<>0 и 0<>epa+)
    ln=val;
    if(val<0) ln*=channel->epa[0];
    else ln*=channel->epa[1];
    val=(signed int)(ln/120);
    #else
    //epa 3 (мастабирование линейное epa-<>epa+ со сдвигом центра)
    ln=channel->epa[0]; ln+=channel->epa[1]; ln*=val;
    val=(signed int)(ln/240);
    v=channel->epa[1]; v-=channel->epa[0]; v*=90; v/=24;
    val+=v;
    #endif
    #endif
    //----------------------------------
    val*=(signed int)channel->reverse;
    val+=2250; // 1,5 ms
    return (unsigned int)val;
    }
    //-------------------------------------------------------------
    signed int interpol(signed int val, signed char* nodes )
    {
    unsigned char n;
    signed int n1, n2, vmin;
    signed long ln;
    
    ln=val; ln*=6; n=ln/1500;
    n1=*(nodes+n); n1=(n1*75)/10;
    n2=*(nodes+n+1); n2=(n2*75)/10;
    vmin=n; vmin*=250;
    ln=(val-vmin); ln*=(n2-n1); ln/=250;
    return ln + n1;
    }
    //-------------------------------------------------------------
    signed int rate_calc(signed int val, unsigned char min, unsigned char max)
    {
    unsigned char rate;
    signed long v;
    
    if(val<0) rate=min;
    else rate=max;
    v=val; v*=rate; v/=100;
    return v;
    }
    //-------------------------------------------------------------
    unsigned char ReadKeys(void)
    {
    unsigned char f;
    
    f=0;
    if(!SW1) f|=F_SW1;
    if(!SW2_1) f|=F_SW2_1;
    if(!SW2_2) f|=F_SW2_2;
    if(!SW3) f|=F_SW3;
    if(!DUAL_ail) f|=F_DUAL1;
    if(!DUAL_elev) f|=F_DUAL2;
    if(!DUAL_rud) f|=F_DUAL3;
    if(!Tcut_KEY) f|=F_TCUT;
    return f;
    }
    //-------------------------------------------------------------
    void Calc (void)
    { // 50Hz (20ms)
    static unsigned char div_trim;
    signed char *trim;
    signed int input[10];
    unsigned int i, n;
    signed long vl;
    const unsigned char acntr[]={ ch_Ailerons, ch_Elevator, ch_Throttle, ch_Rudder, ch_Rpop_contr };
    signed int vi;
    unsigned char mn, mx;
    DEF_MODE *mode;
    unsigned char f_dual[3];
    unsigned char keys;
    unsigned char f;
    
    //опрос переключателя режимов
    if(!MODE_KEY2)           i=0;
    else if(!MODE_KEY1)      i=2;
    else                     i=1;
    if(cur_mode_ind!=i) { BEEP; save_trimmer(); cur_mode_ind=i; }
    
    //опрос триммеров
    trim=cur_model.modes[cur_mode_ind].trimmers;
    if (div_trim)
      {
      f=0;
      if(!trim_0up && trim[0]<80) { trim[0]++; f|=1;  }
      if(!trim_0down && trim[0]>-80) { trim[0]--;  f|=1; }
      if(!trim_1up && trim[1]<80) { trim[1]++; f|=2; }
      if(!trim_1down && trim[1]>-80) { trim[1]--; f|=2; }
      if(!trim_2up && trim[2]<80) { trim[2]++;   f|=4; }
      if(!trim_2down && trim[2]>-80) { trim[2]--; f|=4; }
      if(!trim_3up && trim[3]<80) { trim[3]++; f|=8; }
      if(!trim_3down && trim[3]>-80) { trim[3]--; f|=8; }
      if((f & 1) && trim[0]==0) f_beep_trimmer_c=1;
      if((f & 2) && trim[1]==0) f_beep_trimmer_c=1;
      if((f & 4) && trim[2]==0) f_beep_trimmer_c=1;
      if((f & 8) && trim[3]==0) f_beep_trimmer_c=1;
      if(f)
        {
        div_trimmer=1500;
        if(f_beep_trimmer_c==0) f_beep_trimmer=1;
        }
      }
    div_trim=!div_trim;
    
    mode=&cur_model.modes[cur_mode_ind];
    // исходные данные
    for(i=0; i<5; i++)
      {
      n=i; if(i==4) n=7;
      vl=read_adc(acntr[i]);
      if(vl<ADmid[i])
        {
        if(ADmin[i]>vl) ADmin[i]=vl;
        vl-=ADmin[i]; vl*=750; input[n]=vl/(ADmid[i]-ADmin[i]);
        }
      else
        {
        if(ADmax[i]<vl) ADmax[i]=vl;
        vl-=ADmid[i]; vl*=750; input[n]=750+(vl/(ADmax[i]-ADmid[i]));
        }
      }
    gAddPropVal=input[7];
    keys=ReadKeys(); if(keys!=g_keys) { BEEP; g_keys=keys; }
    if(keys & F_SW1) input[4]=0; else input[4]=1500;
    if(keys & F_SW2_1) input[5]=0;
    else if(keys & F_SW2_2) input[5]=1500;
    else input[5]=750;
    if(keys & F_SW3) input[6]=0; else input[6]=1500;
    for(i=0; i<3; i++)
      {
      vi=mode->contr_d[i].delay;
      if(vi==0) g_pos_d[i]=input[4+i];
      else if(g_pos_d[i]!=input[4+i])
        {
        vl=g_pos_d[i]; vl*=vi; vl/=(300/2); vl++; vl/=2;
        if(g_pos_d[i]<input[4+i])
          {
          vl++; vl*=(300*2); vl/=vi; vl++; vl/=2;
          if(vl>input[4+i]) vl=input[4+i];
          }
        else
          {
          vl--; vl*=(300*2); vl/=vi; vl++; vl/=2;
          if(vl<input[4+i]) vl=input[4+i];
          } 
          g_pos_d[i]=vl; input[4+i]=vl;
        }
      }
    input[8]=input[mode->contr_v[0].from];
    input[9]=input[mode->contr_v[1].from];
    //опрос кнопки выключения двигателя
    if (keys & F_TCUT) f_TCut=1; else f_TCut=0;
    // Двойные расходы
    f_dual[0]=(keys & F_DUAL1);
    f_dual[1]=(keys & F_DUAL2);
    f_dual[2]=(keys & F_DUAL3);
    // Вся математика
    for(i=0; i<3; i++)
      {
      n=i; if(i==2) n++;
      vi=interpol(input[n], mode->contr_ab[i].cur_nodes+1);
      if(f_dual[i]) { mn=mode->contr_ab[i].minDRates; mx=mode->contr_ab[i].maxDRates; }
      else { mn=mode->contr_ab[i].minRates; mx=mode->contr_ab[i].maxRates; }
      out_control[n]=rate_calc(vi, mn, mx);
      vi=mode->trimmers[n]; vi*=5; out_control[n]+=vi;
      }
    if(f_TCut) { vi=mode->contr_tr.tcut; vi*=-75; out_control[2]=vi/10; }
    else
      {
      vi=interpol(input[2], mode->contr_tr.cur_nodes+1);
      out_control[2]=rate_calc(vi, mode->contr_tr.minRates, mode->contr_tr.maxRates);
      vi=mode->trimmers[2]; vi*=5; out_control[2]+=vi;
      }
    if(cur_model.timer_mode==2) { if(!f_TCut && input[2]>150) f_timer_en=1; else f_timer_en=0; }
    
        for(i=0; i<3; i++)
        {
        vi=input[4+i]-750;
        out_control[4+i]=rate_calc(vi, mode->contr_d[i].minRates, mode->contr_d[i].maxRates);
        }
    
        vi=interpol(input[7], mode->contr_ap.cur_nodes+1);
        out_control[7]=rate_calc(vi, mode->contr_ap.minRates, mode->contr_ap.maxRates);
    
        for(i=0; i<2; i++)
        {
            vi=interpol(input[8+i], mode->contr_v[i].cur_nodes+1);
            out_control[8+i]=rate_calc(vi, mode->contr_v[i].minRates, mode->contr_v[i].maxRates);
        }
    }
    //------------------------------------------------------
    Вроде этот кусок отвечает за математику. А вот так она сделана у меня(вынесена в отдельный файл):
    Код:
    /*******************************************************************************
    *  Math.c
    *
    *  Радиоуправление: Математика
    *
    *       Copyright (c) 2007-2008 Nick Shl, focus
    *           All rights reserved.
    *
    *
    *  Изменения:
    *
    *  Apr 20, 2009  Nick_Shl  Переработка
    *  Apr 10, 2008  Nick_Shl  Форматирование, комментарии
    *  *** **, ****  focus     Первоначальная версия
    *
    */// ***************************************************************************
    
    // *****************************************************************************
    // ***   Системные инклюды   ***************************************************
    // *****************************************************************************
    #include <mega128.h>
    #include <string.h>
    
    // *****************************************************************************
    // ***   Пользовательские инклюды   ********************************************
    // *****************************************************************************
    #include "Def.h"
    #include "Coder.h"
    #include "Sound.h"
    #include "Tasks.h"
    #include "Variables.h"
    
    // *****************************************************************************
    // ***   Рассчет времени канальных импульсов для вывода (Микширование)  ********
    // *****************************************************************************
    void math_CalcChannel(char CH)
    {
        char i;
        signed long Factor;
    
        // Если передали отритцательный номер канала - выходим
        if(CH < 0) return;
        // Если передали номер канала превышающий количество каналов - выходим
        if(CH > MAX_CHANNELS) return;
    
        // Обнуляем значение длительности канального импульса
        output[CH] = 0;
    
        // Формирование выходного канала
        for(i=0; i < MAX_CONTROLS; i++)
        {
            // Если влияние управляющего элемента i на канал CH отсутстует - идем дальше
            if(CurModel.Mode[FLY_MODE].Chanels[CH][i] != 0)
            {
                // Получаем влияние управляющего элемента i на канал CH
                Factor = CurModel.Mode[FLY_MODE].Chanels[CH][i];
                // Добавляем управляющий элемент i к каналу CH
                output[CH] += out_cur[i] * Factor / 100;
            }
        }
    
        // Длительность импульса:
        // значение канала(+-0,5 мс) + центральное положение(1,5 мс)
        output[CH] += TimerClockPerSec(0.0015);
        // приведение к int нужно для оптимизации: вычисленное на этапе компиляции число использовать как int
        // забавно получилось: 1,5 мс это 1/666,6(6) секунды...
    
        // Если получившийся импульс меньше 0,0009 сек (0,9 мс) - ограничиваем
        if(output[CH] < TimerClockPerSec(0.0009)) output[CH] = TimerClockPerSec(0.0009);
    
        // Если получившийся импульс больше 0,0021 сек (2,1 мс) - ограничиваем
        if(output[CH] > TimerClockPerSec(0.0021)) output[CH] = TimerClockPerSec(0.0021);
    }
    
    // *****************************************************************************
    // ***   Расширенный рассчет кривой   ******************************************
    // *****************************************************************************
    signed int math_InterPolEx(signed int Val, signed int Max, signed int K, signed char * Nodes, signed char NodesCount)
    {
        unsigned char n;
        signed int n1, n2, ln;
        // Размер интервала. Должен быть long, потому что в дальнейшем рассчете
        // получатся числа большой размерности.
        signed long InterPoolSize;
    
        // Если не передали указатель на массив точек кривой - возвращаем переданное значение
        if(Nodes == NULL) return(Val);
        // Если передали размер массива точек кривой 0 и меньше - возвращаем переданное значение
        if(NodesCount <= 0) return(Val);
    
        // Если переданное значение окажется меньше 0 - нулим
        if(Val < 0) Val = 0;
        // Если переданное значение окажется больше или равно Max
        // выйдем за границы массива - корректируем
        if(Val >= Max) Val = Max - 1;
    
        // Вычисляем размер интервала - максимальное значение / количество точек кривой
        InterPoolSize = Max / (NodesCount - 1);
    
        // Вычисляем интервал в который попали:
        // значение умножаем на количество интервалов и делим на максимальное значение
        n  = (Val * (NodesCount - 1)) / Max;
        // Вычисляем значение одной границы интервала
        n1 = (*(Nodes + n)     * K) / 10;
        // Вычисляем значение другой границы интервала
        n2 = (*(Nodes + n + 1) * K) / 10;
        // Вычисляем смещение
        // Значение относительно начала интервала умножается на величину интервала(Y)
        // и делится на величину интервала(X)
        ln = (Val - n * InterPoolSize) * (n2 - n1) / InterPoolSize;
    
        return(n1 + ln);
    }
    
    // *****************************************************************************
    // ***   Рассчет кривой   ******************************************************
    // *****************************************************************************
    static inline signed int math_CurveInterPol(signed int Val, signed char * Nodes)
    {
        // Добавляем 0,5 мс - сдвигаем в положительную область
        Val += TimerClockPerSec(0.0005);
        // Выполняем рассчет кривой с использованием универсальной функции
        return(math_InterPolEx(Val, TimerClockPerSec(0.001), TimerClockPerSec(0.0005) / 10, Nodes, CURVE_NODES));
    }
    
    // *****************************************************************************
    // ***   Общий рассчет кривой   ************************************************
    // *****************************************************************************
    // Может использоватся внешними задачами для реализации своих нужд. Например
    // при выводе информации на стрелочный индикатор проградуирыванный не линейно.
    // Или для приблизительного расчета оставшейся емкости по напряжению батареи.
    inline signed int math_InterPol(signed int Val, signed int Max, signed char * Nodes, signed char NodesCount)
    {
        // Выполняем общий рассчет кривой с использованием универсальной функции
        return(math_InterPolEx(Val, Max, 10, Nodes, NodesCount));
    }
    
    // *****************************************************************************
    // ***   Изменение триммеров   *************************************************
    // *****************************************************************************
    void math_ChangeTrimmer(signed char * trim, signed char dir)
    {
        if(dir == 0) return;
        if((dir > 0) && (*trim + dir >  96)) return;
        if((dir < 0) && (*trim + dir < -96)) return;
        *trim += dir;
        Trimmers_Need_Save(15);
        trim_sound_en = 1;
    }
    
    // *****************************************************************************
    // ***   Опрос устройств ввода и рассчет их значений   *************************
    // *****************************************************************************
    void math_CalcControls(void)
    {
        char i, Dual[MAX_CONTROLS];
        int TrimFactor;
        signed long Factor;
        unsigned char NewTrimMask = 0;
        static unsigned char TrimMask = 0;
    
        //опрос переключателя режимов
        if(MODE_KEY2)                FLY_MODE = 1;
        if(!MODE_KEY1 && !MODE_KEY2) FLY_MODE = 0;
        if(MODE_KEY1)                FLY_MODE = 2;
    
        // Загоняем все нажатые триммера в битовую маску
        if(trim_0up)   NewTrimMask |= 0x01;
        if(trim_0down) NewTrimMask |= 0x02;
        if(trim_1up)   NewTrimMask |= 0x04;
        if(trim_1down) NewTrimMask |= 0x08;
        if(trim_2up)   NewTrimMask |= 0x10;
        if(trim_2down) NewTrimMask |= 0x20;
        if(trim_3up)   NewTrimMask |= 0x40;
        if(trim_3down) NewTrimMask |= 0x80;
        // Если состояние маски изменилось - запоминаем его
        if(NewTrimMask != TrimMask)
        {
            TrimMask = NewTrimMask;
        }
        // Если не изменилось и присутствуют нажатые триммера - обрабатываем
        else if(TrimMask != 0)
        {
            // 8 кнопок триммеров и 8 бит в переменной
            for(i=0; i<8; i++)
            {
                // Если в маске установлен i-тый бит
                if(TrimMask & (1 << i))
                    // И i - нечёт нужно уменьшить значение триммера
                    if(i & 0x01) math_ChangeTrimmer(&CurModel.Mode[FLY_MODE].trimmers[i/2], -1);
                    // Иначе нужно увеличить значение триммера
                    else         math_ChangeTrimmer(&CurModel.Mode[FLY_MODE].trimmers[i/2],  1);
            }
        }
    
        //опрос кнопки выключения двигателя
        if(Tcut_KEY) Cut_enable = 1;
        else         Cut_enable = 0;
    
        // Чтение АЦП и нормализация полученных данных
        for(i=0; i < MAX_ADC; i++)
        {
            AD[i] = read_adc(i);
            // Если ADmid unsigned возникает проблема в вычислениях при отритцательных
            // числах. Не понятно почему так происходит...
            if(AD[i] > Settings.ADmid[i]) AD_NORM[i] = ((AD[i] - Settings.ADmid[i]) * Settings.Kmax[i]) / 10;
            else                          AD_NORM[i] = ((AD[i] - Settings.ADmid[i]) * Settings.Kmin[i]) / 10;
        }
    
        // Копирование нормализованных данных с АЦП в управляющие элементы
        // для дальнейшей обработки
        input[CTRL_AIL]  = AD_NORM[ADC_AIL];
        input[CTRL_ELE]  = AD_NORM[ADC_ELE];
        input[CTRL_THR]  = AD_NORM[ADC_THR];
        input[CTRL_RUD]  = AD_NORM[ADC_RUD];
        input[CTRL_AUX1] = AD_NORM[ADC_AUX1];
    
    #ifdef SW1
        // Опрос и установка значения переключателя SW1 (двухрозиционный)
        if(SW1) input[CTRL_SW1] =   TimerClockPerSec(0.0005); // +0,5 мс
        else    input[CTRL_SW1] = - TimerClockPerSec(0.0005); // -0,5 мс
    #else
        // Опрос и установка значения переключателя SW1 (трехрозиционный)
        if(SW1_1)            input[CTRL_SW1] =   TimerClockPerSec(0.0005); // +0,5 мс
        if(!SW1_1 && !SW1_2) input[CTRL_SW1] =   0;                     //  0   мс
        if(SW1_2)            input[CTRL_SW1] = - TimerClockPerSec(0.0005); // -0,5 мс
    #endif
    
        // Опрос и установка значения переключателя SW2 (двухрозиционный)
        if(SW2) input[CTRL_SW2] =   TimerClockPerSec(0.0005); // +0,5 мс
        else    input[CTRL_SW2] = - TimerClockPerSec(0.0005); // -0,5 мс
    
        // Опрос и установка значения переключателя SW3 (двухрозиционный)
        if(SW3) input[CTRL_SW3] =   TimerClockPerSec(0.0005); // +0,5 мс
        else    input[CTRL_SW3] = - TimerClockPerSec(0.0005); // -0,5 мс
    
        // Копирование виртуальных каналов из реальных
        input[CTRL_V1] = input[CurModel.Mode[FLY_MODE].Control[CTRL_V1].from];
        input[CTRL_V2] = input[CurModel.Mode[FLY_MODE].Control[CTRL_V2].from];
    
        // Это значение триммера задаваемого в меню. Всегда равно 0,5 мс.
        // В результате влияние зависит только от заданного коэффициента.
        input[CTRL_TRIM] = TimerClockPerSec(0.0005);
    
        // Нулим массив двойных расходов
        memset(Dual, 0, sizeof(Dual));
        // Опрос двойных расходов
        Dual[CTRL_AIL] = DUAL_AIL;
        Dual[CTRL_ELE] = DUAL_ELE;
        Dual[CTRL_RUD] = DUAL_RUD;
    
        for(i=0; i < MAX_CONTROLS; i++)
        {
            // Для этих каналов нет кривых - мы их просто копируем на выход.
            if((i == CTRL_SW1) ||
               (i == CTRL_SW2) ||
               (i == CTRL_SW3) ||
               (i == CTRL_TRIM))
            {
                out_cur[i] = input[i];
            }
            else
            {
                // Рассчет значения с использованием кривой
                out_cur[i] = math_CurveInterPol(input[i], CurModel.Mode[FLY_MODE].Control[i].nodes);
            }
    
            // Расходы
            if(Dual[i])
            {
                if(input[i] < 0) Factor = CurModel.Mode[FLY_MODE].Control[i].minDRates;
                else             Factor = CurModel.Mode[FLY_MODE].Control[i].maxDRates;
            }
            else
            {
                if(input[i] < 0) Factor = CurModel.Mode[FLY_MODE].Control[i].minRates;
                else             Factor = CurModel.Mode[FLY_MODE].Control[i].maxRates;
            }
            if(Factor != 100) out_cur[i] = out_cur[i] * Factor / 100;
    
            // Если включен T.Cut
            if((i == CTRL_THR) && Cut_enable)
            {
                Factor = CurModel.Mode[FLY_MODE].Control[i].minDRates; // minDRates в канале газа - положение при T.Cut
                out_cur[i] = (- TimerClockPerSec(0.0005)) * Factor / 100;
            }
    
            // Прибавляем триммера к основным управляющим каналам
            // FIX ME: доделать триммеры через enum
            if(i < MAX_TRIMMERS)
            {
                TrimFactor = CurModel.Mode[FLY_MODE].trimmers[i];
                out_cur[i] += TrimFactor * 2; // FIX ME: нужно вычисляемое число, зависящее от частоты
            }
    
            // Применение реверса канала
            out_cur[i] *= CurModel.Mode[FLY_MODE].Control[i].reverse;
        }
    }
    Это просто про оформление... а интересного там гораздо больше: и кооперативная многозадачность(отдельные задачи вызываемые по прерыванию таймера), и пользовательский интерфейс, и много чего еще...

  12. #9

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    При написании кода, надо стараться, что бы структура его была логична и понятна. Например разбить на файлы, соответствующим образом именованные.
    Например все(почти все) определения я вынес в файл defs.h:
    Код:
    // *****************************************************************************
    // ***   Общие определения   ***************************************************
    // *****************************************************************************
    #define AVR_Clock_Freq 16000000     // Частота работы МК
    #define TimerDevider 8              // Делитель главного таймера
    #define TASK_TICK_TIME 20           // Время одного тика таймера задач(в мс)
    #define BAUD_RATE 115200            // Частота работы порта UART0
    
    // Если задан - режим отладки. Применяется для вывода отладочных сообщений
    // в UART0.
    //#define DEBUG
    
    // Если задан - экран рисуется перевёрнутым  - для установки экрана вверх тормашками.
    #define GFX_REVERSED
    
    // ***   Количество точек в кривой   *******************************************
    #define CURVE_NODES   7
    // ***   Количество моделей   **************************************************
    #define MAX_MODELS    5
    // ***   Длинна названия модели (максимум n символов + нуль-терминатор)   ******
    #define MODEL_NAME_LEN (12 + 1)
    // ***   Длинна названия полётного режима (n символов + нуль-терминатор)   *****
    #define MODE_NAME_LEN  (10 + 1)
    
    // *****************************************************************************
    // ***   Триммеры   ************************************************************
    // *****************************************************************************
    #define trim_0up        !PINE.7
    #define trim_0down      !PINE.6
    #define trim_1up        !PINB.2
    #define trim_1down      !PINB.3
    #define trim_2up        0// У меня отсутствует
    #define trim_2down      0// У меня отсутствует
    #define trim_3up        !PINE.4
    #define trim_3down      !PINE.5
    
    
    // *****************************************************************************
    // ***   Кнопки навигации   ****************************************************
    // *****************************************************************************
    #define HB_UP              !PIND.3
    #define HB_DOWN            !PIND.1
    #define HB_LEFT            !PIND.2
    #define HB_RIGHT           !PIND.0
    #define HB_BACK            !PIND.4
    #define HB_ENTER           !PIND.5
    
    // *****************************************************************************
    // ***   Стрелочный индикатор                                                ***
    // ***   Значения 0x00 - 0xFF                                                ***
    // *****************************************************************************
    #define GAUGE(x)        OCR0 = x
    
    // *****************************************************************************
    // ***   Зуммер                                                              ***
    // ***   "1" включен, "0" выключен. PORTG.2 отсутствует :(                   ***
    // *****************************************************************************
    //#define BUZ             PORTG.2
    //#define BUZ(x)          PORTG = (PORTG & (~(1 << 2))) | (x << 2)
    #define BUZ(x)          PORTB.7 = x
    
    // *****************************************************************************
    // ***   Светодиоды   **********************************************************
    // *****************************************************************************
    #define LED1(x)
    #define LED2(x)         PORTB.4 = x
    
    // *****************************************************************************
    // ***   Переключатели   *******************************************************
    // *****************************************************************************
    #define MODE_KEY1       !PINE.2
    #define MODE_KEY2       !PINE.3
    
    // Возможно использование SW1 как трехпозиционный, так и как двухпозиционный
    // Ксли определен SW1 - преключатель двухпозиционный
    //#define SW1             !PIND.7
    // Иначе(должены быть определёны SW1_1 и SW1_2) - трехпозиционный
    #define SW1_1           !PINA.1
    #define SW1_2           !PINA.2
    #define SW2             !(PING&(1 << 1))
    #define SW3             0
    #define SW4             0
    
    #define Tcut_KEY        !(PING&(1 << 0))
    #define DUAL_AIL        !PIND.6
    #define DUAL_ELE        !PIND.7
    #define DUAL_RUD        0
    
    // *****************************************************************************
    // ***   Каналы АЦП   **********************************************************
    // *****************************************************************************
    enum
    {
        ADC_AUX2 = 0,
        ADC_AUX3,
        ADC_AUX1,
        ADC_AIL,
        ADC_ELE,
        ADC_THR,
        ADC_RUD,
        ADC_BAT,
        MAX_ADC
    };
    
    // *****************************************************************************
    // ***   Элементы управления   *************************************************
    // *****************************************************************************
    enum
    {
        CTRL_AIL = 0, // \
        CTRL_ELE,     // | Должны быть первыми, потому как триммеры
        CTRL_THR,     // | добавляются к первым 4-м каналам
        CTRL_RUD,     // /
        CTRL_SW1,
        CTRL_SW2,
        CTRL_SW3,
        CTRL_AUX1,
        CTRL_V1, // Виртуальные каналы должны быть последними, CTRL_V1 должен быть первым из
        CTRL_V2, // них, т.к. всё каналы что ниже его нельзя выбрать в качестве источника.
        CTRL_TRIM,
        MAX_CONTROLS
    };
    
    // *****************************************************************************
    // ***   Параметры управляющих элементов   *************************************
    // *****************************************************************************
    enum
    {
        CTRLS_REV = 0,
        CTRLS_MAXR,
        CTRLS_MINR,
        CTRLS_MAXDR,
        CTRLS_MINDR,
        CTRLS_TCUT,
        CTRLS_FROM,
        CTRLS_CURVE,
        MAX_CTRL_SETTINGS
    };
    
    // *****************************************************************************
    // ***   Trimmers   ************************************************************
    // *****************************************************************************
    enum
    {
        TRM_AIL = 0,
        TRM_ELE,
        TRM_THR,
        TRM_RUD,
        MAX_TRIMMERS
    };
    
    // *****************************************************************************
    // ***   Каналы PPM   **********************************************************
    // *****************************************************************************
    enum
    {
        CH_AIL = 0,
        CH_ELE,
        CH_THR,
        CH_RUD,
        CH_AUX1,
        CH_AUX2,
        CH_AUX3,
        CH_BAT,
        MAX_CHANNELS
    };
    
    // *****************************************************************************
    // ***   Model types   *********************************************************
    // *****************************************************************************
    enum
    {
        TYPE_PLANE = 0,
        TYPE_HELI,
        TYPE_GLIDER,
        MAX_TYPES
    };
    
    // *****************************************************************************
    // ***   Fly modes   ***********************************************************
    // *****************************************************************************
    enum
    {
        M_NORMAL = 0,
        M_IDLEUP,
        M_THOLD,
        MAX_MODES
    };
    
    // *****************************************************************************
    // ***   TX Modulation types   *************************************************
    // *****************************************************************************
    enum
    {
        MODUL_PPM = 0,
        MODUL_IPPM,
        MODUL_PCM,
        MAX_MODULS
    };
    
    // *****************************************************************************
    // *****************************************************************************
    // ***   Определения ниже - платформонезависимые - НЕ МЕНЯТЬ !!!   *************
    // *****************************************************************************
    // *****************************************************************************
    
    // ***   Количество тиков таймера за n сек   ***********************************
    #define TimerClockPerSec(s) ((unsigned long)(s * AVR_Clock_Freq) / TimerDevider)
    
    // ***   Подсчет количества элементов массива   ********************************
    #define NumberOf(x) (sizeof(x)/sizeof(x[0]))
    
    // ***   Определения   *********************************************************
    #define TRUE  1
    #define FALSE 0
    #define ON    1
    #define OFF   0
    #define On    1
    #define Off   0
    #define High  1
    #define Low   0
    
    // *****************************************************************************
    // ***   Описание типов указателей   *******************************************
    // *****************************************************************************
    enum
    {
        // String (char) ptrs
        PTR_FLASH = 0,
        PTR_SRAM,
        PTR_EEPROM,
        // Variables ptrs
        PTR_CHAR,
        PTR_UCHAR,
        PTR_INT,
        PTR_UINT,
        MAX_PTR_TYPES
    };
    
    // *****************************************************************************
    // *****************************************************************************
    // *****************************************************************************
    // *****************************************************************************
    // *****************************************************************************
    Первым делом идут определения частоты, делителя и т.д. Зачем? Первое с чем я столкнулся в кодере focus'а - жесточайший хардкодинг: где только можно были вписаны числовые значения, соответственно прошивка заточена под 12 МГц кварц, что был у focus'а. Мне же сахотелось поставить на 16 МГц - если чип допускает, почему бы не использовать всю мощь?
    Используя эти определения рассчитываются на этапе компиляции необходимые значения(делители для таймеров и т.д.).

    Далее идут определения понятные по комментариям, потом кнопочки, потом стрелочный индикатор который у меня был - подключался на порт связанный с таймером и управлялся ШИМом, далее определение динамика(которого у меня тоже нет - использую ШИМ и могу играть мелодии), светодиоды, кнопки.
    Хочу отметить, что полной модульности не получилось, т.к. надо править инициализацию потров(назначение входов-выходов). Зато заглянув сюда всегда можно вспомнить что есть и куда подключено.

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

    В конце идут несколько определений, которые используются по всей программе для улучшения читаемости. Последнее перечисление нужно для передачи в функции указателей. AVR имеет гарвардскую структуру, а значит мало передать в функцию указатель на данные, нужно еще передать куда он указывает - на флешь, ОЗУ или еепром(если у нас данные могут находится в разных областях памяти). Изменять их нет надобности о чем говорится в заголовке блока.

    Продолжение следует... надеюсь

  13. #10

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Теперь пришло время рассмотреть главный файл:
    Код:
    /*******************************************************************************
    *  Coder.c
    *
    *  Радиоуправление: Главный файл
    *
    *       Copyright (c) 2007-2008 Nick Shl, focus
    *           All rights reserved.
    *
    *
    *  Изменения:
    *
    *  Apr 20, 2009  Nick_Shl  Переработка
    *  Apr 10, 2008  Nick_Shl  Форматирование, комментарии.
    *  *** **, ****  focus     Первоначальная версия
    *
    *  Chip type           : ATmega128
    *  Program type        : Application
    *  Clock frequency     : 16,000000 MHz
    *  Memory model        : Small
    *  External SRAM size  : 0
    *  Data Stack size     : 1024
    */// ***************************************************************************
    
    // *****************************************************************************
    // ***   Системные инклюды   ***************************************************
    // *****************************************************************************
    #include <mega128.h>
    #include <delay.h>
    #include <stdio.h>
    
    // *****************************************************************************
    // ***   Работа с COM портом - сгенерирована CodeVisionAVR   *******************
    // *****************************************************************************
    #define RXB8 1
    #define TXB8 0
    #define UPE 2
    #define OVR 3
    #define FE 4
    #define UDRE 5
    #define RXC 7
    
    #define FRAMING_ERROR (1 << FE)
    #define PARITY_ERROR (1 << UPE)
    #define DATA_OVERRUN (1 << OVR)
    #define DATA_REGISTER_EMPTY (1 << UDRE)
    #define RX_COMPLETE (1 << RXC)
    
    // USART0 Receiver buffer
    #define RX_BUFFER_SIZE0 32
    char rx_buffer0[RX_BUFFER_SIZE0];
    
    #if RX_BUFFER_SIZE0 < 256
        unsigned char rx_wr_index0, rx_rd_index0, rx_counter0;
    #else
        unsigned int rx_wr_index0, rx_rd_index0, rx_counter0;
    #endif
    
    // This flag is set on USART0 Receiver buffer overflow
    bit rx_buffer_overflow0;
    
    // USART0 Receiver interrupt service routine
    interrupt [USART0_RXC] void usart0_rx_isr(void)
    {
        char status, data;
        status = UCSR0A;
        data = UDR0;
        if((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0)
        {
            rx_buffer0[rx_wr_index0] = data;
            if(++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0 = 0;
            if(++rx_counter0 == RX_BUFFER_SIZE0)
            {
                rx_counter0 = 0;
                rx_buffer_overflow0 = 1;
            };
        };
    }
    
    #ifndef _DEBUG_TERMINAL_IO_
    // Get a character from the USART0 Receiver buffer
    #define _ALTERNATE_GETCHAR_
    #pragma used+
    char getchar(void)
    {
        char data;
        while(rx_counter0 == 0);
        data = rx_buffer0[rx_rd_index0];
        if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0 = 0;
        #asm("cli")
        --rx_counter0;
        #asm("sei")
        return data;
    }
    #pragma used-
    #endif
    
    // USART0 Transmitter buffer
    #define TX_BUFFER_SIZE0 32
    char tx_buffer0[TX_BUFFER_SIZE0];
    
    #if TX_BUFFER_SIZE0 < 256
        unsigned char tx_wr_index0, tx_rd_index0, tx_counter0;
    #else
        unsigned int tx_wr_index0, tx_rd_index0, tx_counter0;
    #endif
    
    // USART0 Transmitter interrupt service routine
    interrupt [USART0_TXC] void usart0_tx_isr(void)
    {
        if(tx_counter0)
        {
            --tx_counter0;
            UDR0 = tx_buffer0[tx_rd_index0];
            if(++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0 = 0;
        };
    }
    
    #ifndef _DEBUG_TERMINAL_IO_
    // Write a character to the USART0 Transmitter buffer
    #define _ALTERNATE_PUTCHAR_
    #pragma used+
    void putchar(char c)
    {
        while(tx_counter0 == TX_BUFFER_SIZE0);
        #asm("cli")
        if(tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY) == 0))
        {
            tx_buffer0[tx_wr_index0] = c;
            if(++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0 = 0;
            ++tx_counter0;
        }
        else UDR0 = c;
        #asm("sei")
    }
    #pragma used-
    #endif
    
    // *****************************************************************************
    // ***   Конец кода работы с COM портом   **************************************
    // *****************************************************************************
    
    // *****************************************************************************
    // ***   Пользовательские инклюды   ********************************************
    // *****************************************************************************
    #include "Def.h"
    #include "Hardware.h"
    #include "Variables.h"
    #include "Graphic.h"
    #include "Sound.h"
    #include "Math.h"
    #include "System.h"
    #include "Crc.h"
    #include "Tasks.h"
    #include "UI_Engine.h"
    #include "User_Interface.h"
    
    // *****************************************************************************
    // ***   Глобальные переменные   ***********************************************
    // *****************************************************************************
    static unsigned long TickCount = 0;
    flash unsigned int TxStartSound[] = {784<<4 + 2, 660<<4 + 1, 523<<4 + 1, 784<<4 + 2};
    
    // *****************************************************************************
    // ***   Прототипы функций   ***************************************************
    // *****************************************************************************
    
    // *****************************************************************************
    // ***   Определения   *********************************************************
    // *****************************************************************************
    
    // *****************************************************************************
    // ***   Возвращает количество тиков с момента запуска устройства   ************
    // *****************************************************************************
    inline unsigned long GetTickCount(void)
    {
    #ifdef DEBUG
        return(TickCount / TASK_TICK_TIME);
    #else
        return(TickCount);
    #endif
    }
    
    // *****************************************************************************
    // ***   Возвращает количество мс с момента запуска устройства   ***************
    // *****************************************************************************
    inline unsigned long GetRunningTime(void)
    {
    #ifdef DEBUG
        return(TickCount);
    #else
        return(TickCount * TASK_TICK_TIME);
    #endif
    }
    
    // *****************************************************************************
    // ***   Прерывание таймера                                                  ***
    // ***   В котором собственно говоря и идет вычисление импульсов :)          ***
    // *****************************************************************************
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
        // Номер текущего канала
        static unsigned char nb = 0;
        // Длительность паузы между пачками PPM импульсов
        static unsigned int del = 0;
    
    #ifdef DEBUG
        // Для отладки
        static unsigned char gauge = 0; // Для отладки
        static char dir = 1;            // Для отладки
    #endif
    
        if(nb < CurModel.num_ch)
        {
            // Рассчет канального импульса - микширование
            math_CalcChannel(nb);
    
            ICR1H = output[nb] >> 8;         // Заливаем длительность канала (Hi)
            ICR1L = output[nb] & 0b11111111; // Заливаем длительность канала (Lo)
    
            del += output[nb]; // Добавляем длительность канала к суммарному значению канальных импульсов
    
            nb++; // Увеличиваем номер канала
        }
        else
        {
            del = TimerClockPerSec(0.020) - del; // Длительность паузы: количество отсчетов
                                                 // за 0.020 секунды(20 мс) - время канальных импульсов
            ICR1H = del >> 8;                    // Заливаем длительность паузы (Hi)
            ICR1L = del & 0b11111111;            // Заливаем длительность паузы (Lo)
    
            del = 0; // Обнуляем суммарное значение канальных импульсов
            nb = 0;  // Сбрасываем номер канала
    
    #ifdef DEBUG
            // Код нужен для отладки - гоняние стрелочного индикатора туда-сюда.
            if(gauge == 0x00) dir = +1;
            if(gauge == 0xFF) dir = -1;
            GAUGE(gauge);
            gauge += dir;
    #endif
    
            // Получение статуса управляющих элементов
            math_CalcControls();
    
            // Читаем и обрабатываем значение опорного напряжения:
            // (напряжение на встроенном ИОН * разрядность АЦП) / прочитанное значение встроенного ИОН
            Aref = (123L * 1023L) / (long)read_adc(0x1E);
        }
    }
    
    // *****************************************************************************
    // ***   Прерывание таймера                                                  ***
    // ***   Данное прерывание необходимо для реализации второстепенных задач,   ***
    // ***   таких как опрос клавиатуры, пищание при нажатии на кнопки и т.д.    ***
    // ***   Предусматривается не возможность повторного входа в прерывание.     ***
    // ***   FIX ME: Возможно стоит переделать в функцию и вызвать в конце       ***
    // ***   timer1_compa_isr с помощью строчки:                                 ***
    // ***   if(nb == 0) timer3_compa_isr();                                     ***
    // *****************************************************************************
    interrupt [TIM3_COMPA] void timer3_compa_isr(void)
    {
        static unsigned char InterruptEnterFlag = 0;
        static unsigned char MissedIntCount = 0;
        unsigned char MissedInterruptsCount = 0;
    
        // Увеличиваем счетчик системного времени в TASK_TICK_TIME или в мс(DEBUG) интервалах
        TickCount++;
    
    #ifdef DEBUG
        if(TickCount % TASK_TICK_TIME) return;
    #endif
    
        // Если мы уже находимся в этом прерывании - увеличиваем счетчик количества
        // пропущенных прерываний и выходим.
        if(InterruptEnterFlag)
        {
            MissedIntCount++;
            return;
        }
    
        // Иначе устанавливаем флаг, что мы уже находимся в данном прерывании
        InterruptEnterFlag = 1;
        // Копируем количество пропущенных прерываний в дополнительную переменную,
        // т.к. счетчик будет увеличиватся при повторном вызове данного прерывания.
        MissedInterruptsCount = MissedIntCount;
        // Обнуляем счетчик пропущенных прерываний.
        MissedIntCount = 0;
    
        // Разрешаем прерывания для более приоритетной задачи - опрос АЦП и передачи
        #asm("sei")
    
        // Вызываем драйвер клавиатуры
        Keyboard_Driver_Task(MissedInterruptsCount);
    
        // Вызываем задачу подсчета таймера
        Timer_Task(MissedInterruptsCount);
    
        // Вызываем задачу проигрывания мелодии
        PlaySound_Task(MissedInterruptsCount);
    
        // Вызываем драйвер батареи
        Battery_Driver_Task(MissedInterruptsCount);
    
        // Задача сохранение триммеров
        Trimmers_Save_Task(MissedInterruptsCount);
    
        // Вызываем задачу обновления экрана
    //    gfx_AutoRefreshTask(MissedInterruptsCount);
    
        // Запрещаем прерывания
        #asm("cli")
        //  Cбрасываем флаг, что бы в следующий раз зайти в прерывание
        InterruptEnterFlag = 0;
    
        return;
    }
    
    // *****************************************************************************
    // ***   Главная функция   *****************************************************
    // *****************************************************************************
    void main(void)
    {
        // Время последнего обновления главного экрана
        unsigned long LastRefreshTime = 0;
        // Переменная для хранения значения кнопок
        unsigned char Kbd = 0;
    
    // *** Инициализация железа   **************************************************
        hwl_InitPorts(); // Ports initialization
        hwl_InitTimers(); // Timers/Counters initialization
        hwl_InitUSART0(BAUD_RATE); // USART0 initialization
        hwl_InitMisc(); // All other hardware initialization
    
        // Информация для отладки
    #ifdef DEBUG
        printf("Started program...\r");
        printf("CRC FLASH:  0x%04X\r", Crc16_flash((unsigned char flash *)0, 0x1000 - sizeof(unsigned short)));
        printf("CRC EEPROM: 0x%04X ", Get_EEPROM_CRC());
        if(Is_EEPROM_CRC_Correct() == TRUE) printf("CORRECT\r");
        else printf("INCORRECT\r");
        if(sizeof(EEPROM_MODEL_SETTINGS) != sizeof(MODEL_SETTINGS)) printf("WARNING!!! ");
        printf("EEPROM_MODEL_SETTINGS(%d) == MODEL_SETTINGS(%d);\r", sizeof(EEPROM_MODEL_SETTINGS), sizeof(MODEL_SETTINGS));
        delay_ms(1);
    #endif
    
        // Инициализация графической подсистемы
        gfx_Init();
        // Очищаем экран
        gfx_ClearBuf();
        // Выводим запрос подтверждения сброса
        MsgBoxF("Starting...", NULL, "TRANSMITTER", NULL);
    
        // Если первое включение, то сбросить все модели и вызвать калибровку
        if((EEPROM_SETTINGS.FirstON != 1) || (HB_BACK && HB_ENTER)) TX_Reset();
        // Если на проверка контрольной суммы EEPROM не пройдена
        if(Is_EEPROM_CRC_Correct() == FALSE)
        {
            // Выводим запрос подтверждения сброса
            MsgBoxF("EEPROM CRC ERROR\nReset to factory\ndefaults ?", &Font_6x8, "ERROR", NULL);
    
            // Ждем отпускания кнопок, если были нажаты
            while(HB_ENTER || HB_BACK);
            // Ждем нажатия кнопок
            while(!HB_ENTER && !HB_BACK);
            // Eсли нажали ВВОД - сбрасываем
            if(HB_ENTER) TX_Reset();
        }
    
        #asm("cli")
            // Инициализируем кодер (чтение установок из EEPROM)
            TX_Init();
            // Разрешение выработки прерываний таймером выходных импульсов
            TIMSK = 0x10;
            // Разрешение выработки прерываний таймером задач
            ETIMSK = 0x10;
            // Первоначальный рассчет значений управляющих элементов
            math_CalcControls();
        #asm("sei")
    
        // Пауза для гарантированной отработки всех драйверов
        delay_ms(50);
    
        // Мелодия включения
        PlaySound(TxStartSound, NumberOf(TxStartSound));
    
    #ifdef DEBUG
    //    StartTime = GetRunningTime();
    //    printf("Execute time = %d ms\r", GetRunningTime() - LastRefreshTime);
    #endif
    
        while(1)
        {
            // Засыпаем до первого прерывания
            Sleep();
    
            trim_sound();
    
            // Этот цикл будет выполнятся как минимум один раз. Если ранее были нажаты кнопки,
            // цикл будет выполнятся до тех пор, пока их не отпустят. Нужно для того, что бы
            // экран не подвисал на время удержания кнопок.
            do
            {
                // Если прошло 100 мс с момента последней отрисовки
                if(LastRefreshTime + 100 <= GetRunningTime())
                {
                    // Запоминаем время последней отрисовки
                    LastRefreshTime = GetRunningTime();
                    // Отрисовываем главный экран
                    MainScreen();
    #ifdef DEBUG
    //printf("MainScreen() execute time = %d ms (%d Ticks)\r", (GetTickCount() - LastRefreshTime) * TICK_TIME, GetTickCount() - LastRefreshTime);
    #endif
                }
            }
            while(Kbd && AskButtons());
    
            // Получаем состояние кнопок
            Kbd = AskButtons();
    
            // Если таймер включил звук и нажали кнопку
            if(GetTimerSoundStatus() == On && Kbd)
            {
                // Выключаем заук таймера
                TimerSoundOff();
                // пропускаем последующий анализ кнопок
                continue;
            }
    
            // Останов счета и переинициализация таймера кнопкой ВЛЕВО
            if(Kbd & B_LEFT) Timer_Init();
            // Запуск таймера кнопкой ВВЕРХ
            if(Kbd & B_UP) Timer_Stop();
            // Останов таймера кнопкой ВНИЗ
            if(Kbd & B_DOWN) Timer_Start();
    
            // Управляем подсветкой на главном экране кнопкой BACK
            // При нажати BACK подсветка включается/выключается
            // Изменение сохраняется только в SRAM
            if(Kbd == B_BACK)
            {
                if(Settings.BacklightFlag == On) gfx_BackLight(Off);
                else                             gfx_BackLight(On);
            }
    
            // Вход в главное меню
            if(Kbd == B_ENTER) MainMenu();
        };
    }
    Первым делом в нем идут системные инклюды и код сгенерированный CodeVisionAVR для работы с UART портом. В дальнейшем его можно было бы использовать для подключения к компьютеру, но я его использовал только для отладки - выводил в него сообщения, которые просматривал в терминале. Говоря про определения я не рассказал про определение "#define DEBUG" - именно оно определяет, собираем прошивку с отладкой или без. Анализируя это определение можно указать какой код должен быть учтен на этапе компиляции, а какой - нет. В прочем в этом файле вы это увидите.

    Дальше идет подключение пользовательских заголовков(обратите внимание на количество и названия) и глобальные переменные. Их всего две. Кстати, оперирование глобальными переменными - плохая практика. Например переменная TickCount. Напрямую к ней обращаться не стоит - для этого есть функции GetTickCount() и GetRunningTime() которые вам ее вернут. Первая возвращает количество тиков, вторая - время в мс. Это первое место, где мы сталкиваемся с анализом определения DEBUG. В целях отладки я устанавливал срабатывания таймера каждую мс, а в релизной версии он срабатывает каждые 20 мс. Поэтому в отладочной версии мы подсчитываем количество тиков, а в релизной - количество мс.

    Дальше идет прерывание формирующее сигнал PPM. В нем так же есть код для отладки - в режиме отладки имеющийся у меня стрелочный индикатор я гонял туда-сюда. В релизной версии предполагал использовать как индикатор батарей.

    Дальше идет очень интересное прерывание, но о нем чуть ниже, а пока рассмотрим функцию main(). Это главная функция, которая крутится в фоновом режиме. Сначала мы делаем инициализацию железа. Она вынесена в отдельный файл hardware.с и не занимает много места - код более читабельный. В отладочном блоке выводится всякая информация, дальше идет инициализация графики, очистка экрана, вывод сообщения о старте. Если включение первое или зажаты одновременно кнопки "Back" и "Enter" - сбрасываем передатчик к заводским значениям. После проверяем CRC eeprom. Если оно не верно - предлагаем сбросить к заводским настройкам. Дальше инициализируется передатчик, играется мелодия и идем в главный цикл.

    В главном цикле стоит засыпание до прерывания, вывод звука если нажат триммер, цикл отрисовки экрана. Данный цикл будет выполнятся до тех пор, пока нажаты кнопки, которые были уже обработаны. Дальше идет опрос клавиатуры. Опрос делается функцией AskButtons(), а не прямым чтением портов. Дальше идет проверка сработавшего сигнала таймера, и если он сработал и нажата кнопка - мы его выключаем.
    После идет код управления таймером(сброс, запуск, останов), управление подсветкой и вход в главное меню, которое реализовано функцией. О нем мы поговорим позже.

    Теперь про "интересное прерывание". Это прерывание поддерживает обработку "задач" и подсчет системного времени в тиках. Кроме того, данное прерывание разрешает прерывания, что бы на время его выполнения могли формироваться импульсы PPM. При этом, если предыдущее прерывание не успеет отработать к следующему вызову, то задачи повторно запущены не будут, но для времязависимых задач(таймер например) ведется подсчет пропущеных прерывний и передает это значение задачам.

    Какие задачи тут имеются:

    • "Драйвер" клавиатуры меню(обрабатывает стрелки и "Back" с "Enter")
    • Таймер
    • Проигрывание мелодии в фоне
    • "Драйвер" батареи
    • Задача по сохранению триммеров
    • Задача по автоматическому обновлению экрана - признана бесполезной
    Вот о задачах, наверное и поговорим в следующий раз...

  14. #11

    Регистрация
    04.10.2004
    Адрес
    Балашиха
    Возраст
    42
    Сообщений
    2,892
    Дисплей там на TLS8201, практически аналог st7565r Шина паралельная. Подробности тут (и кусок схемы в том числе я выкладывал). какой дисплей на imax/turnigy 9x ?

    Запустить то нет проблем. Вопрос что дальше? Есть менее удобная, но более функциональная - ер9х. При использовании еепе неудобства нивелируются. Сомневаюсь, что кому-нибудь это нужно.

  15. #12

    Регистрация
    22.03.2004
    Адрес
    Кемерово
    Возраст
    44
    Сообщений
    3,132
    Записей в дневнике
    19
    гыгы. Сергея код понятен почти сразу. попробуйте в коде менюшек er9x разобраться. вот там ад и израиль.
    Николай, вы всетаки решились причесать. это очень хорошо. может станет еще легче ее портировать.

  16. #13

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от RW9UAO Посмотреть сообщение
    Николай, вы всетаки решились причесать. это очень хорошо. может станет еще легче ее портировать.
    Это не причесывание, это почти полная переработка. Большинство вещей не имеет ничего общего с остальными тут представленными версиями.

    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    Запустить то нет проблем. Вопрос что дальше?
    Дальше упражнятся в программировании... впрочем, судя по всему этот раздел не для таких, а для тех, кто лишь повторяет чужие разработки. Тогда действительно, делать нечего.

    Цитата Сообщение от Aleksey_Gorelikov Посмотреть сообщение
    Сомневаюсь, что кому-нибудь это нужно.
    Действительно не нужно. И это - очередное тому подтверждение, что распинаюсь я тут зря. А потому заканчиваю.

    Если кому что понадобится - интересующее спрашивать может тут.

  17. #14

    Регистрация
    27.11.2004
    Адрес
    Ярославль
    Возраст
    36
    Сообщений
    418
    Цитата Сообщение от Nick_Shl Посмотреть сообщение
    Действительно не нужно. И это - очередное тому подтверждение, что распинаюсь я тут зря. А потому заканчиваю. Если кому что понадобится - интересующее спрашивать может тут.

    Это вы зря, при всём своём уважении к Вашей работе.
    У меня по этому поводу вопрос есть - на сколько сложно перевести проект msv под предлагаемый вами способ разработки? если не сильно всё трудно и Автор проекта будет не против я поучаствую в этом деле.

  18. #15

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Иван Посмотреть сообщение
    Это вы зря, при всём своём уважении к Вашей работе.
    Ну никому же не интересно, разве не так? А кому интересно будет - может задать вопрос.

    Цитата Сообщение от Иван Посмотреть сообщение
    У меня по этому поводу вопрос есть - на сколько сложно перевести проект msv под предлагаемый вами способ разработки? если не сильно всё трудно и Автор проекта будет не против я поучаствую в этом деле.
    Абсолютно не сложно. Скачиваете TortoiseSVN, устанавливаете, создаете каталог для репозитория(например "D:\Repository", заходите в него проводником, нажимаете правую кнопку мыши, выбираете "TortoiseSVN -> Create repository here". Может спросить про создание структуры директорий в репозитории - можете не жать "Create ...", а сразу жать "Exit".
    Потом идете проводником к каталогу, где у вас лежит проект. Пусть это будет "D:\OSD" для примера. На нем нажимаем правую кнопку мыши и выбираем "TortoiseSVN -> Import"/ В открывшемся окне вводим URL репозитория, добавив название папки(т.к. в репозиторий кладется только содержимое папки), например "file:///D:/Repository/OSD". Чуть ниже вводим комментарий, например "Первоначальная версия" и жмем ОК. Теперь код лежит там. Нужно только взять его из репозитория, а как и как дальше работать расписано в первом посте этой темы.

  19. #16

    Регистрация
    27.11.2004
    Адрес
    Ярославль
    Возраст
    36
    Сообщений
    418
    в качестве репозитория можно сетевый ресурс использовать и получить общественный проект ?
    Спасибо за развёрнутый ответ.

  20. #17

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Иван Посмотреть сообщение
    в качестве репозитория можно сетевый ресурс использовать и получить общественный проект ?
    Спасибо за развёрнутый ответ.
    Можно, но как- я не разбирался... попробуйте разобраться с Google Project Hosting например. Там при создании проекта можно выбрать Subversion или Git(тогда используем TortoiseGit).

  21. #18

    Регистрация
    12.02.2011
    Адрес
    Москва
    Возраст
    51
    Сообщений
    806
    Ох не зря я про вьетнам с китаем ляпнул. Разобраться с гуглем, общественный проект, ваши наработки для затравки, на ARM перевести, краудфайндинг ну и....

  22. #19

    Регистрация
    30.10.2012
    Адрес
    Hochiminh,vietnam
    Возраст
    32
    Сообщений
    70
    hello Nick_scl

    TX can setup program ''slow servo '' for any channel ? i want to use for a FLAP , so have to control speed servo .

  23. #20

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Dinotron Посмотреть сообщение
    Ох не зря я про вьетнам с китаем ляпнул. Разобраться с гуглем, общественный проект, ваши наработки для затравки, на ARM перевести, краудфайндинг ну и....
    Заморочек много. А когда нет нормального железа и не используешь его постоянно...
    Может закажу себе как-нибудь все-таки 9XR. Надо только самолет достроить, а то крылья уже несколько лет валяются...
    Но тут уже китайцы козлы... 9X с модулями за вменяемые деньги есть, но в ней нет ISP, надо лезть с паяльником - в общем гемор. А 9XR идет только без модулей, а если еще и модули купить, то слишком уж получается...

    Цитата Сообщение от minhthien1988 Посмотреть сообщение
    TX can setup program ''slow servo'' for any channel ? i want to use for a FLAP , so have to control speed servo .
    I dont know what mean "program ''slow servo"". But I think it possible to programm it, if it needed

  24. #21

    Регистрация
    30.10.2012
    Адрес
    Hochiminh,vietnam
    Возраст
    32
    Сообщений
    70
    hello NICK_shl

    can you post here full your program ? I like to use a lcd KST1080 .

  25. #22

    Регистрация
    24.04.2012
    Адрес
    Novosibirsk
    Возраст
    58
    Сообщений
    1,096
    вопрос к Nick_Shl у вас существует прошивка или нет под вашу схему
    Миниатюры Миниатюры Нажмите на изображение для увеличения
Название: ShemSimple.jpg‎
Просмотров: 293
Размер:	72.4 Кб
ID:	988962  

  26. #23

    Регистрация
    07.04.2015
    Адрес
    Альметьевск
    Возраст
    46
    Сообщений
    5
    Можно ли использовать платы Ардуино для приемника и передатчика?

  27. #24

    Регистрация
    12.02.2011
    Адрес
    Москва
    Возраст
    51
    Сообщений
    806
    Цитата Сообщение от Вовуся Посмотреть сообщение
    Можно ли использовать платы Ардуино для приемника и передатчика?
    Да в лёгкую! Тремя командами со стандартными библиотеками. Они ж под это и заточены. http://www.ianjohnston.com/index.php?option=com_content&view=article&id=30:project-rc-ppm-trainer-port-joystick&catid=3:hobbies&Itemid=8
    А там хоть любую чушь туда с терминалом гнать. А уж принимать-то. PulseIn http://arduino.ua/ru/prog/PulseIn Короче третье после мигания светодиодиком и часов.


  28. #25

    Регистрация
    12.02.2011
    Адрес
    Москва
    Возраст
    51
    Сообщений
    806
    Цитата Сообщение от Nick_Shl Посмотреть сообщение
    А 9XR идет только без модулей, а если еще и модули купить, то слишком уж получается...
    Кстати, насчёт модуля под 9XR. Нажмите на изображение для увеличения
Название: DSC00123.jpg
Просмотров: 187
Размер:	56.7 Кб
ID:	1054970 Только не смейтесь и не бейте сильно. От Esky напильником доточил. Подумал, жаль выбрасывать.

  29. #26

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Давненько я сюда не заходил...
    Цитата Сообщение от Alibaba Посмотреть сообщение
    вопрос к Nick_Shl у вас существует прошивка или нет под вашу схему
    Так прошивка тут выложена же. Достаточно скачать репозиториий, вынуть её оттуда и скомпилировать. Если схема другая - подправить Def файл. Могут быть проблемы только с подключением экрана - все что к нему относится кажись в файле "драйвера" экрана.

    P.S. подвязок в Hobbico(они же "Башня") ни у кого нет? Не в плане покупок, а в плане трудоустройства?

  30. #27

    Регистрация
    24.04.2012
    Адрес
    Novosibirsk
    Возраст
    58
    Сообщений
    1,096
    Цитата Сообщение от Nick_Shl Посмотреть сообщение
    Так прошивка тут выложена же. Достаточно скачать репозиториий, вынуть её оттуда и скомпилировать.
    слово репозиториий это что, потом мне нужно искать к-то софт, чтоб это собрать. ну и вопрос: а нельзя ли это в виде гекс файла под конкретную схему: скажем та что приведена.

  31. #28

    Регистрация
    30.10.2012
    Адрес
    Hochiminh,vietnam
    Возраст
    32
    Сообщений
    70
    Nick Shl , please post a file hex here if you can share . thanks

  32. #29

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    C hex проблемка... вернее не с ним, а со схемой. Это первый вариант, потом я сделал другую схему, но не рисовал её, а просто развел плату. Потом подключается я смотрел на какой пин что подключается и вбивал в Def.h

    Выложил последнюю версию кода. Там же и Hex.

    Про подключение. Начнем с LCD. Его подключение описано в MT12864.c:
    Код:
    #define LCD_DATA_PORT PORTC
    #define LCD_DATA_DDR  DDRC
    #define LCD_DATA_PIN  PINC
    
    #define LCD_BL(x)  PORTA.0 = x // Подсветка ЖКИ
    #define LCD_E(x)   PORTA.3 = x // Линия E ЖКИ (строб)
    #define LCD_A0(x)  PORTA.4 = x // Линия A0 ЖКИ (данные/команда)
    #define LCD_RW(x)  PORTA.5 = x // Линия RW ЖКИ (запись/чтение)
    #define LCD_RES(x) PORTA.6 = x // Линия RES ЖКИ (сброс)
    
    // Линии CS ЖКИ (выборка)
    #define LCD_C1(x)  PORTG = (PORTG & (~(1 << 2))) | (x << 2) // PORTG.2
    #define LCD_C2(x)  PORTA.7 = x
    Линии Data на LCD подключаются на PORTC 1 к 1: 0 к 0 ... 7 к 7
    Остальные линии смотрите на название порта и номер пина после точки(нумеруются с 0).

    Далее остальное:
    Код:
    // *****************************************************************************
    // ***   Триммеры   ************************************************************
    // *****************************************************************************
    #define trim_0up        !PINE.7
    #define trim_0down      !PINE.6
    #define trim_1up        !PINB.2
    #define trim_1down      !PINB.3
    #define trim_2up        0// У меня отсутствует
    #define trim_2down      0// У меня отсутствует
    #define trim_3up        !PINE.4
    #define trim_3down      !PINE.5
    
    
    // *****************************************************************************
    // ***   Кнопки навигации   ****************************************************
    // *****************************************************************************
    #define HB_UP              !PIND.3
    #define HB_DOWN            !PIND.1
    #define HB_LEFT            !PIND.2
    #define HB_RIGHT           !PIND.0
    #define HB_BACK            !PIND.4
    #define HB_ENTER           !PIND.5
    
    // *****************************************************************************
    // ***   Стрелочный индикатор                                                ***
    // ***   Значения 0x00 - 0xFF                                                ***
    // *****************************************************************************
    #define GAUGE(x)        OCR0 = x
    
    // *****************************************************************************
    // ***   Зуммер                                                              ***
    // ***   "1" включен, "0" выключен. PORTG.2 отсутствует :(                   ***
    // *****************************************************************************
    #define BUZ(x)          PORTB.7 = x
    
    // *****************************************************************************
    // ***   Светодиоды   **********************************************************
    // *****************************************************************************
    #define LED1(x)
    #define LED2(x)         PORTB.4 = x
    
    // *****************************************************************************
    // ***   Переключатели   *******************************************************
    // *****************************************************************************
    #define MODE_KEY1       !PINE.2
    #define MODE_KEY2       !PINE.3
    
    // Возможно использование SW1 как трехпозиционный, так и как двухпозиционный
    // Ксли определен SW1 - преключатель двухпозиционный
    //#define SW1             !PIND.7
    // Иначе(должены быть определёны SW1_1 и SW1_2) - трехпозиционный
    #define SW1_1           !PINA.1
    #define SW1_2           !PINA.2
    #define SW2             !(PING&(1 << 1)) // PING.1
    #define SW3             0
    #define SW4             0
    
    #define Tcut_KEY        !(PING&(1 << 0)) // PING.0
    #define DUAL_AIL        !PIND.6
    #define DUAL_ELE        !PIND.7
    #define DUAL_RUD        0
    Вложения

  33. #30

    Регистрация
    24.04.2012
    Адрес
    Novosibirsk
    Возраст
    58
    Сообщений
    1,096
    так, попробую поразобраться.

    Николай, а нельзя ли схемку в чем-нибудь простом - картинкой
    Последний раз редактировалось Alibaba; 15.06.2015 в 14:59.

  34. #31

    Регистрация
    20.03.2007
    Адрес
    Minneapolis, MN, US
    Возраст
    38
    Сообщений
    344
    Цитата Сообщение от Alibaba Посмотреть сообщение
    Николай, а нельзя ли схемку в чем-нибудь простом - картинкой
    Ну нет у меня схемы - не рисовал. Делал сразу разводку, схема была в голове. Впрочем, не такая уж она сложная что бы её было рисовать.
    Плата во вложении.
    Миниатюры Миниатюры Нажмите на изображение для увеличения
Название: Coder.jpg‎
Просмотров: 159
Размер:	115.1 Кб
ID:	1081837  

  35. #32

    Регистрация
    24.04.2012
    Адрес
    Novosibirsk
    Возраст
    58
    Сообщений
    1,096
    все понял, отстал. просто я думал, что у вас там файлик это схема. ну а по плате все будет понятно

Закрытая тема

Похожие темы

  1. Ответов: 1
    Последнее сообщение: 17.02.2014, 19:32
  2. Продам - приёмник impulse 2.4 diversity с хеликсом и 2 передатчика
    от Павел 28 в разделе Барахолка. Оборудование и модели для FPV
    Ответов: 5
    Последнее сообщение: 14.10.2013, 01:10
  3. Продам Блок света RC4WD12 диодов с поворотниками Scale Lighting System (Ver 2)
    от Pinger01 в разделе Барахолка. Автомодели - комплектующие
    Ответов: 0
    Последнее сообщение: 08.06.2013, 14:05
  4. Продам Комплект Fy-21AP ver 2 с Телеметрией AP 117
    от xalex1377 в разделе Барахолка. Оборудование и модели для FPV
    Ответов: 1
    Последнее сообщение: 28.05.2013, 01:33
  5. а кто-нибудь женил v-bar и kontronik helijive 120+ hv ver 13 ?
    от Nikolik в разделе Электродвигатели, регуляторы, аккумуляторы, зарядники
    Ответов: 7
    Последнее сообщение: 07.05.2013, 20:56

Метки этой темы

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения