Примером реализации схемы подключения потенциометра может стать макетная плата с подключенным переменным резистором и светодиодом. При помощи потенциометра будет выполняться управление уровнем яркости свечения.
Для проведения работ следует подготовить такие детали:
· 1 плату Arduino Uno
· 1 беспаячную макетную плату
· 1 светодиод
· 1 резистор с сопротивлением 220 Ом
· 6 проводов «папа-папа»
· 1 потенциометр..
Для использования меньшего количества проводов от макетной платы к контроллеру следует подключить светодиод и потенциометр проводом земли к длинному рельсу минуса.
Пример скетча. В этом примере важно понимать, что яркость свечения светодиода управляется не напряжением, подаваемым с потенциометра, а кодом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #define PIN_LED 11 #define PIN_POT A0 void setup() { // Пин, к которому подсоединяется светодиод определяем как выход pinMode(PIN_LED, OUTPUT); // Пин с переменным резистором является входом pinMode(PIN_POT, INPUT); } void loop(){ // Определяем 2 переменные типа int int rotat, brightn; // Считывание в переменную rotat напряжения с переменного резистора: // микроконтроллер будет выдавать числа от 0 до 1023 // пропорциональны положению поворота вала rotat = analogRead(PIN_POT); // Преобразуем значение в яркость. Для этого делим rotat на 4, что с учетом округления даст нам число от 0 до 255. Именно это число мы подадим на шим-выход, с помощью которого можно управлять яркостью. brightn = rotat / 4; // Запись шим значения яркости на светодиод analogWrite(PIN_LED, brightn); } |
****************************************************************
Лаб_5 - Программирование Питон IDLE GUI
Примеры создания типовых элементов GUI Tkinter
Класс Tk
Tk является базовым классом любого Tkinter приложения. При создании объекта этого класса запускается интерпретатор tcl/tk и создаётся базовое окно приложения.
Tkinter является событийно-ориентированной библиотекой. В приложениях такого типа имеется главный цикл обработки событий. В Tkinter такой цикл запускается методом mainloop. Для явного выхода из интерпретатора и завершения цикла обработки событий используется метод quit.
Таким образом минимальное приложение на Tkinter будет таким:
from tkinter import *
root = Tk()
root . mainloop ()
Button
Виджет Button - самая обыкновенная кнопка, которая используется в тысячах программ. Пример кода:
from Tkinter import *
root=Tk()
button1=Button(root,text='ok',14')
Button1.pack()
Root.mainloop()
Разберем этот небольшой код. За создание, собственно, окна, отвечает класс Tk(), и первым делом нужно создать экземпляр
этого класса. Этот экземпляр принято называть root, хотя вы можете назвать его как угодно. Далее создаётся кнопка, при
этом мы указываем её свойства (начинать нужно с указания окна, в примере - root). Здесь перечислены некоторые из них:
text - какой текст будет отображён на кнопке (в примере - ок)
width,height - соответственно, ширина и длина кнопки.
bg - цвет кнопки (сокращенно от background, в примере цвет - чёрный)
fg - цвет текста на кнопке (сокращённо от foreground, в примере цвет - красный)
font - шрифт и его размер (в примере - arial, размер - 14)
Далее, нашу кнопку необходимо разместить на окне. Для этого, в Tkinter используются специальные упаковщики( pack(),
place(), grid() ). Поподробнее об упаковщиках узнаем позже. Пока, чтобы разместить несколько виджетов на окне, будем
применять самый простой упаковщик pack(). В конце программы, нужно использовать функцию mainloop (см. пример),
иначе окно не будет создано.
Label
Label - это виджет, предназначенный для отображения какой-либо надписи без возможности редактирования пользователем.
Имеет те же свойства, что и перечисленные свойства кнопки.
Entry
Entry - это виджет, позволяющий пользователю ввести одну строку текста. Имеет дополнительное свойство bd (сокращённо от borderwidth), позволяющее регулировать ширину границы.
borderwidth - ширина бордюра элемента
bd - сокращение от borderwidth
width - задаёт длину элемента в знакоместах.
show - задает отображаемый символ.
Text
Text - это виджет, который позволяет пользователю ввести любое количество текста. Имеет дополнительное свойство wrap,
отвечающее за перенос (чтобы, например, переносить по словам, нужно использовать значение WORD). Например:
from Tkinter import *
root=Tk()
text1=Text(root,height=7,14',wrap=WORD)
Text1.pack()
Root.mainloop()
Методы insert, delete и get добавляют, удаляют или извлекают текcт. Первый аргумент - место вставки в виде 'x.y', где x – это
строка, а y – столбец. Например:
text 1. insert (1.0,'Добавить Текст \ n \ в начало первой строки' )
Text1.delete('1.0', END) # Удалить все
Text1.get('1.0', END) # Извлечь все
Listbox
Listbox - это виджет, который представляет собой список, из элементов которого пользователь может выбирать один или
несколько пунктов. Имеет дополнительное свойство selectmode, которое, при значении SINGLE, позволяет пользователю
выбрать только один элемент списка, а при значении EXTENDED - любое количество. Пример:
from Tkinter import *
root=Tk()
listbox1=Listbox(root,height=5,
listbox2=Listbox(root,height=5,
list1=[u"Москва",u"Санкт-Петербург" ,u"Саратов",u"Омск"]
list2=[u"Канберра",u"Сидней",u"Мельбурн",u"Аделаида"]
For i in list1:
listbox1.insert(END,i)
For i in list2:
listbox2.insert(END,i)
Listbox1.pack()
Listbox2.pack()
Root.mainloop()
Стоит заметить, что в этой библиотеке для того, чтобы использовать русские буквы в строках, нужно использовать Unicode-
строки. В Python 2.x для этого нужно перед строкой поставить букву u, в Python 3.x этого делать вообще не требуется, т.к.
все строки в нем изначально Unicode. Кроме того в первой или второй строке файла необходимо указать кодировку файла (в комментарии): coding: utf-8. Чаще всего используется формат в стиле текстового редактора emacs:
# encoding : utf -8
В Python 3.x кодировку файла можно не указывать, в этом случае по умолчанию предполагается utf-8.
Frame
Виджет Frame (рамка) предназначен для организации виджетов внутри окна. Рассмотрим пример:
from tkinter import *
root=Tk()
frame1=Frame(root,bg='green',bd=5)
frame2=Frame(root,bg='red',bd=5)
button1=Button(frame1,text=u'Первая кнопка' )
button2=Button(frame2,text=u'Вторая кнопка' )
Frame1.pack()
Frame2.pack()
Button1.pack()
Button2.pack()
Root.mainloop()
Свойство bd отвечает за толщину края рамки.
Checkbutton
Checkbutton - это виджет, который позволяет отметить „галочкой“ определенный пункт в окне. При использовании
нескольких пунктов нужно каждому присвоить свою переменную. Разберем пример:
from tkinter import *
root=Tk()
var1=IntVar()
var2=IntVar()
check1=Checkbutton(root,text=u'1 пункт',variable=var1,onvalue=1,offvalue=0)
check2=Checkbutton(root,text=u'2 пункт',variable=var2,onvalue=1,offvalue=0)
Check1.pack()
Check2.pack()
Root.mainloop()
IntVar() - специальный класс библиотеки для работы с целыми числами. variable - свойство, отвечающее за прикрепление к
виджету переменной. onvalue, offvalue - свойства, которые присваивают прикреплённой к виджету переменной значение,
которое зависит от состояния(onvalue - при выбранном пункте, offvalue - при невыбранном пункте).
Radiobutton
Виджет Radiobutton выполняет функцию, схожую с функцией виджета Checkbutton. Разница в том, что в виджете Radiobutton
пользователь может выбрать лишь один из пунктов. Реализация этого виджета несколько иная, чем виджета Checkbutton:
from tkinter import *
root=Tk()
var=IntVar()
rbutton1=Radiobutton(root,text='1',variable=var,value=1)
rbutton2=Radiobutton(root,text='2',variable=var,value=2)
rbutton3=Radiobutton(root,text='3',variable=var,value=3)
Rbutton1.pack()
Rbutton2.pack()
Rbutton3.pack()
Root.mainloop()
В этом виджете используется уже одна переменная. В зависимости от того, какой пункт выбран, она меняет своё значение.
Самое интересное, что если присвоить этой переменной какое-либо значение, поменяется и выбранный виджет. На этом мы
прервём изучение типов виджетов (потом мы к ним обязательно вернёмся).
Scale
Scale (шкала) - это виджет, позволяющий выбрать какое-либо значение из заданного диапазона. Свойства:
orient - как расположена шкала на окне. Возможные значения: HORIZONTAL, VERTICAL (горизонтально,
вертикально).
length - длина шкалы.
from_ - с какого значения начинается шкала.
to - каким значением заканчивается шкала.
tickinterval - интервал, через который отображаются метки шкалы.
resolution - шаг передвижения (минимальная длина, на которую можно передвинуть движок)
Пример кода:
from tkinter import *
root = Tk()
Def getV(root):
a = scale1.get()
print "Значение", a
scale1 = Scale(root,orient=HORIZONTAL,length=300,from_=50,to=80,tickinterval=5,
resolution=5)
button1 = Button(root,text=u"Получить значение" )
Scale1.pack()
Button1.pack()
button1.bind("<Button-1>",getV)
Root.mainloop()
Здесь используется специальный метод get(), который позволяет снять с виджета определенное значение, и используется не только в Scale.
Scrollbar
Scrollbar – этот виджет даёт возможность пользователю "прокрутить" другой виджет (например текстовое поле) и часто бывает
полезен. Использование этого виджета достаточно нетривиально. Необходимо сделать две привязки: command полосы
прокрутки привязываем к методу xview/yview виджета, а xscrollcommand/yscrollcommand виджета привязываем к методу set
полосы прокрутки.
Рассмотрим на примере:
from tkinter import *
root = Tk()
text = Text(root, height=3,
text.pack(side='left')
scrollbar = Scrollbar(root)
scrollbar.pack(side='left')
# первая привязка
scrollbar['command'] = text.yview
# вторая привязка
text['yscrollcommand' ] = scrollbar.set
Root.mainloop()
Упаковщики
Упаковщик (менеджер геометрии, менеджер расположения) это специальный механизм, который размещает (упаковывает)виджеты на окне. В Tkinter есть три упаковщика: pack, place, grid. Обратите внимание, что в одном виджете можно использовать только один тип упаковки, при смешивании разных типов упаковки программа, скорее всего, не будет работать.
Разберем каждый из них по порядку:
Pack()
Упаковщик pack() является самым интеллектуальным (и самым непредсказуемым). При использовании этого упаковщика с
помощью свойства side нужно указать к какой стороне родительского виджета он должен примыкать. Как правило этот
упаковщик используют для размещения виджетов друг за другом (слева направо или сверху вниз). Пример:
from tkinter import *
root=Tk()
button1 = Button(text="1")
button2 = Button(text="2")
button3 = Button(text="3")
button4 = Button(text="4")
button5 = Button(text="5")
button1.pack(side='left')
button2.pack(side='top')
button3.pack(side='left')
button4.pack(side='bottom')
button5.pack(side='right')
Root.mainloop()
Результат работы можно увидеть на скриншоте справа.
Для создания сложной структуры с использованием этого упаковщика обычно используют Frame,
вложенные друг в друга.
Аргументы:
При применении этого упаковщика можно указать следующие аргументы:
side ("left"/"right"/"top"/"bottom") - к какой стороне должен примыкать размещаемый виджет.
fill (None/"x"/"y"/"both") - необходимо ли расширять пространство предоставляемое виджету.
expand (True/False) - необходимо ли расширять сам виджет, чтобы он занял всё предоставляемое ему
пространство.
in_ - явное указание в какой родительский виджет должен быть помещён.
Дополнительные функции
Кроме основной функции у виджетов есть дополнительные методы для работы с упаковщиками.
pack_configure - синоним для pack.
pack_slaves (синоним slaves) - возвращает список всех дочерних упакованных виджетов.
pack_info - возвращает информацию о конфигурации упаковки.
pack_propagate (синоним propagate) (True/False) - включает/отключает распространении информации о
геометрии дочерних виджетов. По умолчанию виджет изменяет свой размер в соответствии с размером своих
потомков. Этот метод может отключить такое поведение (pack_propagate(False)). Это может быть полезно,
если необходимо, чтобы виджет имел фиксированный размер и не изменял его по прихоти потомков.[7]
pack_forget (синоним forget) - удаляет виджет и всю информацию о его расположении из упаковщика.
Позднее этот виджет может быть снова размещён.
Grid()
Этот упаковщик представляет собой таблицу с ячейками, в которые помещаются виджеты.
Аргументы:
row - номер строки, в который помещаем виджет.
rowspan - сколько строк занимает виджет
column - номер столбца, в который помещаем виджет.
columnspan - сколько столбцов занимает виджет.
padx / pady - размер внешней границы (бордюра) по горизонтали и вертикали.
ipadx / ipady - размер внутренней границы (бордюра) по горизонтали и вертикали. Разница между pad и ipad
в том, что при указании pad расширяется свободное пространство, а при ipad расширяется помещаемый
виджет.
sticky ("n", "s", "e", "w" или их комбинация) - указывает к какой границе "приклеивать" виджет. Позволяет
расширять виджет в указанном направлении. Границы названы в соответствии со сторонами света. "n"
(север) - верхняя граница, "s" (юг) - нижняя, "w" (запад) - левая, "e" (восток) - правая.
in_ - явное указание в какой родительский виджет должен быть помещён.
Для каждого виджета указываем, в какой он находится строке, и в каком столбце. Если нужно, указываем, сколько ячеек он
занимает (если, например, нам нужно разместить три виджета под одним, необходимо "растянуть" верхний на три ячейки).
Пример:
entry1.grid(row=0,column=0,columnspan=3)
button1.grid(row=1,column=0)
button2.grid(row=1,column=1)
button3.grid(row=1,column=2)
Дополнительные функции
grid_configure - синоним для grid.
grid_slaves (синоним slaves) - см. pack_slaves.
grid_info - см. pack_info.
grid_propagate (синоним propagate) - см. pack_propagate.
grid_forget (синоним forget) - см. pack_forget.
grid_remove - удаляет виджет из-под управления упаковщиком, но сохраняет информацию об упаковке. Этот
метод удобно использовать для временного удаления виджета (см. пример в описании метода destroy).
grid_bbox (синоним bbox) - возвращает координаты (в пикселях) указанных столбцов и строк.[9]
grid_location (синоним location) - принимает два аргумента: x и y (в пикселях). Возвращает номер строки и
столбца в которые попадают указанные координаты, либо -1 если координаты попали вне виджета.
grid_size (синоним size) - возвращает размер таблицы в строках и столбцах.
grid_columnconfigure (синоним columnconfigure) и grid_rowconfigure (синоним rowconfigure) - важные
функции для конфигурирования упаковщика. Методы принимают номер строки/столбца и аргументы
конфигурации. Список возможных аргументов:
minsize - минимальная ширина/высота строки/столбца.
weight - "вес" строки/столбца при увеличении размера виджета. 0 означает, что строка/столбец не будет
расширяться. Строка/столбец с "весом" равным 2 будет расширяться вдвое быстрее, чем с весом 1.
uniform - объединение строк/столбцов в группы. Строки/столбцы имеющие одинаковый параметр uniform
будут расширяться строго в соответствии со своим весом.
pad - размер бордюра. Указывает, сколько пространства будет добавлено к самому большому виджету в
строке/столбце.
Пример, текстовый виджет с двумя полосами прокрутки:
from tkinter import *
root=Tk()
text = Text(wrap=NONE)
vscrollbar = Scrollbar(orient='vert', command=text.yview)
text['yscrollcommand' ] = vscrollbar.set
hscrollbar = Scrollbar(orient='hor', command=text.xview)
text['xscrollcommand' ] = hscrollbar.set
# размещаем виджеты
text.grid(row=0, column=0, sticky='nsew')
vscrollbar.grid(row=0, column=1, sticky='ns')
hscrollbar.grid(row=1, column=0, sticky='ew')
# конфигурируем упаковщик, чтобы текстовый виджет расширялся
root.rowconfigure(0, weight=1)
root.columnconfigure (0, weight=1)
Root.mainloop()
Place()
place представляет собой простой упаковщик, позволяющий размещать виджет в фиксированном месте с фиксированным
размером. Также он позволяет указывать координаты размещения в относительных единицах для реализации "резинового"
размещения. При использовании этого упаковщика, нам необходимо указывать координаты каждого виджета. Например:
button1.place(x=0,y=0)
Этот упаковщик, хоть и кажется неудобным, предоставляет полную свободу в размещении виджетов на окне.
Аргументы:
anchor ("n", "s", "e", "w", "ne", "nw", "se", "sw" или "center") - какой угол или сторона размещаемого виджета будет указана в аргументах x/y/relx/rely. По умолчанию "nw" - левый верхний
bordermode ("inside", "outside", "ignore") - определяет в какой степени будут учитываться границы при размещении виджета.
in_ - явное указание в какой родительский виджет должен быть помещён.
x и y - абсолютные координаты (в пикселях) размещения виджета.
width и height - абсолютные ширина и высота виджета.
relx и rely - относительные координаты (от 0.0 до 1.0) размещения виджета.
relwidth и relheight - относительные ширина и высота виджета.
Относительные и абсолютные координаты (а также ширину и высоту) можно комбинировать. Так например, relx=0.5,
x=-2 означает размещение виджета в двух пикселях слева от центра родительского виджета, relheight=1.0,
height=-2 - высота виджета на два пикселя меньше высоты родительского виджета.
Дополнительные функции:
place_slaves, place_forget, place_info - см. описание аналогичных методов упаковщика pack.
Привязка событий
Command
Для большинства виджетов, реагирующих на действие пользователя, активацию виджета (например нажатие кнопки) можно
привязать с использованием опции command. К таким виджетам относятся: Button, Checkbutton, Radiobutton, Spinbox,
Scrollbar, Scale. Выше мы уже неоднократно пользовались этим способом:
button = Button(command=callback )
Такой способ является предпочтительным и наиболее удобным способом привязки.
bind()
Метод bind[1] привязывает событие к какому-либо действию (нажатие кнопки мыши, нажатие клавиши на клавиатуре и т.д.).
bind принимает три аргумента:
название события
функцию, которая будет вызвана при наступлении события
третий аргумент (необязательный) - строка "+" - означает, что эта привязка добавляется к уже существующим.
Если третий аргумент опущен или равен пустой строке - привязка замещает все другие привязки данного
события к виджету.
Метод bind возвращает идентификатор привязки, который может быть использован в функции unbind.
Обратите внимание, что если bind привязан к окну верхнего уровня, то Tkinter будет обрабатывать события всех виджетов
этого окна (см. также bind_all ниже).
Функция, которая вызывается при наступлении события, должна принимать один аргумент. Это объект класса Event, в котором описано наступившее событие. Объект класса Event имеет следующие атрибуты (в скобках указаны события, для которых этот атрибут установлен):
serial - серийный номер события (все события)
num - номер кнопки мыши (ButtonPress, ButtonRelease)
focus - имеет ли окно фокус (Enter, Leave)
height и width - ширина и высота окна (Configure, Expose)
keycode - код нажатой клавиши (KeyPress, KeyRelease)
state - состояние события (для ButtonPress, ButonRelease, Enter, KeyPress, КeyRelease, Leave, Motion - в
виде числа; для Visibility - в виде строки)
time - время наступления события (все события)
x и y - координаты мыши
x _ root и y _ root - координаты мыши на экране (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)
char - набранный на клавиатуре символ (KeyPress, KeyRelease)
send _ event - см. документацию по X/Windows
keysym - набранный на клавиатуре символ (KeyPress, KeyRelease)
keysym _ num- набранный на клавиатуре символ в виде числа (KeyPress, KeyRelease)
type - тип события в виде числа (все события)
widget - виджет, который получил событие (все события)
delta - изменение при вращении колеса мыши (MouseWheel)
Эта функция может возвращать строки "continue" и "break". Если функция возвращает "continue" то Tkinter продолжит обработку других привязок этого события, если "break" - обработка этого события прекращается. Если функция ничего не возвращает (если возвращает None), то обработка событий продолжается (т.е. это эквивалентно возвращению "continue").
Названия событий
Есть три формы названия событий. Самый простой случай это символ ASCII. Так описываются события нажатия клавиш на
клавиатуре:
widget . bind( "z" , callback )
callback вызывается каждый раз, когда будет нажата клавиша "z".
Второй способ длиннее, но позволяет описать больше событий. Он имеет следующий синтаксис: <modifier-modifier-type-detail>
Название события заключено в угловые скобки. Внутри имеются ноль или более модификаторов, тип события и дополнительная информация (номер нажатой клавиши мыши или символ клавиатуры) Поля разделяются дефисом или пробелом. Пример (привязываем одновременное нажатие Ctrl+Shift+q):
widget.bind("<Control-Shift-KeyPress-q>" , callback ) (в данном примереKeyPress можно убрать).
Третий способ позволяет привязывать виртуальные события - события, которые генерируются самим приложением. Такие события можно создавать самим, а потом привязывать их. Имена таких событий помещаются в двойные угловые скобки: <<Paste>>. Есть некоторое количество уже определённых виртуальных событий.
Список модификаторов
Return - Enter
Escape - Esc
Control - Ctrl
Alt
Shift
Lock
Extended
Prior - PgUp
Next - PgDown
Button1, B1 - нажата первая (левая) кнопка мыши
Button2, B2 - вторая (средняя) кнопка мыши
Button3, B3 - третья (правая)
Button4, B4 - четвёртая
Button5, B5 - пятая
Mod1, M1, Command
Mod2, M2, Option
Mod3, M3
Mod4, M4
Mod5, M5
Meta, M
Double - двойной щелчок мыши (например, <Double-Button-1>)
Triple - тройной
Quadruple - четверной
Типы событий
Здесь перечислены все возможные типы событий, для самых часто используемых дано описание. Более подробно см. man bind.
Activate, Deactivate
MouseWheel- прокрутка колесом мыши
KeyPress, KeyRelease- нажатие и отпускание клавиши на клавиатуре
ButtonPress, ButtonRelease, Motion- нажатие, отпускание клавиши мыши, движение мышью
Configure - изменение положения или размера окна
Map, Unmap- показывание или сокрытие окна (например, в случае сворачивания/разворачивания окна пользователем)
Visibility
Expose - событие генерируется, когда необходимо всё окно или его часть перерисовать
Destroy - закрытие окна
FocusIn, FocusOut- получение или лишение фокуса
Enter, Leave - Enter генерируется когда курсор мыши "входит" в окно, Leave - когда "уходит" из окна
Property
Colormap
MapRequest, CirculateRequest, ResizeRequest, ConfigureRequest, Create
Gravity, Reparent, Circulate
Клавиатурные символы
Полный список см.man keysyms.
Примеры
<Button-1>или <1> - нажата левая клавиша мыши.
<Alt-Motion>- движение мышью с нажатой на клавиатуре клавишей Alt.
<Key> - нажатие любой клавиши на клавиатуре.
Пример:
from Tkinter import *
root = Tk()
def leftclick (event):
print u'Вы нажали левую кнопку мыши'
def rightclick (event):
print u'Вы нажали правую кнопку мыши'
button1=Button(root, text=u'Нажми')
button1.pack()
button1.bind('<Button-1>' , leftclick )
button1.bind('<Button-3>' , rightclick )
root.mainloop ()
Дополнительные методы
bind_all - создаёт привязку для всех виджетов приложения. Отличие от привязки к окну верхнего уровня
заключается в том, что в случае привязки к окну привязываются все виджеты этого окна, а этот метод
привязывает все виджеты приложения (у приложения может быть несколько окон).
bind_class - создаёт привязку для всех виджетов данного класса
Пример:
from Tkinter import *
def callback (e):
print u'Нажата кнопка' , e . widget[ 'text' ]
root = Tk()
button1 = Button(root, text = '1' )
button1 . pack()
button2 = Button(root, text = '2' )
button2 . pack()
root . bind_class ( 'Button' , '<1>' , callback )
root . mainloop ()
bindtags - позволяет изменить порядок обработки привязок. По умолчанию порядок следующий: виджет,
класс, окно, all; где виджет - привязка к виджету (bind), класс - привязка к классу (bind_class), окно - привязка к
окну (root.bind), all - привязка всех виджетов (bind_all).
Пример, меняем порядок обработки привязок на обратный:
from Tkinter import *
def callback1 (e): print 'callback1'
def callback2 (e): print 'callback2'
def callback3 (e): print 'callback3'
def callback4 (e): print 'callback4'
root = Tk()
button = Button(root)
button . pack()
button . bind( '<1>' , callback1 )
root . bind_class ( 'Button' , '<1>' , callback2 )
root . bind( '<1>' , callback3 )
root . bind_all ( '<1>' , callback4 )
button . bindtags (( 'all' , root, 'Button' , button))
root . mainloop ()
unbind - отвязать виджет от события. В качестве аргумента принимает идентификатор, полученный от
метода bind.
unbind_all - то же, что и unbind, только для метода bind_all.
unbind_class- то же, что и unbind, только для метода bind_class
****************************************************************
Лаб_6 - Программирование Питон PyGame . Классы
Познакомимся с основами ООП - использованием с классов в Python, на примере собственной игры «Wild West». Игра создана на основе кода игры «Alien» подробно описанной в этой книге - Эрик Мэтиз. Изучаем Питон. Программирование игр, визуализация данных, веб-приложения. Питер. 2017.
Для создание игровых аудио и видео эффектов, которых нет в исходном примере, используем собственные аудио и видео образы:
Код программы
----------------------------------------------------------------------------------------------------------
alien_invasion.py
import pygame
from pygame.sprite import Group
from pygame.sprite import GroupSingle
import myvar
from settings import Settings
from game_stats import GameStats
from scoreboard import Scoreboard
from button import Button
from ship import Ship
import game_functions as gf
pygame.mixer.music.load('audio/music.wav')
pygame.mixer.music.set_volume(0.3)
pygame.mixer.music.play(-1)
def run_game():
# Initialize pygame, settings, and screen object.
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
clock = pygame.time.Clock()
# впишем фон игры и название огры
screen.blit(myvar.my_image, (0, 0)) ##
pygame.display.set_caption("Western 1.0")
# Make the Play button.
play_button = Button(ai_settings, screen, "Play")
# Create an instance to store game statistics, and a scoreboard.
stats = GameStats(ai_settings)
sb = Scoreboard(ai_settings, screen, stats)
# Make a ship, a group of bullets, and a group of aliens.
ship = Ship(ai_settings, screen)
bullets = Group()
aliens = Group()
gbullets = Group()
# создадим группу основного игрового ship
m_ships = GroupSingle()
m_ships.add(ship)
# Create the fleet of aliens.
gf.create_fleet(ai_settings, screen, aliens)
# Start the main loop for the game.
while True:
gf.check_events(ai_settings, screen, stats, sb, play_button, m_ships,
aliens, bullets)
if stats.game_active:
gf.update_ships(m_ships)
bullets.clear(screen, myvar.my_image)
gf.update_bullets(ai_settings, screen, stats, sb, m_ships, aliens,
bullets)
gbullets.clear(screen, myvar.my_image)
gf.update_gbullets(ai_settings, screen, stats, sb, m_ships, aliens,
gbullets)
gf.update_aliens(ai_settings, screen, stats, sb, m_ships, aliens,
bullets, gbullets)
gf.update_screen(ai_settings, screen, stats, sb, m_ships, aliens,
bullets, gbullets, play_button)
clock.tick(200)
run_game()
----------------------------------------------------------------------------------------------------------
game_functions.py
import sys
from time import sleep
import pygame
import myvar
from bullet import Bullet
from gbullet import Gbullet
from alien import Alien
from ship import Ship
pygame.init() ##
bgr_img = myvar.my_image
shoot_sound1 = pygame.mixer.Sound('audio/shooter.wav') ## звук выстрела ship
shoot_sound2 = pygame.mixer.Sound('audio/sh_reload.wav') ## звук перезарядки ship
shoot_sound3 = pygame.mixer.Sound('audio/alien.wav') ## звук крика alien
shoot_sound4 = pygame.mixer.Sound('audio/ship.wav') ## звук крика ship
shoot_sound5 = pygame.mixer.Sound('audio/guns.wav') ## звук выстрела alien
def check_keydown_events(event, ai_settings, screen, m_ships, bullets):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
for ship in m_ships:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
for ship in m_ships:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai_settings, screen, m_ships, bullets)
elif event.key == pygame.K_q:
pygame.quit()
sys.exit()
def check_keyup_events(event, m_ships):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
for ship in m_ships:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
for ship in m_ships:
ship.moving_left = False
def check_events(ai_settings, screen, stats, sb, play_button, m_ships, aliens,
bullets):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, m_ships, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, m_ships)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
check_play_button(ai_settings, screen, stats, sb, play_button,
m_ships, aliens, bullets, mouse_x, mouse_y)
def check_play_button(ai_settings, screen, stats, sb, play_button, m_ships,
aliens, bullets, mouse_x, mouse_y):
"""Start a new game when the player clicks Play."""
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
if button_clicked and not stats.game_active:
# Reset the game settings.
ai_settings.initialize_dynamic_settings()
# Hide the mouse cursor.
pygame.mouse.set_visible(False)
# Reset the game statistics.
stats.reset_stats()
stats.game_active = True
# Установим флаг активации кнопки для погашения
stats.game_button_pressed = True
# Reset the scoreboard images.
sb.prep_score()
sb.prep_high_score()
sb.prep_level()
sb.prep_ships()
# Empty the list of aliens and bullets.
aliens.empty()
bullets.empty()
m_ships.empty()
# Create a new fleet and center the ship.
create_fleet(ai_settings, screen, aliens)
# создаем новый объект ship
ship = Ship(ai_settings, screen)
ship.center_ship()
m_ships.add(ship)
def fire_bullet(ai_settings, screen, m_ships, bullets):
"""Fire a bullet, if limit not reached yet."""
# Create a new bullet, add to bullets group.
if len(bullets) < ai_settings.bullets_allowed:
for ship in m_ships:
new_bullet = Bullet(ai_settings, screen, ship)
ship.aliene_fight = True # Установить флаг ответного огня противника
bullets.add(new_bullet)
shoot_sound1.play() ## выстрел
sleep(0.3) ##
shoot_sound2.play() ## перезарядка
sleep(0.3)
def fire_gbullet(ai_settings, screen, m_ships, bullets, aliens, gbullets):
""" ответный огонь alien в зоне поражения ship """
if len(gbullets) < ai_settings.gbullets_allowed:
for alien in aliens:
for ship in m_ships:
if (alien.rect.x > ship.zonx_min) and (alien.rect.x < ship.zonx_max):
new_gbullet = Gbullet(ai_settings, screen, alien)
gbullets.add(new_gbullet)
shoot_sound5.play() ##
sleep(0.3) ##
ship.aliene_fight = False
def update_screen(ai_settings, screen, stats, sb, m_ships, aliens, bullets,
gbullets, play_button):
"""Update images on the screen, and flip to the new screen."""
# Redraw the screen, только один раз для удаления кнопки
if stats.game_button_pressed:
screen.blit(bgr_img, (0, 0))
stats.game_button_pressed = False
bullets.draw(screen)
gbullets.draw(screen)
m_ships.clear(screen, bgr_img)
m_ships.draw(screen)
aliens.clear(screen, bgr_img)
aliens.draw(screen)
# Draw the score information.
sb.show_score()
# Draw the play button if the game is inactive.
if not stats.game_active:
play_button.draw_button()
# Make the most recently drawn screen visible.
pygame.display.flip()
def update_bullets(ai_settings, screen, stats, sb, m_ships, aliens, bullets):
"""Update position of bullets, and get rid of old bullets."""
# Update bullet positions.
bullets.update()
# Get rid of bullets that have disappeared.
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
check_bullet_alien_collisions(ai_settings, screen, stats, sb, m_ships,
aliens, bullets)
def update_gbullets(ai_settings, screen, stats, sb, m_ships, aliens,
gbullets):
"""Update position of bullets, and get rid of old bullets."""
# Update gbullet positions.
gbullets.update()
# Get rid of bullets that have disappeared.
for gbullet in gbullets.copy():
if gbullet.rect.bottom >= ai_settings.screen_height:
gbullets.remove(gbullet)
#check_g_bullet_ship_collisions(ai_settings, screen, stats, sb, ship,
# aliens, g_bullets)
def update_ships(m_ships):
""" обновление Group m_ships """
for ship in m_ships:
ship.update()
def check_high_score(stats, sb):
"""Check to see if there's a new high score."""
if stats.score > stats.high_score:
stats.high_score = stats.score
sb.prep_high_score()
def check_bullet_alien_collisions(ai_settings, screen, stats, sb, m_ships,
aliens, bullets):
"""Respond to bullet-alien collisions."""
# Remove any bullets and aliens that have collided.
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
if collisions:
for aliens in collisions.values():
stats.score += ai_settings.alien_points * len(aliens)
sb.prep_score()
check_high_score(stats, sb)
shoot_sound3.play() ## звук попадания в противника
if len(aliens) == 0:
# If the entire fleet is destroyed, start a new level.
bullets.empty()
ai_settings.increase_speed()
# Increase level.
stats.level += 1
sb.prep_level()
create_fleet(ai_settings, screen, aliens)
def check_fleet_edges(ai_settings, aliens):
"""Respond appropriately if any aliens have reached an edge."""
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai_settings, aliens)
break
def change_fleet_direction(ai_settings, aliens):
"""Drop the entire fleet, and change the fleet's direction."""
for alien in aliens.sprites():
alien.rect.y += ai_settings.fleet_drop_speed
ai_settings.fleet_direction *= -1
def ship_hit(ai_settings, screen, stats, sb, ship, m_ships, aliens, bullets):
"""Respond to ship being hit by alien."""
if stats.ships_left > 0:
# Decrement ships_left.
stats.ships_left -= 1
# Update scoreboard.
sb.prep_ships()
else:
stats.game_active = False
pygame.mouse.set_visible(True)
# Empty the list of aliens and bullets.
aliens.empty()
bullets.empty()
# m_ships.empty()
# Create a new fleet, and center the ship.
create_fleet(ai_settings, screen, aliens)
ship.center_ship()
m_ships.add(ship)
# Pause.
sleep(0.5)
def check_aliens_bottom(ai_settings, screen, stats, sb, ship, m_ships, aliens,
bullets):
"""Check if any aliens have reached the bottom of the screen."""
screen_rect = screen.get_rect()
for alien in aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
stats.game_button_pressed = True # для перезаписи полностью экрана (ships_left)
# Treat this the same as if the ship got hit.
ship_hit(ai_settings, screen, stats, sb, ship, m_ships, aliens, bullets)
shoot_sound4.play() ## звук крушения корабля
break
def update_aliens(ai_settings, screen, stats, sb, m_ships, aliens, bullets,
gbullets):
"""
Check if the fleet is at an edge,
then update the postions of all aliens in the fleet.
"""
check_fleet_edges(ai_settings, aliens)
aliens.update()
# при флаге ответного огня начать стрелять противнику
for ship in m_ships :
if ship.aliene_fight == True :
fire_gbullet(ai_settings, screen, m_ships, bullets, aliens, gbullets)
# Look for alien-ship collisions.
for ship in m_ships:
if pygame.sprite.spritecollideany(ship, aliens):
ship_hit(ai_settings, screen, stats, sb, ship, m_ships, aliens, bullets)
shoot_sound4.play() ## звук крушения корабля
stats.game_button_pressed = True # для перезаписи полностью экрана (ships_left)
# Look for aliens hitting the bottom of the screen.
check_aliens_bottom(ai_settings, screen, stats, sb, ship, m_ships, aliens, bullets)
def get_number_aliens_x(ai_settings, alien_width):
"""Determine the number of aliens that fit in a row."""
available_space_x = ai_settings.screen_width - 4 * alien_width ##
number_aliens_x = int(available_space_x / (6 * alien_width)) ##
return number_aliens_x
def create_alien(ai_settings, screen, aliens, alien_number, row_number):
"""Create an alien, and place it in the row."""
alien = Alien(ai_settings, screen)
alien_width = alien.rect.width
alien.x = 4*alien_width + 6 * alien_width * alien_number ##
alien.rect.x = alien.x
alien.rect.y = 2*alien.rect.height + 6 * alien.rect.height * row_number ##
aliens.add(alien)
def create_fleet(ai_settings, screen, aliens):
"""Create a full fleet of aliens."""
# Create an alien, and find number of aliens in a row.
alien = Alien(ai_settings, screen)
number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
number_rows = int(1) # get_number_rows(ai_settings, ship.rect.height,
# alien.rect.height)
# Create the fleet of aliens.
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
create_alien(ai_settings, screen, aliens, alien_number, row_number)
----------------------------------------------------------------------------------------------------------
Ship.py
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
def __init__(self, ai_settings, screen):
"""Initialize the ship, and set its starting position."""
super(Ship, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
# Load the ship image, and get its rect.
self.image = pygame.image.load('images/shooter.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# Start each new ship at the bottom center of the screen.
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# Store a decimal value for the ship's center.
self.center = float(self.rect.centerx)
# Movement flags.
self.moving_right = False
self.moving_left = False
# Добавим флаг разрешения на ответ враж. огонь
self.aliene_fight = False
def center_ship(self):
"""Center the ship on the screen."""
self.center = self.screen_rect.centerx
def update(self):
"""Update the ship's position, based on movement flags."""
# Update the ship's center value, not the rect.
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
# определим зону вражеского обстрела ship (x_min и x_max)
self.zonx_min = self.center - self.ai_settings.ship_zonx
self.zonx_max = self.center + self.ai_settings.ship_zonx
# Update rect object from self.center.
self.rect.centerx = self.center
def blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
----------------------------------------------------------------------------------------------------------
Alien.py
import pygame
from pygame.sprite import Sprite
import myvar
class Alien(Sprite):
"""A class to represent a single alien in the fleet."""
def __init__(self, ai_settings, screen):
"""Initialize the alien, and set its starting position."""
super(Alien, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
# Load the alien image, and set its rect attribute.
self.image = pygame.image.load('images/gans.bmp')
self.rect = self.image.get_rect()
# Start each new alien near the top left of the screen.
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Store the alien's exact position.
self.x = float(self.rect.x)
def check_edges(self):
"""Return True if alien is at edge of screen."""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right:
return True
elif self.rect.left <= 0:
return True
def update(self):
"""Move the alien right or left."""
self.x += (self.ai_settings.alien_speed_factor *
self.ai_settings.fleet_direction)
self.rect.x = self.x
def blitme(self):
"""Draw the alien at its current location."""
self.screen.blit(self.image, self.rect)
----------------------------------------------------------------------------------------------------------
Bullet.py
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage bullets fired from the ship."""
def __init__(self, ai_settings, screen, ship):
"""Create a bullet object, at the ship's current position."""
super(Bullet, self).__init__()
self.screen = screen
# Load the bullit image, and set its rect attribute.
self.image = pygame.image.load('images/bullet.bmp')
self.rect = self.image.get_rect()
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Create bullet rect at (0, 0), then set correct position.
# self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
# ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
# Store a decimal value for the bullet's position.
self.y = float(self.rect.y)
# self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""Move the bullet up the screen."""
# Update the decimal position of the bullet.
self.y -= self.speed_factor
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""Draw the bullet to the screen."""
# pygame.draw.rect(self.screen, self.color, self.rect)
self.screen.blit(self.image, self.rect)
----------------------------------------------------------------------------------------------------------
Button.py
import pygame.font
class Button():
def __init__(self, ai_settings, screen, msg):
"""Initialize button attributes."""
self.screen = screen
self.screen_rect = screen.get_rect()
# Set the dimensions and properties of the button.
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
# Build the button's rect object, and center it.
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
# The button message only needs to be prepped once.
self.prep_msg(msg)
def prep_msg(self, msg):
"""Turn msg into a rendered image, and center text on the button."""
self.msg_image = self.font.render(msg, True, self.text_color,
self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
# Draw blank button, then draw message.
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect)
----------------------------------------------------------------------------------------------------------
Settings.py
class Settings():
"""A class to store all settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's static settings."""
# Screen settings.
self.screen_width = 1423 #1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# Ship settings.
self.ship_limit = 3
# добавим размер зоны ответного враж. огня
self.ship_zonx = 50
# Bullet settings.
self.bullet_width = 3
self.bullet_height = 10 #15
self.bullet_color = 60, 60, 60
self.bullets_allowed = 3
# Добавим колв-о ответного огня
self.gbullets_allowed = 5
# Alien settings.
self.fleet_drop_speed = 10
# How quickly the game speeds up.
self.speedup_scale = 1.1
# How quickly the alien point values increase.
self.score_scale = 1.5
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
"""Initialize settings that change throughout the game."""
self.ship_speed_factor = 1.5
self.bullet_speed_factor = 2
self.alien_speed_factor = 1
# Scoring.
self.alien_points = 50
# fleet_direction of 1 represents right, -1 represents left.
self.fleet_direction = 1
def increase_speed(self):
"""Increase speed settings and alien point values."""
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor *= self.speedup_scale
self.alien_points = int(self.alien_points * self.score_scale)
----------------------------------------------------------------------------------------------------------
game_stats.py
class GameStats():
"""Track statistics for Alien Invasion."""
def __init__(self, ai_settings):
"""Initialize statistics."""
self.ai_settings = ai_settings
self.reset_stats()
# Start game in an inactive state.
self.game_active = False
self.game_button_pressed = False
# High score should never be reset.
self.high_score = 0
def reset_stats(self):
"""Initialize statistics that can change during the game."""
self.ships_left = self.ai_settings.ship_limit
self.score = 0
self.level = 1
----------------------------------------------------------------------------------------------------------
Scoreboard.py
import pygame.font
from pygame.sprite import Group
from ship import Ship
class Scoreboard():
"""A class to report scoring information."""
def __init__(self, ai_settings, screen, stats):
"""Initialize scorekeeping attributes."""
self.screen = screen
self.screen_rect = screen.get_rect()
self.ai_settings = ai_settings
self.stats = stats
# Font settings for scoring information.
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)
# Prepare the initial score images.
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ships()
def prep_score(self):
"""Turn the score into a rendered image."""
rounded_score = int(round(self.stats.score, -1))
score_str = "{:,}".format(rounded_score)
self.score_image = self.font.render(score_str, True, self.text_color,
self.ai_settings.bg_color)
# Display the score at the top right of the screen.
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right - 20
self.score_rect.top = 20
def prep_high_score(self):
"""Turn the high score into a rendered image."""
high_score = int(round(self.stats.high_score, -1))
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.font.render(high_score_str, True,
self.text_color, self.ai_settings.bg_color)
# Center the high score at the top of the screen.
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top
def prep_level(self):
"""Turn the level into a rendered image."""
self.level_image = self.font.render(str(self.stats.level), True,
self.text_color, self.ai_settings.bg_color)
# Position the level below the score.
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10
def prep_ships(self):
"""Show how many ships are left."""
self.ships = Group()
for ship_number in range(self.stats.ships_left):
ship = Ship(self.ai_settings, self.screen)
ship.rect.x = 10 + ship_number * ship.rect.width
ship.rect.y = 10
self.ships.add(ship)
def show_score(self):
"""Draw score to the screen."""
self.screen.blit(self.score_image, self.score_rect)
self.screen.blit(self.high_score_image, self.high_score_rect)
self.screen.blit(self.level_image, self.level_rect)
# Draw ships.
self.ships.draw(self.screen)
----------------------------------------------------------------------------------------------------------
Myvar.py
import pygame
my_image = pygame.image.load('images/land.bmp')
----------------------------------------------------------------------------------------------------------
Gbullet.py
import pygame
from pygame.sprite import Sprite
class Gbullet(Sprite):
"""A class to manage bullets fired from the alien."""
def __init__(self, ai_settings, screen, alien):
"""Create a bullet object, at the ship's current position."""
super(Gbullet, self).__init__()
self.screen = screen
# Load the bullit image, and set its rect attribute.
self.image = pygame.image.load('images/bullet.bmp')
self.rect = self.image.get_rect()
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Create bullet rect at (0, 0), then set correct position.
# self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
# ai_settings.bullet_height)
self.rect.centerx = alien.rect.centerx
self.rect.top = alien.rect.top
# Store a decimal value for the bullet's position.
self.y = float(self.rect.y)
# self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""Move the bullet down the screen."""
# Update the decimal position of the bullet.
self.y += self.speed_factor
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""Draw the bullet to the screen."""
# pygame.draw.rect(self.screen, self.color, self.rect)
self.screen.blit(self.image, self.rect)
****************************************************************
Лаб_7 - Подключение, USB передача сигналов сигналов трехкоординатного датчика с АЦП на PC осциллограф (Питон).
В качестве трехкоординатного датчика подключенного к Arduino используем три потенциометра подключенных по схеме приведенной в Лаб 4.( п.п. 4.2), при этом средний вывод потенциометров подключены соответственно к АЦП входам A0, A1, A2 соответственно. Передача данных переменных напряжений с потенциометров X,Y,Z по COM каналу связи на РС осуществляется в пакетном режиме.
Код Arduino:
#define PIN_LED 11
#define PIN_X A0
#define PIN_Y A1
#define PIN_Z A2
#define PIN_SOUND 3
int analogVal_X = 0;
int analogVal_Y = 0;
int analogVal_Z = 0;
int brightn = 0;
void setup() {
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_X, INPUT);
pinMode(PIN_Y, INPUT);
pinMode(PIN_Z, INPUT);
pinMode(PIN_SOUND, OUTPUT);
Serial.begin(19200);
}
void loop() {
delay(200);
analogVal_X = analogRead(PIN_X);
analogVal_Y = analogRead(PIN_Y);
analogVal_Z = analogRead(PIN_Z);
brightn = analogVal_X/4;
analogWrite(PIN_LED, brightn);
Serial.print(analogVal_X);
Serial.print(" ");
Serial.print(analogVal_Y);
Serial.print(" ");
Serial.print(analogVal_Z);
Serial.print("\n");
analogWrite(PIN_SOUND, 50);
delay(100);
analogWrite(PIN_SOUND, 0);
delay(200);
}
Для приема, визуализации, записи в файл получаемых на PC от Arduino данных напишем на Python программу.
GUI программы приема и обработки данных
Код программа (serial_monitor&plot_tkinter_val3_TKinter_07.py ):
from serial import *
from tkinter import *
from tkinter import messagebox
from tkinter.filedialog import *
import fileinput
serialPort = "COM3" # ИЗМЕНИТЬ НА НОМЕР ИСПОЛЬЗУЕМОГО COM ПОРТА!!!
baudRate = 9600
ser = Serial(serialPort , baudRate, timeout=0, writeTimeout=0)
#make a TkInter Window
root = Tk()
root.wm_title("Reading Serial")
# строчные переменные для строчных потоков данных порта и
# окрытого файла
ComStrData = ""
FileStrData = ""
#make our own buffer
serBuffer = ""
FileStrBuff = ""
# битовая переменная чтения данных из порта
dd = b"a"
# переменная текущего количества принятых строк данных XYZ
DStrNum = 0
FStrNum = 0
# переменная стартового номера строки для анимационного (онлайн) графика
LGraph_StartStrNum = 0
StartMode = False
ContinueStartMode = False
LiveGraphMode = False
# массивы для получаемых данных COM порта
comX = []
comY = []
comZ = []
# массивы для данных открытого файла
fopX = []
fopY = []
fopZ = []
# переменная индикации графика данных - com(TRUE) file(False)
ComFile_PlotMod = True
# создаем надписи и окна индкации GUI программы
label_ComDataXYZ = Label(root, text="ComXYZ ", font='Arial 8')
label_ComStrNum = Label(root, text="CStrNum -", font='Arial 8')
label_FileStrNum = Label(root, text="FStrNum -", font='Arial 8')
label_SaveFNote = Label(root, text="SaveFNote -", font='Arial 8')
label_OpenFNote = Label(root, text="OpenFNote -", font='Arial 8')
txt_DataStr = Text(root, height=32, takefocus=0)
txt_X = Text(root, height=1, font='Arial 14', takefocus=0)
txt_Y = Text(root, height=1, font='Arial 14', takefocus=0)
txt_Z = Text(root, height=1, font='Arial 14', takefocus=0)
txt_N = Text(root, height=1, font='Arial 14', takefocus=0)
txt_FileStrN = Text(root, height=1, font='Arial 14', \
takefocus=0)
txt_SaveFNote = Text(root, height=2, font='Arial 8', \
takefocus=0)
txt_OpenFNote = Text(root, height=2, font='Arial 8', \
takefocus=0)
def FnStopWarningMsg():
messagebox.showwarning("Предупреждение", "Нужно остановить чтение порта (кн.STOP)")
def FnStartWarningMsg():
messagebox.showwarning("Предупреждение", "Нужно запустить чтение порта (кн.START)")
# Функ инициализации запуска процесса чтения из сериал порта
def FnButStart():
global StartMode
global ContinueStartMode
global DStrNum
global serBuffer
global comX, comY, comZ
# если ранее не установлен режима старта чтения из порта
# включаем флаги и стартовая инициализация переменных
if StartMode == False:
StartMode = True
ContinueStartMode = False
DStrNum = 0
txt_N.delete('0.0', END)
txt_N.insert('0.0', DStrNum)
ComStrData = ""
serBuffer = ""
txt_DataStr.delete('0.0',END)
comX = []
comY = []
comZ = []
# Функ остановки процесса чтения из сериал порта
def FnButStop():
global StartMode
# выключаем режим старта чтения из порта
if StartMode == True:
StartMode = False
# Функ продолжения процесса чтения из сериал порта
def FnButContinue():
global StartMode
global ContinueStartMode
global ComStrData
# включаем режим старта без стартовой инициализации переменных
if StartMode == False:
StartMode = True
ContinueStartMode = True
# Функ сохранения в файл сериал данных
def FnButSAVE_FILE():
global StartMode
global ComStrData
#предупреждаем и выходим если идет чтение из порта
if StartMode == True:
FnStopWarningMsg()
return
sa = asksaveasfilename()
f = open(sa,"w")
f.write(ComStrData)
f.close()
# Функ чтения из файла ранее сохраненных сериал данных
def FnButOPEN_FILE():
global StartMode
global FileStrData
global fopX, fopY, fopZ
global FileStrBuff
global FStrNum
#предупреждаем и выходим если идет чтение из порта
if StartMode == True:
FnStopWarningMsg()
return
# читаем данные из файла и обрабатываем
FileStrBuff = ""
FStrNum = 0
op = askopenfilename()
FileStrData = ""
txt_DataStr.delete('0.0', END)
for FileStrData in fileinput.input(op):
txt_DataStr.insert('0.0', FileStrData)
OpnFileData_list = list(map(int, FileStrData.split(' ')))
fopX.append(OpnFileData_list[0])
fopY.append(OpnFileData_list[1])
fopZ.append(OpnFileData_list[2])
FileStrData = ""
FStrNum += 1
txt_FileStrN.delete('0.0', END)
txt_FileStrN.insert('0.0', FStrNum)
# Функ рисования осей O_X и O_Y координат для plot canvas (1008x520)
def PlotAxis():
plot.create_line(8,520,8,4, # ось O_Y (вертикал)
plot.create_line(4,518,1004,518,# ось O_X (горизонт)
# Функ графического отображения сериал данных полученных из порта
def FnButDATA_GRAPH():
global StartMode
global FStrNum
#предупреждаем и выходим если идет чтение из порта
if StartMode == True:
FnStopWarningMsg()
return
GraphPlot()
# Функ графического отображения сериал данных полученных из файла
def FnButFILE_GRAPH():
global StartMode
#предупреждаем и выходим если идет чтение из порта
if StartMode == True:
FnStopWarningMsg()
return
def FnButLIVE_GRAPH():
global StartMode, LiveGraphMode
# предупреждаем и выходим если не запущено чтение из порта (START)
if StartMode == False:
FnStartWarningMsg()
return
# если режим анимации не установлен, то запускаем, иначе останавливаем
# режим анимации графика
if LiveGraphMode == False:
LiveGraphMode = True
else:
LiveGraphMode = False
plot.delete("all")
PlotAxis()
# создаем управляющие элементы GUI программы
plot = Canvas(root, width = 1008, height = 520, bg = "lightblue")
button1_START = Button(root, text='START', height=1, \
font='Arial 10', command=FnButStart)
button2_STOP = Button(root, text='STOP', height=1, \
font='Arial 10', command=FnButStop)
button3_CONTINUE = Button(root, text='CONTINUE', \
height=1, font='Arial 10', command=FnButContinue)
button4_SAVE_FILE = Button(root, text='SAVE_FILE', \
height=1, font='Arial 10', command=FnButSAVE_FILE)
button5_OPEN_FILE = Button(root, text='OPEN_FILE', \
height=1, font='Arial 10', command=FnButOPEN_FILE)
button6_DATA_GRAPH = Button(root, text='COM_GRAPH', \
height=1, font='Arial 10', command=FnButDATA_GRAPH)
button7_FILE_GRAPH = Button(root, text='FILE_GRAPH', \
height=1, font='Arial 10', command=FnButFILE_GRAPH)
button8_LIVE_GRAPH = Button(root, text='LIVE_GRAPH', \
height=1, font='Arial 10', command=FnButLIVE_GRAPH)
# make a scrollbar
scrollbar = Scrollbar(root, orient=VERTICAL)
# через grid размещаем элементы GUI в главном окне
scrollbar.grid(row=1, column=0,columnspan = 1, sticky='ns', rowspan = 3)
# размещаем окна входных данных порта
label_ComDataXYZ.grid(row=0, column=0)
txt_X.grid(row=0, column=1)
txt_Y.grid(row=0, column=2)
txt_Z.grid(row=0, column=3)
# размещаем окно числа принятых строк
label_ComStrNum.grid(row=0, column=4)
txt_N.grid(row=0, column=5)
# размещаем окно индикации принятых строк и окно графика
txt_DataStr.grid(row=1, column=1,columnspan = 3)
plot.grid(row=1, column=4,columnspan = 12, rowspan = 2)
# размещаем кнопки управелния процессами
button1_START.grid(row=0, column=6)
button2_STOP.grid(row=0, column=7)
button3_CONTINUE.grid(row=0, column=8)
button4_SAVE_FILE.grid(row=0, column=9)
label_FileStrNum.grid(row=0, column=10)
txt_FileStrN.grid(row=0, column=11)
button5_OPEN_FILE.grid(row=0, column=12)
button6_DATA_GRAPH.grid(row=0, column=13)
button7_FILE_GRAPH.grid(row=0, column=14)
button8_LIVE_GRAPH.grid(row=0, column=15)
# размещаем окна примечаний для записываемомго и считанного файла
label_SaveFNote.grid(row=3, column=2)
txt_SaveFNote.grid(row=3, column=3, columnspan = 12)
label_OpenFNote.grid(row=4, column=2)
txt_OpenFNote.grid(row=4, column=3, columnspan = 12)
# attach text box to scrollbar
txt_DataStr.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=txt_DataStr.yview)
# Функ воспроизведения статической графика
def GraphPlot():
global DStrNum
if ComFile_PlotMod == True:
for i in range(2, 125):
if i < DStrNum:
px = 8+(i-1)*5
pyX = 520 - comX[i-1]//2
pyY = 520 - comY[i-1]//2
pyZ = 520 - comZ[i-1]//2
px_ = 8+i*5
pyX_ = 520 - comX[i]//2
pyY_ = 520 - comY[i]//2
pyZ_ = 520 - comZ[i]//2
plot.create_line(px,pyX,px_,pyX_,= 'black')
plot.create_line(px,pyY,px_,pyY_,= 'red')
plot.create_line(px,pyZ,px_,pyZ_,= 'blue')
else:
break
# Функ воспроизведения анимированной (онлайн) графика
def LiveGraphPlot():
global DStrNum, LGraph_StartStrNum
if LGraph_StartStrNum == 0:
LGraph_StartStrNum = DStrNum
index = 1
if ComFile_PlotMod == True:
for i in range(2, 125):
if i < DStrNum:
px = 8+(i-1)*5
pyX = 520 - comX[i-1+LGraph_StartStrNum]//2
pyY = 520 - comY[i-1+LGraph_StartStrNum]//2
pyZ = 520 - comZ[i-1+LGraph_StartStrNum]//2
px_ = 8+i*5
pyX_ = 520 - comX[i+LGraph_StartStrNum]//2
pyY_ = 520 - comY[i+LGraph_StartStrNum]//2
pyZ_ = 520 - comZ[i+LGraph_StartStrNum]//2
plot.create_line(px,pyX,px_,pyX_,= 'black')
plot.create_line(px,pyY,px_,pyY_,= 'red')
plot.create_line(px,pyZ,px_,pyZ_,= 'blue')
else:
break
# увеличиваем индекс воспроизводимого количества данных с начала
# анимации но не более макс размерности графика по O_X (1000/шаг индикации)
index += 1
# ФУНКЦИЯ чтения из сериал (COM_N) порта строчные данные и воспроизводим
# данные в индикаторных окнах
def readSerial():
while True:
dd = ser.read() # attempt to read a character from Serial
c=dd.decode("utf-8")
#was anything read?
if len(c) == 0:
break
# get the buffer from outside of this function
global ComStrData
global serBuffer
global DStrNum
global StartMode
global comX, comY, comZ
# после буферного набора данных очередной строки из строчного потока данных
if c == '\n':
serBuffer += "\n" # add the newline to the buffer
# читаем из строки данных отдельные числа X,Y,Z
numbers_list = list(map(int, serBuffer.split(' ')))
X=numbers_list[0]
Y=numbers_list[1]
Z=numbers_list[2]
DStrNum += 1
comX.append(X)
comY.append(Y)
comZ.append(Z)
# перепишем полученные данные в соответствующие окна X,Y,Z
txt_X.delete('0.0', END)
txt_X.insert('0.0', X)
txt_Y.delete('0.0', END)
txt_Y.insert('0.0', Y)
txt_Z.delete('0.0', END)
txt_Z.insert('0.0', Z)
if StartMode == True:
#add the line to the TOP of the log
txt_DataStr.insert('0.0', serBuffer)
txt_N.delete('0.0', END)
txt_N.insert('0.0', DStrNum)
ComStrData += serBuffer
if LiveGraphMode == True:
plot.delete("all")
PlotAxis()
LiveGraphPlot()
serBuffer = "" # empty the buffer
else: # набираем в буфер данные текущей отдельной строки(до символа \n)
serBuffer += c # add to the buffer
root.after(10, readSerial) # check serial again soon
# пропишем в окна начальные значения переменных
txt_N.delete('0.0', END)
txt_N.insert('0.0', DStrNum)
txt_FileStrN.delete('0.0', END)
txt_FileStrN.insert('0.0', FStrNum)
# Рисуем оси координат для plot canvas (1008x520)
PlotAxis()
# plot.create_line(8,520,8,4, # ось O_Y (вертикал)
# plot.create_line(4,518,1004,518,# ось O_X (горизонт)
# after initializing serial, an arduino may need a bit of time to reset
root.after(100, readSerial)
root.mainloop()
****************************************************************
Лаб_8 - Подключение, USB передача сигналов звукового модуля на PC осциллограф (Питон).
****************************************************************
Лаб_9 - Конфигурирование и программирование ультразвуковой системы измерения расстояния.
****************************************************************
Лаб_10 - Конфигурирование и программирование ультразвуковой системы измерения расстояния.
****************************************************************
Лаб_10 - Конфигурирование и программирование робокара
****************************************************************
Лаб_11 - Конфигурирование и программирование робокара
****************************************************************
Лаб_12 - Конфигурирование и программирование робота манипулятора
****************************************************************
Лаб_13 - Конфигурирование и программирование робота манипулятора
****************************************************************
Лаб_14 - Конфигурирование и программирование Интернет сети.
****************************************************************
Лаб_15 - Конфигурирование и программирование Интернет сети.
****************************************************************
****************************************************************
Приложение 1.
Устройство платы Arduino Uno R3
Плата Arduino Uno — центр большой империи Arduino, самое популярное и самое доступное устройство Arduino. В ее основе лежит чип ATmega — в последней ревизии Arduino Uno R3 это ATmega328 (хотя на рынке можно еще встретить варианты платы UNO с ATmega168). Arduino Uno является самым подходящим вариантом для начала работы с платформой: она имеет удобный размер (не слишком большой, как у Mega и не такой маленький, как у Nano), достаточно доступна из-за массового выпуска всевозможных клонов, под нее написано огромное количество бесплатных уроков и скетчей. В этой статье мы рассмотрим основные особенности, характеристики и устройство платы Arduino Uno R3, требования к питанию и возможности подключения внешних устройств.
1 Характеристики Arduino Uno R3
2 Изображения плат Ардуино Уно
3 Устройство Arduino Uno
3.1 Схема платы Arduino Uno
3.2 Описание элементов платы Arduino Uno R3
3.3 Распиновка микроконтроллера ATMega 328
4 Описание пинов Ардуино
4.1 Цифровые пины Arduino Uno
4.2 Аналоговые пины Arduino Uno
4.3 Дополнительные разъемы
5 Варианты питания Ардуино Уно
6 Память Arduino Uno R3
7 Отличие Arduino Uno от других плат
7.1 Отличия Arduino Uno от Arduino Nano
8 Краткие выводы
Дата: 2019-05-28, просмотров: 245.