-
Вложений: 1
Помогите. Не могу понять тянет ли ардуино проект.
Добрый день.
Я тут решил нагрузить Arduino Nano v5 практической задачей и не могу понять - то ли я делаю что-то не так, то ли ардуино просто не справляется с задачей физически.
Что мы имеем? Имеем сигнал, показанный на картинке желтым цветом. Его амплитуда +20В - -20В. Сигнал преобразовывается оптроном и получается то, что показано голубым цветом. Амплитуда полученного сигнала +5В.
Вот этот сигнал я хочу считать с помощью ардуино и понять, что же именно закодировано. Кодирование 0 и 1 происходит длительностью импульса - на картинке видно.
И вот тут-то у меня затык. Как не бьюсь - ничего не выходит.
Алгоритм вроде бы простой:
1) контролируем состояние ноги - ноль там или единица
2) как только на ноге появился ноль, засекаем системное время
3) ждем, пока появится единица, второй раз засекаем время
4) ждем, пока появится ноль, третья засечка времени.
Потом определяем продолжительность нуля и продолжительность единицы. В теории, время должно приблизительно совпасть. И по значению определяем - ноль это был, или единица.
Так вот - НИФИГА НЕ ВЫХОДИТ. Замеренные значения интервалов пляшут как им угодно. Совершенно хаотично и без системы. Как бы я ни извращался - ни в лоб, ни через прерывания. Если нужен программный код - скажите, напишу. И значения могу тоже дать.....
Что я делаю не так? В чем проблема? У меня в руках, или просто ардуино не успевает обработать сигнал и поэтому выдает ошметки того, что успело "ухватить"?
Заранее спасибо.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Сигнал имеет очень короткую длительность меньше 100мкс.
Нужно во первых принимать сигнал выводом D2 или D3 , настроить один нужный из этих входов на прерывание по перепаду сигнала .
В обработчике прерывания написать код с минимумом инструкций желательно на ассемблере.
Вот пример работы на ассемблере:
PHP код:
//http://compcar.ru
#include <avr/pgmspace.h>
#include <Spi.h>
//-----------------------------------------------------------------------------------------------------------------------------------------
// ' ' A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
const byte ltrs[189] PROGMEM = {255,231,131,195,135,129,129,195,189,131,129,189,191,125,125,195,131,195,131,195,131,189,189,125,125,125, 1,
255,219,189,189,187,191,191,189,189,239,247,187,191, 57, 61,189,189,189,189,189,239,189,189,125,187,187,251,
255,189,189,191,189,191,191,191,189,239,247,183,191, 85, 93,189,189,189,189,191,239,189,189,109,215,215,247,
255,189,131,191,189,131,131,177,129,239,247,143,191,109,109,189,131,189,131,195,239,189,219,109,239,239,239,
255,129,189,191,189,191,191,189,189,239,247,183,191,125,117,189,191,179,183,253,239,189,219,109,215,239,223,
255,189,189,189,187,191,191,189,189,239,183,187,129,125,121,189,191,185,187,189,239,189,219,147,187,239,191,
255,189,131,195,135,129,191,195,189,131,207,189,129,125,125,195,191,205,189,195,239,195,231,147,125,239, 1 };
//------------------------------------------------------------------------------------------------------------------------------------------
/* - . / 0 1 2 3 4 5 6 7 8 9 : */
byte nums[98]= {255,255,207,131,239,131,131,227, 1,131, 1,131,131,255,
255,255,187,125,207,125,125,219,127,127,253,125,125,239,
255,255,187,125,239,253,253,187,127,127,251,125,125,255,
131,255,207,125,239,243,227,123,131, 3,247,131,129,255,
255,255,255,125,239,207,253, 1,253,125,239,125,251,255,
255,231,255,125,239,191,125,251,125,125,239,125,247,239,
255,231,255,131,199, 1,131,251,131,131,239,131,207,255};
byte i=0;
byte reg = 8;
byte result = 25;
word *ptr=0;
word addr ;
//----------------------------------------------------------------
void setup()
{
//ptr = <rs[0]; // младший байт адреса
//addr = ltrs[*ptr]; // полный 16 бит адрес
//addr = <rs[0]; // полный 16 бит адрес
//word paddr = ltrs[0];
pinMode(8, INPUT); // portb0
pinMode(9, INPUT); // portb1
Spi.mode((1<<MSTR) | (1<<CPHA)); //mode 0, clock/4, SPI Enable, DORD старший первый, MSTR Master Enable
Serial.begin(115200);
}
//----------------------------------------------------------------
void loop()
{
//i=i+1;
//Spi.transfer(ltrs[i]);
addr = ltrs[*ptr];
//addr = *ltrs;
//result=checkline(addr);
Serial.println( *ptr, DEC );
Serial.println( addr, DEC );
Serial.println( *ltrs, DEC );
//Serial.println( result, DEC );
Serial.println(' ');
delay(500);
}
//--------------------------------------------------------------
byte checkline( unsigned char in_char )
{
asm volatile(
"cli \n" // отключить прерывания
"push r26 \n"
// "mov r30, %A[ADDR16] \n" // загрузить младший 16 бит адрес
// "mov r31, %B[ADDR16] \n" //
"label_1%=: \n"
"sbic %[PIN_B], 1 \n" // ловим кадровый импульс
"rjmp label_1%= \n"
"label_1e%=: \n"
"sbis %[PIN_B], 1 \n" // ждем начала кадра
"rjmp label_1e%= \n"
"rcall Wait_Line%= \n" // отступ с верху (переднее гашение)
"label_2%=: \n"
"sbic %[PIN_B], 0 \n" // ловим строчный импульс
"rjmp label_2%= \n"
"label_2e%=: \n"
"sbis %[PIN_B], 0 \n" // ждем начала строки
"rjmp label_2e%= \n"
"rcall Step_Line%= \n" //отступаем слева xx пикселей
//--------------------выводим изображение------------------------------------
"Transmit%=: \n"
"ld r26, %a[ADDR]+ \n" // загрузка данных из памяти программ с постинкрементом
// "ldi r26, 170 \n"
"out %[SPI_DATA], r26 \n"
"sbic %[PIN_B], 0 \n" // ловим строчный импульс
"rjmp Transmit%= \n" // переходим на вывод следующего байта
"sbic %[PIN_B], 1 \n" // ловим кадровый импульс
"rjmp label_2e%= \n" // продолжаем вывод данных если не конец кадра
"rjmp label_1e%= \n" // переходим на навый кадр
"mov %[RESULT], r30 \n" // возвращаем адрес в переменную result
"pop r26 \n"
"sei \n" // включить прерывания
"rjmp data%= \n" // на выход
//-------------------------------------------------
"Data_seg%=: \n"
//-----------------------подпрограмма отступа сверху--------------------------
"Wait_Line%=: \n"
"ldi r26, 30 \n" // чило пропускаемых строк , отступ сверху
"label_str%=: \n"
"sbic %[PIN_B], 0 \n" // ловим строчный импульс
"rjmp label_str%= \n"
"label_new%=: \n"
"sbis %[PIN_B], 0 \n" // ждем начала строки
"rjmp label_new%= \n"
"dec r26 \n"
"brne label_str%= \n" // считаем строки
"ret \n"
//-----------------------подпрограмма отступа слева--------------------------
"Step_Line%=: \n"
"ldi r26, 35 \n" // чило пропускаемых пикселей в начале строки , отступ слева
"label_step%=: \n"
"dec r26 \n"
"brne label_step%= \n" // считаем пропуски
"ret \n"
//---------------------------------------------------------------------------
"data%=: \n"
//".EQU 200 \n"
//".db 12, 34, 45, 23 \n"
// "sbi ADCSR, 6 \n" //включить бит преобразования
// "sbi r38, 6 \n" //включить бит преобразования
//"mov %0, r4 \n" // прочитать из младшего регистра АЦП ADCL
//"ret \n"
//---------------------------------------------------------------------------
: [RESULT] "=&r" (result) // Список выходных операндов
: [PORT_B] "I" (_SFR_IO_ADDR(PORTB)),
[SPI_DATA] "I" (_SFR_IO_ADDR(SPDR)),
[PIN_B] "I" (_SFR_IO_ADDR(PINB)),
[SPI_STAT] "I" (_SFR_IO_ADDR(SPSR)),
// [REG_IN] "r" (in_char),
[ADDR] "e" (ltrs),
// [ADDR] "m" (ltrs[*ptr]),
[ADDR16] "e" (addr)
: "memory", "r30", "r31" ); // //резервируем регистры
return (result);
}
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
Chip
Сигнал имеет очень короткую длительность меньше 100мкс.
Нужно во первых принимать сигнал выводом D2 или D3 , настроить один нужный из этих входов на прерывание по перепаду сигнала .
В обработчике прерывания написать код с минимумом инструкций желательно на ассемблере.
Спасибо.
А вообще, потянет ли ардуино это или нет? Мне же помимо того, что принять данные, надо их обработать, да и еще кое-какие действия сделать.
Если уж простой сигнал она не в состоянии принять без ассемблерных подпорок....
Я же делал через прерывания - там кода полстроки:
void setup() {
pinMode(2, INPUT);
attachInterrupt(1, blink, FALLING);
Serial.begin(38400);
}
void loop() { }
void blink(){
time2 = micros(); time3=time2-time1;
Serial.print(" time="); Serial.println(time3);
time1=time2;
}
Может сменить платформу и не мучиться? Хотя уж больно приятно с ардуино работать...
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Не могу ничего сказать нужно хотябы понимать что за задача.
Serial.print убери из обработки прерывания, данная функция будет вносить большие задержки
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
Chip
Не могу ничего сказать нужно хотябы понимать что за задача.
Serial.print убери из обработки прерывания, данная функция будет вносить большие задержки
Задача читать сигнал DCC с рельс на жд-макете. Построение стрелочного (аксессуарного) декодера. DCC сигнал (пример) есть на осциллограмме.
Если я уберу из прерывания печать в основную программу, то проц может 10 раз проколбасить прерывания и только один раз вывести мне что-то на печать.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Так ты в массив считывай , а потом отправляй данные из массива функцией Serial.write(buf, len) ; иначе ничего не получится.
Скорость порта измени Serial.begin(115200); побыстрей будет
У DCC сигнала есть разрыв или он без остановки шлет данные?
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Согласен с Chip.
1. Убрать запись в uart сразу после измерения. Это очень длительная операция и выполнять ее надо в фоне.
2. Прикинуть длительность записи в uart нужных данных. Если длительность около 100мкс, то ни о каком тексте в uart речь вообще идти не может, ибо это 10000 записей в секунду.
3. 100 мкс - это до фига с точки зрения простой обработки, это порядка 1600 тактов, в такое время можно слона печеного уместить и без ассемблера.
Нужна информация о минимальной, максимальной длительности и о необходимой точности измерения длительности. От этого и придется плясать.
Можно, к примеру, сделать таймер, который будет опрашиваться каждые n микросекунд. И в нем будет анализироваться состояние ноги и если оно не изменилось - увеличивать счетчик, а если изменилось - переписывать счетчик куда-либо и очищать его.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
я когда делал анализ посылки сигнализации, делал подобную феню. Сделал там очень просто - пока идет нужный импульс - считаю до 255. Досчитал, отправил 255, обнулил счетчик и считаю дальше. Импульс кончился - послал сколько было. Если 255, то послал 255 и 0.
Все. Никаких более прерываний. Ибо в AVR по умолчанию пока программа находится в прерывании, другие прерывания вызваться не могут.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
В обработчике прерывания я бы сначала положил в массив данные таймера счетчика и запустил новый отсчет, выход из обработчика и потом пока таймер считает выполняй другие задачи
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Вот выписка из стандарта по DCC:
А: Принципы кодирования битов
Основной сигнал цифрового управления согласно NMRA состоит из потока переходов между двумя уровнями напряжения, которые имеют противоположную полярность (Существенный момент заключается именно в переходах между уровнями напряжения, т.к. с точки зрения декодера, подключенного к ДСС шине невозможно определить полярность присутствующего на конкретный момент напряжения, потому что локомотив с декодером может быть, например установлен на рельсы как в прямом, так и в обратном направлениях). Переходом с одного уровня на другой определяется раздел между двумя битами, последующим за ним переходом в первоначальное состояние бит делится на две части – первую и вторую. Цифровая командная станция должна кодировать биты путем подачи на выход потока из изменения уровней, причем в зависимости от значения бита временной интервал между изменениями уровней должен изменяться, или другими словами должна изменяться частота изменений уровней.
Для передачи бита «1» первая и вторая части бита должны иметь одинаковые длительности, которые номинально должны быть равны 58мкс (все временные измерения производятся на уровне перехода через ноль). Т.о. общая длительность «1» бита составляет 116мкс. Компоненты цифровой командной станции должны передавать «1» бит с длительностями первой и второй частей в пределах от 55 до 61мкс. Декодер должен корректно распознавать «1» бит если длительность между переходами составляет от 52 до 64мкс.
Для передачи «0» бита длительность первой и второй частей бита между переходами должна номинально быть больше или равна 100мкс. Для сохранения постоянной составляющей всего ДСС сигнала на уровне 0В обе части «0» бита должны быть идентичны по длительности между переходами. Компоненты цифровой командной станции должны передавать «0» биты с длительностью каждой их части от 95 до 9900мкс, с общей длительностью «0» бита не превышающей 12000мкс. Цифровой декодер должен корректно распознавать первую и вторую части «0» бита, если их длительности находятся в интервале времен от 90 до 10000мкс. Рис. 1 демонстрирует наглядно принцип кодирования битов.
Цифровой декодер должен достоверно распознавать «1» бит, если длительности его первой и второй частей отличаются не более чем на 6мкс.
-
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 очищает.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Ща напишу общий модуль arduino
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Ругается компилятор на
using namespace IO;
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
SBorovkov
Итого - логика такая - таймер считает время, пока нога в верхнем положении. Для этого использует переменную - счетчик WaveLength.
Когда таймер обнаруживает, что нога в нижнем положении, она копирует WaveLength в CalcedWaveLength, а WaveLength очищает.
А почему считаем, пока нога в верхнем положении? Мне кажется более правильным считать пока не будет перепада с единицы на ноль. Ведь бит кодируется так: сначала низкий уровень, потом высокий. Обе половинки одинаковые по продолжительности (в теории). Но это половинки одного бита.
Короткий по продолжительности - значит единица. Длинный - ноль.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint16_t WaveLength;
volatile uint16_t CalcedWaveLength;
#define TCNT2_Const (256-2)
#define UART_BAUD_RATE 115200
#define UART_DOUBLESPEED
#ifdef UART_DOUBLESPEED
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1)
#else
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1)
#endif
#define UART_TXREADY UDRE0
#define UART_RXREADY RXC0
#define UART_DOUBLE U2X0
#define UDR UDR0
#define UCRA UCSR0A
#define UCRB UCSR0B
#define UCRC UCSR0C
#define UCRC_VALUE ((1<<UCSZ01) | (1<<UCSZ00))
#define RXCIE RXCIE0
#define TXCIE TXCIE0
#define RXEN RXEN0
#define TXEN TXEN0
#define UBRRL UBRR0L
#define UBRRH UBRR0H
#define SIG_UART_TRANS SIG_USART_TRANS
#define SIG_UART_RECV SIG_USART_RECV
#define SIG_UART_DATA SIG_USART_DATA
#define UART_STATUS UCSR0A
void UART_Init(void)
{
UBRRH = (UART_CALC_BAUDRATE(UART_BAUD_RATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(UART_BAUD_RATE) & 0xFF);
#ifdef UART_DOUBLESPEED
UART_STATUS = ( 1<<UART_DOUBLE );
#endif
UCRB = ((1<<TXEN) | (1<<RXEN));
UCRC = UCRC_VALUE;
}
void UART_SendByte(uint8_t data)
{
while (!(UCRA & (1<<UART_TXREADY)));
UDR = data;
}
void setup(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.
WaveLength=0;
CalcedWaveLength=0;
sei();
UART_Init();
}
void loop (void)
{
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 ( PIND|(1<<2)!=0)
WL++;
else
{
if (WL!=0)
{
CalcedWaveLength=WL;
WL=0;
}
}
WaveLength=WL;
}
Всю работу с UART можешь заменить на стандартную Serial.<чего-то>
Единственное - слать надо бинарные данные, а не в текстовом виде.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Да - все равно что считать. Сейчас условие, что счет надо проводить описано
if ( PIND|(1<<2)!=0)
это означает, что нога DIGITAL2 находится в верхнем положении.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Вот эти команды что делают?
UART_SendByte(cwl&255);
UART_SendByte(cwl>>8);
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Вообще если нужно считать только длительности 50-65 мкс и 95-130 мкс, то спокойно можно таймер поставить на каждые 16 мкс и при длительности импульса 3-4 вызова таймера считать, что пришел 0, при длительности 5-8 - считать, что пришла 1. Если пришло что угодно другое - считать, что пришел мусор.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Шлют в serial последовательно младшую и старшую части счетчика.
UPD:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t WaveLength;
volatile uint8_t CalcedWaveLength;
#define TCNT2_Const (256-8)
#define UART_BAUD_RATE 115200
#define UART_DOUBLESPEED
#ifdef UART_DOUBLESPEED
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1)
#else
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1)
#endif
#define UART_TXREADY UDRE0
#define UART_RXREADY RXC0
#define UART_DOUBLE U2X0
#define UDR UDR0
#define UCRA UCSR0A
#define UCRB UCSR0B
#define UCRC UCSR0C
#define UCRC_VALUE ((1<<UCSZ01) | (1<<UCSZ00))
#define RXCIE RXCIE0
#define TXCIE TXCIE0
#define RXEN RXEN0
#define TXEN TXEN0
#define UBRRL UBRR0L
#define UBRRH UBRR0H
#define SIG_UART_TRANS SIG_USART_TRANS
#define SIG_UART_RECV SIG_USART_RECV
#define SIG_UART_DATA SIG_USART_DATA
#define UART_STATUS UCSR0A
void UART_Init(void)
{
UBRRH = (UART_CALC_BAUDRATE(UART_BAUD_RATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(UART_BAUD_RATE) & 0xFF);
#ifdef UART_DOUBLESPEED
UART_STATUS = ( 1<<UART_DOUBLE );
#endif
UCRB = ((1<<TXEN) | (1<<RXEN));
UCRC = UCRC_VALUE;
}
void UART_SendByte(uint8_t data)
{
while (!(UCRA & (1<<UART_TXREADY)));
UDR = data;
}
void setup(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.
WaveLength=0;
CalcedWaveLength=0;
sei();
UART_Init();
}
void loop (void)
{
for (;CalcedWaveLength==0;);
uint8_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
if ((cwl>2)&&(cwl<5))
UART_SendByte('0');
else
if ((cwl>=5)&& (cwl<8))
UART_SendByte('1');
else
UART_SendByte('?');
}
SIGNAL(TIMER2_OVF_vect)
{
TCNT2=TCNT2_Const;
uint8_t WL=WaveLength;
if ( PIND|(1<<2)!=0)
WL++;
else
{
if (WL!=0)
{
CalcedWaveLength=WL;
WL=0;
}
}
WaveLength=WL;
}
Тут изменил счетчик на вызов каждые 16 мкс.
Считается интервал между таймерами так:
32 такта (это заложено в инициализации)*8 (эта восьмерка участвует в TCNT2_Const).
Итого каждые 256 тактов.
Контроллер делает 16 млн. тактов в секунду. Итого - раз в 16 микросекунд.
Кроме этого сделал посылку разных значков в зависимости от длительности которую посчитал таймер.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
SBorovkov
Вообще если нужно считать только длительности 50-65 мкс и 95-130 мкс, то спокойно можно таймер поставить на каждые 16 мкс и при длительности импульса 3-4 вызова таймера считать, что пришел 0, при длительности 5-8 - считать, что пришла 1. Если пришло что угодно другое - считать, что пришел мусор.
Я окончательно запутался. Сорри.
В дебри лезть уже не буду, пройду по поверхности:
void loop (void)
{
for (;CalcedWaveLength==0;);
uint16_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
UART_SendByte(cwl&255);
UART_SendByte(cwl>>8);
}
вот основной цикл программы.
for (;CalcedWaveLength==0;);
здесь мы чего ждем? пока не получим из таймера длительность высокого уровня?
uint16_t cwl=CalcedWaveLength;
что будет в cwl? зачем конвертить порядок бит?
CalcedWaveLength=0;
обнулили и ждем следующее значение?
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Сорри. Все сделал, но не работает.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
95% времени основной цикл занимается тем, что ждет, пока таймер запишет в CalcedWaveLength что-либо ненулевое.
Таймер в CalcedWaveLength записывает посчитанную длительность импульса как только импульс закончится. При этом в качестве единицы измерения используются не микросекунды, а в вызовы таймера. Если на ноге существовала 1 в течении 4х вызовов таймера - в CalcedWaveLength попадет именно 4. И попадет она туда строго после того, как импульс закончится.
Этот веселый цикл for (;CalcedWaveLength==0;) со смайликом тупо стоит и ждет пока таймер не запишет CalcedWaveLength. Как только обнаружилось, что в переменной CalcedWaveLength не 0 (таймер записал значение), цикл ожидания завершается и идет программа дальше.
После получения CalcedWaveLength сохраняем ее значение, обнуляем (чтобы не пропустить следующую длительность импульса) и шлем в комп полученные данные.
В новом коде сразу идет анализ полученных данных исходя из известных длительностей.
Код:
uint8_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
if ((cwl>2)&&(cwl<5))
UART_SendByte('0');
else
if ((cwl>=5)&& (cwl<8))
UART_SendByte('1');
else
UART_SendByte('?');
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Ты на какую ногу вешаешь вход данных?
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Чтобы проверить работает ли хоть что-то, вставил "неправильные" функции вывода:
void loop (void)
{
for (;CalcedWaveLength==0;);
uint8_t cwl=CalcedWaveLength;
CalcedWaveLength=0;
if ((cwl>2)&&(cwl<5)) {
UART_SendByte('0');
Serial.print('0'); }
else
if ((cwl>=5)&& (cwl<8)) {
UART_SendByte('1');
Serial.print('1');
}
else {
UART_SendByte('?');
Serial.print('2');
}
}
открыл монитор порта - тишина
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Цитата:
Сообщение от
SBorovkov
Ты на какую ногу вешаешь вход данных?
Менял. Пробую и D2 и D3. Сейчас висит на D2.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Используй либо мои функции отсылки данных в UART либо свои. Мешать их в одном проекте нельзя.
"Неправильную" инициализацию порта не забыл добавить?
И мою инициализацию UART_Init() убирай тогда.
Если не поможет инициализация порта, пробуй поменять содержимое таймера на какое-нибудь простое, в духе.
WaveLength++;
if (WaveLength==50)
{
WaveLength=0;
CalcedWaveLength=3;
}
Ну и в начале попробуй что-нибудь заслать в порт для теста.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
"Неправильную" инициализацию порта не забыл добавить? - просто не понял, что и куда добавлять.
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
И еще:
for (;CalcedWaveLength==0;);
судя по всему, из этого цикла программа уже не выходит
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Проверял банально управляя зажиганием и гашением светодиода. 8-)
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
Вместо моей инициализации UART_init() надо вписать твою инициализацию порта
Serial.begin(115200);
Из цикла видимо не выходит потому, что CalcedWaveLength==0
-
Re: Помогите. Не могу понять тянет ли ардуино проект.
другой код в прерывание пробовал записать? Который просто до 50 считает