Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
Chip
В обработчике прерывания я бы сначала положил в массив данные таймера счетчика и запустил новый отсчет, выход из обработчика и потом пока таймер считает выполняй другие задачи
Вот пример кодовой посылки, которую надо считать и расшифровать:
11111111111111 0 00000000 0 11111111 1
(пробелы вставил для удобства чтения)
сначала идет преамбула из 14-ти единиц
потом разделитель - 0
потом первый байт команды
опять разделитель - 0
второй байт команды
стоповый бит - 1
Вот и скажите, как мне все это получить?
Ведь сначала надо поймать преамбулу. Это просто... Всего-то 14 раз поймать единицу. Если научиться ее ловить. Потом уже все остальное.
Куда я буду запихивать столько данных из прерывания?
Re: Помогите. Не могу понять тянет ли ардуино проект.
Так тебе вообще не нужно писать все длятельности, достаточно делать записи битов только после смены 1 на 0 или наоборот
Записывай биты функциями bitSet() это 1 и bitClear() это 0
Вложений: 1
Re: Помогите. Не могу понять тянет ли ардуино проект.
Вот код, в реале не проверял, но в отладчике вроде работает
Код:
#include <avr/io.h>
#include "SmallUart.h"
#include <avr/interrupt.h>
#include <iopins.h>
using namespace IO;
volatile uint16_t WaveLength;
volatile uint16_t CalcedWaveLength;
#define TCNT2_Const (256-2)
int main(void)
{
TIMSK2 &= ~(1<<TOIE2); //разрешения прерывания по переполнению таймера/счетчика Т2
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));// Режим работы таймера/счетчика
TCCR2B &= ~(1<<WGM22);// Режим работы таймера/счетчика
TCCR2B |= (1<<CS20)|(1<<CS21); //(1<<CS21)|(1<<CS20)|(1<<CS22); //установка предделителя 32
ASSR &= ~(1<<AS2); //Выбор источника синхронизации таймера если AS2=0 от системного генератора
TCNT2 = TCNT2_Const; // 16000000/256/100/64=8 tcnt2=256-8=248.
TIMSK2 |= (1<<TOIE2);//Разрешение прерывания по переполнению Т2.
sei();
WaveLength=0;
CalcedWaveLength=0;
for (;;)
{
for (;CalcedWaveLength==0;);
uint16_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
UART_SendByte(cwl&255);
UART_SendByte(cwl>>8);
}
}
SIGNAL(TIMER2_OVF_vect)
{
TCNT2=TCNT2_Const;
uint16_t WL=WaveLength;
if (Pd2::IsSet())
WL++;
else
{
if (WL!=0)
{
CalcedWaveLength=WL;
WL=0;
}
}
WaveLength=WL;
}
Таймер выполняется примерно 50 тактов. Вызыается - каждые 64 такта процессора, т.е. считает каждые 4 микросекунды.
В приложении - полный проект AVR Studio. Единственное, там стоит скорость 9600. ее надо увеличить до 115200 и в SmallUart.h включить
@define UART_DOUBLESPEED
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
Chip
Так тебе вообще не нужно писать все длятельности, достаточно делать записи битов только после смены 1 на 0 или наоборот
attachInterrupt(1, blink, FALLING);
Я так и делал. А что толку? Все равно ничего не выходит.
Вот я иду в прерывание:
time2 = micros(); time3=time2-time1;
вычислил текущее время и вычел из него ранее запомненное
Serial.print(" time="); Serial.println(time3);
для понимания того, что делает у меня программа вывожу в порт замерянное значение
time1=time2;
запоминаю новое время и выхожу из обработчика...
Вот скажи - что я делаю не так?
Re: Помогите. Не могу понять тянет ли ардуино проект.
Я уже говорил, еще раз повторюсь , выкинь из обработчика
Serial.print(" time="); Serial.println(time3);
И лучше используй код от SBorovkov
Re: Помогите. Не могу понять тянет ли ардуино проект.
Строки
Serial.print(" time=");
Serial.println(time3);
съедают астрономическое время. Во-первых это передача как минимум 7 (или 8) байт в uart. Что даже при скорости 115200 займет 115200/9/7 то есть 1/1800 секунды. А у тебя импульсы следуют 5 тыс раз в секунду. Это почти мгновенно должно приводить к переполнению буфера отправки.
Кроме этого еще непосредственно Serial.println(time3) занимает кучу времени - нужно же преобразовать int32 в строку циклическим делением. А AVR аппаратного делителя не имеет.
Кроме этого, micros() возвращает время с достаточно плохой точностью.
Поэтому:
1. Никаких делений и отправки данных в прерывании.
2. Лучше воспользоваться собственным таймером.
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
Chip
Я уже говорил, еще раз повторюсь , выкинь из обработчика
Serial.print(" time="); Serial.println(time3);
И лучше используй код от SBorovkov
Я понял. Спасибо.
Вся загвоздка в том, что я не могу понять ничего в коде SBorovkov`а... Это явно не для начинающих.
Re: Помогите. Не могу понять тянет ли ардуино проект.
посмотрел, micros() возвращает время с точностью до 4 микросекунд. То есть рядом крутится еще один таймер, вызывающийся каждые 64 такта.
Поэтому для начала лучше прописать
#define TCNT2_Const (256-4)
В результате наш таймер будет вызываться каждые 32*4 такта.
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
SBorovkov
посмотрел, micros() возвращает время с точностью до 4 микросекунд. То есть рядом крутится еще один таймер, вызывающийся каждые 64 такта.
Поэтому для начала лучше прописать
#define TCNT2_Const (256-4)
В результате наш таймер будет вызываться каждые 32*4 такта.
Все бы хорошо, но как "засунуть" этот код в "стандартную" среду от ардуины?
P.S. Написал вопрос в личку, но ответа нет. Буду писать тут. Сорри.
Re: Помогите. Не могу понять тянет ли ардуино проект.
TIMSK2 &= ~(1<<TOIE2); //разрешения прерывания по переполнению таймера/счетчика Т2
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));// Режим работы таймера/счетчика
TCCR2B &= ~(1<<WGM22);// Режим работы таймера/счетчика
TCCR2B |= (1<<CS20)|(1<<CS21); //(1<<CS21)|(1<<CS20)|(1<<CS22); //установка предделителя 32
ASSR &= ~(1<<AS2); //Выбор источника синхронизации таймера если AS2=0 от системного генератора
TCNT2 = TCNT2_Const;
TIMSK2 |= (1<<TOIE2);//Разрешение прерывания по переполнению Т2.
sei();
Это можно просто переписать - инициализирует таймер.
volatile uint16_t WaveLength;
volatile uint16_t CalcedWaveLength;
объявляет две переменных, которые не должны быть оптимизированы процессором.
Беззнаковые, 16-битные.
for (;;)
{
for (;CalcedWaveLength==0;);
uint16_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
UART_SendByte(cwl&255);
UART_SendByte(cwl>>8);
}
Это основной цикл, который можно запихнуть в void Loop(void);
Ждет пока в CalcedWaveLength будет что-то отличное от нуля, копирует его в переменную, отправляет в uart (в бинарном виде), и обнуляет.
SIGNAL(TIMER2_OVF_vect)
{
TCNT2=TCNT2_Const; // задает параметр таймера. Переписать как есть.
uint16_t WL=WaveLength; // копирует счетчик в локальную переменную
if (Pd2::IsSet()); // если нога Digital2 в верхнем положении
WL++; // то увеличиваем счетчик
else // иначе
{
if (WL!=0) // если там что-то было в счетчике (не 0)
{
CalcedWaveLength=WL; // то то, что было складываем в CalcedWaveLength
WL=0; // и очищаем
}
}
WaveLength=WL; Задаем новое значение в основной счетчик (или 0)
}
Итого - логика такая - таймер считает время, пока нога в верхнем положении. Для этого использует переменную - счетчик WaveLength.
Когда таймер обнаруживает, что нога в нижнем положении, она копирует WaveLength в CalcedWaveLength, а WaveLength очищает.