Ceci est une ancienne révision du document !
Les DEL RGB sont des DEL contenant en fait 3 DEL : une rouge (R), une verte (G), et une bleue (B). Le format est celui d'une DEL classique, sauf qu'il y a 4 pattes. On peut allumer l'une des 3 couleurs, pour avoir du rouge, du vert ou du bleu, mais on peut également allumer des combinaisons de deux couleurs (Rouge + Vert = jaune, par ex), ou même les trois couleurs en même temps pour faire du blanc. Enfin, si vous contrôlez le niveau de chaque led avec de la PWM, vous pouvez faire varier l'intensité de chaque couleur. Imaginons que vous puissiez faire varier en pwm chaque patte de la led de 0 à 255 : en pratique, vous obtenez des nuances de couleurs comme dans un logiciel d'image, avec 256 nuances de chaque couleur de base, et une combinaison de 256*256*256 = environ 16 millions de couleurs! Aujourd'hui, nous ne nous occuperons pas de PWM, car le PI ne dispose que d'une broche PWM. On se contentera d'allumer chaque couleur, et de combiner les couleurs de façon simple.
En premier lieu, vous trouverez divers types de LED RGB. Il y en aura des “clear”, dont le boitier epoxy est transparent. La luminosité de celles ci est maximale devant la LED, mais plus faible sur le coté. Elles sont souvent éblouissantes vues de face. Il y aura aussi les “diffused”, dont le boitier est translucide, vous ne verrez pas l'intérieur clairement. Celles ci diffusent davantage la lumière, et sont mieux visibles dans tous les sens. L'autre point important, c'est la distinction entre les common cathode (cathode commune) et les common anode (anode commune). Les premières, les common cathode ont une patte pour le + de chaque couleur, et une patte commune pour le - de toutes les couleurs. Pour les common anode, c'est le contraire, la patte commune est l'anode, donc on a une patte commune pour le + (l'anode), et une patte pour le - de chaque couleur. Cela signifie que le câblage ne sera pas le même, et la logique de contrôle sera également différente. Si vous avez le choix, les common cathode sont plus simples, bien que les common anode ne soient pas particulièrement complexes.
Dans les deux cas, voici la disposition des pattes de la LED :
En pratique, voici ce que peut donner une LED RGB:
Ici, c'est donc le - qui est commun. Le câblage est donc très simple : vous branchez la cathode (patte 2), qui est la plus grande patte, sur le -, vous reliez les pattes 1 et 4 à des GPIO, et la patte 3 à une résistance qui va dans un GPIO. Il suffit alors de définir le GPIO à high pour allumer une couleur, et à low pour l'eteindre. Idéalement, la résistance en série pour la patte 3 (rouge) devrait faire 65 Ohms.
Voici un schéma de câblage pour Arduino, avant de passer à la version Raspberry Pi :) Le schéma de câblage sera donc le suivant, en utilisant un MCP23017 pour profiter de ses GPIO :
-très bientôt- Quand au code, il est relativement simple :
#!/usr/bin/python from Adafruit_I2C import Adafruit_I2C import smbus import time MCP23017_IODIRA = 0x00 MCP23017_IODIRB = 0x01 MCP23017_GPIOA = 0x12 MCP23017_GPIOB = 0x13 MCP23017_GPPUA = 0x0C MCP23017_GPPUB = 0x0D MCP23017_OLATA = 0x14 MCP23017_OLATB = 0x15 MCP23008_GPIOA = 0x09 MCP23008_GPPUA = 0x06 MCP23008_OLATA = 0x0A class Adafruit_MCP230XX(object): OUTPUT = 0 INPUT = 1 def __init__(self, address, num_gpios, busnum = 0): assert num_gpios >= 0 and num_gpios <= 16, "Number of GPIOs must be between 0 and 16" self.i2c = Adafruit_I2C(address=address, bus=smbus.SMBus(busnum)) self.address = address self.num_gpios = num_gpios # set defaults if num_gpios <= 8: self.i2c.write8(MCP23017_IODIRA, 0xFF) # all inputs on port A self.direction = self.i2c.readU8(MCP23017_IODIRA) self.i2c.write8(MCP23008_GPPUA, 0x00) elif num_gpios > 8 and num_gpios <= 16: self.i2c.write8(MCP23017_IODIRA, 0xFF) # all inputs on port A self.i2c.write8(MCP23017_IODIRB, 0xFF) # all inputs on port B self.direction = self.i2c.readU8(MCP23017_IODIRA) self.direction |= self.i2c.readU8(MCP23017_IODIRB) << 8 self.i2c.write8(MCP23017_GPPUA, 0x00) self.i2c.write8(MCP23017_GPPUB, 0x00) def _changebit(self, bitmap, bit, value): assert value == 1 or value == 0, "Value is %s must be 1 or 0" % value if value == 0: return bitmap & ~(1 << bit) elif value == 1: return bitmap | (1 << bit) def _readandchangepin(self, port, pin, value, currvalue = None): assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios) #assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin if not currvalue: currvalue = self.i2c.readU8(port) newvalue = self._changebit(currvalue, pin, value) self.i2c.write8(port, newvalue) return newvalue def pullup(self, pin, value): if self.num_gpios <= 8: return self._readandchangepin(MCP23008_GPPUA, pin, value) if self.num_gpios <= 16: if (pin < : return self._readandchangepin(MCP23017_GPPUA, pin, value) else: return self._readandchangepin(MCP23017_GPPUB, pin-8, value) # Set pin to either input or output mode def config(self, pin, mode): if self.num_gpios <= 8: self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode) if self.num_gpios <= 16: if (pin < <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/>: self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode) else: self.direction = self._readandchangepin(MCP23017_IODIRB, pin-8, mode) return self.direction def output(self, pin, value): # assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin if self.num_gpios <= 8: self.outputvalue = self._readandchangepin(MCP23008_GPIOA, pin, value, self.i2c.readU8(MCP23008_OLATA)) if self.num_gpios <= 16: if (pin < <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/>: self.outputvalue = self._readandchangepin(MCP23017_GPIOA, pin, value, self.i2c.readU8(MCP23017_OLATA)) else: self.outputvalue = self._readandchangepin(MCP23017_GPIOB, pin-8, value, self.i2c.readU8(MCP23017_OLATB)) return self.outputvalue self.outputvalue = self._readandchangepin(MCP23017_IODIRA, pin, value, self.outputvalue) return self.outputvalue def input(self, pin): assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios) assert self.direction & (1 << pin) != 0, "Pin %s not set to input" % pin if self.num_gpios <= 8: value = self.i2c.readU8(MCP23008_GPIOA) elif self.num_gpios > 8 and self.num_gpios <= 16: value = self.i2c.readU16(MCP23017_GPIOA) temp = value >> 8 value <<= 8 value |= temp return value & (1 << pin) def readU8(self): result = self.i2c.readU8(MCP23008_OLATA) return(result) def readS8(self): result = self.i2c.readU8(MCP23008_OLATA) if (result > 127): result -= 256 return result def readU16(self): assert self.num_gpios >= 16, "16bits required" lo = self.i2c.readU8(MCP23017_OLATA) hi = self.i2c.readU8(MCP23017_OLATB) return((hi << <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/> | lo) def readS16(self): assert self.num_gpios >= 16, "16bits required" lo = self.i2c.readU8(MCP23017_OLATA) hi = self.i2c.readU8(MCP23017_OLATB) if (hi > 127): hi -= 256 return((hi << <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/> | lo) def write8(self, value): self.i2c.write8(MCP23008_OLATA, value) def write16(self, value): assert self.num_gpios >= 16, "16bits required" self.i2c.write8(MCP23017_OLATA, value & 0xFF) self.i2c.write8(MCP23017_OLATB, (value >> & 0xFF) # RPi.GPIO compatible interface for MCP23017 and MCP23008 class MCP230XX_GPIO(object): OUT = 0 IN = 1 BCM = 0 BOARD = 0 def __init__(self, busnum, address, num_gpios): self.chip = Adafruit_MCP230XX(busnum, address, num_gpios) def setmode(self, mode): # do nothing pass def setup(self, pin, mode): self.chip.config(pin, mode) def input(self, pin): return self.chip.input(pin) def output(self, pin, value): self.chip.output(pin, value) def pullup(self, pin, value): self.chip.pullup(pin, value) def lightRGBLed(rState,gState,bState,rPin,gPin,bPin): mcp.output(rPin, rState) mcp.output(gPin, gState) mcp.output(bPin, bState) def lightRGBLed2(color,rPin,gPin,bPin): if color == 'red': lightRGBLed(1,0,0,rPin,gPin,bPin) elif color == 'green': lightRGBLed(0,1,0,rPin,gPin,bPin) elif color == 'blue': lightRGBLed(0,0,1,rPin,gPin,bPin) elif color == 'yellow': lightRGBLed(1,1,0,rPin,gPin,bPin) elif color == 'magenta': lightRGBLed(1,0,1,rPin,gPin,bPin) elif color == 'cyan': lightRGBLed(0,1,1,rPin,gPin,bPin) elif color == 'white': lightRGBLed(1,1,1,rPin,gPin,bPin) if __name__ == '__main__': mcp = Adafruit_MCP230XX(busnum = 1, address = 0x20, num_gpios = 16) r1=10 g1=8 b1=9 mcp.config(b1, mcp.OUTPUT) mcp.config(g1, mcp.OUTPUT) mcp.config(r1, mcp.OUTPUT) while (True): print "off" lightRGBLed(0,0,0,r1,g1,b1) time.sleep(1) print "rouge" lightRGBLed(1,0,0,r1,g1,b1) time.sleep(1) print "vert" lightRGBLed(0,1,0,r1,g1,b1) time.sleep(1) print "bleu" lightRGBLed(0,0,1,r1,g1,b1) time.sleep(1) print "vert+bleu" lightRGBLed(0,1,1,r1,g1,b1) time.sleep(1) print "rouge+bleu" lightRGBLed(1,0,1,r1,g1,b1) time.sleep(1) print "rouge+vert" lightRGBLed(1,1,0,r1,g1,b1) time.sleep(1) print "rouge+vert+bleu" lightRGBLed(1,1,1,r1,g1,b1) time.sleep(1)
Ici, c'est donc le + qui est commun. Le câblage sera donc différent : on connecte toujours chaque couleur à un GPIO, et toujours une résistance en série pour le rouge. En revanche, la broche commune, l'anode, sera branchée sur le +3.3v. La différence c'est qu'ici, pour allumer une couleur, il faudra mettre le GPIO correspondant à 0. Si le GPIO est à 0, il est à 0V. Donc, le courant entre par l'anode a +3.3V, cela fait une tension de 3.3V au bornes de la DEL.En revanche, si on met le GPIO à 1, il sera à 3.3V. Ce qui fait qu'a chaque borne de la DEL, on a du +3.3V. du coup la tensionaux bornes de celle ci est de 0V, et elle reste éteinte! Le code est donc inversé, puisqu'il faut passer le GPIO à 0 pour allumer, et à 1 pour éteindre:
#!/usr/bin/python from Adafruit_I2C import Adafruit_I2C import smbus import time MCP23017_IODIRA = 0x00 MCP23017_IODIRB = 0x01 MCP23017_GPIOA = 0x12 MCP23017_GPIOB = 0x13 MCP23017_GPPUA = 0x0C MCP23017_GPPUB = 0x0D MCP23017_OLATA = 0x14 MCP23017_OLATB = 0x15 MCP23008_GPIOA = 0x09 MCP23008_GPPUA = 0x06 MCP23008_OLATA = 0x0A class Adafruit_MCP230XX(object): OUTPUT = 0 INPUT = 1 def __init__(self, address, num_gpios, busnum = 0): assert num_gpios >= 0 and num_gpios <= 16, "Number of GPIOs must be between 0 and 16" self.i2c = Adafruit_I2C(address=address, bus=smbus.SMBus(busnum)) self.address = address self.num_gpios = num_gpios # set defaults if num_gpios <= 8: self.i2c.write8(MCP23017_IODIRA, 0xFF) # all inputs on port A self.direction = self.i2c.readU8(MCP23017_IODIRA) self.i2c.write8(MCP23008_GPPUA, 0x00) elif num_gpios > 8 and num_gpios <= 16: self.i2c.write8(MCP23017_IODIRA, 0xFF) # all inputs on port A self.i2c.write8(MCP23017_IODIRB, 0xFF) # all inputs on port B self.direction = self.i2c.readU8(MCP23017_IODIRA) self.direction |= self.i2c.readU8(MCP23017_IODIRB) << 8 self.i2c.write8(MCP23017_GPPUA, 0x00) self.i2c.write8(MCP23017_GPPUB, 0x00) def _changebit(self, bitmap, bit, value): assert value == 1 or value == 0, "Value is %s must be 1 or 0" % value if value == 0: return bitmap & ~(1 << bit) elif value == 1: return bitmap | (1 << bit) def _readandchangepin(self, port, pin, value, currvalue = None): assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios) #assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin if not currvalue: currvalue = self.i2c.readU8(port) newvalue = self._changebit(currvalue, pin, value) self.i2c.write8(port, newvalue) return newvalue def pullup(self, pin, value): if self.num_gpios <= 8: return self._readandchangepin(MCP23008_GPPUA, pin, value) if self.num_gpios <= 16: if (pin < <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/>: return self._readandchangepin(MCP23017_GPPUA, pin, value) else: return self._readandchangepin(MCP23017_GPPUB, pin-8, value) # Set pin to either input or output mode def config(self, pin, mode): if self.num_gpios <= 8: self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode) if self.num_gpios <= 16: if (pin < <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/>: self.direction = self._readandchangepin(MCP23017_IODIRA, pin, mode) else: self.direction = self._readandchangepin(MCP23017_IODIRB, pin-8, mode) return self.direction def output(self, pin, value): # assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin if self.num_gpios <= 8: self.outputvalue = self._readandchangepin(MCP23008_GPIOA, pin, value, self.i2c.readU8(MCP23008_OLATA)) if self.num_gpios <= 16: if (pin < <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/>: self.outputvalue = self._readandchangepin(MCP23017_GPIOA, pin, value, self.i2c.readU8(MCP23017_OLATA)) else: self.outputvalue = self._readandchangepin(MCP23017_GPIOB, pin-8, value, self.i2c.readU8(MCP23017_OLATB)) return self.outputvalue self.outputvalue = self._readandchangepin(MCP23017_IODIRA, pin, value, self.outputvalue) return self.outputvalue def input(self, pin): assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios) assert self.direction & (1 << pin) != 0, "Pin %s not set to input" % pin if self.num_gpios <= 8: value = self.i2c.readU8(MCP23008_GPIOA) elif self.num_gpios > 8 and self.num_gpios <= 16: value = self.i2c.readU16(MCP23017_GPIOA) temp = value >> 8 value <<= 8 value |= temp return value & (1 << pin) def readU8(self): result = self.i2c.readU8(MCP23008_OLATA) return(result) def readS8(self): result = self.i2c.readU8(MCP23008_OLATA) if (result > 127): result -= 256 return result def readU16(self): assert self.num_gpios >= 16, "16bits required" lo = self.i2c.readU8(MCP23017_OLATA) hi = self.i2c.readU8(MCP23017_OLATB) return((hi << <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/> | lo) def readS16(self): assert self.num_gpios >= 16, "16bits required" lo = self.i2c.readU8(MCP23017_OLATA) hi = self.i2c.readU8(MCP23017_OLATB) if (hi > 127): hi -= 256 return((hi << <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/> | lo) def write8(self, value): self.i2c.write8(MCP23008_OLATA, value) def write16(self, value): assert self.num_gpios >= 16, "16bits required" self.i2c.write8(MCP23017_OLATA, value & 0xFF) self.i2c.write8(MCP23017_OLATB, (value >> <img src='http://forum.pcinpact.com/public/style_emoticons/<#EMO_DIR#>/lunettes1.gif' class='bbc_emoticon' alt='8)' />/>/>/>/>/>/> & 0xFF) # RPi.GPIO compatible interface for MCP23017 and MCP23008 class MCP230XX_GPIO(object): OUT = 0 IN = 1 BCM = 0 BOARD = 0 def __init__(self, busnum, address, num_gpios): self.chip = Adafruit_MCP230XX(busnum, address, num_gpios) def setmode(self, mode): # do nothing pass def setup(self, pin, mode): self.chip.config(pin, mode) def input(self, pin): return self.chip.input(pin) def output(self, pin, value): self.chip.output(pin, value) def pullup(self, pin, value): self.chip.pullup(pin, value) def lightRGBLed(rState,gState,bState,rPin,gPin,bPin): mcp.output(rPin, rState) mcp.output(gPin, gState) mcp.output(bPin, bState) def lightRGBLed2(color,rPin,gPin,bPin): if color == 'red': lightRGBLed(0,1,1,rPin,gPin,bPin) elif color == 'green': lightRGBLed(1,0,1,rPin,gPin,bPin) elif color == 'blue': lightRGBLed(1,1,0,rPin,gPin,bPin) elif color == 'yellow': lightRGBLed(0,0,1,rPin,gPin,bPin) elif color == 'magenta': lightRGBLed(0,1,0,rPin,gPin,bPin) elif color == 'cyan': lightRGBLed(1,0,0,rPin,gPin,bPin) elif color == 'white': lightRGBLed(0,0,0,rPin,gPin,bPin) if __name__ == '__main__': mcp = Adafruit_MCP230XX(busnum = 1, address = 0x20, num_gpios = 16) r1=10 g1=8 b1=9 mcp.config(b1, mcp.OUTPUT) mcp.config(g1, mcp.OUTPUT) mcp.config(r1, mcp.OUTPUT) while (True): print "off" lightRGBLed(1,1,1,r1,g1,b1) time.sleep(1) print "rouge" lightRGBLed(0,1,1,r1,g1,b1) time.sleep(1) print "vert" lightRGBLed(1,0,1,r1,g1,b1) time.sleep(1) print "bleu" lightRGBLed(1,1,0,r1,g1,b1) time.sleep(1) print "vert+bleu" lightRGBLed(1,0,0,r1,g1,b1) time.sleep(1) print "rouge+bleu" lightRGBLed(0,1,0,r1,g1,b1) time.sleep(1) print "rouge+vert" lightRGBLed(0,0,1,r1,g1,b1) time.sleep(1) print "rouge+vert+bleu" lightRGBLed(0,0,0,r1,g1,b1) time.sleep(1)