Сегодня я сделал очень простой проект, основная идея которого заключается в создании приложения с графическим интерфейсом для управления платой arduino. Конечно, управление светодиодом было бы очень простым способом начать работу, а затем мы сможем применить его к более сложным проектам в будущем, когда наши навыки будут постоянно расти.
Я разделю этот проект на 2 части
Часть 1 связана с созданием приложения с графическим интерфейсом.
Часть 2 — написать код Arduino для получения входных данных из графического интерфейса, который я создал заранее.
Хорошо, давайте перейдем к части 1.
Часть 1 Проектирование графического интерфейса и написание кода для его создания.
Во-первых, мне нужно разработать кнопки для отправки данных в порт Arduino через UART.
В этом проекте мой порт com7, а скорость передачи 96oo. (Вы можете вставить свои данные). Кстати, это обычные и подходящие значения платы Arduino. Если вы хотите подключить Wi-Fi с помощью ESP8266 или ESP32, вы всегда заметите, что эти платы используют 115200 в качестве подходящей скорости передачи.
Написание кода Python
Давайте посмотрим в коде Python, я импортировал 3 модуля; сериал, время, ткинтер
serial >>> Для связи между arduino и python.
time >>> Управляем временем.
tkinter >>> Создание приложением с графическим интерфейсом.
import serial import time import tkinter
Создание соединения
ser = serial.Serial('com7', 9600) print("Сброс Arduino") time.sleep(3) ser.write(bytes('L', 'UTF-8'))
Последовательную связи определили в переменную «ser» для хранения данных последовательной связи.
Установили com 7 и 9600 как номер com-порта и скорость передачи соответственно. (Здесь можем ввести свой номер порта).
Выводим текст в Python IDE, через print(“Сброс Arduino”)
« time.sleep(3) » задерживает на 3 секунды.
Создаём байтовую строку, и через «ser.write» отправляем «L» на Arduino для сброса включенного состояния, при первом подключении.
Создание приложение
tkTop = tkinter.Tk() tkTop.geometry('300x400') tkTop.title("IoT24hours") label3 = tkinter.Label(text = 'Building Python GUI to interface an arduino,' '\n and control an LED',font=("Courier", 12,'bold')).pack()
Рассмотрим подробнее:
tkTop = tkinter.Tk()
Создаем Корневое окно tkinter и передаем данные в переменную tkTop.
tkTop.geometry(‘300×400’)
Создаем размеры окна.
tkTop.title(“IoT24hours”)
Создаем заголовок окна.
label3 = tkinter.Label(text = ‘Building Python GUI to interface an arduino,’ ‘\n and control an LED’,font=(“Courier”, 12,’bold’)).pack()
Создаем текст с переносом \n на новую строку. ВЫбираем шрифт и размер текста font=(“Courier”, 12,’bold’).
Для позиционирования виджетов в контейнере применяются различные способы. Один из них представляет вызов у виджета метода pack().
tkTop.counter = 0
Переменная хранится в корневом окне, и первое значение равно нулю.
b = tkTop.counter
Передаем значение переменной в корневом окне переменной b.
3 функции для 3 кнопок
quit (Кнопка Quit) >>>
Чтобы выйти из приложения, когда мы хотим
set_button1_state (кнопка ON)>>>
Чтобы отправить символ «H» на Arduino, возможно, включение светодиода.
set_button2_state (кнопка OFF)>>>
Чтобы отправить символ «L» в Arduino, возможно, выключение светодиода.
def quit(): global tkTop ser.write(bytes('L', 'UTF-8')) tkTop.destroy() def set_button1_state(): b += 1 varLabel.set("LED ON") ser.write (bytes('H', 'UTF-8')) varLabel2.set(b) print(b) def set_button2_state(): varLabel.set("LED OFF") ser.write(bytes('L', 'UTF -8')
Разберем код функции def quit:
def quit():
Создание функции.
global tkTop
Определяем переменную tkTop как глобальную.
ser.write(bytes(‘L’, ‘UTF-8’))
Создаём байтовую строку, и через «ser.write» отправляем «L» на Arduino при работе функции.
tkTop.destroy()
Уничтожаем переменную tkTop, по сути закрываем приложение.
Разберем код функции def set_button1_state:
def set_button1_state():
Создание функции
b += 1
При каждой работе функции прибавляем единицу к переменной b.
varLabel.set(“LED ON”)
В переменную varLabel устанавливаем текст “LED ON”
ser.write (bytes(‘H’, ‘UTF-8’))
Создаём байтовую строку, и через «ser.write» отправляем «H» на Arduino при работе функции.
varLabel2.set(b)
В переменную varLabel2 вводим значение переменной b. Значение которой увеличивается на единицу.
print(b)
Печатаем значение переменной b.
Разберем код функции def set_button1_state:
def set_button2_state():
Создание функции
varLabel.set(“LED OFF”)
В переменную varLabel устанавливаем текст “LED OFF”
ser.write(bytes(‘L’, ‘UTF -8’)
Создаём байтовую строку, и через «ser.write» отправляем «L» на Arduino при работе функции.
Текстовое поле tkLabel
varLabel = tkinter.IntVar() tkLabel = tkinter.Label(textvariable=varLabel, ) tkLabel.pack()
Рассмотрим код:
varLabel = tkinter.IntVar()
Переменная, определенная с помощью IntVar()
функции, содержит целочисленные данные, где мы можем установить целочисленные данные, а также можем получить их, используя методы получения и установки. Эти переменные могут быть переданы в различные параметры виджета, например, переменный параметр Radio Button и CheckBox, текстовый параметр Label Widget и т. д., как мы увидим в примерах. Как только эти переменные подключаются к виджетам, соединение работает в обоих направлениях: если переменная IntVar() изменяется, значение виджета также автоматически обновляется новым значением.
Передаем значение в переменную varLabel.
tkLabel = tkinter.Label(textvariable=varLabel, )
Виджет Label представляет текстовую метку. Этот элемент позволяет выводить статический текст без возможности редактирования.
В данном случае определяется переменная tkLabel, которая представляет класс StringVar, то есть такая переменная, которая хранит некоторую строку.
С помощью параметра textvariable эта переменная привязана к текстовой метки.
textvariable: как следует из названия, она связана с переменной Tkinter (обычно StringVar) с меткой. Если переменная изменяется, текст метки обновляется.
И если мы изменим текст в поле Entry, автоматически синхронно изменится и значение привязанной переменной tkLabel. а поскольку к этой переменной также привязана текстовая метка, то автоматически также изменится текст метки.
tkLabel.pack()
Pack – это менеджер геометрии, который размещает виджеты по горизонтали и вертикали.
Текстовое поле tkLabel2
varLabel2 = tkinter.IntVar() tkLabel2 = tkinter.Label(textvariable=varLabel2, ) tkLabel2.pack()
Рассмотрим код:
varLabel2 = tkinter.IntVar()
Переменная, определенная с помощью IntVar()
функции, содержит целочисленные данные, где мы можем установить целочисленные данные, а также можем получить их, используя методы получения и установки. Эти переменные могут быть переданы в различные параметры виджета, например, переменный параметр Radio Button и CheckBox, текстовый параметр Label Widget и т. д., как мы увидим в примерах. Как только эти переменные подключаются к виджетам, соединение работает в обоих направлениях: если переменная IntVar() изменяется, значение виджета также автоматически обновляется новым значением.
Передаем значение в переменную varLabel2.
tkLabel2= tkinter.Label(textvariable=varLabel2, )
Виджет Label представляет текстовую метку. Этот элемент позволяет выводить статический текст без возможности редактирования.
В данном случае определяется переменная tkLabel2, которая представляет класс StringVar, то есть такая переменная, которая хранит некоторую строку.
С помощью параметра textvariable эта переменная привязана к текстовой метки.
textvariable: как следует из названия, она связана с переменной Tkinter (обычно StringVar) с меткой. Если переменная изменяется, текст метки обновляется.
И если мы изменим текст в поле Entry, автоматически синхронно изменится и значение привязанной переменной tkLabel2. а поскольку к этой переменной также привязана текстовая метка, то автоматически также изменится текст метки.
tkLabel2.pack()
Pack – это менеджер геометрии, который размещает виджеты по горизонтали и вертикали.
Кнопка button1
button1 = tkinter.IntVar() button1state = tkinter.Button(tkTop, text="ON", command=set_button1_state, height = 4, fg = "black", width = 8, bd = 5, activebackground='green' ) button1state.pack(side='top', ipadx=10, padx=10, pady=15);
Рассмотрим код:
button1 = tkinter.IntVar()
Переменная, определенная с помощью IntVar()
функции, содержит целочисленные данные.
button1state = tkinter.Button(tkTop,
text=”ON”,
command=set_button1_state,
height = 4,
fg = “black”,
width = 8,
bd = 5,
activebackground=’green’
)
В переменную button1state записываем следующие значения:
tkTop: расположение кнопки в корневом окне tkTop .
text=”ON”: текст на кнопке.
command=set_button1_state: при нажатии, выполнение функции set_button1_state.
height = 4: высота кнопки.
fg = “black”: цвет кнопки.
width = 8: ширина кнопки.
bd = 5: ширина линии кнопки
activebackground=’green’: фон при нажатии.
И упаковщик кнопки
button1state.pack(side=’top’, ipadx=10, padx=10, pady=15)
Метод pack, который я понимаю, заключается в том, как разместить контейнер в вашем окне. В основном это концепция относительного положения, и самое главное, метод pack размещается построчно в порядке выполнения кода. Да, порядок имеет большое влияние на результат.
Прежде всего, атрибуты метода pack () следующие:
-after, -anchor, -before, -expand, -fill, -in, -ipadx, -ipady, -padx, -pady, -side
Метод pack можно применить ко всем контейнерам в Tkinter;
Более подробно здесь или здесь
У метода pack
есть параметр side
(сторона), который принимает одно из четырех значений-констант tkinter
– TOP
, BOTTOM
, LEFT
, RIGHT
(верх, низ, лево, право). По умолчанию, когда в pack
не указывается side
, его значение равняется TOP
. Из-за этого виджеты располагаются вертикально.
Можно задавать внутренние (ipadx
и ipady
) и внешние (padx
и pady
) отступы:
Кнопка button1 и tkButtonQuit имеют такие же настройки как выше.
И последняя строчка кода.
tkinter.mainloop()
Для отображения окна и взаимодействия с пользователем у окна вызывается метод mainloop()
Полный код:
import serial import time import tkinter def quit(): global tkTop ser.write(bytes('L', 'UTF-8')) tkTop.destroy() def set_button1_state(): global b b += 1 varLabel.set("LED ON ") ser.write(bytes('H', 'UTF-8')) varLabel2.set(b) print(b) def set_button2_state(): varLabel.set("LED OFF") ser.write(bytes('L', 'UTF-8')) ser = serial.Serial('com1', 9600) print("Reset Arduino") time.sleep(3) ser.write(bytes('L', 'UTF-8')) tkTop = tkinter.Tk() tkTop.geometry('300x400') tkTop.title("IoT24hours") label3 = tkinter.Label(text = 'Building Python GUI to interface an arduino,' '\n and control an LED',font=("Courier", 12,'bold')).pack() tkTop.counter = 0 b = tkTop.counter varLabel = tkinter.IntVar() tkLabel = tkinter.Label(textvariable=varLabel, ) tkLabel.pack() varLabel2 = tkinter.IntVar() tkLabel2 = tkinter.Label(textvariable=varLabel2, ) tkLabel2.pack() button1 = tkinter.IntVar() button1state = tkinter.Button(tkTop, text="ON", command=set_button1_state, height = 4, fg = "black", width = 8, bd = 5, activebackground='green' ) button1state.pack(side='top', ipadx=10, padx=10, pady=15) button2 = tkinter.IntVar() button2state = tkinter.Button(tkTop, text="OFF", command=set_button2_state, height = 4, fg = "black", width = 8, bd = 5 ) button2state.pack(side='top', ipadx=10, padx=10, pady=15) tkButtonQuit = tkinter.Button( tkTop, text="Quit", command=quit, height = 4, fg = "black", width = 8, bg = 'yellow', bd = 5 ) tkButtonQuit.pack(side='top', ipadx=10, padx=10, pady=15) tkinter.mainloop()
Часть 2 Написание кода arduino
Я не использовал никаких светодиодных устройств, я просто использую свою плату arduino. Как вы уже знаете, если вы познакомитесь с arduino, вы увидите, что это встроенный светодиодный вывод, прикрепленный к выводу 13 на его плате, и, конечно же, я буду использовать его для этого проекта, потому что теперь у меня нет никаких светодиодов. . Но на самом деле я очень хочу создать этот пост сейчас, поэтому мне достаточно начать с использования светодиода на плате Arduino. Кстати, если у вас есть собственный светодиод, не проблема, вы тоже можете его использовать, но вам потребуется подключить к нему провод и иметь некоторые базовые знания схемы.
Код вначале скетча
const int ledPin = 13; // пин, к которому подключен светодиод int incomingByte; // переменная хранит последовательные данные
В настройке void не было ничего сложного, просто добавили 9600 в качестве скорости передачи и определили «ledPin» как выходной контакт.
void setup() { // инициализируем последовательную связь: Serial.begin(9600); // инициализируем вывод светодиода как выход: pinMode(ledPin, OUTPUT); }
Основная идея написания кода Arduino — открыть последовательный порт, ожидая получения входящих данных из графического интерфейса. Посмотрим в void loop.
// смотрим, есть ли входящие последовательные данные: if (Serial.available() > 0) { // читаем самый старый байт в последовательном буфере: incomingByte = Serial.read();
Когда я нажимаю кнопку «ON», приложение с графическим интерфейсом отправит символ «H» на Arduino через последовательную связь.
Затем я напишу несколько кодов для получения этих данных, и я использую код ниже.
if (incomingByte == 'L') { digitalWrite(ledPin, LOW); Serial.println("Getting L"); //print out to serial monitor to check state }
Полная версия кода Arduino
// Arduino IDE: // Файл -> Примеры -> 04. Связь -> PhysicalPixel const int ledPin = 13; // пин, к которому подключен светодиод int incomingByte; // переменная хранит последовательные данные void setup() { // инициализируем последовательную связь: Serial.begin(9600); // инициализируем вывод светодиода как выход: pinMode(ledPin, OUTPUT); } void loop() { // смотрим, есть ли входящие последовательные данные: if (Serial.available() > 0) { // читаем самый старый байт в последовательном буфере: incomingByte = Serial.read(); // если это заглавная буква H (ASCII 72), включить светодиод: if (incomingByte == 'H') { digitalWrite(ledPin, HIGH); Serial.println("Получение H"); // вывод в последовательный монитор для проверки состояния } // если это L (ASCII 76), выключаем светодиод: if (incomingByte == 'L') { digitalWrite(ledPin, LOW); Serial.println("Получение L"); // вывод в последовательный монитор для проверки состояния } } }
Заключение
Просто помните, что основные концепции этого проекта
- Нажатие кнопок из графического интерфейса для отправки данных на плату Arduino через последовательную связь.
- Получение входных данных от кнопок графического интерфейса, которые мы нажимали ранее, чтобы использовать эти данные для применения к условиям if-else для управления светодиодом или любыми устройствами, которые вы хотите.