Сдвиг массива.

Hayabusa
Offline
Зарегистрирован: 29.03.2012

Здравствуйте, есть масив вида (0,1.2.3.4.5.6). Размерности 10. Заполняется он постоянно значениями analogRead (0), скажем, раз в секунду по таймеру. И должен принять вид (1.2.3.4.5.новое значение из analogRead (0). Но размерность всегда 10. Задайте пожалуйста направление, код не прошу, но буду благодарен.

rkit
Offline
Зарегистрирован: 23.11.2016

Бери да сдвигай значения, в чем проблема-то? array[0] = array[1]; и так далее.

Hayabusa
Offline
Зарегистрирован: 29.03.2012
int array [10];//={100,200,300,400,500,600,700,800,900,1001};
	int x=0;
void setup()
{
Serial.begin(9600);

}

void loop()
{
	array[10]=analogRead(0);
	Serial.println("Array: " + String(array[x]) + ", X: " + String(x) );

	x++;
	if (x==10)
	{
		x=0;
	}
	array[x]=array[x+1];

delay(400);
}

 

Hayabusa
Offline
Зарегистрирован: 29.03.2012

Благодарю!

Все хорошо, кроме одного момента. Поначалу массив пустой, выводит нули.

если заменить

array[10]=analogRead(0);

на 

array[х]=analogRead(0);

 

то заполняет сразу, но сдвига не происходит, массив заполнен значениями которые идут из порта.

 

rkit
Offline
Зарегистрирован: 23.11.2016

    array[10]=analogRead(0);

Вылез за границу массива. И не только тут

Hayabusa
Offline
Зарегистрирован: 29.03.2012

Да, понял ошибку. При объявлении указываем размерность 10. При обращении к 10му элементу [9]. Я обращался в неизвестную ячейку памяти. 

Hayabusa
Offline
Зарегистрирован: 29.03.2012

И еще в условии получается?

if (x==10)

исправить на 9, так?

b707
Offline
Зарегистрирован: 26.05.2017

Hayabusa пишет:

И еще в условии получается?

if (x==10)

исправить на 9, так?


нет, в условии не надо
Только все равно никакого сдвига у вас в коде нет.
Это не так делается, почитайте про кольцевой буфкр

rkit
Offline
Зарегистрирован: 23.11.2016

b707 пишет:
Hayabusa пишет:

И еще в условии получается?

if (x==10)

исправить на 9, так?

нет, в условии не надо Только все равно никакого сдвига у вас в коде нет. Это не так делается, почитайте про кольцевой буфкр

Как ты определил, что "это"?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

rkit пишет:

b707 пишет:
Hayabusa пишет:

И еще в условии получается?

if (x==10)

исправить на 9, так?

нет, в условии не надо Только все равно никакого сдвига у вас в коде нет. Это не так делается, почитайте про кольцевой буфкр

Как ты определил, что "это"?

а что там определять, считывать надо в переменную иначе идёт потеря последнего элемента массива и потом сдвигает только один элемент. а надо все

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А зачем его сдвигать? Обычно сдвигают не сам массив, а указатели на начало и на конец. Например, вот готовая библиотека для кольцевого буфера

#ifndef	RINGBUFFER_H
#define	RINGBUFFER_H

#define	RingBuffer8 RingBuffer<8>
#define	RingBuffer16 RingBuffer<16>
#define	RingBuffer32 RingBuffer<32>
#define	RingBuffer64 RingBuffer<64>
#define	RingBuffer128 RingBuffer<128>

template <const uint8_t bufSize>
class RingBuffer
#ifdef	USE_PRINTABLE
: public Printable 
#endif
{
private:
	uint8_t buffer[bufSize];
	uint8_t startIndex, endIndex;
	
public:
	RingBuffer(void) : startIndex(0), endIndex(0) {}

	inline void clear(void) {
		startIndex = endIndex = 0;
	}
	
	inline bool add(const uint8_t bt) {
		const uint8_t nextIndex = static_cast<uint8_t>(endIndex + 1) % bufSize;
		if (nextIndex == startIndex) return false; // буфер переполнен
		buffer[endIndex] = bt;
		endIndex = nextIndex;
		return true;
	}

	inline uint8_t available(void) const {
		return static_cast<uint8_t>(endIndex - startIndex) % bufSize;
	}

	inline uint8_t get(void) {
		if (! available()) return 0; // нету там ничего
		const uint8_t res = buffer[startIndex];
		startIndex = static_cast<uint8_t>(startIndex + 1) % bufSize;
		return res;
	}

#ifdef	USE_PRINTABLE
	inline size_t printTo(Print& p) const {
		return 
			p.print("RingBuffer (startIndex=") +
			p.print(startIndex) +
			p.print("; endIndex=") +
			p.print(endIndex) +
			p.print("; available()=") +
			p.print(available()) +
			p.print(")");
	}
#endif
};

#endif	//	RINGBUFFER_H

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

А зачем его сдвигать? Обычно сдвигают не сам массив, а указатели на начало и на конец. Например, вот готовая библиотека для кольцевого буфера

#ifndef	RINGBUFFER_H
#define	RINGBUFFER_H

#define	RingBuffer8 RingBuffer<8>
#define	RingBuffer16 RingBuffer<16>
#define	RingBuffer32 RingBuffer<32>
#define	RingBuffer64 RingBuffer<64>
#define	RingBuffer128 RingBuffer<128>

template <const uint8_t bufSize>
class RingBuffer
#ifdef	USE_PRINTABLE
: public Printable 
#endif
{
private:
	uint8_t buffer[bufSize];
	uint8_t startIndex, endIndex;
	
public:
	RingBuffer(void) : startIndex(0), endIndex(0) {}

	inline void clear(void) {
		startIndex = endIndex = 0;
	}
	
	inline bool add(const uint8_t bt) {
		const uint8_t nextIndex = static_cast<uint8_t>(endIndex + 1) % bufSize;
		if (nextIndex == startIndex) return false; // буфер переполнен
		buffer[endIndex] = bt;
		endIndex = nextIndex;
		return true;
	}

	inline uint8_t available(void) const {
		return static_cast<uint8_t>(endIndex - startIndex) % bufSize;
	}

	inline uint8_t get(void) {
		if (! available()) return 0; // нету там ничего
		const uint8_t res = buffer[startIndex];
		startIndex = static_cast<uint8_t>(startIndex + 1) % bufSize;
		return res;
	}

#ifdef	USE_PRINTABLE
	inline size_t printTo(Print& p) const {
		return 
			p.print("RingBuffer (startIndex=") +
			p.print(startIndex) +
			p.print("; endIndex=") +
			p.print(endIndex) +
			p.print("; available()=") +
			p.print(available()) +
			p.print(")");
	}
#endif
};

#endif	//	RINGBUFFER_H

 

можно пример применения?

rkit
Offline
Зарегистрирован: 23.11.2016

Функции, определенные в декларации класса, являются inline по умолчанию.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

Функции, определенные в декларации класса, являются inline по умолчанию.

Это Вы меня поучить решили? Спасибо.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

можно пример применения?

Да. можно. 

//
// Если не предполагается печатать содержимое буфера целиком
// то следующая строка не нужна
#define	USE_PRINTABLE

#include "RingBuffer.h"

#define printVar(x) do { Serial.print(#x "="); Serial.println(x); } while (false)

void setup(void) {
	Serial.begin(115200);
	
	RingBuffer8 buffer; // 8 байтов, можно 16, 32, 64 и 128. РЕАЛЬНАЯ вместимость на 1 меньше.

	// Печатаем пустой буфер
	Serial.println("Пустой буфер:");
	Serial.println(buffer);

	// добавляем два элемента
	buffer.add(101);
	buffer.add(102);
	
	// Печатаем буфер с двумя элементами
	Serial.println("Два элемента:");
	Serial.println(buffer);

	// добавляем шесть элементов (последний не добавится, т.к. нет места)
	buffer.add(103);
	buffer.add(104);
	buffer.add(105);
	buffer.add(106);
	buffer.add(107);
	buffer.add(108);
	
	// Печатаем буфер с семью элементами
	Serial.println("Семь элемента:");
	Serial.println(buffer);
	
	// Забираем один элемент
	printVar(buffer.get());
	
	// добавляем два элемента (второй не добавится, т.к. нет места)
	buffer.add(109);
	buffer.add(110);
	
	// Печатаем буфер с семью элементами
	Serial.println("Семь элемента:");
	Serial.println(buffer);

	// Выбираем все элементы по available
	Serial.println("Выбираем всё:");
	while (buffer.available()) printVar(buffer.get());

	// Печатаем пустой буфер
	Serial.println("Пустой буфер:");
	Serial.println(buffer);
}

void loop(void) {}

Только реализация всё равно ублюдочная.

Во-первых непонятно для чего сделано "реальный размер на 1 меньше", а во вторых, если это использовать как буфер, то явно не хватает методов peek и unget, а если использовать как массив, то очевидно не хватает метода взятия элемента по индексу.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Только реализация всё равно ублюдочная.

Во-первых непонятно для чего сделано "реальный размер на 1 меньше", а во вторых, если это использовать как буфер, то явно не хватает методов peek и unget, а если использовать как массив, то очевидно не хватает метода взятия элемента по индексу.

Вот тока хотел написать про индекс, но подумал, что творение твое и не стал расстраивать... а оно вона как!

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

ТС нужно простое решение, вариант на практике не проверял.

const uint8_t maxIndex = 9;

void setup() {
	Serial.begin(9600);
}

void loop() {
	static uint16_t array[maxIndex + 1]{};
	for (uint8_t i = 0; i < maxIndex; i++) array[i] = array[i + 1];
	array[maxIndex] = analogRead(0);
	
	for (uint8_t i = 0; i < maxIndex; i++) {Serial.print(array[i]);  Serial.print(" ");}
	Serial.println(); 

	delay(1000); //типа таймер
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

ЕвгенийП пишет:

Только реализация всё равно ублюдочная.

Во-первых непонятно для чего сделано "реальный размер на 1 меньше", а во вторых, если это использовать как буфер, то явно не хватает методов peek и unget, а если использовать как массив, то очевидно не хватает метода взятия элемента по индексу.

Вот тока хотел написать про индекс, но подумал, что творение твое и не стал расстраивать... а оно вона как!

неееееее...  в коде Евгения я бы разобрался )))

rkit
Offline
Зарегистрирован: 23.11.2016

ЕвгенийП пишет:

Это Вы меня поучить решили? Спасибо.

Ты тоже из дебилов по убеждению? Ок, буду знать.

sadman41
Offline
Зарегистрирован: 19.10.2016

Может всё же как-то так: memmove(&array[0], &array[1], (sizeof(array)/*array)-1) ?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

Ты тоже из дебилов по убеждению? Ок, буду знать.

Это Ваша реакция на благодарность? На слово "спасибо"? Ок, буду знать.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Блин, зашел форум почитать... Вот мне интересно, почему одного представителя "высшей рассы" забанили, а его коллегу - нет. Несправедливо...

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Pyotr пишет:

Блин, зашел форум почитать... Вот мне интересно, почему одного представителя "высшей рассы" забанили, а его коллегу - нет. Несправедливо...

ты апчом? ... нуи, шоп два раза не вставать, в слове "раса" адна буква "Сы".

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

rkit пишет:

Ты тоже из дебилов по убеждению? Ок, буду знать.

Это Ваша реакция на благодарность? На слово "спасибо"? Ок, буду знать.

я давно говорил, что му..ка нужно банить. Это Дет у нас добрый, нашел грамотность у клоуна.

Это не грамотность, а занудство и мания величия.

У меня уже коллекция "грамотностей", я собираю, хобби такое.

Pyotr
Offline
Зарегистрирован: 12.03.2014

wdrakula пишет:

Pyotr пишет:

Блин, зашел форум почитать... Вот мне интересно, почему одного представителя "высшей рассы" забанили, а его коллегу - нет. Несправедливо...

ты апчом? ... нуи, шоп два раза не вставать, в слове "раса" адна буква "Сы".

 Помнишь клапа под каким последним номером был? А ркита знаешь?)))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Pyotr пишет:

 Помнишь клапа под каким последним номером был? А ркита знаешь?)))

я как бы не из фан-клуба Ркита, но нацистской символики у него не видел. Клапу выгнали по моему настоянию именно за нацистскую символику. Я что-то пропустил?

Pyotr
Offline
Зарегистрирован: 12.03.2014

Влад, считаю, что человек, обзывающий всех подряд прямо или косвенно дебилами, этим причисляет себя к "высшей расе". Нацизм это или психиатрия не знаю.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не понял, а что ркита кто-то забанил? Я что-то пропустил?

По мне, так особо не за что. Хамло, так всегда им был - не новость. Что изменилось-то?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Не понял, а что ркита кто-то забанил? Я что-то пропустил?

По мне, так особо не за что. Хамло, так всегда им был - не новость. Что изменилось-то?

 - Ви баните Ркитов?

 - Нет, только показываю.

 - Занятное.

Pyotr
Offline
Зарегистрирован: 12.03.2014

ЕвгенийП пишет:

Не понял, а что ркита кто-то забанил? Я что-то пропустил?

По мне, так особо не за что. Хамло, так всегда им был - не новость. Что изменилось-то?

Забанить бы неплохо. Исключительно в целях воспитания. Для его же блага. Для начала на недельку.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Pyotr пишет:

Забанить бы неплохо. Исключительно в целях воспитания. Для его же блага. Для начала на недельку.

Ну как бэ... Это такая изюминка форума. Я всерьез его наезды не воспринимаю и вам советую :) Говорят же "в семье не без урода".  Правильно же сказали, хамло. Практически в любом дворе старых спальных районов Москвы есть такие кадры, у них всегда морда битая :)

И клоп был бы не плох, если бы не перегибал палку. Но с Дракулой я полностью согласен. 

 

b707
Offline
Зарегистрирован: 26.05.2017

безотносительно ркита...

право называть дебилов дебилами - одна из отличительных особенностей форума, за которую я готов голосовать двумя руками. Но если ты назвал кого-то дебилом и не смог этого подтвердить - значит сам дебил и есть.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

b707 пишет:

Но если ты назвал кого-то дебилом и не смог этого подтвердить - значит сам дебил и есть.

+100500

Hayabusa
Offline
Зарегистрирован: 29.03.2012

Всем отписавшимся по делу, огромное спасибо! 

По поводу разборок, вы б##дь профессионалы, а ведете себя, как мудаки полные. За те пару лет, что я изредка заходил на форум, он скатился в говно, до уровня оскорблений и выяснения кто дебил кто нет. Вы на мой взгляд, умнейшие люди, так с#ка  держите марку. 

И снова по делу.

Возможно моя задача решается проще. Но основании библиотеки UTFT задумал сделать график температуры от датчика, чтение раз секунду например, с отображением на экране. План был такой, собираю 320 значений (по ширине экрана), рисую что получилось, и как только получаю последнее значение массива, закрашиваю все черным, сдвигаю массив на одно значение, рисую снова красным (на черном фоне). Таким образом получаю картинку "а-ля осциллограф". Используя DUE, теоретически скорости должно хватить. Библиотеки готовой я не нашел, может искал плохо конечно. Поправьте меня, или натолкните на альтернативное решение. Спасибо.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

мне проще на страничке смотреть и доступ отовсюду

Hayabusa
Offline
Зарегистрирован: 29.03.2012

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

b707
Offline
Зарегистрирован: 26.05.2017

Для вашей задачки не требуется "сдвигать массив". Вам уже сказали - используйте кольцевой буфер. Или вы готового кода ждете?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Hayabusa пишет:

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

на ESP - вполне

Logik
Offline
Зарегистрирован: 05.08.2014

Буфер на десять значений всего. Кольцевой организовывать - из пушки по воробьям.  Да еще невесть с каких либ - чужой код отлаживать. Здесь прямой сдвиг через мув самое оно, см. #19. Да хоть своим циклом - тоже не грешно. Особенно если этот цикл уже есть для вывода графика.

Ресурсов на хотелку хватит на любой ардуине, но не злоупотребляйте числами с плавающей запятой.

То, что ua6em пишет - тоже верно, web-интерфейс как правило предпочтительней, экран спецом не нужен становится, а смотреть на мобилке, планшете, ПК, т.е. везде где браузер удобней и функциональней. Картинку можно и сохранить, и вайбером отослать. Причем это сразу и есть, кодить ниче не надо..

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Кольцевой организовывать - из пушки по воробьям. 

для тебя кольцевой буфер - это что-то из разряда космических технологий? он пишется на коленке за 10 минут, там буквально 10-15 строк.

Реально все ваши советы со сдвигном массива - по сути делают то же, что и кольцевой буфер, только криво и некрасиво. И кода не сильно меньше.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Если нее нравится термин "кольцевой буфер", можно использовать "очередь".

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Если нее нравится термин "кольцевой буфер", можно использовать "очередь".

надеюсь короткая? а то патроны нынче дорогие )))

Logik
Offline
Зарегистрирован: 05.08.2014

b707 пишет:

Logik пишет:

Кольцевой организовывать - из пушки по воробьям. 

для тебя кольцевой буфер - это что-то из разряда космических технологий? он пишется на коленке за 10 минут, там буквально 10-15 строк.

Реально все ваши советы со сдвигном массива - по сути делают то же, что и кольцевой буфер, только криво и некрасиво. И кода не сильно меньше.

Ну тебе космические- пусть будут тебе космические. 10 минут - ну напишешь за десять, верю. А за сколько строку из #19? За десять секунд. Нахрена писать более сложное, даже если лично ты его доблесно освоил? Беда ограниченного личного опыта в том, что единожды найденное решение начинают пихать во все ситуации, даже туда куда не нужно и не лезет. Не делай так.

Все определяется задачей. Буфер на 10 элементов - сдвиг. И пишется быстрей и обработка проще. Хочешь спорить - ну напиши хотяб сортировку пузырьком для обоих случаев. Оценим объем кода, расход памяти, скорость работы...   Были бы в задаче несколько десятков-несколько сотен элементов, да расклад бы поменялся, кольцевой бухер бы рулил. А может и список односвязный или еще чего. По требованиям задачи все.

Logik
Offline
Зарегистрирован: 05.08.2014

andriano пишет:

Если нее нравится термин "кольцевой буфер", можно использовать "очередь".

А это не совсем синонимы. Очередь скорей логический термин и кольцевой бухер только одна из технологий реализации очереди. Списки, например, другая.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Logik ТС потом написал: "План был такой, собираю 320 значений (по ширине экрана)...".

Logik
Offline
Зарегистрирован: 05.08.2014

AndreyD пишет:

Logik ТС потом написал: "План был такой, собираю 320 значений (по ширине экрана)...".

Выделено мной. А вопрос содержал четко "Размерности 10".  У меня тоже когда-то план был стать зам министра )))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Сдвинуть 10 байт на одну позицию это (1+1)+(1)+10*((2+2+1)+1) = 54 такта на AVR. Пояснять надо? Я специально скобками выделил.

загрузка адреса, загрузка счетчика "10", 10 шагов по 5 тактов: прочесть, сохранить, проверить счетчик, на последнем шаге еще плюс такт на выход из цикла.

Так вот Логик, по твоему предложению выходит дополнительно 3.5 мкс на каждую операцию записи.

При кольцевом буфере нужно и на чтение и на запись прочесть смещение - 2 такта, сложить и наложить маску  - еще по такту (маска если длина буфера - степень двойки, а так всегда можно сделать -  не 10, а 8 или 16). 4 дополнительных такта или 0.25 мкс.

Для меня решение очевидно 4 такта на каждую операцию или 54 на каждую запись (и ноль дополнительных на чтение). Если развернуть цикл, то можно 54 уменьшить до 42. Все равно много.

Ты часто прав в замене сложного кода на "брут-форс", но тут, уже от 8 значений, я бы выбрал буфер, ессно длиной в степень двойки, чтобы не считать остатки от деления.  10 байт рукам двигать или сделать одну переменную смешения и буфер в 16 позиций? Хотя, конечно, "каждый дрочит, как он хочет" (с).

Logik
Offline
Зарегистрирован: 05.08.2014

Тяп ляп подсчёты. Код, дизасм? Для добавления,значения, для выборки, с контролем границ, без фантазий про всегда можно к степени двойки. Не всегда. ТС спросил про 10 элементов, значить не 8, и не 16 и не 320.

По цифрам - сплошная у тя лажа, начиная от того что сдвигаются 9 элементов при добавлении 10-года и заканчивая тем, что при встраивании в цикл перебора, например при отрисовке, очередной элемент все равно извлекается, такты на это учитывать не надо, только на запись в соседний адрес.