Dziś chciałbym zaprezentować moduł służący do sterowania 16-ma serwomechanizmami z wykorzystaniem magistrali i2c. Układem wykonawczym jest PCA9685, który jest scalonym 16 kanałowym generatorem PWM o rozdzielczości 12 bitów. Prezentowany moduł posiada złącza typu goldpin do których można wpiąć bezpośrednio modelarskie wtyczki serwomechanizmów. Zaletą układu jest możliwość pracy zarówno w standardach 3v3 i 5V zależnie od zasilania ale co najważniejsze: serwomechanizmy zasilane są niezależnie napięciem do 6V. Z noty producenta możemy wyczytać również, że zakres regulacji PWM wynosi od 40 do 1000Hz. Prezentowany moduł możemy kupić za mniej niż 2$. My wykorzystamy nasz PCA9685 do sterowania LED-bara, czyli listwy diod LED. Oczywiście nic nie stoi na przeszkodzie by zasilać stopnie mocy i przykładowo wysterować całe taśmy LED
Układ:
Sposób podłączenia naszego modułu jest następujący: goldpiny poszczególnych kanałów PWM podłączamy do katod diod LED. Anody zaś przez rezystory ograniczające (u mnie jest to 300 Ohm przy zasilaniu 3V3) do zasilania układu... jeśli potrzebny będzie schemat, proszę o informacje
Program sterujący
Zmierzenie się z tematem nie jest trywialne ze względu na stopień skomplikowania instrukcji serwisowej (sic!), jednak udało ni się w wystarczającym stopniu rozszyfrować rejestry i ich znaczenie. Program zasadniczo wyjaśnia tok postępowania, konfiguracji i sterowania układem, jednak jeśli oczekujesz większej swobody - odsyłam do wnikliwej analizy serwisówki.
Code: Select all
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
from I2C import Device
import smbus
import os
import time
#Register defines from data sheet
PCA9685_MODE1 = 0x00 # location for Mode1 register address
PCA9685_MODE2 = 0x01 # location for Mode2 reigster address
PCA9685_LED0 = 0x06 # location for start of LED0 register
PCA9685_LED0_OFF= 0x08 # location for start of LED0_OFF register
PCA9685_ALL_LED_ON = 0xfa # enable all LEDs
PCA9685_ALL_LED_OFF = 0xfc # disable all LEDs
PCA9685_PRE_SCALE = 0xfe # PWM frequency PRE_SCALE register
# Details regarding MODE1_REG
PCA_MODE1_ALLCALL = 0b00000001
PCA_MODE1_SLEEP = 0b00010000
PCA_MODE1_AI = 0b00100000
PCA_MODE1_SOFTRESET = 0b10000000
#The default I2C address
PCA9685_I2CADDR_DEFAULT = 0x40
# PCA9685 Address:
ADDRESSpca = PCA9685_I2CADDR_DEFAULT
# I2C BUS: 1 - for CT, 4 - for PC with Ch341A Interface
BUS = 1
#BUS = 4
# initialize I2C BUS
pca=Device(ADDRESSpca, BUS)
#functions:
def initPCA ():
""" Initialize PCA9685. For PWM = 1000Hz PRE_SCALE = 5 = (25000000/(4096x1000)-1) """
time.sleep(0.1)
pca.write8(PCA9685_MODE1,(0x00 |PCA_MODE1_ALLCALL | PCA_MODE1_SLEEP)) # SLLEP mode is necessary in order to set PRE_SCALE Register
pca.write8(PCA9685_PRE_SCALE,5) # PWM freq = 1000Hz
pca.write8(PCA9685_MODE1,(0x00 |PCA_MODE1_ALLCALL | PCA_MODE1_SOFTRESET)) # comeback to NORMAL MODE with SOFTRESET possibility
pca.write8(PCA9685_MODE2,0b00010000) # set output mode to inverted
state = pca.readU8(PCA9685_MODE1)
return state
def readLEDonValue (LEDnumber):
""" Read LEDon value """
if (LEDnumber >= 0 and LEDnumber <16):
LEDonLSB = pca.readU8(PCA9685_LED0 +4*LEDnumber)
LEDonMSB = pca.readU8((PCA9685_LED0 +4*LEDnumber)+1)
value = LEDonMSB*256 + LEDonLSB
return value
else:
return "Wrong LED number - readLEDonValue()"
def readLEDoffValue (LEDnumber):
""" Read LEDoff value """
if (LEDnumber >= 0 and LEDnumber <16):
LEDoffLSB = pca.readU8(PCA9685_LED0_OFF +4*LEDnumber)
LEDoffMSB = pca.readU8((PCA9685_LED0_OFF +4*LEDnumber)+1)
value = LEDoffMSB*256 + LEDoffLSB
return value
else:
return "Wrong LED number - readLEDoffValue()"
def writeLED (LEDnumber, LEDon, LEDoff):
""" LEDon and LEDoff are 12bit values (0-4095) """
if (LEDnumber >= 0 and LEDnumber <16):
if (LEDon < 0 and LEDon > 0x1000):
LEDon = 0x1000
if (LEDoff < 0 and LEDoff > 0x1000):
LEDoff = 0x1000
LEDonMSB = (LEDon & 0b1111111100000000) >> 8
LEDonLSB = LEDon & 0b0000000011111111
LEDoffMSB = (LEDoff & 0b1111111100000000) >> 8
LEDoffLSB = LEDoff & 0b0000000011111111
pca.write8(PCA9685_LED0 + 4*LEDnumber,LEDonLSB)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+1,LEDonMSB)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+2,LEDoffLSB)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+3,LEDoffMSB)
else:
return "Wrong LED number - writeLED()"
def setLEDon (LEDnumber):
""" Set LED ON (Full Light) """
pca.write8(PCA9685_LED0 + 4*LEDnumber,0x00)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+1,0x10)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+2,0x00)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+3,0x00)
def setLEDoff (LEDnumber):
""" Set LED off """
pca.write8(PCA9685_LED0 + 4*LEDnumber,0x00)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+1,0x00)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+2,0x00)
pca.write8((PCA9685_LED0 + 4*LEDnumber)+3,0x10)
#MAIN:
state = initPCA()
#print "MODE1: ", hex(state)
#print "PRESCALLER:", hex(pca.readU8(PCA9685_PRE_SCALE))
time.sleep(3)
for i in range(0,10):
setLEDoff(i)
for i in range(0,10):
setLEDon(i)
time.sleep(.1)
for i in range(0,10):
setLEDoff(i)
time.sleep(.1)
for i in range(0,10):
setLEDon(i)
time.sleep(.1)
time.sleep(2)
#for i in range(0,10):
# setLEDoff(i)
# time.sleep(.10)
writeLED(0,0x001,0x000)
writeLED(1,0x200,0x000)
writeLED(2,0x400,0x000)
writeLED(3,0x600,0x000)
writeLED(4,0x800,0x000)
writeLED(5,0xa00,0x000)
writeLED(6,0xc00,0x000)
writeLED(7,0xe00,0x000)
writeLED(8,0xf00,0x000)
writeLED(9,0xf80,0x000)
time.sleep(3)
writeLED(9,0x001,0x000)
writeLED(8,0x200,0x000)
writeLED(7,0x400,0x000)
writeLED(6,0x600,0x000)
writeLED(5,0x800,0x000)
writeLED(4,0xa00,0x000)
writeLED(3,0xc00,0x000)
writeLED(2,0xe00,0x000)
writeLED(1,0xf00,0x000)
writeLED(0,0xf80,0x000)
time.sleep(3)
for i in range(0,10):
setLEDoff(i)
time.sleep(.10)
https://youtu.be/LS7mrRDXs5s