AVR + DFPlayer. Анализ обратной связи с модулем

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Сообщения: 129
Зарегистрирован: Ср янв 18, 2012 19:37:10

Сообщение Prosperous »

Здравствуйте! Как вы знаете, AVR и DFPlayer общаются по UART. Команды обратной связи отсылаются и принимаются тут вопросов нет. Не могу реализовать следующий алгоритм:
1. Нажали кнопку - послали модулю команду воспроизведения
2. От модуля пришел ответ - провели анализ
3. Если ответ положительный - отправили команду зациклить трек, если отрицательный - зажгли светодиод
4. От модуля пришел ответ о зацикливании - провели анализ
5. и т.д.
6 Нажали на ту же кнопку - отправили команду прекратить воспроизведение
7. От модуля пришел ответ - провели анализ
8. и т.д.
Все работает, кроме анализа. Вроде несложно, но не могу понять как МК заставить ждать ответа, точнее накопления буфера.
Есть код, но явно неверный (могу выложить, чтобы носом меня ткнуть в ошибки).
Подскажите алгоритм. Спасибо.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18677
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Опытный кот
Аватара пользователя
Сообщения: 819
Зарегистрирован: Вт окт 23, 2012 13:17:25
Откуда: Прокопьевск

Сообщение Oxford »

Привет. В каком плане вы имеете ввиду анализ ? Вы имеете ввиду не знаете какой длины пакет будет?
Инженер R@D

Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Контактная информация:
Встал на лапы
Сообщения: 129
Зарегистрирован: Ср янв 18, 2012 19:37:10

Сообщение Prosperous »

2ARV
На самом деле не получается сделать анализ даже если карта воткнута/вынута. Например, я послал команду "плей".пришел ответ, что карта вынута, я поcлал еще раз "плей", чтобы убедится, что она действительно вынута (т.е. должно прийти еще одно подтверждение). Т.е. надо проанализировать ответ и в зависимости от него послать ту или другую команду по UART. Ошибка в коде явно в ожидании ответа. Прикладываю код, все лишнее удалил. Посмотрите где косяк, пжлст. Спасибо.
P.S. Пользуясь случаем спрошу. В этой программе есть анализ данных по АЦП. Когда опрос АЦП закомментирован - вывод данных на дисплей от UART мгновенный. Когда раскомментирован - секунд 5. Как можно оптимизировать?
Спойлер

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

#define F_CPU 16000000UL
#define StartConvAdc() ADCSRA |= (1<<ADSC)

#define MODULE_OK				0x41
#define MODULE_ONLINE			0x3F
#define MODULE_ERROR			0x40
#define MODULE_BUSY			0x01
#define SD_IN					0x3A
#define SD_OUT				0x3B
#define MODULE_PLAY			0x0D
#define MODULE_STOP			0x16
#define MODULE_REPEAT			0x19

unsigned char RX_Buffer[8];
unsigned char RX_Counter = 0;
unsigned char RX_Bait = 0;
unsigned char key=1;
unsigned char key1=1;
unsigned char key_on = 0;
unsigned char module_OK = 0;
unsigned char TX_OK = 0;	

unsigned char USART_Receive(void)
{
	
	while (!(UCSR0A & (1 << RXC0)))
	;
	return UDR0;
}

ISR(USART_RX_vect)
{
	if (RX_Bait<10){
	RX_Buffer[RX_Counter] = USART_Receive();	
	RX_Counter++;
	if (RX_Counter == 10)
	RX_Counter = 0;
	RX_Bait++;
	}
}

void Packet_Analyze()
{
unsigned char code;
unsigned char databyte;
	
	if (RX_Bait == 10)
{
	
	code = RX_Buffer[3];
	databyte = RX_Buffer[6];

	
switch (code)
{
		
		case MODULE_OK:
		{
		TX_OK = 1;
		break;	
		}
		case MODULE_ERROR:
		{
			TX_OK = 0;
			
		break;
		}
		case SD_IN:	
		{
		module_OK = 1;
		
		break;	
		}
		case SD_OUT:
		{
		module_OK = 0;
		break;
		}
		case MODULE_ONLINE:
		{
			module_OK = 1;
			break;
		}
		}
	USART_FlushRxBuf();
}
}	

void USART_FlushRxBuf(void)
{
	cli();
	RX_Counter = 0;
	RX_Bait = 0;
	sei();
}


void main(void)
{
	
	usart_init();
	sei();

PORTD = 0b00000100;
DDRD = 0x01;	

mp3_status(MODULE_ONLINE);


	while(1) {
	
key = ~(PIND & _BV(2));
_delay_ms(20);
key1 = ~(PIND & _BV(2));
if (key == 0xff && key1 == 0xff){
		flag_EN = 1;
		
			if (flag_EN!=flag_EN_old)
			{
			flag_EN_old = flag_EN; 
			flag = !flag;
		        key_on = 1;
			}
	}
	
else{
flag_EN = 0;	 	
flag_EN_old = 0;
}

if (key_on==1){
  
				if (flag)
				 {
		        mp3_play(MODULE_PLAY);
							
					if (TX_OK) //анализ ответа от модуля
						 {
				
					TX_OK = 0;
					mp3_repeat(0x19);
                                         //здесь также должен быть анализ ответа
				    	key_on=0;
					
						}
					 else
						 {
			        
					key_on=0;
					 }
				}
				else{
		        mp3_stop(MODULE_STOP);
                        //здесь также должен быть анализ ответа
					key_on=0;
				}

}

	
Packet_Analyze();
	
		}
	
}

2Oxford
Тупо не выставляется флаг TX_OK (например) по завершении приема. Точнее он выставляется позже чем надо и поэтому программа работает неверно .
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

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

Сообщение ARV »

посмотрите на мои старания:

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

// прием данных от модуля и их разбор по прерываниям
ISR(RX_VECTOR){
	static uint8_t cur;
	static mp3_buf_t buf;
	static uint8_t old = 0xFF;

	uint8_t d = _UDR;
	// ждем стартовый байт - синхронизация
	if(cur == 0){
		if(d != MP3_START_BYTE) return;
	}
	// накапливаем пакет
	buf.bytes[cur++] = d;

	if(d == MP3_STOP_BYTE){
		// готов пакет
		cur = 0;
		switch(buf.command){
		case MP3_ERROR: // ошибка
			if(status == P_PLAY) status = P_READY;
			break;
		case MP3_STAY_USB:// конец воспроизведения
		case MP3_STAY_SD:
			// STAY приходит дважды, один раз надо игнорировать
				if(old != buf.param_lo)
					status = P_READY;
				old = buf.param_lo;
			break;
		case MP3_DEV_STATUS: // инициализация закончена
			if((status == P_NOT_READY) && (buf.param_lo == DEV_SD))
				status = P_READY;
			break;
		case MP3_PLUG_IN: // подключение источника
			status = P_READY;
			break;
		case MP3_PULL_OUT: // отключение источника
			status = P_NOT_READY;
			break;
		default: // все прочие пакеты
			break;
		}
	}
}
в основном цикле смотрю уже на status и принимаю решения.

Добавлено after 2 minutes 6 seconds:
вот заголовочник с константами и типами:
Спойлер

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

/** \file mp3_tf_16p.h
 * \brief определения для общенияс модулем MP3-плейера
 *
 * все константы, макросы, структуры данных и т.п. сделаны на основе документации
 * на модуль.
 * \author ARV
 * \date	10 дек. 2018 г.
 * \copyright 2015 © ARV. All rights reserved.
 *
 */

#ifndef MP3_TF_16P_H_
#define MP3_TF_16P_H_

/// максимальное значение громкости
#define MP3_MAX_VOL		30
/// размер пакета обмена с модулем
#define MP3_PACKET_SZ	10

/// формат пакета обмена данными с MP3-плейером
typedef union{
	uint8_t bytes[MP3_PACKET_SZ];	//!< представление пакета в виде массива байтов
	struct{
		uint8_t	start;				//!< стартовый байт
		uint8_t	ver;				//!< версия
		uint8_t	number;				//!< количество байт в пакете
		uint8_t	command;			//!< команда
		uint8_t	feedback;			//!< запрос подтверждения
		union{
			struct{
				uint8_t	param_hi;	//!< старший байт параметра команды
				uint8_t	param_lo;	//!< младший байт параметра команды
			};
			uint16_t	param_ui;	//!< параметр команды, как двухбайтное слово
		};
		uint8_t	crc_hi;				//!< старший байт контрольной суммы
		uint8_t crc_lo;				//!< младший байт контрольной суммы
		uint8_t	end;				//!< стоповый байт
	};
} mp3_buf_t;

/// стартовый байт пакета
#define MP3_START_BYTE			0x7E
/// стоповый байт пакета
#define MP3_STOP_BYTE			0xEF

#define MP3_IS_PLAYING			0x01
#define MP3_IS_PAUSED			0x02
#define MP3_IS_STOPPED			0x00

/// воспроизведение следующего трека
#define MP3_CMD_PLAY_NEXT		0x01
/// воспроизведение предыдущего трека
#define MP3_CMD_PLAY_PREV		0x02
/// воспроизведение трека из корня устройства
#define MP3_CMD_PLAY_ONE		0x03
/// увеличить громкость
#define MP3_CMD_INC_VOL			0x04
/// уменьшить громкость
#define MP3_CMD_DEC_VOL			0x05
/// установить громкость
#define MP3_CMD_SET_VOL			0x06
/// установить эквалайзер
#define MP3_CMD_SET_EQ			0x07

/// варианты настроек эквалайзера
typedef enum{
	EQ_NORMAL	= 0,	//!< нет эквалайзера
	EQ_POP		= 1,	//!< поп
	EQ_ROCK		= 2,	//!< рок
	EQ_JAZZ		= 3,	//!< джаз
	EQ_CLASSIC	= 4,	//!< классика
	EQ_BASS		= 5		//!< басы
} equalizer_t;

/// повтор выбранного трека
#define MP3_CMD_REP_TRK			0x08
/// выбор устройства
#define MP3_CMD_SET_DEV			0x09
/// режим сна
#define MP3_CMD_SLEEP			0x0A
/// сброс плейера
#define MP3_CMD_RESET			0x0C
/// продолжение воспроизведения
#define MP3_CMD_PLAY			0x0D
/// пауза
#define MP3_CMD_PAUSE			0x0E
/// воспроизведение трека из папки, содержащей не более 255 треков
#define MP3_CMD_PLAY_FOLDER		0x0F
/// дополнительное усиление
#define MP3_CMD_SET_AMP			0x10
/// циклическое воспроизведение всего
#define MP3_CMD_REPEAT_ALL		0x11
/// выбор папки MP3 для воспроизведения
#define MP3_CMD_SELECT_MP3		0x12
/// врезка рекламы
#define MP3_CMD_START_ADV		0x13
/// воспроизведение трека из папки, содержащей не более 3000 треков
#define MP3_CMD_PLAY_3000		0x14
/// останока рекламы и продолжение прерванного трека
#define MP3_CMD_STOP_ADV		0x15
/// остановить воспроизведение
#define MP3_CMD_STOP			0x16
/// циклическое воспроизведение папки
#define MP3_CMD_REPEAT_FOLDER	0x17
/// слуяайный порядок воспроизведения
#define MP3_CMD_RANDOM_PLAY		0x18
/// зацикливание текущего трека
#define MP3_CMD_REPEAT_CUR		0x19
/// включение ЦАП
#define MP3_CMD_SET_DAC			0x1A

/// инфо о подключении источника
#define MP3_PLUG_IN				0x3A
/// инфо об отключении источника
#define MP3_PULL_OUT			0x3B
/// инфо об окончани трека на USB
#define MP3_STAY_USB			0x3C
/// инфо об окончании трека на SD
#define MP3_STAY_SD				0x3D
/// инфо о текущем активном устройстве
#define MP3_DEV_STATUS			0x3F
/// инфо об ошибке
#define MP3_ERROR				0x40
/// подтверждение приема команды от плейера
#define MP3_ACK					0x41
/// инфо о статусе плейера
#define MP3_GET_STATUS			0x42
/// инфо об уровне громкости
#define MP3_GET_VOL				0x43
/// инфо о текущем эквалайзере
#define MP3_GET_EQ				0x44
/// инфо об общем количестве файлов на USB-устройстве
#define MP3_USB_FCOUNT			0x47
/// инфо об общем количестве файлов на SD-карте
#define MP3_SD_FCOUNT			0x47
/// инфо о текущем треке на USB
#define MP3_USB_CUR_TRACK		0x4B
/// инфо о текущем треке на SD
#define MP3_SD_CUR_TRACK		0x4C
/// инфо о количестве файлов в папке
#define MP3_FOLDER_FCOUNT		0x4E
/// инфо о количестве папок на устройстве
#define MP3_FOLDER_COUNT		0x4F

/// устройства (для команды #MP3_DEV_STATUS)
typedef enum{
	DEV_USB		= 1,	//!< USB-флешка
	DEV_SD		= 2,	//!< SD-карта
	DEV_USB_SD	= 3,	//!< И флешка и карта
	DEV_PC		= 4		//!< компьютер ?
} mp3_device_t;

/// коды ошибок
typedef enum{
	ERR_BUSY	= 1,	//!< модуль занят (не инициализирован)
	ERR_SLEEP	= 2,	//!< модуль в режиме сна
	ERR_SERIAL	= 3,	//!< ошибочный фрейм последовательного порта
	ERR_CRC		= 4,	//!< неверная контрольная сумма
	ERR_TRACKOUT= 5,	//!< трек поврежден (?)
	ERR_NOTFOUND= 6,	//!< трек не найден
	ERR_INTERCUT= 7,	//!< врезка рекламы возможна тоько во время воспроизведения трека
	ERR_SD		= 8		//!< ошибка чтения SD-карты (или карта вынута неожиданно)
} mp3_error_t;

#endif /* MP3_TF_16P_H_ */
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Встал на лапы
Сообщения: 129
Зарегистрирован: Ср янв 18, 2012 19:37:10

Сообщение Prosperous »

2Dimon456
7E FF 06 41 00 00 00 xx xx EF - команда принята удачно
7E FF 06 40 00 00 01 xx xx EF - модуль не инициализирован/занят
7E FF 06 40 00 00 03 xx xx EF - ошибка приема
7E FF 06 40 00 00 08 xx xx EF - SD карта повреждена
7E FF 06 3A 00 00 02 xx xx EF - SD карта установлена
7E FF 06 3B 00 00 02 xx xx EF - SD карта извлечена
7E FF 06 3F 00 00 02 xx xx EF - модуль инициализирован
где xx - CRC пакета
Как можно видеть, нам фактически интересны только 3 и 6 байт
2ARV
Спасибо. Буду смотреть
Ответить

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