Перевод скетча с Arduino IDE в AtmelStudio

Тема в разделе "Микроконтроллеры AVR", создана пользователем BAit, 2 янв 2018.

  1. BAit

    BAit Нерд

    Здравствуйте!
    Есть скетч на ардуино, решил перевести на AVR. Но что то не работает можете помочь?
    Код (C++):
    #define ENC_BUT 1       //PD1

    #define CH1_ACT 5              //PD5
    #define CH2_ACT 6              //PD6

    #define CH1 11          //PB3    PWM
    #define CH2 10          //PB2    PWM

    byte ACT=1;
    byte CH1_PWM=0;
    byte CH2_PWM=0;

    void setup() {

      pinMode(CH1_ACT, OUTPUT);
      pinMode(CH2_ACT, OUTPUT);

      pinMode(CH1, OUTPUT);
      pinMode(CH2, OUTPUT);

      pinMode(ENC_BUT, INPUT);
      pinMode(2, INPUT);
      pinMode(3, INPUT);

      digitalWrite(ENC_BUT, HIGH);
      digitalWrite(2, HIGH);
      digitalWrite(3, HIGH);
     
      EICRA = 0b00001111;
      EIMSK = 0b00000011;
     
    }

    void loop() {

    // Set the Active Channel LED
      if (ACT == 1){
        digitalWrite(CH1_ACT, HIGH);
        digitalWrite(CH2_ACT, LOW);  }
      else if (ACT == 2){
        digitalWrite(CH1_ACT, LOW);
        digitalWrite(CH2_ACT, HIGH); }

    // Apply the PWM duty cycles
    analogWrite(CH1, CH1_PWM);
    analogWrite(CH2, CH2_PWM);

    // Read the encoder Push-On button
    if (!digitalRead(ENC_BUT)) {
     
      if (ACT == 1){
        ACT = 2;}
      else if (ACT == 2){
        ACT = 1;}

      delay(10);
      do {} while (!digitalRead(ENC_BUT));
      }
    }


    ISR (INT0_vect) {
     
      if (digitalRead(3) == HIGH) {
        if (ACT == 1) {if (!(CH1_PWM == 255)) CH1_PWM += 5;}
        else if (ACT == 2) {if (!(CH2_PWM == 255))CH2_PWM += 5;}
         }
    }

    ISR (INT1_vect) {
                       
      if (digitalRead(2) == HIGH) {
        if (ACT == 1) {if (!(CH1_PWM == 0)) CH1_PWM -= 5;}
        else if (ACT == 2) {if (!(CH2_PWM == 0))CH2_PWM -= 5;}
         }
       
    }
     
    Код (C++):
    /*
    * CH2-LED-Controller.cpp
    *
    * Created: 27.12.2017 17:43:32
    * Author : Ysupov
    */

    #define F_CPU 16000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <avr/sfr_defs.h>

    #define CH1_ACT PD5
    #define CH2_ACT PD6
    #define CH1        PB1
    #define CH2        PB2

    #define ENC_BUT    PD1
    #define PIN_A    PD2
    #define PIN_B    PD3

    unsigned char ACT = 1;
    unsigned char CH1_PWM = 0;
    unsigned char CH2_PWM = 0;

    void timer_counter1_INIT()
    {
        TCCR1A |= _BV(WGM10);
        TCCR1B |= _BV(WGM12);
       
        TCCR1A |= _BV(COM1A1) | _BV(COM1B1);
        TCCR1A &= ~_BV(COM1A0) & ~_BV(COM1B0);
       
        TCCR1B |= _BV(CS12);
        TCCR1B &= ~_BV(CS11) & ~_BV(CS10);
    }
    void INT_INIT()
    {
        EICRA |= _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11);
        EIMSK |= _BV(INT0) | _BV(INT1);
    }

    int main(void)    {
        DDRD &= ~_BV(ENC_BUT) & ~_BV(PIN_A) & ~_BV(PIN_B);        // Выводы порта на вход
        PORTD |= _BV(ENC_BUT) | _BV(PIN_A) | _BV(PIN_B);        // Подтяжка порта к +5
       
        DDRD |= _BV(CH1_ACT) | _BV(CH2_ACT);                    // Выводы порта на выход
        DDRB |= _BV(CH1) | _BV(CH2);                            //
       
        OCR1A = 0;
        OCR1B = 0;
       
        timer_counter1_INIT();
        INT_INIT();
       
        while (1) {
            // Отображение выбранного канала
            if (ACT == 1)    {
                PORTD |= (1<<CH1_ACT);
                PORTD &= ~(1<<CH2_ACT);
            }
            else if (ACT == 2)    {
                PORTD &= ~(1<<CH1_ACT);
                PORTD |= (1<<CH2_ACT);
            }
           
            //
            if (CH1_PWM ==0) {
                PORTB &= ~(1<<CH1);
            }
            else if (CH1_PWM == 255) {
                PORTB |= (1<<CH1);
            }
            else {
                CH1_PWM = OCR1A;
            }
           
            //
            if (CH2_PWM ==0) {
                PORTB &= ~(1<<CH2);
            }
            else if (CH2_PWM == 255) {
                PORTB |= (1<<CH2);
            }
            else {
                CH2_PWM = OCR1B;
            }
           
            // Выбор канала ШИМ
            if (!(PIND&(1<<PIND1))) {
                if (ACT == 1){
                ACT = 2;}
                else if (ACT == 2)    {
                ACT = 1;
                }
                _delay_ms(10);
                do {} while (!(PIND&(1<<PIND1)));
            }
        }
    }

    ISR (INT0_vect) {
        if (PIND & (1<<PIND2)) {
            if (ACT == 1) {if (!(CH1_PWM == 255)) CH1_PWM += 5;}
            else if (ACT == 2) {if (!(CH2_PWM == 255))CH2_PWM += 5;}
        }
        _delay_ms(10);
    }

    ISR (INT1_vect) {
        if ((PIND&(1<<PIND3))) {
            if (ACT == 1) {if (!(CH1_PWM == 0)) CH1_PWM -= 5;}
            else if (ACT == 2) {if (!(CH2_PWM == 0))CH2_PWM -= 5;}
        }
        _delay_ms(10);
    }

    Действие скетча: управлять яркостью светодиодов. два канала шим
    Прикрепил проект симуляции в Протеус
     

    Вложения:

  2. ostrov

    ostrov Гуру

    AVRS не знает что такое pinMode, digitalWrite и прочее. Варианты: писать в порты напрямую (что потребует изучения матчасти), установить насадку для Ардуино (что сделает использование AVRS почти бессмысленным) или написать собственные одноимнные функции, что примерно первый вариант.
     
  3. BAit

    BAit Нерд

    Ну я знаю. Просто код на AVRS не работает не могу найти ошибку
     
  4. Airbus

    Airbus Радиохулиган Модератор

    Откомпилить получить НЕХ код залить его в AVR.Всегда так делаю.
     
  5. BAit

    BAit Нерд

    Код AtmelStudio не работает где то ошибка
    Код на Arduino работает хорошо.
     
  6. Unixon

    Unixon Оракул Модератор

    @BAit , зачем это все? Чем вам библиотечные функции помешали, в память не помещаются?
     
  7. akl

    akl Гуру

    надо написать (или накопипастить) годную функцию шима, а остальное дело техники.
    Но ты даже не указал модель своего процессора, так что в том что ты там написал вряд ли кто-то будет разбираться.
    а нет написал, просто я слепой. но в любом случае данных маловато - как именно не работает, есть ли ошибки при компиляции и т.д.
     
    Последнее редактирование: 2 янв 2018
  8. BAit

    BAit Нерд

    Всё это для практики и интереса ( Программа на AS сбрасывает вес на половину)
    Ошибок при компиляции нет, микросхема atmega328(arduino pro mini)
     

    Вложения:

  9. Airbus

    Airbus Радиохулиган Модератор

    Bilnk на ассемблере сбрасывает ещё 80% и что?Я где то для сравнения выкладывал их рядом.Родной раз в 8 больше по обьёму.У М-328 достаточно ресурсов подо всё что я видел здесь.У вас какой то супер код?
     
  10. ostrov

    ostrov Гуру

    Это смотря какая программа. Чем больше, тем меньше относительнвй сброс. Для тиньки13 особенно актуально, для меги328 разницы почти нет.
     
  11. Airbus

    Airbus Радиохулиган Модератор

    Можно писать грамотно и красиво даже в IDE Ардуино.Например не использовать software serial.
     
    ostrov нравится это.
  12. ostrov

    ostrov Гуру

    В 95% случаев AIDE запросто подойдет. Особенно если не использовать digiralWrite и прочие библиотечные функции. И размер кода будет практически такой же.
     
    Airbus нравится это.
  13. BAit

    BAit Нерд

    Код (C++):
    #define F_CPU 16000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <avr/sfr_defs.h>

    #define CH1_ACT PD5
    #define CH2_ACT PD6
    #define CH1        PB1
    #define CH2        PB2

    #define ENC_BUT    PD1
    #define PIN_A    PD2
    #define PIN_B    PD3

    unsigned char ACT = 1;
    unsigned char CH1_PWM = 0;
    unsigned char CH2_PWM = 0;

    void timer_counter1_INIT()
    {
        TCCR1A |= _BV(WGM10);
        TCCR1B |= _BV(WGM12);
     
        TCCR1A |= _BV(COM1A1) | _BV(COM1B1);
        TCCR1A &= ~_BV(COM1A0) & ~_BV(COM1B0);
     
        TCCR1B |= _BV(CS12);
        TCCR1B &= ~_BV(CS11) & ~_BV(CS10);
    }
    void INT_INIT()
    {
        EICRA |= _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11);
        EIMSK |= _BV(INT0) | _BV(INT1);
    }

    int main(void)    {
        DDRD &= ~_BV(ENC_BUT) & ~_BV(PIN_A) & ~_BV(PIN_B);        // Выводы порта на вход
        PORTD |= _BV(ENC_BUT) | _BV(PIN_A) | _BV(PIN_B);        // Подтяжка порта к +5
     
        DDRD |= _BV(CH1_ACT) | _BV(CH2_ACT);                    // Выводы порта на выход
        DDRB |= _BV(CH1) | _BV(CH2);                            //
     
        OCR1A = 0;
        OCR1B = 0;
     
        timer_counter1_INIT();
        INT_INIT();
     
        while (1) {
            // Отображение выбранного канала
            if (ACT == 1)    {
                PORTD |= (1<<CH1_ACT);
                PORTD &= ~(1<<CH2_ACT);
            }
            else if (ACT == 2)    {
                PORTD &= ~(1<<CH1_ACT);
                PORTD |= (1<<CH2_ACT);
            }
         
            //
            if (CH1_PWM ==0) {
                PORTB &= ~(1<<CH1);
            }
            else if (CH1_PWM == 255) {
                PORTB |= (1<<CH1);
            }
            else {
                CH1_PWM = OCR1A;
            }
         
            //
            if (CH2_PWM ==0) {
                PORTB &= ~(1<<CH2);
            }
            else if (CH2_PWM == 255) {
                PORTB |= (1<<CH2);
            }
            else {
                CH2_PWM = OCR1B;
            }
         
            // Выбор канала ШИМ
            if (!(PIND&(1<<PIND1))) {
                if (ACT == 1){
                ACT = 2;}
                else if (ACT == 2)    {
                ACT = 1;
                }
                _delay_ms(10);
                do {} while (!(PIND&(1<<PIND1)));
            }
        }
    }

    ISR (INT0_vect) {
        if (PIND & (1<<PIND2)) {
            if (ACT == 1) {if (!(CH1_PWM == 255)) CH1_PWM += 5;}
            else if (ACT == 2) {if (!(CH2_PWM == 255))CH2_PWM += 5;}
        }
        _delay_ms(10);
    }

    ISR (INT1_vect) {
        if ((PIND&(1<<PIND3))) {
            if (ACT == 1) {if (!(CH1_PWM == 0)) CH1_PWM -= 5;}
            else if (ACT == 2) {if (!(CH2_PWM == 0))CH2_PWM -= 5;}
        }
        _delay_ms(10);
    }
     
  14. akl

    akl Гуру

    чет мне кажется, делать в прерываниях дилеи по 10 мс это очень плохо
     
    b707 и ostrov нравится это.
  15. ostrov

    ostrov Гуру

    Особенно в прерывании.
     
  16. akl

    akl Гуру

    не очень понял что происходит в этих местах. если тут надо устанавливать скважность в пвм, то должно быть наоборот например OCR1A = CH1_PWM;(значение от 0 до 255)

    и лучше использовать не фаст-пвм, а фаз-коррект-пвм (вроде в ардуино как раз оно и используетя).
    но это не точно

    а еще я сам пока не знаю - надо ли отключать пин от таймера прежде чем обычным цифровыым способом прописать в него 1 или 0?
     
    Последнее редактирование: 3 янв 2018
  17. akl

    akl Гуру

    вот например я побыстрому наклепал шим (правда для атмеги8 и на 8мгц) на таймерах 1 и 2.
    там еще встроено миллис() к слову о переносе ардуиновых функций.
    делитель минимальный, поэтому частота около 15,6кгц получается судя по симулятору VMLAB
    Код (C++):
    #include <avr/io.h>
    #define F_CPU 8000000UL
    #include <avr/interrupt.h>
    #include <util/delay.h>

    #define setH(port,bit)  do{port |= (1 << bit);}while(0)
    #define setL(port,bit)  do{port &= ~(1 << bit);}while(0)
    #define readP(reg,bit)    (reg & (1 << bit))


    #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
    #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
    #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
    #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
    #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
    #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
    #define FRACT_MAX (1000 >> 3)

    volatile unsigned long timer0_overflow_count = 0;
    volatile unsigned long timer0_millis = 0;
    static unsigned char timer0_fract = 0;

    ISR(TIMER0_OVF_vect)
    {
        unsigned long m = timer0_millis;
        unsigned char f = timer0_fract;
        m += MILLIS_INC;
        f += FRACT_INC;
        if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;
        }
        timer0_fract = f;
        timer0_millis = m;
        timer0_overflow_count++;
    }

    unsigned long millis()
    {
        unsigned long m;
        uint8_t oldSREG = SREG;
        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        SREG &= ~(0b10000000);
        m = timer0_millis;
        SREG = oldSREG;
        return m;
    }

    unsigned long micros() {
        unsigned long m;
        uint8_t oldSREG = SREG;
        uint8_t t;
        SREG &= ~(0b10000000);
        m = timer0_overflow_count;
        t = TCNT0;
        if ((TIFR & _BV(TOV0)) && (t < 255))
            m++;
        SREG = oldSREG;
        return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
    }

    unsigned long mil = 0;
    int main(void) {
        //millis
        TCCR0 = 0b00000011;
         TIMSK |= (1<<0);

        //timer1 pwm
        TCCR1B |= (1<<CS10); //prescaler /1
        TCCR1A |= (1<<WGM10); //phase correct pwm 8bit
        TCCR1A |= (1<<COM1A1); //connect chanel A (PB1)
        TCCR1A |= (1<<COM1B1); //connect chanel B (PB2)
        OCR1A = 100; // pwm duty
        OCR1B = 100;

        //timer2 pwm
        TCCR2 |= (1<<CS20); //prescaler /1
        TCCR2 |= (1<<WGM20); //phase correct pwm 8bit
        TCCR2 |= (1<<COM21); //connect chanel (PB3)
        OCR2 = 100; // pwm duty

        SREG |= 0b10000000;//global interrupts enable

        DDRB = 0b00101110;

        setH(PORTB,5);
        _delay_ms(10);
        setL(PORTB,5);
        _delay_ms(10);
     
        mil=millis();

        while (1==1) {
            if(millis()-mil>50){
                mil=millis();
                if(readP(PINB,5)){setL(PORTB,5);}
                else{setH(PORTB,5);}
            }
            _delay_ms(1);
        }
       
        return 0;
    }
    если интересно еще могу поделиться опытом более-менее удачного выколупывания библиотеки серво.
     
    Последнее редактирование: 4 янв 2018
  18. Airbus

    Airbus Радиохулиган Модератор

    Ну да по возможности избегать эту хератень если надо то напрямую в регистры
     
    ostrov нравится это.
  19. ostrov

    ostrov Гуру

    Нет, ну когда не требуется большой скорости вполне можно. Например, после пятого нажатия кнопки надо включить реле. Да проще сделать digitalWrite, чем искать какой порт, какой бит. Особенно если пин потом придется поменять или добавить второе реле. И займет это 2% памяти. Да плевать.
     
  20. akl

    akl Гуру

    вот оформил шим в функцию, по идее должно работать так же как в ардуино (хотя и на другой частоте, но можно предделитель исправить).
    заодно еще (помимо миллис) напихал функции АДЦ и ЕЕПРОМ.
    УАРТ не стал добавлять, т.к. у меня он скорее всего неполноценный.

    Код (C++):
    #include <avr/io.h>
    #define F_CPU 8000000UL
    #include <avr/interrupt.h>
    #include <util/delay.h>

    #define setH(port,bit)  do{port |= (1 << bit);}while(0)
    #define setL(port,bit)  do{port &= ~(1 << bit);}while(0)
    #define readP(reg,bit)    (reg & (1 << bit))

    //millis
    #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
    #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
    #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
    #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
    #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
    #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
    #define FRACT_MAX (1000 >> 3)
    volatile unsigned long timer0_overflow_count = 0;
    volatile unsigned long timer0_millis = 0;
    static unsigned char timer0_fract = 0;
    ISR(TIMER0_OVF_vect){
        unsigned long m = timer0_millis;
        unsigned char f = timer0_fract;
        m += MILLIS_INC;
        f += FRACT_INC;
        if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;
        }
        timer0_fract = f;
        timer0_millis = m;
        timer0_overflow_count++;
    }
    unsigned long millis(){
        unsigned long m;
        uint8_t oldSREG = SREG;
        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        SREG &= ~(0b10000000);
        m = timer0_millis;
        SREG = oldSREG;
        return m;
    }
    unsigned long micros() {
        unsigned long m;
        uint8_t oldSREG = SREG;
        uint8_t t;
        SREG &= ~(0b10000000);
        m = timer0_overflow_count;
        t = TCNT0;
        if ((TIFR & _BV(TOV0)) && (t < 255))
            m++;
        SREG = oldSREG;
        return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
    }

    //ADC
    static inline uint16_t AdcRead(uint8_t analog_pin){  //ADC
        ADMUX = 0b01000000 | analog_pin; //VCC
        ADCSRA = 0b11000110; // СК/64 (125KHZ)
        while ((ADCSRA & (1 << ADIF)) == 0);
        uint16_t adcw;
        adcw= ADC;
        ADCSRA |= (1 << ADIF);
        return adcw;
    }

    //EEPROM
    void EepromWrite(uint16_t addr, uint8_t dat){
       while(EECR & (1<<EEWE));
       EEAR = addr;
       EEDR = dat;
       EECR |= (1<<EEMWE);
       EECR |= (1<<EEWE);
    }
    uint8_t EepromRead(int addr){
       while(EECR & (1<<EEWE));
       EEAR = addr;
       EECR |= (1<<EERE);
       return EEDR;
    }

    //PWM (timers 1,2)
    void timer1_init(void){ //timer1
        TCCR1B |= (1<<CS10); //prescaler /1
        TCCR1A |= (1<<WGM10); //phase correct pwm 8bit
    }
    void timer2_init(void){ //timer2
        TCCR2 |= (1<<CS20); //prescaler /1
        TCCR2 |= (1<<WGM20); //phase correct pwm 8bit
    }
    void pwm(uint8_t ch, uint8_t du){ //ch=1(PB1) ch=2(PB2) ch=3(PB3)
        switch(ch){
            case 1:
                if(du==0){
                    if(TCCR1A & (1<<COM1A1)){
                        TCCR1A &= ~(1<<COM1A1);}
                    setL(PORTB,1);
                }
                else if(du==255){
                    if(TCCR1A & (1<<COM1A1)){
                        TCCR1A &= ~(1<<COM1A1);}
                    setH(PORTB,1);
                }
                else{
                    TCCR1A |= (1<<COM1A1);
                    OCR1A = du;
                }
            break;
            case 2:
                if(du==0){
                    if(TCCR1A & (1<<COM1B1)){
                        TCCR1A &= ~(1<<COM1B1);}
                    setL(PORTB,2);
                }
                else if(du==255){
                    if(TCCR1A & (1<<COM1B1)){
                        TCCR1A &= ~(1<<COM1B1);}
                    setH(PORTB,2);
                }
                else{
                    TCCR1A |= (1<<COM1B1);
                    OCR1B = du;
                }
            break;
            case 3:
                if(du==0){
                    if(TCCR2 & (1<<COM21)){
                        TCCR2 &= ~(1<<COM21);}
                    setL(PORTB,3);
                }
                else if(du==255){
                    if(TCCR2 & (1<<COM21)){
                        TCCR2 &= ~(1<<COM21);}
                    setH(PORTB,3);
                }
                else{
                    TCCR2 |= (1<<COM21);
                    OCR2 = du;
                }
            break;
            default:
            break;
        }
    }

    unsigned long mil = 0;
    int main(void) {
        //millis timer0 init
        TCCR0 = 0b00000011; //prescaler /64
         TIMSK |= (1<<0);  //timer0 ovf.int. enable
        SREG |= 0b10000000;//global interrupts enable

        timer1_init(); //timer1 pwm init

        timer2_init(); //timer2 pwm init

        DDRB = 0b00101110;

        pwm(3, 100);
        _delay_ms(5);
        pwm(3, 0);
        _delay_ms(5);
        pwm(3, 200);
        _delay_ms(5);
        pwm(3, 255);
        _delay_ms(5);
        pwm(3, 100);
        _delay_ms(5);
        pwm(3, 0);

        mil=millis();

        while (1==1) {
            if(millis()-mil>10){
                mil=millis();
                if(readP(PINB,5)){
                    setL(PORTB,5);
                    pwm(1, 0);
                    pwm(2, 100);
                }
                else{
                    setH(PORTB,5);
                    pwm(1, 100);
                    pwm(2, 0);
                }
            }
            _delay_ms(1);
        }
         
        return 0;
    }
    естественно это все для атмеги8, для 328 надо посмотреть все регистры и исправить по мере необходимости, но это несложно.
     
    Последнее редактирование: 4 янв 2018