Справка - Atmega328p, преобразование ШИМ-сервокода из pin9 в pin6

Я нашел рабочий код, который использует pin9 (PB1) на ардуино для управления сервоприводом, но в моем проекте ультразвуковой датчик уже использует этот pin / таймер. Я хочу преобразовать код для использования pin6 (PD6), изменил регистры в соответствии с таблицей данных atmega, но это не работает. Нужна помощь:/

Код должен позволить мне поворачивать сервопривод с помощью потенциометра.

#define F_CPU 16000000 //16MHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#define PWM_PRESCALLER 64
#define ICR_MAX (long double)F_CPU/PWM_PRESCALLER/50
#define OCR_MIN (float)ICR_MAX/37.5 // /8.75
#define OCR_MAX (float)ICR_MAX/8.7 // 37.5

volatile unsigned long adc_val=0;
volatile unsigned long counter=0;
unsigned long curr_adc=0;

ISR (ADC_vect)
{
adc_val += ADC;
counter++;
}

int main(void)
{
    DDRD |= (1<<DDD6);
    ICR1 = ICR_MAX;
    OCR0A = OCR_MIN;
    TCCR0A = (1 << COM1A1) | (1<<WGM00) | (1<<WGM01);
    TCCR0B = (1<<WGM02) | (1<<CS01) | (1<<CS00);
    ADMUX = (1 << REFS0);
    ADCSRA = (1 << ADEN)|(1 << ADATE)|(1 << ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

    sei();
    ADCSRA |= (1<<ADSC);

    while(1)
    {
        if(counter >= 1000)
        {
            cli();
            unsigned long round_val = round(adc_val / counter);
            adc_val=0;
            counter=0;
            if(abs(round_val - curr_adc) > 1)
            {
                curr_adc = round_val; 
            }
            long double ocr = OCR_MIN + ((long double)curr_adc * (OCR_MAX - OCR_MIN)/1024);

            OCR0A = (int)round(ocr);
            sei();
        }
    } 
}

, 👍1

Обсуждение

Пожалуйста, отредактируйте свой вопрос и попробуйте вставить код еще раз. Каким-то образом появились дополнительные новые строки, и все отступы были удалены, что сделало код довольно трудным для чтения., @Gerben

Разве не было бы намного проще просто делать analogRead каждый раз через ваш цикл? И используйте [Servo library] (https://www.arduino.cc/en/Reference/servo ) для управления сервоприводом?, @Nick Gammon


2 ответа


1

Бит PORTB 6 управляется с помощью TIMER0, а бит PORTB 1 - с помощью TIMER1. Поэтому вам необходимо соответствующим образом изменить переменные таймера. Одна из ошибок в вашем коде заключается в том, что вы покидаете ICR1. Это должно быть OCRA, если вы хотите использовать TIMER0.

,

Я думал о ICR0, но, согласно таблице данных, ICR0 нет., @Peti

Проверил это, вы правы. Я думаю, что вы можете использовать только OCRA. Не OCR0A?, @MichaelT

Отсутствие OCRA по данным Atmel studio, @Peti

Timer0 уже используется для delay и millis . Используйте контакт 3 или 11, так как они используют timer2, который не используется., @Gerben

Моя проблема теперь в том, что я должен использовать ICR0 для моего сервопривода и ультразвукового датчика, а затем они путаются. Есть ли альтернатива для этого ICR0?, @Peti

Я думаю, что вы решите эту проблему, прочитав технический паспорт. Значения для TCR0A и TCR0B определяются режимом генерации формы сигнала, значением TOP и тактовым прескалером. Согласно вашему коду, WGM = 0x7, т.е. Быстрый ШИМ, OCR0A = TOP. Читать раздел 19.7.3 Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016, @MichaelT


-1

Я согласен с комментарием Ника Гэммонао том, что намного проще использовать платформу Arduino и использовать функцию analogRead() в сочетании с библиотекой servo.

Сказав это, вы решили написать программу с нуля, как это предпочитают делать многие другие по той или иной причине. Я хотел передать 2 веб-страницы, на которые я всегда захожу, когда играю с частотами ШИМ и настройками.

  • http://playground.arduino.cc/Main/TimerPWMCheatsheet
  • https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
,