Сегодня я сделал очень простой проект, основная идея которого заключается в создании приложения с графическим интерфейсом для управления платой 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 для управления светодиодом или любыми устройствами, которые вы хотите.