로보테크AI

융합_로보테크 AI 자율주행 로봇 개발자 과정-26/02/24[Arduino]

steezer 2026. 2. 24. 18:30

프로젝트 구조 변경

guiprj/

├── app.py                     # 프로그램 진입점
├── config.py                  # DB 설정 파일
├── samsung.sql                # 테이블 생성 및 초기 데이터

├── db/
│       ├── connection.py          # DB 연결 관리
│       └── item_repository.py     # items 테이블 CRUD 로직

├── models/
│       └── item.py                # Item 모델 클래스

├── views/
│       ├── login_dialog.py        # 로그인 창
│       ├── main_window.py         # 메인 GUI
│       ├── insert_dialog.py       # 데이터 추가 창
│       ├── update_dialog.py       # 데이터 수정 창
└── └── delete_dialog.py       # 데이터 삭제 창

 

PyQt 디자인 변경

SQL에 데이터 추가

검색, 수정, 정렬 기능 수정

 

app.py

import sys
from PyQt5.QtWidgets import QApplication
from views.login_dialog import LoginDialog
from views.main_window import MainWindow

if __name__ == "__main__":
    app = QApplication(sys.argv)

    login = LoginDialog()
    if login.exec_() == LoginDialog.Accepted:
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    else:
        sys.exit(0)

 

config.py

DB_CONFIG = {
    "host": "localhost",
    "user": "root",
    "password": "0000",
    "database": "samsung",
    "charset": "utf8"
}

 

samsung.sql

DROP TABLE IF EXISTS items;

CREATE TABLE items (
    id INT PRIMARY KEY AUTO_INCREMENT,
    code VARCHAR(10) UNIQUE,
    name VARCHAR(50),
    price INT,
    stock INT
);

INSERT INTO items (code, name, price, stock) VALUES
('1001','Galaxy_S', 945000,15),
('1002','Galaxy_S2', 880000,18),
('1003','Galaxy_S3', 990000,22),
('1004','Galaxy_S4', 957000,19),
('1005','Galaxy_S5', 866000,14),
('1006','Galaxy_S6', 858000,13),
('1007','Galaxy_S6_Edge', 979000,10),
('1008','Galaxy_S7', 836000,16),
('1009','Galaxy_S7_Edge', 935000,12),
('1010','Galaxy_S8', 935000,20),
('1011','Galaxy_S8_Plus', 990000,18),
('1012','Galaxy_S9', 957000,15),
('1013','Galaxy_S9_Plus', 1056000,11),
('1014','Galaxy_S10e', 899800,14),
('1015','Galaxy_S10', 1056000,17),
('1016','Galaxy_S10_Plus', 1155000,12),
('1017','Galaxy_S20', 1248500,13),
('1018','Galaxy_S20_Plus', 1353000,11),
('1019','Galaxy_S20_Ultra', 1595000,9),
('1020','Galaxy_S21', 999900,25),
('1021','Galaxy_S21_Plus', 1199000,16),
('1022','Galaxy_S21_Ultra', 1452000,14),
('1023','Galaxy_S22', 999900,22),
('1024','Galaxy_S22_Plus', 1199000,18),
('1025','Galaxy_S22_Ultra', 1452000,13),
('1026','Galaxy_S23', 1155000,30),
('1027','Galaxy_S23_Plus', 1353000,21),
('1028','Galaxy_S23_Ultra', 1599400,12),
('1029','Galaxy_S24', 1155000,28),
('1030','Galaxy_S24_Plus', 1353000,19),
('1031','Galaxy_S24_Ultra', 1698400,10),
('1032','Galaxy_S25', 1199000,20),
('1033','Galaxy_S25_Plus', 1399000,18),
('1034','Galaxy_S25_Ultra', 1699000,12),
('1035','Galaxy_S26', 1250000,25),
('1036','Galaxy_S26_Plus', 1450000,19),
('1037','Galaxy_S26_Ultra', 1750000,14),
('1101','Galaxy_Note', 946000,7),
('1102','Galaxy_Note2', 1089000,8),
('1103','Galaxy_Note3', 1067000,9),
('1104','Galaxy_Note4', 957000,6),
('1105','Galaxy_Note5', 899800,5),
('1106','Galaxy_Note7_FE', 699600,4),
('1107','Galaxy_Note8', 1094500,7),
('1108','Galaxy_Note9', 1094500,6),
('1109','Galaxy_Note10', 1248500,5),
('1110','Galaxy_Note10_Plus', 1397000,4),
('1111','Galaxy_Note20', 1199000,6),
('1112','Galaxy_Note20_Ultra', 1452000,3),
('1201','Galaxy_Fold', 2398000,5),
('1202','Galaxy_Z_Fold2', 2398000,6),
('1203','Galaxy_Z_Fold3', 1998700,7),
('1204','Galaxy_Z_Fold4', 1998700,6),
('1205','Galaxy_Z_Fold5', 2097700,5),
('1206','Galaxy_Z_Fold6', 2229700,4),
('1207','Galaxy_Z_Fold7', 2290000,6),
('1301','Galaxy_Z_Flip', 1650000,10),
('1302','Galaxy_Z_Flip3', 1254000,14),
('1303','Galaxy_Z_Flip4', 1353000,11),
('1304','Galaxy_Z_Flip5', 1399200,9),
('1305','Galaxy_Z_Flip6', 1485000,7),
('1306','Galaxy_Z_Flip7', 1499000,10),
('1401','Galaxy_A5_2016', 548900,12),
('1402','Galaxy_A7_2017', 598400,14),
('1403','Galaxy_A8_2018', 599500,16),
('1404','Galaxy_A31', 374000,20),
('1405','Galaxy_A32', 374000,18),
('1406','Galaxy_A42_5G', 449900,15),
('1407','Galaxy_A52', 499400,17),
('1408','Galaxy_A53', 599500,19),
('1409','Galaxy_A54', 599500,22),
('1410','Galaxy_A55', 649000,21),
('1411','Galaxy_A73', 699600,10),
('1412','Galaxy_A56', 699000,23),
('1501','Galaxy_M20', 220000,15),
('1502','Galaxy_M12', 198000,17),
('1503','Galaxy_M32', 299000,16),
('1504','Galaxy_M52', 399000,12),
('1601','Galaxy_J5', 298000,12),
('1602','Galaxy_J7', 348000,14);

CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50),
    password VARCHAR(50)
);

INSERT INTO users (username, password)
VALUES ('admin', '1234');

 

connection.py

import pymysql
from config import DB_CONFIG

def get_connection():
    return pymysql.connect(**DB_CONFIG)

 

item_repository.py

from db.connection import get_connection

class ItemRepository:

    def fetch_all(self):
        sql = "SELECT id, code, name, price, stock FROM items ORDER BY id"
        with get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql)
                return cur.fetchall()

    def insert(self, code, name, price, stock):
        sql = "INSERT INTO items (code, name, price, stock) VALUES (%s, %s, %s, %s)"
        try:
            with get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(sql, (code, name, price, stock))
                conn.commit()
            return True
        except:
            return False

    def update(self, item_id, code, name, price, stock):
        sql = """
        UPDATE items
        SET code=%s, name=%s, price=%s, stock=%s
        WHERE id=%s
        """
        try:
            with get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(sql, (code, name, price, stock, item_id))
                conn.commit()
            return True
        except:
            return False

    def delete(self, item_id):
        sql = "DELETE FROM items WHERE id=%s"
        with get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql, (item_id,))
            conn.commit()

    def exists_code(self, code):
        sql = "SELECT COUNT(*) FROM items WHERE code=%s"
        with get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql, (code,))
                count, = cur.fetchone()
                return count > 0

 

item.py

class Item:
    def __init__(self, id, code, name, price, stock):
        self.id = id
        self.code = code
        self.name = name
        self.price = price
        self.stock = stock

 

login_dialog.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from db.connection import get_connection

class LoginDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self.setWindowTitle("로그인")

        self.username = QLineEdit()
        self.password = QLineEdit()
        self.password.setEchoMode(QLineEdit.Password)

        form = QFormLayout()
        form.addRow("아이디", self.username)
        form.addRow("비밀번호", self.password)

        btn = QPushButton("로그인")
        btn.clicked.connect(self.try_login)

        layout = QVBoxLayout()
        layout.addLayout(form)
        layout.addWidget(btn)
        self.setLayout(layout)

    def try_login(self):
        uid = self.username.text().strip()
        pw = self.password.text().strip()

        sql = "SELECT COUNT(*) FROM users WHERE username=%s AND password=%s"

        with get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql, (uid, pw))
                count, = cur.fetchone()

        if count == 1:
            self.accept()
        else:
            QMessageBox.warning(self, "실패", "아이디 또는 비밀번호 오류")

 

main_window.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QHeaderView
from db.item_repository import ItemRepository
from views.insert_dialog import InsertDialog
from views.update_dialog import UpdateDialog
from views.delete_dialog import DeleteDialog


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Samsung")
        self.resize(950, 550)

        self.repo = ItemRepository()

        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        central = QWidget()
        self.setCentralWidget(central)
        main_layout = QVBoxLayout(central)
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(15)

        # 상단 통합 바
        top_layout = QHBoxLayout()

        label = QLabel("검색")
        label.setFixedWidth(40)

        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("상품명 또는 코드 검색...")
        self.search_input.setFixedWidth(300)
        self.search_input.setFixedHeight(28)
        self.search_input.textChanged.connect(self.load_items)

        self.btn_insert = QPushButton("추가")
        self.btn_update = QPushButton("수정")
        self.btn_delete = QPushButton("삭제")

        self.btn_insert.setFixedWidth(80)
        self.btn_update.setFixedWidth(80)
        self.btn_delete.setFixedWidth(80)

        self.btn_insert.clicked.connect(self.open_insert)
        self.btn_update.clicked.connect(self.open_update)
        self.btn_delete.clicked.connect(self.open_delete)

        top_layout.addWidget(label)
        top_layout.addWidget(self.search_input)
        top_layout.addStretch()
        top_layout.addWidget(self.btn_insert)
        top_layout.addWidget(self.btn_update)
        top_layout.addWidget(self.btn_delete)

        # 테이블
        self.table = QTableWidget()
        self.table.setColumnCount(5)
        self.table.setHorizontalHeaderLabels(["ID", "코드", "상품명", "가격", "재고"])

        self.table.setAlternatingRowColors(True)
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        self.table.setSelectionMode(QTableWidget.SingleSelection)
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table.verticalHeader().setVisible(False)
        self.table.setSortingEnabled(True)

        header = self.table.horizontalHeader()

        header.setSectionResizeMode(0, QHeaderView.Fixed)
        self.table.setColumnWidth(0, 50)

        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.Stretch)
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeToContents)

        # 스타일
        self.setStyleSheet("""
            QMainWindow {
                background-color: #e9e9e9;
            }

            QPushButton {
                background-color: #d0d0d0;
                color: black;
                padding: 5px 12px;
                border: 1px solid #a0a0a0;
                border-radius: 0px;
            }

            QPushButton:hover {
                background-color: #c2c2c2;
            }

            QPushButton:pressed {
                background-color: #b0b0b0;
            }

            QTableWidget {
                background-color: white;
                gridline-color: #c8c8c8;
                font-size: 12px;
            }

            QHeaderView::section {
                background-color: #dcdcdc;
                border: 1px solid #b5b5b5;
                font-weight: bold;
                padding: 4px;
            }

            QLineEdit {
                padding: 5px;
                border: 1px solid #b5b5b5;
                background: white;
            }
        """)

        # 레이아웃 적용
        main_layout.addLayout(top_layout)
        main_layout.addWidget(self.table)

        self.load_items()

    # 데이터 로드
    def load_items(self):
        keyword = self.search_input.text().strip().lower()
        rows = self.repo.fetch_all()

        if keyword:
            rows = [
                row for row in rows
                if keyword in row[1].lower() or keyword in row[2].lower()
            ]

        # 정렬 완전 비활성화
        self.table.setSortingEnabled(False)

        self.table.clearContents()
        self.table.setRowCount(len(rows))

        for r, row in enumerate(rows):
            for c, value in enumerate(row):

                item = QTableWidgetItem()

                # ID 컬럼 숫자 정렬 처리
                if c == 0:
                    numeric_value = int(value)
                    item.setData(Qt.EditRole, numeric_value)

                # 가격 숫자 정렬 처리
                elif c == 3:
                    numeric_value = int(value)
                    item.setData(Qt.EditRole, numeric_value)
                    item.setText(f"{numeric_value:,}")

                else:
                    item.setText(str(value))

                if c in (3, 4):
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)

                self.table.setItem(r, c, item)

        # 정렬 활성화
        self.table.setSortingEnabled(True)

    # 다이얼로그
    def open_insert(self):
        dialog = InsertDialog()
        if dialog.exec_() == QDialog.Accepted:
            self.load_items()

    def open_update(self):
        row = self.table.currentRow()
        if row < 0:
            return

        item_id = self.table.item(row, 0).text()
        dialog = UpdateDialog(item_id)
        if dialog.exec_() == QDialog.Accepted:
            self.load_items()

    def open_delete(self):
        row = self.table.currentRow()
        if row < 0:
            return

        item_id = self.table.item(row, 0).text()
        dialog = DeleteDialog(item_id)
        if dialog.exec_() == QDialog.Accepted:
            self.load_items()

 

insert_dialog.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from db.item_repository import ItemRepository


class InsertDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self.setWindowTitle("상품 추가")
        self.repo = ItemRepository()

        self.input_code = QLineEdit()
        self.input_name = QLineEdit()
        self.input_price = QLineEdit()
        self.input_stock = QLineEdit()

        form = QFormLayout()
        form.addRow("코드", self.input_code)
        form.addRow("상품명", self.input_name)
        form.addRow("가격", self.input_price)
        form.addRow("재고", self.input_stock)

        self.btn_ok = QPushButton("추가")
        self.btn_cancel = QPushButton("취소")

        self.btn_ok.clicked.connect(self.insert_item)
        self.btn_cancel.clicked.connect(self.reject)

        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.btn_ok)
        btn_layout.addWidget(self.btn_cancel)

        layout = QVBoxLayout()
        layout.addLayout(form)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def insert_item(self):
        code = self.input_code.text().strip()
        name = self.input_name.text().strip()
        price = self.input_price.text().strip()
        stock = self.input_stock.text().strip()

        if not code or not name:
            QMessageBox.warning(self, "오류", "코드와 상품명은 필수입니다.")
            return

        if not price.isdigit() or not stock.isdigit():
            QMessageBox.warning(self, "오류", "가격과 재고는 숫자만 입력하세요.")
            return

        if self.repo.exists_code(code):
            QMessageBox.warning(self, "오류", "이미 존재하는 코드입니다.")
            return

        ok = self.repo.insert(code, name, int(price), int(stock))

        if ok:
            QMessageBox.information(self, "완료", "추가되었습니다.")
            self.accept()
        else:
            QMessageBox.critical(self, "실패", "추가 중 오류 발생")

 

update_dialog.py

from PyQt5.QtWidgets import *
from db.item_repository import ItemRepository


class UpdateDialog(QDialog):
    def __init__(self, item_id):
        super().__init__()
        self.setWindowTitle("상품 수정")
        self.repo = ItemRepository()
        self.item_id = item_id

        self.input_code = QLineEdit()
        self.input_name = QLineEdit()
        self.input_price = QLineEdit()
        self.input_stock = QLineEdit()

        form = QFormLayout()
        form.addRow("코드", self.input_code)
        form.addRow("상품명", self.input_name)
        form.addRow("가격", self.input_price)
        form.addRow("재고", self.input_stock)

        self.btn_ok = QPushButton("수정")
        self.btn_cancel = QPushButton("취소")

        self.btn_ok.clicked.connect(self.update_item)
        self.btn_cancel.clicked.connect(self.reject)

        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.btn_ok)
        btn_layout.addWidget(self.btn_cancel)

        layout = QVBoxLayout()
        layout.addLayout(form)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

        self.load_data()

    def load_data(self):
        rows = self.repo.fetch_all()
        for row in rows:
            if str(row[0]) == str(self.item_id):
                self.input_code.setText(row[1])
                self.input_name.setText(row[2])
                self.input_price.setText(str(row[3]))
                self.input_stock.setText(str(row[4]))
                break

    def update_item(self):
        code = self.input_code.text().strip()
        name = self.input_name.text().strip()
        price = self.input_price.text().strip()
        stock = self.input_stock.text().strip()

        if not code or not name:
            QMessageBox.warning(self, "오류", "코드와 상품명은 필수입니다.")
            return

        if not price.isdigit() or not stock.isdigit():
            QMessageBox.warning(self, "오류", "가격과 재고는 숫자만 입력하세요.")
            return

        ok = self.repo.update(
            self.item_id,
            code,
            name,
            int(price),
            int(stock)
        )

        if ok:
            QMessageBox.information(self, "완료", "수정되었습니다.")
            self.accept()
        else:
            QMessageBox.critical(self, "실패", "수정 중 오류 발생")

 

delete_dialog.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from db.item_repository import ItemRepository


class DeleteDialog(QDialog):
    def __init__(self, item_id):
        super().__init__()

        self.setWindowTitle("상품 삭제")
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self.repo = ItemRepository()
        self.item_id = item_id

        # 안내 문구
        label = QLabel("정말 삭제하시겠습니까?")
        label.setAlignment(Qt.AlignCenter)

        # 버튼
        self.btn_ok = QPushButton("삭제")
        self.btn_cancel = QPushButton("취소")

        self.btn_ok.setFixedWidth(80)
        self.btn_cancel.setFixedWidth(80)

        self.btn_ok.clicked.connect(self.delete_item)
        self.btn_cancel.clicked.connect(self.reject)

        # 버튼 레이아웃
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        btn_layout.addWidget(self.btn_ok)
        btn_layout.addWidget(self.btn_cancel)

        # 메인 레이아웃
        layout = QVBoxLayout()
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(15)
        layout.addWidget(label)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def delete_item(self):
        self.repo.delete(self.item_id)
        QMessageBox.information(self, "완료", "삭제되었습니다.")
        self.accept()

 

.gitignore

.venv/
__pycache__/
*.pyc
.idea/

.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

.idea/**/aws.xml

.idea/**/contentModel.xml

.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

.idea/**/gradle.xml
.idea/**/libraries

cmake-build-*/

.idea/**/mongoSettings.xml

*.iws

out/

.idea_modules/

atlassian-ide-plugin.xml

.idea/replstate.xml

.idea/sonarlint/

com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

.idea/httpRequests

.idea/caches/build_file_checksums.ser

.idea/**/sonarlint/

.idea/**/sonarIssues.xml

.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/

.idea/$CACHE_FILE$

.idea/codestream.xml

.idea/**/azureSettings.xml
*.py[cod]
*$py.class

*.so

.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

*.manifest
*.spec

pip-log.txt
pip-delete-this-directory.txt

htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

*.mo
*.pot

*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

instance/
.webassets-cache

.scrapy

docs/_build/

.pybuilder/
target/

.ipynb_checkpoints

profile_default/
ipython_config.py

.pdm.toml

__pypackages__/

celerybeat-schedule
celerybeat.pid

*.sage.py

.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

.spyderproject
.spyproject

.ropeproject

/site

.mypy_cache/
.dmypy.json
dmypy.json

.pyre/

.pytype/

cython_debug/

poetry.toml

.ruff_cache/

pyrightconfig.json

아두이노

아두이노(Arduino)는 마이크로컨트롤러 기반의 오픈소스 하드웨어 플랫폼

작은 컴퓨터 역할을 하는 보드에 다양한 센서와 부품을 연결하여 프로그램을 실행할 수 있는 도구

 

오픈소스 하드웨어: 회로도와 소프트웨어가 모두 공개되어 있어 누구나 자유롭게 학습, 응용, 개발 가능

확장성: 센서(온도, 습도, 조도, 거리 등)와 액추에이터(LED, 모터, 부저 등)를 자유롭게 연결할 수 있어, 단순한 LED 깜빡임부터 사물인터넷(IoT) 프로젝트까지 구현이 가능

쉬운 프로그래밍: 아두이노 IDE를 통해 간단한 C/C++ 기반 코드로 제어 가능

교육 및 메이커 활용: 전자·코딩 교육, 창의융합 수업, 프로토타입 제작에 널리 쓰

 

https://www.arduino.cc/en/software/#ide

 

https://www.arduino.cc/en/software/#ide

 

www.arduino.cc

// 내장 LED를 1초마다 깜빡이기

#define LED 13

void setup() {
  pinMode(LED, OUTPUT); // LED_BUILTIN = D13
}

void loop() {
  digitalWrite(LED, HIGH); // LED 켜기
  delay(1000);                     // 1초 대기
  digitalWrite(LED, LOW);  // LED 끄기
  delay(1000);                     // 1초 대기
}

ATMEGA328P: 마이크로 컨트롤러/사용자의 코드를 처리하는 칩

 

전자회로 기초


전압

전기를 밀어주는 힘

물에 비유하면, 전압은 물탱크의 수압과 같음

수압이 높을수록 물이 더 세게 흐르듯, 전압이 높을수록 전류가 잘 흐름

(아두이노는 주로 5V 또는 3.3V 전압을 사용)

전류

전자의 흐름을 의미

물에 비유하면, 전류는 물이 실제로 흐르는 양

저항

전류의 흐름을 방해하는 정도

물에 비유하면, 저항은 흐르는 물을 가로막는 바위 같은 역할

전류를 안전한 수준으로 줄여주기 위해 주로 사용

 

옴의 법칙

V=IR

전압, 전류, 저항의 관계를 나타내는 공식

 

LED 1개 깜빡거리게 하기

void setup(){
  pinMode(3, OUTPUT);
}

void loop(){
  digitalWrite(3, HIGH);
  delay(1000);
  digitalWrite(3, LOW);
  delay(1000);
}

 

3색 LED 제어

다이오드: 한쪽 방향으로 전류가 흐르도록 제어하는 반도체 소자

#define LED_B 3       // B의 핀 번호 3
#define LED_G 4       // G의 핀 번호 4
#define LED_R 5       // R의 핀 번호 5
 
void setup() {
  pinMode(LED_B, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_R, OUTPUT);
}
 
void loop() {
  // 빨강
  digitalWrite(LED_R, HIGH);
  digitalWrite(LED_G, LOW);
  digitalWrite(LED_B, LOW);
  delay(1000);

  // 초록
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_G, HIGH);
  digitalWrite(LED_B, LOW);
  delay(1000);

  // 파랑
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_G, LOW);
  digitalWrite(LED_B, HIGH);
  delay(1000);
}

 

#define LED_B 3       // B의 핀 번호 3
#define LED_G 4       // G의 핀 번호 4
#define LED_R 5       // R의 핀 번호 5
 
void setup() {
  pinMode(LED_B, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_R, OUTPUT);
}
 
void loop() {
  // 노랑 (빨강 + 초록)
  digitalWrite(LED_R, HIGH);
  digitalWrite(LED_G, HIGH);
  digitalWrite(LED_B, LOW);
  delay(1000);

  // 하늘색 (초록 + 파랑)
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_G, HIGH);
  digitalWrite(LED_B, HIGH);
  delay(1000);

  // 보라색 (빨강 + 파랑)
  digitalWrite(LED_R, HIGH);
  digitalWrite(LED_G, LOW);
  digitalWrite(LED_B, HIGH);
  delay(1000);
}

 

PWM 제어

PWM(Pulse Width Modulation, 펄스 폭 변조)은 디지털 출력으로 아날로그처럼 강약을 표현하는 방법

스케치 프로그램의 analogWrite(pin, 값) 함수는 전압의 크기를 0~255 사이의 값으로 제어하는 함수로 전압의 강약을 조절

 

시리얼 통신

보드와 PC, 또는 다른 장치 간에 데이터를 주고받는 방법

통신 속도를 설정할 때는 Serial.begin(보레이트); 함수를 사용

다른 장치로 데이터를 보낼 때는 Serial.print() 또는 Serial.println() 함수를 사용

 

void setup () {
  Serial.begin(9600);
}
 
void loop() {
  int val = analogRead(A5);     
  Serial.println(val);          
  delay(500);
}

실습 과제

키트에 포함된 포토센서가 무엇인지, 연결은 어떻게 해야 하는지 조사해보고, 실제로 조도센서의 값을 시리얼모니터에서 실시간 확인하는 프로젝트를 진행해보세요. 힌트는? 포토센서를 가리켜 ‘조도센서’라고도 합니다.

 

포토센서: 빛의 세기에 따라 전기적 특성이 변하는 센서(포토레지스터,LDR)

어두울수록 저항값 높음

밝을수록 저항값 낮음

 

아두이노는 전압을 읽지만 LDR은 저항이 변함

ㄴ전압 분배 회로 필요: Vout = Vin * R2/(R1+R2)

ㄴLDR과 일반 전항을 직렬로 연결해 중간 지점 전압을 아두이노 A핀에서 읽음

 

풀업

밝아질수록 LDR 저항 낮아짐

출력 전압 감소

analogRead 값 감소

밝으면 값 작아지고 어두우면 값 커짐

 

풀다운

밝아질수록 LDR 저항 낮아짐

출력 전압 감소

analogRead값 증가

밝으면 값 커지고 어두우면 값 작아짐

직관적이라 가장 많이 사용

 

 

구분 풀업 풀다운
LDR 위치 위(5V쪽) 아래(GND쪽)
밝아질 때 값 감소 증가
사용 빈도 적음 많음
직관성 낮음 높음

 

저항값으로 보통 10kΩ 사용

void setup(){
  Serial.begin(9600);
}
void loop(){
  int readValue = analogRead(A0);
  Serial.println(readValue);
}