Интернет-магазин

Просмотр корзины
В корзине:

товаров - 0 шт.



§ 34. WoodmanUSB. PORTB. Передача данных.

Дмитрий Иванов, 09 Декабря 2013

Файлы к статье скачать
Имя: KA034.zip (ZIP архив)
Размер: 557 КБ

Если у Вас желание разбираться с модулем WoodmanUSB после прочтения прошлой статьи не пропало, продолжаем. На практике все не так то уж и сложно. Собственно, и переходим к практической реализации передачи данных от внешнего устройства через модуль WoodmanUSB в компьютер. А тестовую задачу сформулиркем так:

"Необходимо передавать данные по шине USB из микроконтроллера PIC16F877 через порт PORTB модуля WoodmanUSB в компьютер"

Начнем с софтварной части проекта. Внешнее оно выглядит теперь так. Поясню немного его вид. У нас помимо уже стандартного набора элементов управления появились: две кнопки для запуска/остановки процедуры считывания данных их модуля. Запустив считывание мы стартуем поток, котрорый будет "непрерывно" читать данные из модуля, пока его не остановят или контроллер перестанет данные выдавать. Ниже есть еще две кнопки. Они предназначены для чтения еденичного пакета данных и проверки состояния FIFO буферов модуля. Тесты с еденичными пакетами мы рассмотрим в следующей статье, т.к. я хотел на их примере подробно рассмотреть работу вывода модуля PKTEND.

передача данных по USB

Рассмотрим код потоковой функции чтения (общая архитектура системы очень похожа на систему запсии данных, поэтому подробно все не рассматриваю). Тут все как и в прошлых статьях, только в начале работы цикла создаем файл, куда мы будем сбрасывать прочтенные данные. Читаем с помощью функции WUSB_ReadPortB().

//****************************************************************************
UINT ReadLoopRoutine(void* param)
{
	CTestWinDlg* dlg = (CTestWinDlg*)param;

	WUSB_SetupPortB(ASYNC_MODE);

	char buf[512]; 
	

	unsigned int dwRead;
	int status;

	FILE* fl = fopen("DataUSB.txt", "wb");
	if(fl == NULL)
	{
		MessageBox(NULL, "Open file Error", "", MB_ICONERROR);
		return 0;
	}

	while(!dlg->Terminate)
	{
		status = WUSB_ReadPortB(buf, sizeof(buf), &dwRead);
		if(status == WUSB_ERROR)
		{
			MessageBox(NULL, "Read Error!", "", MB_ICONERROR);
			break;
		} 
		else if(status == WUSB_TIMEOUT)
		{
			MessageBox(NULL, "TIMEOUT", "", MB_ICONERROR);
			break;
		}

		dlg->UpdateByteCounter(dwRead);		

		fwrite(buf, dwRead, 1, fl);
	}


	fclose(fl);

	return 0;
}

Повторю, что обработчик нажатия кнопки Read Single Packet рассмотрим в следующей статье. Тепреь займемся хардварной частью проекта. Схема представлена на рис. ниже. В соответствие с алгоритмом передачи данных от внешнего устройства в модуль WoodmanUSB будем задействовать следующие линии: вывод RC0 (нулевой бит порта C PIC16F877) для генерации сигнала записи в модуль (подключим его к выводу PB_WR WoodmanUSB); вывод RC2 будем использовать для мониторинга состояния OUT_FIFO буфера модуля (на факт его переполнения). Соответственно подключаем его к выводу модуля PORTB_FF. К выводу RC1 МК подключен светодиод. На нем мы будм показывать состояние OUT_FIFO буфера (место есть - светодиод затушен, буфер полный - светодиод горит).

Назначение ключа K1 состоит в следующем: как уже упомяналось в предыдущей статье, внешнее устройство может начать записывать данные в OUT_FIFO буфер модуля только после того, как в управляющей программе на PC будет запущена функция WUSB_Open() (если нам вывод PORTB_FF нужен, а он нам в данном примере нужен). Значит, нам нужно сначала разомкнуть ключ K1, подключить кабель USB к модулю WoodmanUSB, затем запустить программу на компьютере, открыть устройство (нажав кнопку Open WoodmanUSB) и только после этого замкнуть ключ K1, подав на контроллер тем самым питание. К этому моменту модуль уже проинициализирован и готов к чтению данных. В реальной системе, разумется, лучше сделать по другому: например, использовать какую-нибудь линию порта PORTA модуля, по которой контроллер будет получать разрешение на генерацию данных.

нажмите для увеличения

Собрав схему можно приступить к фирмварной части. Код для контроллера PIC16F877 предствлен ниже.

#include <pic.h>
__CONFIG(0x03F72);

unsigned char temp;

void main(void)
{		
	//**************** Шины данных ********************
	TRISB = 0; // настраиваем все линии порта B на выход
	PORTB = 0;
	
	TRISD = 0;  // настраиваем все линии порта D на выход
	PORTD = 0;

	//******* Линии контроля и управления *************
	/*
		вывод С0 будем использовать как сигнал записи
		(вывод PB_WR модуля);
		настраиваем его на выход
	*/
	TRISC0 = 0; // PB_WR  
	
	
	/*
		вывод С2 будем использовать для слежения за состоянием 
		OUT_FIFO буфера (вывод PORTB_FF модуля);
		настраиваем его на вход
	*/
	TRISC2 = 1; // PORTB_FF
	
	
	/*
		вывод C1 будем использовать для визуального отображения 
		состояния OUT_FIFO буфера на светодиоде
	*/
	TRISC1 = 0; // LED indicator for PORTB_FF	
		
	RC0 = 0;
	RC1 = 0;
	RC2 = 0;
	
	temp = 0;

	//**********************************************
	while(1 == 1)
	{
		if(RC2 == 1)     //в OUT_FIFO буфере модуля есть свободное место 
		{
			PORTB = temp; 	// записываем в WoodmanUSB
			PORTD = temp; 	// показываем по светодиодах	
						
			RC0  = 0;	// set active   WR level				
			RC0  = 1;     	// set unactive WR level
				
			RC1 = 0; 	// LED indicator for PORTB_FF
			temp++;
		}
		else      	// OUT_FIFO заполнен
		{
			RC1 = 1; 	// LED indicator for PORTB_FF
		}		
				
	}
	//**********************************************
}

В нашем тестовом варианте, данные для отправки в компьютер выглядят очень просто - это увеличивающиеся на еденицу каждый такт записи байты (как только значение переменной temp перевалит за 256 оно обнулиться, т.к. temp - 1 байт, и он начнет инкрементироваться по новому кругу).

Сам же алгоритм записи тоже весьма прост - каждый цикл проверяем есть ли свободное место в OUT_FIFO буфере. Если есть, помещаем на выводы порта PORTB байт данных, затем "передергиваем" вывод модуля PB_WR, благодаря чему байт с выводов порта PORTB перекочует в OUT_FIFO буфер модуля. Если весь буфер занят, показываем это на светодиоде, подключенном к выводу RC1 контроллера, зажигая его.


Итак, настало время протестировать систему. Размыкаем ключ K1, подсоединяем USB кабель к модулю, открываем программу и открываем устройство, замыкаем ключ. При этом моя схема на макетной плате стала выглядеть вот так. То что все светодиоды горят можно легко объяснить - при подаче питания контроллер начинает писать данные в модуль. Однако очень быстро место в буфере закончится, а поскольку мы пока данных из модуля не считываем, WoodmanUSB устанавливает линию PORTB_FF в логический ноль. Контроллер перестает записывать данные и зажигает красный светодиод (подключен к выводу RC1). Последнее число которое контроллер успел отправить в буфер перед тем как он заполнился до конца было число 255 (0xFF) (размер буфера 1024 байта - это 4 раза по 256 чисел от 0 до 255).

передача данных по USB


Вот теперь нажимаем кнопку Start Read Loop. Наша программа теперь будет постоянно считывать данные из модуля, куда их передает PIC16F877. Давайте, например, попишем секунд 10 и нажмем кнопку Stop Loop. При этом мы увидим, сколько же байт данных мы прочли. У меня скорость получилась что-то около 0.39 МБ/с (1 МБ = 1048576 байт). Такое хилое значение обусловлено "медлительностью" PIC16F877 - ну не может он чаще вывод PB_WR "дергать".

программирование USB


Можно убедиться в том что данные мы читаем верно. Откроем с помощью программы Far файл DataUSB.txt в HEX виде. В этот файл мы скидывали все прочтенные данные. Хорошо видны повторяющиеся блоки байт от 0 до 255 (0xFF в HEX).

программирование USB


Вот примерно таким образом проводится операция чтения данных из модуля, куда их помещает внешние устройство, в нашем примере контроллер PIC16F877. Переходим к следующей статье, где мы познакомися поближе с выводом PKT_END модуля WoodmanUSB.


© Дмитрий Иванов
09 Декабря 2013 года
http://www.kernelchip.ru



© KERNELCHIP 2006 - 2017