ich bin sowohl neu in diesem Forum, als auch noch relativ unerfahren was Python und Progammierung angeht.
Ich habe mir einen Hobbybaukasten (FNK0025-Freenove RFID Starter Kit for Raspberry Pi) und einfach mal losgelegt.
Nun habe ich mir einen Schaltkreis aufgebaut, der an sich super funktioniert, allerdings mit der Dauer immer langsamer wird. Ich nutze einen Raspberry Zero mit aktuellster Firmware. Das gleiche Problem tritt aber auch bei einem Raspberry Pi 4 mit 4GB auf.
Zum generellen Aufbau:
ich habe eine RGB LED Lampe verbaut, jeder der Dioden-Pin ist mit einem 220 Ohm Widerstand verknüpft. Ein LCD Display ist angeschlossen, der durchgehend "Hello World" ausgibt, bis eine Aktion eintritt. Dieser liegt an 5V und GND, sowie SDA und SCL. Ein Ultraschallsensor (HC SR04) ist verbaut, der permanent eine Distanz von bis zu 220 cm misst, dieser soll Alarm geben, wenn sich etwas in der Reichtweite von 1 cm bis 10 cm vor dem Sensor befindet. Dabei soll die RGB von grün auf rot wechselt, der Display wechselt den Schriftzug und ein Buzzer wird auf High gesetzt, gibt also einen Warnton aus. Vor dem Echo-Pin ist ein 1k Ohm Widerstand gelegt, von diesem Potential ist ebenfalls ein Kabel mit 2k Ohm an GND. Zusätzlich habe ich einen Push Button eingebaut, bei einmaligem Drücken blinkt die LED blau und es wird mit der Picamera ein Foto gemacht und gespeichert. Sollte der Button mehrfach gedrückt werden, so wird ein die LED auf blau gesetzt und ein Video aufgenommen. Auch bei diesen beiden Aktion verändert sich der Schriftzug der LCD Anzeige.
Der Aufbau und die Parametrierung der Widerstand ist alles aus der Anleitung übernommen, weshalb ich da wenig Fehlerpotential sehe.
Nun zu meinem Problem:
Die erste Zeit läuft dieses Skript einwandfrei, weshalb ich eine fehlerhafte Verkabelung ausschließe. Der eingebaute Ultraschallsensor besitzt beim Starten des Skriptes nahezu gar keine Verzögerung, später ist jedoch ein leichter Delay sichtbar. Schlimmer ist jedoch die Funktion des eingebauten Push-Buttons. Durch die Funktionen ist gegeben, dass dieser beim Einmaligen drücken 1s abwartet und die Knopfdrücke zählt, danach geht es zu einer Fallunterscheidung, ob nur 1 mal gedrückt wurde -> Foto oder ob mehrfach gedrückt wurde -> Video. Lasse ich dieses Skript einige Zeit laufen, dann verzögert sich die Reaktionszeit zwischen Knopfdruck und Foto (bzw. Aufleuchten der dazugehörigen LED Farbe). Ab einer Laufzeit von über 1,5 h ist die Verzögerung dermaßen groß, dass kein Foto oder Video mehr aufgenommen werden kann.
Gibt es eine Art temporären Buffer, den das Programm anlegt, welcher mit der Zeit anwächst und somit das Programm verlangsamt? Wie könnte ich den wieder leeren? Bis auf die gespeicherten Fotos/ Videos muss nichts dauerhaft gespeichert werden. Oder habe ich einen Fehler im Skript, der meinen Loop nach und nach zum erliegen bringt. Ich würde für Hilfe und Anregungen sehr dankbar.
Mein Code:
Code: Alles auswählen
from PCF8574 import PCF8574_GPIO
from Adafruit_LCD1602 import Adafruit_CharLCD
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
import os
import smbus
import datetime
pins = [11, 12, 13] # define the pins for R:11,G:12,B:13 of a RGB LED
trigPin = 16 #Trigger pin of the ultrasonic sensor
echoPin = 18 #Echo Pin of the ultrasonic sensor
buzzerPin = 15 # define buzzerPin
MAX_DISTANCE = 220 # define the maximum measuring distance, unit: cm
timeOut = MAX_DISTANCE*60 # calculate timeout according to the maximum measuring distance
sw_in = 22 #GPIO 25 Data pin of the push Button
camera = PiCamera()
def setup():
global pwmRed,pwmGreen,pwmBlue, maxdistance
maxdistance=10 #max distance for the ultrasonic sensor until the alert comes
GPIO.setmode(GPIO.BOARD) # use PHYSICAL GPIO Numbering
GPIO.setup(pins, GPIO.OUT) # set RGBLED pins to OUTPUT mode
GPIO.output(pins, GPIO.HIGH) # make RGBLED pins output HIGH level
GPIO.setup(trigPin, GPIO.OUT) # set trigPin to OUTPUT mode
GPIO.setup(echoPin, GPIO.IN) # set echoPin to INPUT mode
GPIO.setup(buzzerPin, GPIO.OUT) # set buzzerPin to OUTPUT mode
GPIO.setup(sw_in,GPIO.IN,pull_up_down=GPIO.PUD_UP) #set Push Button as Input
GPIO.add_event_detect(sw_in,GPIO.FALLING)
pwmRed = GPIO.PWM(pins[0], 2000) # set PWM Frequence to 2kHz
pwmGreen = GPIO.PWM(pins[1], 2000) # set PWM Frequence to 2kHz
pwmBlue = GPIO.PWM(pins[2], 2000) # set PWM Frequence to 2kHz
pwmRed.start(0) # set initial Duty Cycle to 0
pwmGreen.start(0)
pwmBlue.start(0)
def setColor(r_val,g_val,b_val):
pwmRed.ChangeDutyCycle(r_val)
pwmGreen.ChangeDutyCycle(g_val)
pwmBlue.ChangeDutyCycle(b_val)
def blink():
r=0
g=0
b=0
setColor(r,g,b)
time.sleep(.05)
r=0
g=0
b=100
setColor(r,g,b)
time.sleep(.05)
return
def pulseIn(pin,level,timeOut): # obtain pulse time of a pin under timeOut
t0 = time.time()
while(GPIO.input(pin) != level):
if((time.time() - t0) > timeOut*0.000001):
return 0;
t0 = time.time()
while(GPIO.input(pin) == level):
if((time.time() - t0) > timeOut*0.000001):
return 0;
pulseTime = (time.time() - t0)*1000000
return pulseTime
def getSonar(): # get the measurement results of ultrasonic module,with unit: cm
GPIO.output(trigPin,GPIO.HIGH) # make trigPin output 10us HIGH level
time.sleep(0.00001) # 10us
GPIO.output(trigPin,GPIO.LOW) # make trigPin output LOW level
pingTime = pulseIn(echoPin,GPIO.HIGH,timeOut) # read plus time of echoPin
distance = pingTime * 340.0 / 2.0 / 10000.0 # calculate distance with sound speed 340m/s
return distance
def loop():
mcp.output(3,1) # turn on LCD backlight
lcd.begin(16,2) # set number of LCD lines and columns
while(True):
lcd.setCursor(0,0) # set cursor position
lcd.message( 'Hello World' )
distance = getSonar() # get distance
#print ("The distance is : %.2f cm"%(distance))
r=0
g=100
b=0
setColor(r,g,b) #set random as a duty cycle value
GPIO.output(buzzerPin,GPIO.LOW)
if distance < maxdistance:
time.sleep(0.1)
distance = getSonar()
if distance < maxdistance:
if distance > 1.0:
r=100
g=0
b=0
setColor(r,g,b)
#GPIO.output(buzzerPin,GPIO.HIGH)
lcd.clear()
lcd.setCursor(0,0) # set cursor position
lcd.message( 'Attention! \n' )# display CPU temperature
lcd.message( 'Keep distance' ) # display the time
time.sleep(0.5)
lcd.clear()
#print ('r=%d, g=%d, b=%d ' %(r ,g, b))
if GPIO.event_detected(sw_in): #geht rein bei falling edge, also beim drücken des knopfes
r=100
g=100
b=100
setColor(r,g,b)
GPIO.remove_event_detect(sw_in)
now = time.time()
count = 1
GPIO.add_event_detect(sw_in,GPIO.FALLING)
while time.time() < now + 1.0:
if GPIO.event_detected(sw_in):
count +=1
if count <= 1:
blink()
blink()
blink()
print("picture will now be captured..")
lcd.clear()
lcd.setCursor(0,0)
lcd.message( 'Picture will \n' )
lcd.message( 'be captured..' )
camera.capture('/test/' + datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S') + '.png')
blink()
blink()
blink()
GPIO.remove_event_detect(sw_in)
GPIO.add_event_detect(sw_in,GPIO.FALLING)
lcd.clear()
else:
print("start recording...")
r=0
g=0
b=100
setColor(r,g,b)
lcd.clear()
lcd.setCursor(0,0)
lcd.message( 'Video is \n' )
lcd.message( 'recording..' )
camera.resolution = (640, 480)
camera.start_recording('/test/' + datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S') + '.h264')
camera.wait_recording(5)
camera.stop_recording()
lcd.clear()
def destroy():
pwmRed.stop()
pwmGreen.stop()
pwmBlue.stop()
GPIO.cleanup()
lcd.clear()
PCF8574_address = 0x27 # I2C address of the PCF8574 chip.
PCF8574A_address = 0x3F # I2C address of the PCF8574A chip.
# Create PCF8574 GPIO adapter.
try:
mcp = PCF8574_GPIO(PCF8574_address)
except:
try:
mcp = PCF8574_GPIO(PCF8574A_address)
except:
print ('I2C Address Error !')
exit(1)
# Create LCD, passing in MCP GPIO adapter.
lcd = Adafruit_CharLCD(pin_rs=0, pin_e=2, pins_db=[4,5,6,7], GPIO=mcp)
if __name__ == '__main__': # Program entrance
print ('Program is starting...')
setup()
try:
loop()
except KeyboardInterrupt: # Press ctrl-c to end the program.
destroy() # release GPIO resource
Code: Alles auswählen
import smbus
import time
class PCF8574_I2C(object):
OUPUT = 0
INPUT = 1
def __init__(self,address):
# Note you need to change the bus number to 0 if running on a revision 1 Raspberry Pi.
self.bus = smbus.SMBus(1)
self.address = address
self.currentValue = 0
self.writeByte(0) #I2C test.
def readByte(self):#Read PCF8574 all port of the data
#value = self.bus.read_byte(self.address)
return self.currentValue#value
def writeByte(self,value):#Write data to PCF8574 port
self.currentValue = value
self.bus.write_byte(self.address,value)
def digitalRead(self,pin):#Read PCF8574 one port of the data
value = readByte()
return (value&(1<<pin)==(1<<pin)) and 1 or 0
def digitalWrite(self,pin,newvalue):#Write data to PCF8574 one port
value = self.currentValue #bus.read_byte(address)
if(newvalue == 1):
value |= (1<<pin)
elif (newvalue == 0):
value &= ~(1<<pin)
self.writeByte(value)
def loop():
mcp = PCF8574_I2C(0x27)
while True:
#mcp.writeByte(0xff)
mcp.digitalWrite(3,1)
print ('Is 0xff? %x'%(mcp.readByte()))
time.sleep(1)
mcp.writeByte(0x00)
#mcp.digitalWrite(7,1)
print ('Is 0x00? %x'%(mcp.readByte()))
time.sleep(1)
class PCF8574_GPIO(object):#Standardization function interface
OUT = 0
IN = 1
BCM = 0
BOARD = 0
def __init__(self,address):
self.chip = PCF8574_I2C(address)
self.address = address
def setmode(self,mode):#PCF8574 port belongs to two-way IO, do not need to set the input and output model
pass
def setup(self,pin,mode):
pass
def input(self,pin):#Read PCF8574 one port of the data
return self.chip.digitalRead(pin)
def output(self,pin,value):#Write data to PCF8574 one port
self.chip.digitalWrite(pin,value)
def destroy():
bus.close()
if __name__ == '__main__':
print ('Program is starting ... ')
try:
loop()
except KeyboardInterrupt:
destroy()
Code: Alles auswählen
from time import sleep
class Adafruit_CharLCD(object):
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO=None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db
self.GPIO.setmode(GPIO.BCM) #GPIO=None use Raspi PIN in BCM mode
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)
for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)
self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right
self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE
# Initialize to default text direction (for romance languages)
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode
self.clear()
def begin(self, cols, lines):
if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
def home(self):
self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!
def clear(self):
self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time
def setCursor(self, col, row):
self.row_offsets = [0x00, 0x40, 0x14, 0x54]
if row > self.numlines:
row = self.numlines - 1 # we count rows starting w/0
self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
def noDisplay(self):
""" Turn the display off (quickly) """
self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def display(self):
""" Turn the display on (quickly) """
self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noCursor(self):
""" Turns the underline cursor off """
self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def cursor(self):
""" Turns the underline cursor on """
self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noBlink(self):
""" Turn the blinking cursor off """
self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def blink(self):
""" Turn the blinking cursor on """
self.displaycontrol |= self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)
def leftToRight(self):
""" This is for text that flows Left to Right """
self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def autoscroll(self):
""" This will 'right justify' text from the cursor """
self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def noAutoscroll(self):
""" This will 'left justify' text from the cursor """
self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def write4bits(self, bits, char_mode=False):
""" Send command to LCD """
self.delayMicroseconds(1000) # 1000 microsecond sleep
bits = bin(bits)[2:].zfill(8)
self.GPIO.output(self.pin_rs, char_mode)
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)
self.pulseEnable()
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4, 8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)
self.pulseEnable()
def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)
def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle
def message(self, text):
""" Send string to LCD. Newline wraps to second line"""
for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char), True)
if __name__ == '__main__':
lcd = Adafruit_CharLCD()
lcd.clear()
lcd.message(" Adafruit 16x2\n Standard LCD")
