Главная » Статьи » Полезная информация

Организуем программный USB в Bascom-AVR на примере USB-вольтметра. Часть 3
автор Aleks8383:

 Что для этого нужно, конечно же PureBasic который нетрудно найти в сети и скачать, у меня установлена версия 4.51. Также понадобится библиотека HID_Lib предназначена для работы с USB HID устройствами, скачать можно тут. Скачиваем распаковываем и копируем по папкам в PureBasic. Также желательно скачать русский хелп, будет проще разбираться в компиляторе, скачать можно тут 
 
 Теперь собственно можно писать программу, начнём! Для начала нужно создать окошко программы, делаем это так.

OpenWindow(0, 497, 191, 565, 404,"USB Вольтметр", #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
Repeat
Event = WaitWindowEvent()
Until Event=#PB_Event_CloseWindow

Нажимаем F5 и смотрим что получилось






 Разберём что к чему команда OpenWindow(..) как видно из названия открывает окно.
Далее в нутрии скобок 0, 497, 191, 565, 404, "USB Вольтметр", #PB_Window_MinimizeGadget | #PB_Window_SizeGadget, 0 это номер окна, идентификаторы по которому будет отслеживаться события в этом именно окне. Цифры 497, 191 определяют в каком месте экрана появится окошко(в пикселях), а цифры 565, 404 это размер окна по вертикали и горизонтали. "USB Вольтметр" тут и так всё понятно, это заголовок в верху окошка, далее идут #PB_Window_MinimizeGadget | #PB_Window_SizeGadget первый параметр позволяет свёртывать окошко, а второй позволяет изменять размер окна мышкой. Какие ещё параметры к окошку добавлять можно посмотреть в хелпе (надеюсь русский хелп скачали). Смотрим далее идёт цикл Repeat Until, для чего он, а для того чтобы окошко не закрылось, ведь выполнив команду OpenWindow(..) нечего будет больше исполнять и окошко закроется, для этого и вводится цикл в котором будем отслеживать события происходящие в окошке командой Event=WaitWindowEvent() и если произошло событие, в данном случае нажали «крестик» т.е. Event=#PB_Event_CloseWindow тем самым мы выполнили условие выхода из цикла и закроем окошко.
 
 Зайдём немного вперёд и рассмотрим как вообще устроен принцип обработки каких либо событий в PureBasic. В PureBasic`е окном называют собственно окно, как оно есть в понимании любого пользователя современной операционной системы. А гаджет - это любой элемент графического интерфейса пользователя (GUI), например кнопка, строка текста, гиперссылка, картинка и т.д. Все гаджеты должны располагается в окне, поэтому чтобы написать приложение с графическим интерфейсом сперва надо создать окно, а потом в них устанавливаем различные гаджеты. Чтобы отследить нажатие кнопок или каких ещё действий в окне нужно отслеживать события происходящих с ними для этого есть несколько команд, вот несколько из них 

#PB_Event_Gadget отслеживает события в гаджетах
#PB_Event_Menu отслеживает события в меню окна
#PB_Event_Timer отслеживает события таймера

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

ButtonGadget(10, 350, 40, 140, 100, "10")
ButtonGadget(20, 350, 160, 140, 100, "20")
ButtonGadget(30, 350, 280, 140, 100, "200")
StringGadget(40, 40, 40, 100, 100, "", #PB_String_ReadOnly)
SetGadgetFont(40,FontID(1))
StringGadget(50, 40, 160, 100, 100, "", #PB_String_ReadOnly)
SetGadgetFont(50,FontID(1))
TextGadget(60,280,10,100,30,"")


 ButtonGadget - это гаджет кнопки, а StringGadget - гаджет окошка для текста
 TextGadget - гаджет для текста (будет выводить надпись если неподключено устройство)
 SetGadgetFont - устанавливает шрифт в гаджете,в данном случае в StringGadget. Его мы расмотрим попозже.

 Тут всё по аналогии с окошком, идентификатор по нему мы будем отслеживать нажатие именно этого гаджета, а не какого либо другого. Также как и в окошке определяется место где будет располагаться гаджет только уже не на экране, а внутри окошка, далее её размеры и наконец в скобочках то что будет написано внутри гаджета. Как видно большинство гаджетов сделано по одному принципу, идентификатор, место положения, размер, надпись и дополнительные флаги для каждого гаджета(какие именно смотрим хелп).

 Жмём F5 и смотрим, что у нас получилось.



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

Repeat 
 Event=#PB_Event_Timer
 If EventTimer()
 FindDevice_Timer()
 EndIf 

 Event=#PB_Event_Gadget
 Select EventGadget()
 Case 10 
 SetGadgetText(50,"10")
 OutBytes(1) = 3
 OutBytes(2) = 10
 SendDevice()
 Case 20
 SetGadgetText(50,"20")
 OutBytes(1) = 3
 OutBytes(2) = 20
 SendDevice()
 Case 30
 SetGadgetText(50,"200")
 OutBytes(1) = 3
 OutBytes(2) = 200
 SendDevice()
 EndSelect 

 Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow

 Добавим эти строки в имеющийся у нас цикл. Рассмотрим поподробнее, здесь мы добавили строку Event=#PB_Event_Timer здесь мы при срабатывании таймера (о нём немного попозже) мы переходим в процедуру(о них тоже попозже) FindDevice_Timer(), а вот далее как раз идёт работа с кнопками.

Event=#PB_Event_Gadget
 Select EventGadget()
 Case 10 
 SetGadgetText(50,"10")
 OutBytes(1) = 3
 OutBytes(2) = 10
 SendDevice()
 Case 20
 SetGadgetText(50,"20")
 OutBytes(1) = 3
 OutBytes(2) = 20
 SendDevice()
 Case 30
 SetGadgetText(50,"200")
 OutBytes(1) = 3
 OutBytes(2) = 200
 SendDevice()
 EndSelect

 Здесь при при нажатии на кнопку происходит событие гаджета и как только оно произошло мы при помощи Select EventGadget() (тоже самое что и Select Case в Баскоме) выбираем какое именно гаджет «сработал» те Case 10 это кнопка 10 вольт (10 это идентификатор кнопки ButtonGadget(10, 350, 40, 140, 100, "10"), кстати ставить цифры в идентификатор хоть и не запрещено но лучше не использовать, а использовать команду Enumeration, о чём можно почитать в небольшом учебнике

 Далее идёт команда SetGadgetText(50,"10") как видно из названия мы устанавливаем гаджете под номером 50 текст 10 те в нижнем окошке высветится цифра 10 это самым мы укажем текущий предел измерения. Смотрим дальше идут команды OutBytes(1) = 3 OutBytes(2) = 10
 Это массив для передачи данных первый бит это цифра 3 для передачи в контроллер, а второй бит передаёт предел выбранный в программе в контроллер (о них я уже упоминал когда описывал программу контроллера), далее командой SendDevice() вызываем процедуру в которой мы передаём данные в контроллер.

 Вот в принципе и всё с обработкой нажатия кнопок. Теперь поговорим о процедурах, они сильно похожи на подпрограммы по подробнее о них можно прочитать в учебнике (ссылка выше по тексту). Процедур в программе у нас две это FindDevice_Timer() и SendDevice() в первой мы отслеживаем подключено у нас устройство компьютеру или нет, а во второй мы передаём данные в компьютер. Прежде чем приступить к их рассмотрению нужно сказать что они как и подпрограммы в Баскоме должны декларироваться в начале программы что мы и делаем

Declare FindDevice_Timer()
Declare SendDevice()

 Начнём с FindDevice_Timer() эта процедура обрабатывается по срабатыванию таймера который включается вот этой командой AddWindowTimer(0, 1, 200) где 0 это номер окна в котором будет работать таймер, далее 1 это номер самого таймера, а 200 это время в миллисекундах через которое будет происходить срабатывание таймера.

Procedure FindDevice_Timer() 
Static Old_Test
Test=HID_Lib_DeviceTest(#USB_PID, #USB_VID)
 If Test<>Old_Test
 Old_Test=Test 
 If Test 
 HID_Lib_CloseDevice(R_DeviceHandle) : HID_Lib_CloseDevice(W_DeviceHandle)
 W_DeviceHandle=HID_Lib_OpenDevice(#USB_PID, #USB_VID)
 R_DeviceHandle=HID_Lib_OpenDevice(#USB_PID, #USB_VID)
 SetGadgetText(60,"")
 Else
 HID_Lib_CloseDevice(R_DeviceHandle) : HID_Lib_CloseDevice(W_DeviceHandle)
 R_DeviceHandle=0 : W_DeviceHandle=0
 SetGadgetText(60,"Устройство неподключено")
 EndIf
 EndIf 
EndProcedure

 Сначала обратим внимание на #USB_PID, #USB_VID это индивидуальные идентификаторы вашего устройство, про них я писал в описании программы для контроллера. Можно их записать цифрами, а можно объявив их константами в начале программы и добавлять их по ходу программы. Добавим их в начале программы.

#USB_PID=$EF01
#USB_VID=$AAAC

Далее нужно объявить переменные чтобы они были доступны в разных процедурах W_DeviceHandle, R_DeviceHandle что мы и делаем.

Global R_DeviceHandle, W_DeviceHandle

Далее в процедуре

HID_Lib_CloseDevice(R_DeviceHandle) : HID_Lib_CloseDevice(W_DeviceHandle)
W_DeviceHandle=HID_Lib_OpenDevice(#USB_PID, #USB_VID)
R_DeviceHandle=HID_Lib_OpenDevice(#USB_PID, #USB_VID)
SetGadgetText(60,"")

 Здесь мы проверяем подключено устройство к компьютеру, если VID и PID идентификаторы соответствуют нашим значением то наше устройство подключено и мы ставим текст в текстовый гаджет под номером 60, а вернее убираем слово в окошке «Устройство не подключено». Ну а если VID и PID не совпадают переходим в другой кусок условия где мы обнуляем переменные VID и PID и выводим надпись «Устройство не подключено».
 Перейдём теперь к процедуре SendDevice() в которой мы передаём данные в контроллер. Она у нас вызывается в обработке нажатия кнопок командой SendDevice().Посмотрим на нашу процедуру

Procedure SendDevice() 
 Shared OutBytes() 
 If W_DeviceHandle 
 HID_Lib_WriteDevice(W_DeviceHandle, @OutBytes(), 9) 
 EndIf
EndProcedure

 Первым делом мы должны в этой процедуре объявить что мы будем работать с массивом OutBytes() (к стати нужно в начале этот массив объявить Dim OutBytes.c(8)) так как переменная или массив объявленный вне процедуры не будут в ней работать, и так объявляем массив в процедуре Shared OutBytes(). Ну а далее передаём данные в контроллер, стоит отметить, что нужно указывать на один больше байт чем нам нужно те в данном случае мы передаём 8 байт, а указываем 9. Специфика библиотеки. На этом с этой процедурой всё.

 Но как мы можем заметить что у нас есть ещё одна процедура ReadDevice_Thread; это процедура работающая с параллельном потоке или если попроще сказать в фоновом режиме. В ней мы принимаем данные от контроллера и выводим их на экране (в окошке). Сначало нужно создать этот поток что мы и делаем командой CreateThread(@ReadDevice_Thread(),0). Посмотрим поподробнее на эту процедуру 

Procedure ReadDevice_Thread(*x) 
 Dim InBytes.c(9) 
Repeat
 If R_DeviceHandle 
 HID_Lib_ReadDevice(R_DeviceHandle, @InBytes(), 9) 
 If InBytes(1)=1
 SetGadgetText(40,Str( InBytes(2)))
 EndIf
 If InBytes(1)=2
 SetGadgetText(50,Str( InBytes(2))) 
 EndIf
 EndIf 
 Delay(20) 
 ForEver
EndProcedure

 Первым делом мы объявляем массив Dim InBytes.c(9) в который мы будем принимать данные. Этот массив мы объявляем именно в процедуре потому что она будет работать только в ней. Далее мы принимаем 8 байт данных и смотрим если 1 байт равен 1 то второй байт (измеренное напряжение) выводим в окошко предварительно переведя число в строку командой Str, вот как это выглядит SetGadgetText(40,Str( InBytes(2))). А если 1 байт равен 2 то 2 байт мы по той же схеме выводим в другое окошко (предел измерения). Далее делаем небольшую задержку и добавляем команду ForEver чтобы поток повторялся бесконечно. Вот в принципе и вся программа, осталось сказать пару строк про шрифт. 

Global FontID1
FontID1 = LoadFont(1, "Times New Roman", 36)

 Так как мы будем использовать его в процедурах, объявим его, а далее собственно выбираем шрифт. Здесь 1 это идентификатор шрифта, далее собственно название шрифта и его размер.
Чтобы поставить шрифт в какой не будь гаджет используем команду SetGadgetFont(40,FontID(1))
Где 40 это номер гаджета в который устанавливает шрифт, и сам шрифт (1 это идентификатор шрифта).

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

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

 Ниже можно скачать две версии скомпилированной программы

 Окно программы в режиме измерения в диапазоне 20 вольт, величина измеренного напряжения 18 вольт:





 В приложенном архиве схема, исходники и компилированная прошивка для контроллера и компьютера (2 программы для 32 и 64 разрядных систем).





Категория: Полезная информация | Добавлено: 14.11.2012
Просмотров: 24364 | Комментарии: 51 | Рейтинг: 5.0/6
Всего комментариев: 511 2 »
51 Zimakos   (30.11.2017 11:25) [Материал]
Сталкнулся с проблемой при компилляции на Bascom 2.0.7.8
а именно:
Error:380 Line:469 Array<>Non Array mismatch [TXSTATE(i),TXSTATE] , in File...
Error:380 Line:507 Array<>Non Array mismatch [TXSTATE(3),TXSTATE] , in File...
Error:380 Line:507 IF THEN expected [644], in File...
Error:380 Line:507 END IF expected, in File...

Использовал проект отсюда, и , даже ничего не меняя.
Библиотеку swusb.lbx пробовал как версию из Bascom по умолчанию, так и версию 1.02

50 sany2   (14.01.2015 21:26) [Материал]
Смотрите ошибки и исправляйте

49 trition007   (13.01.2015 13:08) [Материал]
Что снова не комплируеться.

48 sany2   (11.01.2015 12:48) [Материал]
Ну я написал,что попробовать можно.

47 trition007   (11.01.2015 12:32) [Материал]
Нули значение не меняется, не на жк не на компе. Напряжение подавал.

46 sany2   (09.01.2015 23:22) [Материал]
по нулям в смысле ничего или нули вольт?
Верните dim T as byte,тогда в компьютер данные пойдут как и раньше,Завести ещё одну переменную dim A1 as single и её выводить на дисплей с сотыми
A1 = 0.01953125 * A
.А Т приравнять не к A,а к А1

45 trition007   (09.01.2015 23:11) [Материал]
Ну и на дисплеи тоже по нулям.

44 sany2   (09.01.2015 20:16) [Материал]
Ну и в программе для компьютера нужно изменить строку
SetGadgetText(40,Str( InBytes(2)))
добавить туда InBytes(3)-как правильно написать чтоб не ругался не знаю(не было необходимости разбираться с PureBasic).
На этом же принципе добавить и остальные напряжения

43 sany2   (09.01.2015 20:10) [Материал]
В программе обратите внимание на этот кусок:
Первым делом мы объявляем массив Dim InBytes.c(9) в который мы будем принимать данные.

Т.е. надо с контролёра то,что поймёт компьютер.Там второй байт-целые значения напряжения.Тогда надо передать и дробные(допустим в третьем байте).В прошивке добавить _usb_tx_buffer2(4) = T1(где T1-дробные)
И естественно до этого нужно опять разбить показания на целые и дробные

42 sany2   (09.01.2015 19:54) [Материал]
Ну а я вам и не обещал,что на экране компьютера что-то поменяется.А вот на дисплее должно быть до сотых

41 trition007   (09.01.2015 18:19) [Материал]
прошил во общем, значения не меняется стоит на нуле.

40 sany2   (08.01.2015 23:11) [Материал]
у меня компилируется
https://yadi.sk/i/5ozMnPyJdrPoS

39 trition007   (08.01.2015 22:58) [Материал]
Ну так не компилируеться прошивка.

38 sany2   (08.01.2015 10:25) [Материал]
Dim T As Byte заменить.и конечно будет ругаться- если вместо них в исходнике цифры не подставить
If Vhod = 1 Then '10 âîëüò
A = 0.009765625 * A 'ýòîò âûáèðàåì èç 10 âîëüò/1024=0 , 009765625
End If
If Vhod = 2 Then '20 âîëüò
A = 0.01953125 * A
End If
If Vhod = 3 Then '200 âîëüò
A = 0.1953125 * A
End If

37 trition007   (08.01.2015 03:36) [Материал]
Dim Per As Single
Dim Vtor As Single
Dim Tret As Single на эти значение тоже ругается , если их удалить

36 trition007   (08.01.2015 03:11) [Материал]
Dim T As Wopd нет такого значения. возможно Dim T As Byte либо Dim A As Word

35 sany2   (07.01.2015 23:27) [Материал]
В двух словах?Про программу ничего не скажу-не знаю(хотя всё очень вверху подробно написано).С прошивкой могу помочь как могу(исходник есть в архиве),если конечно у вас есть желание ковыряться в нём.
Для начала на первый взгляд (чтоб сотые работали) добавить строку
Config Single = Scientific , Digits = 2
изменить Dim T As Wopd на Dim T As Single
вот эти строчки удалить
Dim Per As Single
Dim Vtor As Single
Dim Tret As Single
Per = 0.009765625
Vtor = 0.01953125
Tret = 0.1953125
а в коде Per заменить на 0.009765625(так же vtor и tret)
Правда нужно ещё смотреть что можно передавать в компьютер-возможно и там придётся менять...

34 trition007   (07.01.2015 22:42) [Материал]
А как переделать программу для одновременного отображение значений всех трех значений и с точностью сотых долей?

33 sany2   (07.01.2015 22:12) [Материал]
тут дело больше не в прошивке,а в самой программе для компьютера

32 trition007   (07.01.2015 21:46) [Материал]
Народ подскажите, а если прошивка чтоб он одновременно все данные показывал без переключение и хотя бы еще 10 или 100 значением после запитой. Заранее спасибо.

31 iulian_b   (10.01.2014 16:15) [Материал]
А нет ли этой схемы собранной в каком-нибудь симуляторе, к примеру Протеус ( и т.п.)? Хочу посмотреть как работает, и может быть передалать под счетчик электроэнергии постоянного тока.

30 radan   (05.01.2014 00:32) [Материал]
В статье есть рабочий код на VB6 - http://bascom.at.ua/publ/usb_termometr_na_atmega8/1-1-0-30

29 Петр   (04.01.2014 16:44) [Материал]
Есть DLL HID_Lib_Plus.dll с аналогичными функциями. ftp://ftp.radio.ru/pub/2011/04/HID_Lib_Plus.zip
Перепишите код программы на VB6 с использованием этой DLL.

28 KABANiz90   (04.01.2014 02:29) [Материал]
Можно ли каким образом принять данные в VB6 ?
Хоть через текстовый файл
было бы здорово.

27 exersizze   (19.08.2013 23:01) [Материал]
Есть проекты преобразователя UART-USB на тини 2313, только не на баскоме... У китайца Элм Чена если мне память не изменяет, был такой, сейчас ссылку попробую найти
Вот еще нашел, http://www.getchip.net/posts....rsiya-2 переделанный и  написана прошивка вроде в AB

26 artmel   (19.08.2013 22:46) [Материал]
atmega8 точно работает.
Знает ли кто нибудь загрузчик под такой софтовый usb?

25 top   (19.08.2013 21:09) [Материал]
Интересно, а tiny2313 потянет USB?

24 top   (10.08.2013 23:56) [Материал]
artmel, действительно интересные функции) Не знал о их существовании. High возвращает старшие биты, Low - младшие.

+1   Спам
23 artmel   (10.08.2013 22:12) [Материал]
благодаря вашей подсказке нашел решение

HIGH(), LOW()
Действие: Считать старший или младший байт двухбайтной переменной. Применение для разделения байтов двубайтового числа.
Синтаксис: Var = HIGH(s) Var = LOW(s)
Var – имя байтовой переменной результата. S – имя двухбайтовой переменной.
Пример: Dim I As Integer , Z As Byte I = &H1001
Z = High(I) ‘получили 16
BASCOM 8051 image016 Директивы, операторы и функции Bascom 8051 ЧАСТЬ 4
HIGHW(), LOWW()
Действие: Эти функции обеспечивают разделение четырехбайтовых переменных.
HIHGW – возвращает два старших байта четырехбайтовой переменной
LOWW – возвращает два младших байта четырехбайтовой переменной
Синтаксис: Var = LOWW( s ) var = HIGHW( s )
var – переменная, которая примает значения двух байт из четырех имеющихся в переменной S.
S – источник данных
Пример: Dim L As Integer , Z As Long L = &H101001
Z = LowW(L) ‘Z = 1001h Z = HighW(L) ‘Z = 0010h

22 artmel   (10.08.2013 22:07) [Материал]
top спасибо!
Деление слишком меедленно работает.
Буду искать как сдвигать.

1-30 31-51
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]






авторизация
Логин:
Пароль: