# main.py - "민심 온도계" 최종 (DHT 센서 기반 온도/습도 측정)
from machine import Pin, I2C
from time import sleep, sleep_ms, sleep_us # sleep_ms, sleep_us 사용
import random
from dht import DHT # 🚨 dht.py 파일의 DHT 클래스 임포트 (dht.py가 필요합니다.)
# **********************************************
# * 1. LCD 드라이버 코드 (I2cLcd 클래스) *
# **********************************************
# 외부 라이브러리(pico_i2c_lcd) 의존성 제거, 코드를 인라인으로 포함
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_FUNCTIONSET = 0x20
LCD_SETDDRAMADDR = 0x80
MASK_RS = 0x01
MASK_E = 0x04
SHIFT_BACKLIGHT = 3
class I2cLcd:
"""I2C 통신을 통해 LCD를 제어하는 클래스"""
def __init__(self, i2c, i2c_addr, num_lines, num_columns):
self.i2c = i2c
self.i2c_addr = i2c_addr
self.num_lines = num_lines
self.num_columns = num_columns
self.backlight = (1 << SHIFT_BACKLIGHT)
self.display_data = 0
# LCD 초기화 시퀀스
self.hal_write(0)
sleep_ms(20)
self.hal_write_init_nibble(0x03)
sleep_ms(5)
self.hal_write_init_nibble(0x03)
sleep_ms(5)
self.hal_write_init_nibble(0x03)
sleep_ms(5)
self.hal_write_init_nibble(0x02)
self.command(LCD_FUNCTIONSET | 0x08)
self.command(LCD_DISPLAYCONTROL | 0x04)
self.clear()
self.command(LCD_ENTRYMODESET | 0x02)
def hal_write_init_nibble(self, nibble):
self.hal_write(nibble << 4)
self.hal_pulse_enable()
def hal_write(self, data):
data |= self.backlight
# LCD 통신 안정화를 위한 재시도 로직
try:
self.i2c.writeto(self.i2c_addr, bytearray([data]))
except OSError:
sleep_us(100)
try:
self.i2c.writeto(self.i2c_addr, bytearray([data]))
except OSError:
pass
def hal_pulse_enable(self):
self.hal_write(self.display_data | MASK_E)
sleep_us(1)
self.hal_write(self.display_data)
sleep_us(1)
def command(self, cmd):
# 상위 4비트 전송
self.display_data = cmd & 0xF0
self.hal_write(self.display_data)
self.hal_pulse_enable()
# 하위 4비트 전송
self.display_data = (cmd << 4) & 0xF0
self.hal_write(self.display_data)
self.hal_pulse_enable()
def write(self, data):
# 데이터 전송 (RS 비트 활성화)
# 상위 4비트 전송
self.display_data = data & 0xF0 | MASK_RS
self.hal_write(self.display_data)
self.hal_pulse_enable()
# 하위 4비트 전송
self.display_data = (data << 4) & 0xF0 | MASK_RS
self.hal_write(self.display_data)
self.hal_pulse_enable()
def clear(self):
self.command(LCD_CLEARDISPLAY)
sleep_ms(2)
def set_cursor(self, col, row):
row_offsets = [0x00, 0x40]
self.command(LCD_SETDDRAMADDR | (col + row_offsets[row]))
def putstr(self, s):
for char in s:
self.write(ord(char))
# **********************************************
# * 2. 메인 로직 (프로젝트의 핵심) *
# **********************************************
# 핀 설정 및 초기화
lcd = None
I2C_ADDR = None
# --- I2C LCD 초기화 시도 ---
try:
# I2C 통신 초기화 (GP0=SDA, GP1=SCL)
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
sleep_ms(1)
# I2C LCD 주소 0x27 또는 0x3F를 순차적으로 스캔
possible_addrs = [0x27, 0x3F]
for addr in possible_addrs:
try:
lcd = I2cLcd(i2c, addr, 2, 16)
lcd.clear()
lcd.putstr("LCD Init OK")
I2C_ADDR = addr
print(f"I2C LCD 주소 0x{addr:x}로 성공적으로 설정됨")
sleep(1)
break
except OSError:
continue
if I2C_ADDR is None:
print("Error: LCD I2C 장치를 찾을 수 없습니다. 연결을 확인하세요.")
lcd = None
except Exception as e:
print(f"LCD 초기화 오류 발생: {e}")
lcd = None
# 🚨 DHT 센서 인스턴스화 (GP15 핀 사용, DHT22 타입)
# dht.py 파일의 DHT 클래스 사용에 맞춤
dht_sensor = DHT(Pin(15, Pin.IN, Pin.PULL_UP), sensor_type=22)
# 버튼 인스턴스화 (GP14 핀)
button = Pin(14, Pin.IN, Pin.PULL_DOWN)
# --- 로직 변수 ---
mode = 0
modes = ["정책 만족도", "정부 신뢰도", "정치 참여도"]
last_button_state = 0
temp = 0.0
if lcd:
lcd.clear()
lcd.putstr("Political\nThermometer")
sleep(1)
print("--- 민심 온도계 작동 시작 ---")
while True:
# 1. 버튼 입력 처리 (모드 전환)
current_button_state = button.value()
if current_button_state == 1 and last_button_state == 0:
mode = (mode + 1) % len(modes)
if lcd: lcd.clear()
print(f"모드 변경됨: {modes[mode]}")
sleep(0.3)
last_button_state = current_button_state
# 2. DHT22 측정 및 에러 처리 (dht.py의 measure/get_temperature 사용)
try:
# measure()가 성공(True)을 반환해야 값을 가져옴
if dht_sensor.measure():
temp = dht_sensor.get_temperature()
else:
# 측정 실패 시 에러 발생
raise OSError("DHT measurement failed")
except OSError as e:
print(f"센서 측정 오류: {e}. 재시도합니다.")
if lcd:
lcd.set_cursor(0, 0)
lcd.putstr(f"{modes[mode]:<16}")
lcd.set_cursor(0, 1)
lcd.putstr("Sensor Error! ")
sleep(2)
continue
# 3. LCD 출력 및 메시지
if lcd:
lcd.set_cursor(0, 0)
lcd.putstr(f"{modes[mode]:<16}")
message_line = ""
# 4. 정치적 메시지 출력 로직 (온도에 따른 민심 해석)
if temp <= 25:
message_line = "냉담: 정책 소통 필요"
elif temp <= 30: