возможно ли сравнить 16-битное значение с 8-битным сравнением соответствия ISR

Я пытаюсь создать сервоконтроллер с более высоким разрешением, чем 8-битный таймер/счетчик ATtiny85. На данный момент мне удалось получить около 2000 позиций на моем сервоприводе (1 мкс/шаг) за время 21 000 мкс. Мне также удалось переместить 5 сервоприводов последовательно и с разной скоростью, но теперь я хочу переместить их синхронно.

Моя самая большая проблема в том, что я не понимаю, как мне это сделать! Я просмотрел другие коды сервоприводов, включая библиотеку servo8bit, и попытался найти способ. Похоже, что в большинстве примеров используется ISR сравнения совпадений для перемещения сервоприводов «одновременно», моя проблема в том, что у меня есть 16-битное целое число, которое я хочу сравнить.

Есть ли способ сделать что-то волшебное, чтобы я мог использовать 8-битный ISR для сравнения с моим 16-битным целым числом? Или у кого-нибудь из вас есть другие предложения о том, как я могу синхронизировать свои сервоприводы без использования ISR сравнения?

Я надеюсь, что мои вопросы имеют смысл!

Поскольку у меня пока нет кода для показа (только неудачные попытки без сравнения с ISR, что не имеет смысла), я публикую ссылку на свой TinyServo, если это поможет.

РЕДАКТИРОВАТЬ 1:

Вот часть кода, которую я упомянул и не опубликовал в первый раз:

void servoMove(void)
{   
uint16_t nextPulse = hPulse[0];

timerSetup ();      //16-bit setup for counter

for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
    if ( (oTime > nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) )        //check if HIGH pulse (pos) is done
    {
        PORTB &= ~(1 << servo[channel]);

        if (i+1 < sizeof(hPulse)/sizeof(hPulse[0]))
        {
            nextPulse += hPulse[i+1];
        }

        channel++;
    }

    else
    {
        channel = 0;

        oTime = 0;      //resets 16-bit variable
        tot_overflow = 0;       //resets tot_overflow variable  
        TIFR |= (1 << TOV1);        // clear counter1 overflow-flag
        TCNT1 = 0;      //resets Timer/Counter1 
    }

}

for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
    if ( (oTime > tPulse - nextPulse) && (channel < sizeof(servo)/sizeof(servo[0]))   )         //check if LOW pulse (period) is done 
    {   
        PORTB |= (1 << servo[channel]);
        nextPulse -= hPulse[i];
        channel++;  
    }

}

}


void servoPosSet(volatile uint16_t pos[], uint8_t size)
{
     for (i = 0; i < size; i++)
     {
        hPulse[i] = pos[i];
     }

}


int main(void)
{       
TCCR1 |= (1 << CS12);   //set Timer/Counter1 prescaler to increment every 1 µs (PCK/8)

for (channel = 0; channel < size); channel++)
{
    DDRB |= (1 << servo[channel]);  //sets PB0-PB4 as output pins
}

channel = 0;

uint16_t pos[] = {2000, 1500, 1900, 1300, 1700};
uint8_t size = 5;

while(1)        
{
        servoPosSet(pos);

        servoMove();
}

}

РЕДАКТИРОВАТЬ 2:

Это иллюстрация того, как, по моему мнению, должен работать код: введите здесь описание изображения

...но это не так!


person CrowStudio    schedule 10.06.2015    source источник
comment
Код, показанный в ссылке на TinyServo, напрямую не иллюстрирует, что вы пытаетесь сделать, но это не работает. Вы должны подумать о том, чтобы показать то, что вы пробовали, даже если, как вы говорите, это не имеет никакого смысла.   -  person ryyker    schedule 10.06.2015
comment
Вы можете использовать нижние 8 бит вашего целого числа для запуска ISR, в ISR вы подсчитываете, сколько раз это произошло, увеличивая другое 8-битное значение. Если это значение соответствует вашим старшим 8 битам, то вы добились цели.   -  person Nidhoegger    schedule 10.06.2015
comment
@ryyker Я разместил код сейчас ;-)   -  person CrowStudio    schedule 10.06.2015
comment
@Nidhoegger - можете ли вы проиллюстрировать то, что вы только что сказали в ответе?   -  person ryyker    schedule 10.06.2015
comment
@Nidhoegger Прикрепил изображение, иллюстрирующее приведенный выше код. ты это имел в виду?   -  person CrowStudio    schedule 10.06.2015
comment
.... извините, я думал, что это вы, @Nidhoegger, написали вопрос об иллюстрации, надеюсь, это все равно поможет! ;-)   -  person CrowStudio    schedule 10.06.2015
comment
функция servoPosSet() должна иметь два аргумента: один — массив, а второй — количество элементов в массиве. sizeof() предоставляет количество байтов в переменной, поэтому ваш цикл будет отключен в servoPosSet() и в других местах, где вы пытаетесь использовать sizeof() для определения количества элементов массива.   -  person Richard Chambers    schedule 10.06.2015
comment
@RichardChambers Ага, я думал, что sizeof (servo), sizeof (hPulse) или sizeof (pos) возвращают количество элементов массива, следовательно, 5?   -  person CrowStudio    schedule 10.06.2015
comment
Для массива я бы обычно использовал что-то вроде sizeof(ray)/sizeof(ray[0]), которое будет принимать общее количество байтов во всех элементах массива, а затем делить на размер одного элемента массива. Также, когда вы вызываете функцию и передаете ей массив, как вы это делаете, функция не будет знать количество элементов массива. Массив в основном превращается в постоянный указатель. Многие люди называют этот массив распадом на указатель, например, здесь вопросы/1461432/что такое-распад-массива   -  person Richard Chambers    schedule 10.06.2015
comment
@RichardChambers Проверьте! Я прочитал сообщение stackoverflow.com/questions/37538/ за несколько мгновений до того, как я увидел ваш ответ, так что я получил его сейчас (я думаю)! Спасибо! :-)   -  person CrowStudio    schedule 10.06.2015
comment
Посмотрите, имеет ли значение исправление количества элементов массива, и сообщите нам об этом. Я просмотрел некоторую документацию, я ничего об этом не знаю, и похоже, что ISR сравнения соответствия включает загрузку значения в регистр, чтобы позволить аппаратному обеспечению выполнить расчет того, когда прекратить движение. Это не похоже на работу с вашим подходом. Я ожидаю, что вам нужно будет пройтись по вашему массиву сервоприводов и немного переместить каждый из них, пока вы просматриваете список, пока каждый из сервоприводов не окажется в нужной позиции. Кажется, вы делаете это, но ваше обнаружение конца массива неверно, используя sizeof().   -  person Richard Chambers    schedule 10.06.2015
comment
Я думаю, что @Nidhoegger думает об обработке 16-битного значения как серии 8-битных значений, которые загружаются в ISR. Если ui16Val — это ваше 16-битное значение, а ui8Val — 8-битное значение для загрузки в ISR, вы должны сделать что-то вроде: ui8Val = (ui16Val & 0x00ff; while (ui16Val) { SendISR (ui8Val); ui16Val &= 0xff00; ui16Val >>= 1; if (ui16Val) ui8Val = 0xff; } Идея состоит в том, чтобы рассматривать старший байт 16-битного значения как счетчик количества раз отправки. вниз 0xff в качестве значения счетчика ISR после отправки начальных младших 8 бит. Но какая-то ISR синхронизация нужна.   -  person Richard Chambers    schedule 10.06.2015


Ответы (1)


Если вам больше нечего делать во время импульса, вы можете использовать цикл занятости вместо прерываний:

#include <avr/io.h>
#include <util/delay_basic.h>

/* Send a pulse of width = 4*count cycles. */
void pulse(uint16_t count, uint8_t channel)
{
    uint8_t mask     = 1 << channel,
            old_port = PORTB,
            high     = old_port | mask,
            low      = old_port & ~mask;

    PORTB = high;
    _delay_loop_2(count);
    PORTB = low;
}

Это даст вам разрешение 4 тактовых цикла или 0,5 мкс с тактовой частотой 8 МГц.

Отправка импульсов на 5 сервоприводов должна занимать не более 10 мс. Поскольку вы повторяете последовательность импульсов каждые 21 мс, у вас остается 11 мс для вычисления следующего набора позиций, которых должно быть достаточно. Вы можете запрограммировать таймер, чтобы будить вас каждые 21 мс, тогда ваш main() может выглядеть так:

int main(void)
{
    static uint16_t pos[] = {4000, 3000, 3800, 2600, 3400};
    uint8_t i;

    /* Wake up every 21 ms. */
    setup_timer();
    sleep_enable();

    for (;;) {
        /* Update the servos. */
        for (i = 0; i < 5; i++) pulse(pos[i], i);

        /* Compute the next set of positions. */
        ...

        /* Wait for timer interrupt. */
        sleep_cpu();
    }
}
person Edgar Bonet    schedule 15.06.2015
comment
Это близко к тому, что я смотрел некоторое время назад! Это казалось правильным, но я не понимал этого в тот момент, а также это было не так на месте, как этот пример! Теперь все, что мне нужно сделать, это ухитриться высвободить немного времени и включить там свет! ;-) - person CrowStudio; 16.06.2015