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

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

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



§ 30. WoodmanUSB. Передача данных через порт PORTB (Часть 1)

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

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

Итак, после небольшого теоретического экскурса возьмемся непосредственно за практическую реализацию передачи данных. В качестве примера я хотел бы разобрать следующую задачу:

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

Сразу должен предупредить, что в этом примере мы не будем ставить себе задачу получения максимальных скоростей передачи. Почему? Да потому что PIC16F877 мягко скажем "хиловат" для работы даже на 10% от потенциальных скоростных возможностей WoodmanUSB. PIC16F877 максимум может переварить кварц на 20 МГц. Далее учитем что 1 машинный такт = 4 тактам кварца. Итого предельная частота команд в контроллре 5 Мгц. А теперь вспомнив премерный алгоритм чтения данных из модуля (см. прошлую статью) и длительность выполнения отдельных ассемблерных команд в контроллере можно прикинуть что максимальная частота с которой контроллер сможет считывать данные из модуля не будет превышать 1 МГц (т.к. шина 8-ми разрядная, то это соответствует скорости передачи примерно в 1 МБ/с).

Итак, пора возвращяться ближе к делу. Начнем в первую очередь с программы для компьютера. Писать будем на С++ в среде Microsoft Visual C++ 6.0. За основу я предлагаю для начала взять консольную программу из первых статей, когда мы управляли светодиодами через порт PORTA. Она уже содержит ряд готовых операций (напрмер, открытия устройства) котрорые мы оставим без изменений. Добавим теперь возможность записи данных в порт PORTB модуля, откуда их будет считывать контроллер.

Что будет делать эта программа? Она попытается открыть доступ к модулю и если это удасться, запишет в модуль 1024 байт данных. Я думаю код не требует дополнительных пояснений, кроме разве что заполнения последнего элемента массива неким числом, но об этом позже, когда дойдем до "железа".

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "WUSBdrv.h"

int main()
{	
	int status = WUSB_Open();

	if(status == WUSB_ERROR)
	{
		printf("ERROR! Can`t open WodmanUSB device...\n");
		getch();
		return false;
	}
	else
	{
		printf("WodmanUSB Open Ok!\n");		
	}

	//устанавливаем асинхронный режим работы
	WUSB_SetupPortB(ASYNC_MODE); 


	//создаем массив из 1024 байт
	char buf[1024]; 
	
	//заполняем массив данными, например нулями
	memset(buf, 0, sizeof(buf));

	/*
		последний элемент массива заполняем отдельным 
		произвольным числом, например, 220
	*/
	buf[1023] = 220;
	
	unsigned int dwWrite;

	//записываем данные в порт (весь буфер целиком)
	status = WUSB_WritePortB(buf, sizeof(buf), &dwWrite);
	if(status == WUSB_ERROR)
	{
		printf("Write Error!\n");
	} 
	else if(status == WUSB_TIMEOUT)
	{
		printf("TIMEOUT!\n");
	}
	else if(status == WUSB_OK)
	{
		printf("Write OK!\n");
	}


	WUSB_Close();
	return true;
}

Откомпилируйте программу, но пока не запускайте ее, т.к. у нас нет еще прошитого контроллера PIC16F877, который будет принимать данные от модуля. Раз так, то давайте его сделаем. Прежде чем писать программу для контроллера, давайте прикинем схему нашего тестового устройства, состоящего из связки WoodmanUSB + PIC16F877. Какие ресурсы нам потребуются от контроллреа? Во-первых, нам нужен 8-ми битный порт, который будет подсоединен к порту PORTB модуля WoodmanUSB. Для этого я предлагаю выделить порт B контроллера PIC16F877. Далее, необходима линия, по которой мы будем опрашивать состояние IN_FIFO буфера и определять если в нем данные. Резервируем для этого второй бит порта C - RC2 (вывод 17 контроллера). Также нам нужна лния, по которой мы будем подавать сигнал чтения на линию PB_RD модуля - в дело пойдет нулевой бит порта C - RC0. И наконец, нужно решить последний вопрос. Что мы будем делать в контроллере с прочтенными данными? Для теста предлагаю выводить их на светодиоды для наглядной индикации. Подключим их к порту D контроллера. На основе полученной оценки ресурсов собираем вот такую схему:

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

Пара комментариев по схеме. Питание для контроллера будем брать от модуля WoodmanUSB, благо его выводы 27 и 2 есть ни что иное как шина питания +5 В от USB. Поясню наличие некой микросхемы 74LS244. Эта микросхема представляет из себя 8 разрядный буфер с еденичным усилением. Т.е. с формальной точки зрения он ни чего не делает - то что будет подано на вход буфера - тут же будет присутствовать на выходе буфера. Однако, с помощью такого прибора можно "развязать" вход и выход схемы. Вывод PORTB_FNE модуля требует подобной развязки. Поэтому в данной схеме, где нам необходимо использовать вывод PORTB_FNE применена подобная микросхема. Микросхема 74LS244 весьма распространенная, к тому же имеет отечественный аналог, полностью совместимый по выводам - К555АП5.

Я опять по традиции пользуюсь макетными платами. Моя собранная схема имеет примерно следующий вид, как на фото ниже. На фото еще видны светодиоды подключенные к порту PORTA модуля, которых нет на схеме. Пусть стоят, они нам еще пригодятся.

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

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


Со схемой разобрались. Возьмемся за прошивку контроллера. Запускаем MPLAB для PIC`ов и копируем туда ниже следующий код. Что можно сказать по работе кода? Сначала проводим инициализацию необходимых портов и отдельных битов портов. Затем запускаем "бесконечный" цикл. В нем опрашиваем линию PORTB_FNE модуля WoodmanUSB. Напомню, что если она станет в логическую еденицу, то это означает что во входном буфере модуля (IN_FIFO) есть данные для чтения. Как только это событие случилось, проводим считывание данных из буфера модуля в контроллер. Алгоритм следующий: сбросить линию PB_RD в ноль, считать с порта PORTB байт данных, установить PB_RD в еденицу и т.д. до тех пор, пока в буфере есть доступные данные. При прочтении каждого нового байта показываем его на светодиодах через порт D контроллера.

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

unsigned char temp;

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

	//******* Линии контроля и управления *************
	/*
		вывод С0 будем использовать как сигнал чтения
		(вывод PB_RD модуля);
		настраиваем его на выход
	*/
	TRISC0 = 0; // PB_RD  
	
	
	/*
		вывод С2 будем использовать для слежения за состоянием 
		IN_FIFO буфера (вывод PORTB_FNE модуля);
		настраиваем его на вход
	*/
	TRISC2 = 1; // PORTB_FNE
		
	RC0 = 0;
	RC2 = 0;
		
	//**********************************************	
	while(1 == 1)
	{		
		if(RC2 == 1) //в IN_FIFO буфере модуля есть данные 
		{
			RC0=!RC0; 
			if(RC0 == 0)
			{
				temp = PORTB;
				PORTD = temp;				
			}
		}
		else
		{
			//данных нет, ни чего не делаем
		}
	}
	//**********************************************
}

Компилируем программу, полученный HEX файл прошиваем в контроллер. Вставляем прошитый контроллер в схему, соединяем WoodmanUSB с USB портом компьютера. Вот теперь запускаем нашу консольную программу. Все должно выглядеть примерно вот так:

программирование USB модуль WoodmanUSB

программирование USB модуль WoodmanUSB

А теперь рассмотрим что же произошло. Мы открыли доступ к модулю и записали в него 1024 байта. Данные постепенно поступали в IN_FIFO буфер модуля, откуда они побайтно забирались контроллером. Каждый новый байт "высвечивался" на светодиодах, подключенных к порту D контроллера. Все эти операции (чтение 1 КБ данных) прошли довольно быстро (по сравнению со скоростью реакции нашего глаза), поэтому мы не смогли увидеть изменения на светодиодах. На них мы можем видеть только последний байт из буфера, который мы отправили в модуль. Обратите внимание на то, какие из светодиодов горят. Если записать это в двоичной системе счисления, получится: 11011100, что есть ни что иное как число 220. Да-да, то самое странное число, которое мы целенаправлено записали в полседний элемент массива.


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


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



© KERNELCHIP 2006 - 2023