Outils pour utilisateurs

Outils du site


Panneau latéral

Navigation

Plan auto

raspberry_pi:controle_led_rgb

Ceci est une ancienne révision du document !


Contrôler une LED tricolore RGB depuis les GPIO

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 :
cathode communeAnode commune
En pratique, voici ce que peut donner une LED RGB:

Les DEL RGB Common cathode (à cathode commune)

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 :

colorChangeCA.py
#!/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)

Les DEL RGB Common Anode (à anode commune)

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 tension aux 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:

colorChangeCC.py
#!/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)
raspberry_pi/controle_led_rgb.1424560680.txt.gz · Dernière modification: 22/02/2015 00:18 par sky99