Семисегментный LED-индикатор. Эффекты анимации

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение ARV »

Demiurg писал(а):Вот обсуждение, в топике ссылки. Ссылка 1, Ссылка 2.
посмотрел... оказалось, я даже участвовал в той теме... с 2008 года позабыл.

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

тем не менее, к засветке индикаторов упомянутый эффект явно никакого отношения не имел.

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

Мой уютный бложик... заходите!
Реклама
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Dimon456 »

Demiurg писал(а):Убрал засветку.
Тяжелый случай.
Спойлер

Код: Выделить всё

void handle_commons_clr (void) {
	u08 *p;

	for (u08 i = 0; i < MAX_LED_INDS; i++)
	  {
		p = commons_pins [i] .port;
		*p &= (~commons_pins [i] .mask);
      }
}


      case 2:
         if (handle_soft_timer (ST_PROC_7_SEGM_IND))
         {
            //handle_commons ();
            //handle_segments ();
        	 handle_commons_clr();
        	 handle_segments ();
        	 handle_commons ();

            if (++cnt_commons >= MAX_LED_INDS) cnt_commons = 0;
         }
         break;
Реклама
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

ARV, с засветкой вопрос решён.
Dimon456. Я пример дал, что докопался? Может где то и есть чёрновой вариант. Проект выложил. Проверил на железе. Доводи до ума сам.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение ARV »

[uquote="Demiurg",url="/forum/viewtopic.php?p=3883478#p3883478"]В текущей версии проекта прогон вывода сегментов и разрядов занимает 566 тактов. 35.38 мкс. Когда я чуток изменил логику, получилось - 507 тактов. 31.69 мкс. При тактовой частоте 16 МГц.[/uquote]
немного поборол лень и накропал такой вариант:
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>

typedef struct{
	volatile uint8_t * port;
	uint8_t			   and;
	uint8_t			   or;
} seg_pin_t;

#define pn(p,b) {&PORT ## p, ~_BV(b), _BV(b)}

#define A	_BV(0)
#define B	_BV(1)
#define C	_BV(2)
#define D	_BV(3)
#define E	_BV(4)
#define F	_BV(5)
#define G	_BV(6)
#define H	_BV(7)

#define DIG0	(A+B+C+D+E+F)
#define DIG1	(B+C)
#define DIG2	(A+B+G+E+D)
#define DIG3	(A+B+C+D+G)
#define DIG4	(B+F+G+C)
#define DIG5	(A+F+G+C+D)
#define DIG6	(A+C+D+E+F+G)
#define DIG7	(A+B+C)
#define DIG8	(A+B+C+D+E+F+G)
#define DIG9	(A+B+C+D+F+G)

#define FLASH

const __flash uint8_t digs[10] = {DIG0, DIG1, DIG2, DIG3, DIG4, DIG5, DIG6, DIG7, DIG8, DIG9};

const FLASH seg_pin_t pins[8] = {
  pn(B,0),
  pn(C,0),
  pn(D,0),
  pn(B,2),
  pn(C,2),
  pn(D,2),
  pn(B,4),
  pn(C,4)
};

const FLASH seg_pin_t commons[4] = {
  pn(D,1),
  pn(D,4),
  pn(B,1),
  pn(C,1)
};

#define COM_CAT		((PIND & _BV(7)) == 0)

extern uint8_t data[4];
uint8_t scr[4] = {DIG5,DIG2,DIG3,DIG4};

ISR(TIMER0_OVF_vect){
	static uint8_t com;

	const FLASH seg_pin_t *p = commons+com;

	if(COM_CAT)
		*p->port |= p->or;
	else
		*p->port &= p->and;

	if(++com >= 4) com = 0;

	uint8_t d = scr[com];
	if(!COM_CAT) d = ~d;

	p = pins;
	for(uint8_t i=0; i<8; i++, d>>=1){
		*p->port = (*p->port & p->and) | (d & 1 ? p->or : 0);
		p++;
	}

	p = commons+com;
	if(COM_CAT)
		*p->port &= p->and;
	else
		*p->port |= p->or;
}

int main(void){
	DDRB = 255;
	DDRC = 255;
	DDRD = 0x7F;
	PORTD = 0x80;

	TCCR0 = 4;
	TIMSK = _BV(TOIE0);
	sei();
	while(1);
}
все в одном файле, без наворотов, с магическими числами, ибо лень.

константа FLASH позволяет переместить таблицу "распиновки" сегментов и общих катодов/анодов в память программ, если определить ей значение __flash

так вот, от певого push в обработчике прерываний до reti при тактовой 16 МГц проходит 25 мкС (если таблицы в памяти программ) или 24 мкС (если таблицы в ОЗУ). тип индикатора можно переключать на лету:


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

Мой уютный бложик... заходите!
Реклама
Эиком - электронные компоненты и радиодетали
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

Я как раз занимаюсь именно оптимизацией. И именно как у вас. Сразу готовые маски в таблицах. Вообще я этим проектом занялся из поиска баланса. Эффективности.
В данный момент делаю три варианта проекта. В лоб. If-а ми. Массивы функций, и по вашему способу. Это я делаю чисто для себя. Никакого писькомеряния. Эксперимент с индексным обращением к портам и поиск баланса.
За макрос pn(p,b) благодарствую. Вы показали хороший способ сэкономить время на писанине.
Реклама
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Serzh2000 »

все в одном файле, без наворотов, с магическими числами
это очень хорошо, один файл и попроще!
без комментариев сложно для меня разобраться, но я пытаюсь.
Спойлер#include <avr/io.h>
#include <avr/interrupt.h>

typedef struct{
volatile uint8_t * port;
uint8_t and;
uint8_t or;
} seg_pin_t;

#define pn(p,b) {&PORT ## p, ~_BV(b), _BV(b)}

#define A _BV(0)
#define B _BV(1)
#define C _BV(2)
#define D _BV(3)
#define E _BV(4)
#define F _BV(5)
#define G _BV(6)
#define H _BV(7)

#define DIG0 (A+B+C+D+E+F)
#define DIG1 (B+C)
#define DIG2 (A+B+G+E+D)
#define DIG3 (A+B+C+D+G)
#define DIG4 (B+F+G+C)
#define DIG5 (A+F+G+C+D)
#define DIG6 (A+C+D+E+F+G)
#define DIG7 (A+B+C)
#define DIG8 (A+B+C+D+E+F+G)
#define DIG9 (A+B+C+D+F+G)
#define DIGH (B+C+E+F+G)
#define DIGE (A+D+E+F+G)


#define FLASH

const __flash uint8_t digs[12] = {DIG0, DIG1, DIG2, DIG3, DIG4, DIG5, DIG6, DIG7, DIG8, DIG9, DIGH, DIGE};

const FLASH seg_pin_t pins[8] = {
pn(B,0),
pn(B,1),
pn(B,2),
pn(B,3),
pn(B,4),
pn(B,5),
pn(B,6),
pn(B,7)
};

const FLASH seg_pin_t commons[5] = {
pn(D,0),
pn(D,1),
pn(D,2),
pn(D,3),
pn(D,4)
};

#define COM_CAT ((PIND & _BV(7)) == 0)

extern uint8_t data[10];
uint8_t scr[10] = { DIGH,DIGE,DIG1,DIG1,DIG0, DIG9,DIG2,DIG3,DIG4,DIG5};


ISR(TIMER0_OVF_vect){
static uint8_t com;

const FLASH seg_pin_t *p = commons+com;

// if(COM_CAT)
*p->port |= p->or;
// else
// *p->port &= p->and;

if(++com >= 5) com = 0;

uint8_t d = scr[com];
//if(!COM_CAT) d = ~d;

p = pins;
for(uint8_t i=0; i<8; i++, d>>=1){
*p->port = (*p->port & p->and) | (d & 1 ? p->or : 0);
p++;
}

p = commons+com;
// if(COM_CAT)
*p->port &= p->and;
// else
// *p->port |= p->or;
}

int main(void){
DDRB = 255;
// DDRC = 255;
DDRD = 0x7F;
PORTD = 0x80;

TCCR0 = 4;
TIMSK = _BV(TOIE0);
sei();
while(1);
}
хорошо с "движком" боле менее понял. а дальше ? как эффекты делать? тема называется эффекты анимации, прошу объясните дальше.
к примеру чтобы "HELLO" уползло влево и выползло "FIK" или цифры неважно...


Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение ARV »

Serzh2000, в же делали скрипты эффектов DIGISCRIPT, с его примитивным языком, неужели на Си, с его богатыми возможностями, не можете ничего придумать?!

знакогенератор с буквами мне писать лень, но вот вам тупейший "эффект" катающегося колобка:
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

typedef struct{
	volatile uint8_t * port;
	uint8_t			   and;
	uint8_t			   or;
} seg_pin_t;

#define SCR_SZ	4

#define pn(p,b) {&PORT ## p, ~_BV(b), _BV(b)}

#define A	_BV(0)
#define B	_BV(1)
#define C	_BV(2)
#define D	_BV(3)
#define E	_BV(4)
#define F	_BV(5)
#define G	_BV(6)
#define H	_BV(7)

#define DIG0	(A+B+C+D+E+F)
#define DIG1	(B+C)
#define DIG2	(A+B+G+E+D)
#define DIG3	(A+B+C+D+G)
#define DIG4	(B+F+G+C)
#define DIG5	(A+F+G+C+D)
#define DIG6	(A+C+D+E+F+G)
#define DIG7	(A+B+C)
#define DIG8	(A+B+C+D+E+F+G)
#define DIG9	(A+B+C+D+F+G)

#define SYM1	(A+B+F+G)
#define SYM2	(C+D+E+G)

#define FLASH

const __flash uint8_t digs[10] = {DIG0, DIG1, DIG2, DIG3, DIG4, DIG5, DIG6, DIG7, DIG8, DIG9};

const FLASH seg_pin_t pins[8] = {
  pn(B,0),
  pn(C,0),
  pn(D,0),
  pn(B,2),
  pn(C,2),
  pn(D,2),
  pn(B,4),
  pn(C,4)
};

const FLASH seg_pin_t commons[SCR_SZ] = {
  pn(D,1),
  pn(D,4),
  pn(B,1),
  pn(C,1)
};

#define COM_CAT		((PIND & _BV(7)) == 0)

extern uint8_t data[4];
uint8_t scr[SCR_SZ] = {DIG5,DIG2,DIG3,DIG4};

ISR(TIMER0_OVF_vect){
	static uint8_t com;

	const FLASH seg_pin_t *p = commons+com;

	if(COM_CAT)
		*p->port |= p->or;
	else
		*p->port &= p->and;

	if(++com >= SCR_SZ) com = 0;

	uint8_t d = scr[com];
	if(!COM_CAT) d = ~d;

	p = pins;
	for(uint8_t i=0; i<8; i++, d>>=1){
		*p->port = (*p->port & p->and) | (d & 1 ? p->or : 0);
		p++;
	}

	p = commons+com;
	if(COM_CAT)
		*p->port &= p->and;
	else
		*p->port |= p->or;
}

static void clr(void){
	for(uint8_t i=0; i<SCR_SZ; i++){
		scr[i] = 0;
	}
}

int main(void){
	DDRB = 255;
	DDRC = 255;
	DDRD = 0x7F;
	PORTD = 0x80;

	TCCR0 = 4;
	TIMSK = _BV(TOIE0);
	sei();
	while(1){
		for(uint8_t i=0; i<SCR_SZ; i++){
			clr();
			scr[i] = SYM1;
			_delay_ms(200);
		}
		for(int8_t i=SCR_SZ-1; i >= 0; i--){
			clr();
			scr[i] = SYM2;
			_delay_ms(200);
		}
	}
}
собственно, весь эффект вот тут, в главном цикле:

Код: Выделить всё

	while(1){
		for(uint8_t i=0; i<SCR_SZ; i++){
			clr();
			scr[i] = SYM1;
			_delay_ms(200);
		}
		for(int8_t i=SCR_SZ-1; i >= 0; i--){
			clr();
			scr[i] = SYM2;
			_delay_ms(200);
		}
	}
сначала слева направо поочередно рисуем колобка в верхней части дисплея, а потом справа налево в нижней.

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

Добавлено after 13 minutes 15 seconds:
если вы вывели на дисплей, предположим, 1234, то при помощи вот этого кода вы сможете "прокручивать" это число:

Код: Выделить всё

uint8_t tmp = scr[0];
scr[0]=scr[1];
scr[1]=scr[2];
scr[2]=scr[3];
scr[3]=tmp;
_delay_ms(200);
ну а дальше сами :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Serzh2000 »

в же делали скрипты эффектов DIGISCRIPT, с его примитивным языком, неужели на Си, с его богатыми возможностями, не можете ничего придумать?!
спасибо большое буду изучать и пробовать.

в DIGISCRIPT там все просто, Вы за нас придумали все, я только придумывал эффект, брал команду, красил шарик и направлял в нужную сторону.

я писать пробовал в CodeVisionAVR и в ардуине, а Вы все в других программах пишите, вот нашел Atmel Studio
которая понимает Ваши программы, но я ее не понимаю... пока не понимаю.
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

ARV. Хвалю. Очень интересное решение получилось. Особенно понравился перескок переключения общих выводов. Что значительно решило проблему засветку. У вас с указателями, я попробовал, но IAR закапризничал, выдал что то непонятное. Поэтому сделал пока с прямым обращением к данным. Уже поздно, завтра займусь.
Что у меня пока получилось. 370 тактов. 23.13 мкс. 16 МГц. На этом варианте я останавливаюсь. Меня вполне устраивает.
Спойлер

Код: Выделить всё

            volatile u08 *p;

            // Отключение общего вывода.
            p = commons_pins [cnt_commons] .port;

            if (commons_level == HI)
               *p &= commons_pins [cnt_commons] .and;
            else
               *p |= commons_pins [cnt_commons] .or;

            if (++cnt_commons >= MAX_LED_INDS) cnt_commons = 0;

            u08 a;

            if (status == STATUS_EFFECTS)
               a = dsp_buf [cnt_commons];
            else
               a = table_7_segm_char [dsp_buf [cnt_commons]];

            if (segments_level != HI) a = ~a;

            for (u08 i = 0; i < 8; i++, a >>= 1)
            {
               p = segments_pins [i] .port;

               if (a & (1<<0))
                  *p |= segments_pins [i] .or;
               else
                  *p &= segments_pins [i] .and;
            }

            // Включение общего вывода.
            p = commons_pins [cnt_commons] .port;

            if (commons_level == HI)
               *p |= commons_pins [cnt_commons] .or;
            else
               *p &= commons_pins [cnt_commons] .and;
SEVEN_SEGM_PROJECT_INDEX.rar
(460.85 КБ) 154 скачивания
Видео
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение ARV »

Demiurg писал(а):Что значительно решило проблему засветку
проблема засветки никак не связана с общими катодами или анодами, она связана с очередностью переключений пинов.
Demiurg писал(а):23.13 мкс
IAR традиционно генерирует более оптимальный код.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
OKF
Это не хвост, это антенна
Сообщения: 1393
Зарегистрирован: Вт июн 07, 2011 08:03:18

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение OKF »

ARV, зачем volatile в структуре?
Кстати, делал индикацию на Тини26. Весь порт занят сегментами - бага не заметил. Или это всё в прошлом?
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

volatile - потому что обращение к портам. Потому, прибиваем гвоздями, чтобы компилятор даже помыслить не мог что-то наоптимизировать.
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Dimon456 »

Serzh2000, вот вам один эффект
Спойлер

Код: Выделить всё

const FLASH char effect_1[][SCR_SZ]=
{ {A, 0, 0, 0},
  {A, A, 0, 0},
  {A, A, A, 0},
  {A, A, A, A},
  {0, A, A, A+B},
  {0, 0, A, A+B+C},
  {0, 0, 0, A+B+C+D},
  {0, 0, D, B+C+D},
  {0, D, D, C+D},
  {D, D, D, D},
  {E+D, D, D, 0},
  {F+E+D, D, 0, 0},
  {F+E+D, 0, 0, 0},
  {F+E, 0, 0, 0},
  {F, 0, 0, 0},
};

unsigned int sizeArray;


   sizeArray = sizeof(effect_1)/(sizeof(char)*SCR_SZ);
   clr();
   for(int8_t a=0; a < 5; a++)	// число повторов
   for(int8_t i=0; i < sizeArray; i++){

      scr[0] = effect_1[i][0];
      scr[1] = effect_1[i][1];
      scr[2] = effect_1[i][2];
      scr[3] = effect_1[i][3];

      _delay_ms(500);
   }
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Ivanoff-iv »

тема анимации на 7 сегментниках не раскрыта! :))) :))) :))) :beer:
Спойлер
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

Раскрыта на все 100. Как на словах, так и на примерах.
OKF
Это не хвост, это антенна
Сообщения: 1393
Зарегистрирован: Вт июн 07, 2011 08:03:18

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение OKF »

[uquote="Demiurg",url="/forum/viewtopic.php?p=3884801#p3884801"]volatile - потому что обращение к портам. Потому, прибиваем гвоздями, чтобы компилятор даже помыслить не мог что-то наоптимизировать.[/uquote]
А какие причины "помыслить"?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение ARV »

OKF писал(а):А какие причины "помыслить"?
обычные: PORTx объявлен, как volatile uint8_t, соответственно и указатель на него должен быть volatile uint8_t *.

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

Мой уютный бложик... заходите!
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Serzh2000 »

Dimon456. Спасибо за пример "бегущего червячка" пр кругу
я разобрался как писать эффекты, спасибо Всем. :beer:

теперь другая дилемма, куда бы семисегментный LED-индикатор с эффектами анимации пристроить, чего бы этакого сделать?

кроме часов на ум ни чего не приходит, но часы не хочется.
новогоднюю звездочку на макушку елки я сделал, гирлянда (DIGISCRIPT) есть.
может вместо семисегментника взять отдельные светики и сделать снежинку к новому году?
восемь лучей (разрядов) в каждом до 14 светиков :roll: и клепай эффекты :solder:
надо подумать :tea:
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Demiurg »

Последний раз редактировалось Demiurg Пт авг 28, 2020 23:31:01, всего редактировалось 2 раза.
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Семисегментный LED-индикатор. Эффекты анимации

Сообщение Serzh2000 »

это для машины на заднее стекло? :shock: круто! :beer: но у меня машины пока нет :cry: да и прав тоже нет, пока :wink:
Ответить

Вернуться в «AVR»