[아두이노]-[삼색신호등]- [기능 모델링]
13번 - 빨강LED - 전등(L)
12번 - 노랑LED - 에어컨(A)
11번 - 초록LED - 출입문(D)
GND - GND
L0: 전등 끄기, L1: 전등 켜기
A0: 에어컨 끄기, A1: 에어컨 켜기
D0: 출입문 닫기, D1: 출입문 열기
// 시리얼 통신으로 신호등 LED 제어하기
// [가정] 빨강led:전등(L), 노랑led:에어컨(A), 초록led:출입문(D)
// [명령어] 0: 끄기(닫기), 1: 켜기(열기)
// 예)L0(전등 끄기), A1(에어컨 켜기), D1(문 열기)
#define LED_R 13 // 빨강led, 전등(L)
#define LED_Y 12 // 노랑led, 에어컨(A)
#define LED_G 11 // 초록led, 출입문(D)
String inString = "";
char inChar;
void setup() {
Serial.begin(9600);
Serial.println("Arduino ready.");
pinMode(LED_R, OUTPUT);
pinMode(LED_Y, OUTPUT);
pinMode(LED_G, OUTPUT);
}
void loop() {
if (Serial.available()){
while(Serial.available()){
inChar = (char)Serial.read();
inString += inChar;
}
// 수신 문자열 파싱
String inNumber = inString.substring(1, inString.length()); // 제어값 x만 취함
int inValue = inNumber.toInt(); // 제어값 x를 정수로 변환
if(inString[0]=='L'){
digitalWrite(LED_R, inValue); // 전등 제어
Serial.println("Lamp "+(String)inValue);
}else if(inString[0]=='A'){
digitalWrite(LED_Y, inValue); // 에어컨 제어
Serial.println("Aircon "+(String)inValue);
}else if(inString[0]=='D'){
digitalWrite(LED_G, inValue); // 출입문 제어
Serial.println("Door "+(String)inValue);
}else
Serial.println("What?"); // 유효하지 않은 명령어
// 다음 문자열 수신 준비
inString = "";
}
delay(100);
}
홈페이지 https://thonny.org/
다운로드 thonny-3.3.13.exe
윈도우 cmd 창에서 다음 명령을 실행
pip 업그레이드
python -m pip install --upgrade pip
pyserial 설치
pip install pyserial
# 아두이노와 직렬 통신 연결 수립 및 제어
import serial #pyserial 라이브러리
# 아두이노와 직렬 통신 연결(속도 9600, 포트 COMx)
arduino = serial.Serial('COM8' , 9600)
# 아두이노의 시작 메시지 수신
if arduino.readable():
print(arduino.readline().decode())
while True:
cmd = input("제어명령(종료는 x): ")
if cmd == 'x' or cmd == 'X':
break
elif cmd == 'L0' or cmd == 'L1':
cmd = cmd.encode('utf-8')
arduino.write(cmd)
if arduino.readable():
print(arduino.readline().decode())
else:
print(" 알 수 없는 명령어입니다. \n [명령어 예시] L0, L1, A0, A1, D0, D1")
arduino.close() # 직렬 통신 종료
# 출처: https://haesolhanja.tistory.com/45 [KoverJK's Blog]
[프로그램 설명 및 실행]
아두이노는 직렬 통신 연결이 수립되면 재부팅
아두이노로 부터 직렬 통신 수립 메시지 수신하기
아두이노에게 LED 제어 명령을 송신하여 동작 확인하기
# 아두이노와 직렬 통신 연결 수립
import serial
cmd_type = ('L0', 'L1', 'A0', 'A1', 'D0', 'D1') # 명령어 종류
# 아두이노와 직렬통신 연결 수립(속도 9600, 포트 COMx)
arduino = serial.Serial('COM8' , 9600)
# 아두이노의 시작 메시지 수신
if arduino.readable():
print(arduino.readline().decode())
while True:
cmd = input("제어명령(종료는 x): ")
if cmd == 'x' or cmd == 'X':
break
if cmd in cmd_type:
cmd = cmd.encode('utf-8')
arduino.write(cmd)
if arduino.readable():
print(arduino.readline().decode())
else:
print(" 알 수 없는 명령어입니다. \n [명령어 예시] L0, L1, A0, A1, D0, D1")
arduino.close()
# 출처: https://haesolhanja.tistory.com/45 [KoverJK's Blog]
[실습1] 실행
다음의 명령어를 전송하고, 삼색 신호등의 변화 및 아두이노에서 수신한 문자를 확인한다
> L0: 램프(빨강led) 켜기
> L1: 램프(빨강led) 끄기
> A0: 에어컨(노랑led) 켜기
> A1: 에어컨(노랑led) 끄기
> D0: 출입문(초록led) 켜기
> D1: 출입문(초록led) 끄기
> l2: 유효하지 않은 명령어
# 빈화면 만들기
from tkinter import *
root = Tk()
# 더 알아보기
# root.title("스마트홈 제어")
# root.geometry("640x480") # 가로 * 세로
# root.geometry("640x480+300+100") # 가로 * 세로 + x좌표 + y좌표
# root.resizable(True, False) # x(너비), y(높이) 값 변경 불가 (창 크기 변경 불가)
root.mainloop()
[실습2] tkinter 기본 구조
from tkinter import *
root = Tk() # 최상위 윈도우 창 생성
root.mainloop() # 윈도우 창이 종료될 때까지 실행
# 버튼 추가
from tkinter import *
root = Tk()
btnLampON = Button(root, text="전등 ON") # 버튼 생성
btnLampON.pack() # 버튼 넣기
root.mainloop()
[실습3] 버튼 추가
btnLampON = Button(root, text="전등 ON")# 버튼 생성
root: 버튼 위젯을 배치할 윈도우 창
text: 버튼 위젯에 표시할 문자열
btnLampON.pack() # 버튼 넣기
.pack(): 위젯을 윈도우에 배치
# 윈도우 제목/크기 추가
from tkinter import *
root = Tk()
root.title("스마트홈 제어") # 윈도우 제목 추가
root.geometry("300x200") # 윈도우 크기 설정(가로 * 세로)
btnLampON = Button(root, text="램프 ON")
btnLampON.pack()
root.mainloop()
[실습4] 윈도우 제목, 크기 설정
root.title("스마트홈 제어")
.title: 윈도우 창의 제목 문자열 설정
root.geometry("300x200")
.geometry: 윈도우 창 크기 설정(가로 x 세로 픽셀)
# 버튼 추가, 버튼 크기,색상 설정
from tkinter import *
root = Tk()
root.title("스마트홈 제어")
root.geometry("300x200") # 가로 * 세로
btnLampON = Button(root, fg="red", width=10, height=3, text="전등 ON")
btnLampON.pack()
btnLampOFF = Button(root, fg="blue", width=10, height=3, text="전등 OFF")
btnLampOFF.pack()
root.mainloop()
[실습5] 버튼 추가, 버튼 크기/색상 설정
btnLampON = Button(root, fg="red", width=10, height=3, text="전등 ON")
fg: 버튼 문자 색상(fore ground color)
width, height: 버튼 폭/높이 크기(픽셀)
btnLampOFF = Button(root, fg="blue", width=10, height=3, text="전등 OFF")
'전등 끄기' 버튼 추가
# 버튼 추가, 버튼 크기,색상 설정
from tkinter import *
root = Tk()
root.title("스마트홈 제어")
root.geometry("300x200") # 가로 * 세로
btnLampON = Button(root, fg="red", width=10, height=3, text="전등 ON")
btnLampON.pack()
btnLampOFF = Button(root, fg="blue", width=10, height=3, text="전등 OFF")
btnLampOFF.pack()
root.mainloop()
[실습6] 버튼을 클릭하면 실행창에 결과가 나타남
def lampONcmd():
print("전등을 켜시오 L1")
btnLampON = Button(root, fg="red", width=10,
height=3, text="전등 ON", command=lampONcmd)
lampONcmd(): '전등 켜기' 실행 함수
command=: 버튼 클릭 시 실행할 함수
# 문자표시 위젯 추가, 실행결과를 문자표시 위젯에 나타냄
from tkinter import *
import tkinter.font # 글자 폰트 모듈
root = Tk()
root.title("스마트홈 제어")
root.geometry("300x200") # 가로 * 세로
myFont = tkinter.font.Font(family="맑은 고딕", size=20) # 글자 폰트, 크기 설정
def lampONcmd():
print("전등을 켜시오 L1")
txtState.delete(1.0,"end")
txtState.insert(1.0,"전등을 켜시오 L1")
def lampOFFcmd():
print("전등을 끄시오 L0")
txtState.delete(1.0,"end")
txtState.insert(1.0,"전등을 끄시오 L0")
btnLampON = Button(root, fg="red", width=10, height=3, text="전등 ON", command=lampONcmd)
btnLampON.pack()
btnLampOFF = Button(root, fg="blue", width=10, height=3, text="전등 OFF", command=lampOFFcmd)
btnLampOFF.pack()
txtState=Text(root, width=20, height=2, font=myFont) # 문자표시 위젯 추가
txtState.pack(side="bottom") # 문자표시 위젯을 윈도우 맨아래에 배치
root.mainloop()
[실습7] 버튼을 클릭하면 문자표시 위젯에 결과가 나타남
def lampONcmd():
print("전등을 켜시오 L1")
txtState.delete(1.0,"end")
txtState.insert(1.0,"전등을 켜시오 L1")
txtState.delete: 현재 표시된 문자열을 지운다.
txtState.insert: 새로운 문자열을 넣는다.
txtState=Text(root, width=20, height=2, font=myFont)
Text(): 문자표시 위젯 추가
# 직렬 통신으로 아두이노 전등(L) 제어
from tkinter import *
import tkinter.font
import serial
arduino = serial.Serial('COM8' , 9600)
if arduino.readable():
print(arduino.readline().decode())
root = Tk()
root.title("스마트홈 제어")
root.geometry("300x200") # 가로 * 세로
myFont = tkinter.font.Font(family="맑은 고딕", size=20)
def lampONcmd():
cmd = "L1"
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
def lampOFFcmd():
cmd = "L0"
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
btnLampON = Button(root, fg="red", width=10, height=3, text="전등 ON", command=lampONcmd)
btnLampON.pack()
btnLampOFF = Button(root, fg="blue", width=10, height=3, text="전등 OFF", command=lampOFFcmd)
btnLampOFF.pack()
txtState=Text(root, width=20, height=2, font=myFont)
txtState.pack(side="bottom")
root.mainloop()
arduino.close()
# 직렬 통신으로 아두이노 전등(L) 제어 - 화면배치 grid, ver표기
from tkinter import *
import tkinter.font
import serial
arduino = serial.Serial('COM3' , 9600)
if arduino.readable():
print(arduino.readline().decode())
root = Tk()
root.title("스마트홈 제어")
# root.geometry("300x200") # 가로 * 세로
myFont = tkinter.font.Font(family="Arial", size=12, weight="bold")
def lampONcmd():
cmd = "L1"
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
def lampOFFcmd():
cmd = "L0"
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
txtState = Text(root, width=20, height=2, font ="Consolas 16", relief="sunken") # 20글자, 2줄
txtState.insert(1.0, " Welcome! \n AIoT ver. 0.1")
txtState.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
btnLampON = Button(root, fg="red", width=8, height=1, text="전등 ON", font=myFont, command=lampONcmd)
btnLampON.grid(row=1, column=0, padx=10, pady=10)
btnLampOFF = Button(root, fg="blue", width=8, height=1, text="전등 OFF", font=myFont, command=lampOFFcmd)
btnLampOFF.grid(row=1, column=1, padx=10, pady=10)
lblVersion = Label(root, text="AIoT ver. 0.1 by KSYUN, Copyleft 2021")
lblVersion.grid(row=2, column=0, columnspan=2, padx=5, pady=5)
root.mainloop()
arduino.close()
# 직렬 통신으로 아두이노 전등(L) 제어 - lamda 함수로 표현
from tkinter import *
import tkinter.font
import serial
arduino = serial.Serial('COM3' , 9600)
if arduino.readable():
print(arduino.readline().decode())
root = Tk()
root.title("스마트홈 제어")
# root.geometry("300x200") # 가로 * 세로
myFont = tkinter.font.Font(family="Arial", size=12, weight="bold")
def cmdBtnClick(cmd):
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
txtState = Text(root, width=20, height=2, font ="Consolas 16", relief="sunken") # 20글자, 2줄
txtState.insert(1.0, " Welcome! \n AIoT ver. 0.1")
txtState.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
btnLampON = Button(root, fg="red", width=8, height=1, text="전등 ON", font=myFont, command=lambda:cmdBtnClick("L1"))
btnLampON.grid(row=1, column=0, padx=10, pady=10)
btnLampOFF = Button(root, fg="blue", width=8, height=1, text="전등 OFF", font=myFont, command=lambda:cmdBtnClick("L0"))
btnLampOFF.grid(row=1, column=1, padx=10, pady=10)
lblVersion = Label(root, text="AIoT ver. 0.1 by KSYUN, Copyleft 2021")
lblVersion.grid(row=2, column=0, columnspan=2, padx=5, pady=5)
root.mainloop()
arduino.close()
[실습10] 유사한 명령을 람다 함수 인수로 전달
def cmdBtnClick(cmd):
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
명령어 인수 cmd 를 처리하는 함수
btnLampON = Button(root, fg="red", width=8, height=1, text="전등 ON", font=myFont, command=lambda:cmdBtnClick("L1"))
명령어를 람다 함수의 인수로 전달
# 직렬 통신으로 아두이노 전등(L), 에어컨(A), 출입문(D) 제어
from tkinter import *
import tkinter.font
import serial
arduino = serial.Serial('COM3' , 9600)
if arduino.readable():
print(arduino.readline().decode())
root = Tk()
root.title("스마트홈 제어")
# root.geometry("300x200") # 가로 * 세로
myFont = tkinter.font.Font(family="Arial", size=12, weight="bold")
def cmdBtnClick(cmd):
arduino.write(cmd.encode('utf-8'))
if arduino.readable():
state = arduino.readline().decode()
txtState.delete(1.0,"end")
txtState.insert(1.0, "Tx>> "+ cmd + "\nRx<< " + state)
txtState = Text(root, width=20, height=2, font ="Consolas 16", relief="sunken") # 20글자, 2줄
txtState.insert(1.0, " Welcome! \n AIoT ver. 0.1")
txtState.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
btnLampON = Button(root, bg="red", width=10, height=1, text="전등 ON", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("L1"))
btnLampON.grid(row=1, column=0, padx=5, pady=5)
btnLampOFF = Button(root, fg="blue", width=10, height=1, text="전등 OFF", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("L0"))
btnLampOFF.grid(row=1, column=1, padx=5, pady=5)
btnAirON = Button(root, bg="yellow", width=10, height=1, text="에어컨 ON", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("A1"))
btnAirON.grid(row=2, column=0, padx=5, pady=5)
btnAirOFF = Button(root, fg="blue", width=10, height=1, text="에어컨 OFF", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("A0"))
btnAirOFF.grid(row=2, column=1, padx=5, pady=5)
btnDoorON = Button(root, bg="green", width=10, height=1, text="출입문 Open", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("D1"))
btnDoorON.grid(row=3, column=0, padx=5, pady=5)
btnDoorOFF = Button(root, fg="blue", width=10, height=1, text="출입문 Close", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("D0"))
btnDoorOFF.grid(row=3, column=1, padx=5, pady=5)
lblVersion = Label(root, text="AIoT ver. 0.2 by KSYUN, Copyleft 2021")
lblVersion.grid(row=4, column=0, columnspan=2, padx=5, pady=5)
root.mainloop()
arduino.close()
동영상이 재생되지 않을 때 여기 https://youtu.be/xpaSTGQuADw 에서 볼 수 있음.