52_I2C_PCA9685.pm 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. ##############################################################################
  2. # $Id: 52_I2C_PCA9685.pm 13355 2017-02-07 22:16:01Z klausw $
  3. #
  4. ##############################################################################
  5. # Modul for I2C PWM Driver PCA9685
  6. #
  7. # define <name> I2C_PCA9685 <I2C-Adresse>
  8. # set <name> <port> <value>
  9. #
  10. # contributed by Klaus Wittstock (2015) email: klauswittstock bei gmail punkt com
  11. #
  12. ##############################################################################
  13. #Inhalte des Hashes:
  14. #i2caddress 00-127(7F) I2C-Adresse
  15. #direction i2cread|i2cwrite Richtung
  16. #reg 00-255|"" Registeradresse (kann weggelassen werden fuer IC's ohne Registeradressierung)
  17. #nbyte Zahl Anzahl Register, die bearbeitet werden sollen (im mom 0-99)
  18. #data 00-255 ... Daten die an I2C geschickt werden sollen (muessen, wenn nbyte benutzt wird immer ein Vielfaches Desselben sein)
  19. #received 00-255 ... Daten die vom I2C empfangen wurden, durch Leerzeichen getrennt (bleibt leer wenn Daten geschrieben werden)
  20. #pname_SENDSTAT Ok|error zeigt uebertragungserfolg an
  21. package main;
  22. use strict;
  23. use warnings;
  24. use SetExtensions;
  25. #use POSIX;
  26. my $setdim = ":slider,0,1,4095 ";
  27. my %setsP = (
  28. 'off' => 0,
  29. 'on' => 1,
  30. );
  31. my %confregs = (
  32. 0 => 'modereg1',
  33. 1 => 'modereg2',
  34. 2 => 'SUBADR1',
  35. 3 => 'SUBADR2',
  36. 4 => 'SUBADR3',
  37. 5 => 'ALLCALLADR',
  38. );
  39. my %defaultreg = (
  40. 'modereg1' => 32, #32-> Bit 5 -> Autoincrement
  41. 'modereg2' => 0,
  42. 'SUBADR1' => 113,
  43. 'SUBADR2' => 114,
  44. 'SUBADR3' => 116,
  45. 'ALLCALLADR' => 112,
  46. 'PRESCALE' => 30,
  47. );
  48. my %mr1 = (
  49. 'EXTCLK' => 64,
  50. 'SLEEP' => 16,
  51. 'SUBADR1' => 8,
  52. 'SUBADR2' => 4,
  53. 'SUBADR3' => 2,
  54. 'ALLCALLADR' => 1,
  55. );
  56. my %mr2 = (
  57. 'INVRT' => 16,
  58. 'OCH' => 8,
  59. 'OUTDRV'=> 4,
  60. 'OUTNE1'=> 2,
  61. 'OUTNE0'=> 1,
  62. );
  63. #############################################################################
  64. sub I2C_PCA9685_Initialize($) { #
  65. my ($hash) = @_;
  66. $hash->{DefFn} = "I2C_PCA9685_Define";
  67. $hash->{InitFn} = 'I2C_PCA9685_Init';
  68. $hash->{UndefFn} = "I2C_PCA9685_Undefine";
  69. $hash->{AttrFn} = "I2C_PCA9685_Attr";
  70. $hash->{StateFn} = "I2C_PCA9685_State";
  71. $hash->{SetFn} = "I2C_PCA9685_Set";
  72. #$hash->{GetFn} = "I2C_PCA9685_Get";
  73. $hash->{I2CRecFn} = "I2C_PCA9685_I2CRec";
  74. $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 showtime:1,0 ".
  75. "prescale:slider,0,1,255 OnStartup ".
  76. "SUBADR1 SUBADR2 SUBADR3 ALLCALLADR ".
  77. "modereg1:multiple-strict,EXTCLK,SUBADR1,SUBADR2,SUBADR3,ALLCALLADR ".
  78. "modereg2:multiple-strict,INVRT,OCH,OUTDRV,OUTNE0,OUTNE1 ".
  79. "$readingFnAttributes dummy:0,1 extClock";
  80. }
  81. #############################################################################
  82. sub I2C_PCA9685_Define($$) {
  83. my ($hash, $def) = @_;
  84. my @a = split("[ \t]+", $def);
  85. $hash->{STATE} = 'defined';
  86. if ($main::init_done) {
  87. eval { I2C_PCA9685_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); };
  88. return I2C_PCA9685_Catch($@) if $@;
  89. }
  90. return undef;
  91. }
  92. #############################################################################
  93. sub I2C_PCA9685_Init($$) { # wird ausgefuehrt bei Initialisierung und Connect/Reconnect des DEVio
  94. my ( $hash, $args ) = @_;
  95. #my @a = split("[ \t]+", $args);
  96. my $name = $hash->{NAME};
  97. if (defined $args && int(@$args) < 1) {
  98. return "Define: Wrong syntax. Usage:\n" .
  99. "define <name> I2C_PCA9685 <i2caddress>";
  100. }
  101. if (defined (my $address = shift @$args)) {
  102. $hash->{I2C_Address} = $address =~ /^0x.*$/ ? oct($address) : $address;
  103. return "$name: I2C Address not valid" unless ($hash->{I2C_Address} < 128 && $hash->{I2C_Address} > 3);
  104. } else {
  105. return "$name: no I2C Address defined" unless defined($hash->{I2C_Address});
  106. }
  107. if (defined (my $maxbuff = shift @$args)) {
  108. return "$name: I2C buffer size must be a number" if $maxbuff =~ m/^d+$/;
  109. $hash->{I2C_Buff} = $maxbuff;
  110. }
  111. my $msg = '';
  112. eval {
  113. Log3 $hash, 4, "$hash->{NAME}: Init1 Konfigurationsregister auslesen";
  114. AssignIoPort($hash);
  115. #Config Register lesen (einzeln, da Blockweises lesen noch aktiviert werden muss)
  116. I2C_PCA9685_i2cread($hash, 0, 1); # Modereg1
  117. I2C_PCA9685_i2cread($hash, 1, 1); # Modereg2
  118. I2C_PCA9685_i2cread($hash, 2, 1); # Subadr1
  119. I2C_PCA9685_i2cread($hash, 3, 1); # Subadr2
  120. I2C_PCA9685_i2cread($hash, 4, 1); # Subadr3
  121. I2C_PCA9685_i2cread($hash, 5, 1); # Allcalladr
  122. I2C_PCA9685_i2cread($hash, 254, 1); # Frequenz fuer Internal
  123. $hash->{STATE} = 'Initializing';
  124. InternalTimer(gettimeofday() + 10, 'I2C_PCA9685_InitError', $hash, 0); # nach 10s Initialisierungsfehler ablegen
  125. };
  126. return I2C_BME280_Catch($@) if $@;
  127. }
  128. #############################################################################
  129. sub I2C_PCA9685_Init2($) { # wird audgefuehrt wenn Frequenzregisterinhalt empfangen wird und entsprechendes Internal noch leer ist
  130. my ( $hash ) = @_;
  131. my $name = $hash->{NAME};
  132. eval {
  133. Log3 $hash, 4, "$hash->{NAME}: Init2 Konfigurationsregister beschreiben";
  134. RemoveInternalTimer($hash); # Timer fuer Initialisierungsfehler stoppen
  135. # Mode register wiederherstellen
  136. I2C_PCA9685_Attr(undef, $name, "modereg1", AttrVal($name, "modereg1", undef));
  137. I2C_PCA9685_Attr(undef, $name, "modereg2", AttrVal($name, "modereg2", undef));
  138. # alternative I2C Adressen wiederherstellen
  139. I2C_PCA9685_Attr(undef, $name, "SUBADR1", AttrVal($name, "SUBADR1", undef));
  140. I2C_PCA9685_Attr(undef, $name, "SUBADR2", AttrVal($name, "SUBADR2", undef));
  141. I2C_PCA9685_Attr(undef, $name, "SUBADR3", AttrVal($name, "SUBADR3", undef));
  142. I2C_PCA9685_Attr(undef, $name, "ALLCALLADR", AttrVal($name, "ALLCALLADR", undef));
  143. # PWM Frequenz wiederherstellen
  144. I2C_PCA9685_Attr(undef, $name, "prescale", AttrVal($name, "prescale", undef));
  145. #Portzustände wiederherstellen
  146. foreach (0..15) {
  147. my $port = "Port".sprintf ('%02d', $_);
  148. I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
  149. }
  150. $hash->{STATE} = 'Initialized';
  151. };
  152. return I2C_BME280_Catch($@) if $@;
  153. }
  154. #############################################################################
  155. sub I2C_PCA9685_InitError($) { # wird audgefuehrt wenn 10s nach Init immer noch keine Registerwerte empfangen wurden
  156. my ( $hash ) = @_;
  157. $hash->{STATE} = 'Error during Initialisation';
  158. }
  159. #############################################################################
  160. sub I2C_PCA9685_Catch($) { # Fehlermeldung von eval formattieren
  161. my $exception = shift;
  162. if ($exception) {
  163. $exception =~ /^(.*)( at.*FHEM.*)$/;
  164. return $1;
  165. }
  166. return undef;
  167. }
  168. #############################################################################
  169. sub I2C_PCA9685_State($$$$) { # reload readings at FHEM start
  170. my ($hash, $tim, $sname, $sval) = @_;
  171. Log3 $hash, 5, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim";
  172. if ($sname =~ m/^Port(((0|)[0-9])|(1[0-5]))$/i) {
  173. substr($sname,0,4,"");
  174. $sname = sprintf('%d', $sname);
  175. my %onstart = split /[,=]/, AttrVal($hash->{NAME}, "OnStartup", "");
  176. if ( exists($onstart{$sname}) && ( exists($setsP{$onstart{$sname}}) || ($onstart{$sname} =~ m/^\d+$/ && $onstart{$sname} < 4095) ) ) {
  177. Log3 $hash, 5, "$hash->{NAME}: Port" . sprintf('%02d', $sname) . " soll auf $onstart{$sname} gesetzt werden";
  178. readingsSingleUpdate($hash,"Port". sprintf('%02d', $sname), $onstart{$sname}, 1);
  179. } else {
  180. Log3 $hash, 4, "$hash->{NAME}: Port" . sprintf('%02d', $sname) . " soll auf Altzustand: $sval gesetzt werden";
  181. $hash->{READINGS}{'Port'. sprintf('%02d', $sname)}{VAL} = $sval;
  182. $hash->{READINGS}{'Port'. sprintf('%02d', $sname)}{TIME} = $tim;
  183. }
  184. }
  185. return undef;
  186. }
  187. #############################################################################
  188. sub I2C_PCA9685_Undefine($$) { # wird beim loeschen des Device ausgefuehrt
  189. my ($hash, $arg) = @_;
  190. my ($msg, $data, $reg) = I2C_PCA9685_CalcRegs($hash, 61, 'off', undef); # Registerinhalte berechnen alle Ports aus
  191. $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
  192. RemoveInternalTimer($hash);
  193. return undef
  194. }
  195. #############################################################################
  196. sub I2C_PCA9685_Attr(@) { # wird beim setzen eines Attributes ausgefuehrt
  197. my ($command, $name, $attr, $val) = @_;
  198. my $hash = $defs{$name};
  199. my $msg = '';
  200. if ($command && $command eq "set" && $attr && $attr eq "IODev") {
  201. if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) {
  202. main::AssignIoPort($hash,$val);
  203. my @def = split (' ',$hash->{DEF});
  204. I2C_PCA9685_Init($hash,\@def) if (defined ($hash->{IODev}));
  205. }
  206. } elsif ($attr && $attr =~ m/^prescale$/i) { # Frequenz
  207. $val = $defaultreg{'PRESCALE'} unless (defined($val)); #beim loeschen wieder auf Standard setzen
  208. return "wrong value: $val for \"set $name $attr\" use 0-255"
  209. unless($val =~ m/^(\d+)$/ && $val >= 0 && $val < 256);
  210. Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".(defined($hash->{confregs}{PRESCALE})?$hash->{confregs}{PRESCALE}:"empty")." neuer Wert: ".$val;
  211. if ($main::init_done && $val != $hash->{confregs}{PRESCALE}) {
  212. my $modereg1 = defined $hash->{confregs}{$confregs{0}} ? $hash->{confregs}{$confregs{0}} : $defaultreg{'modereg1'};
  213. my $modereg1mod = ( $modereg1 & 0x7F ) | $mr1{ "SLEEP" };
  214. $msg = I2C_PCA9685_i2cwrite($hash, 0, $modereg1mod); #sleep Mode aktivieren
  215. $msg = I2C_PCA9685_i2cwrite($hash, 254 ,$val); #Frequenz aktualisieren
  216. $msg = I2C_PCA9685_i2cwrite($hash, 0 ,$modereg1); #sleep Mode wieder aus
  217. foreach (0..15) { #Portzustände wiederherstellen
  218. my $port = "Port".sprintf ('%02d', $_);
  219. I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
  220. }
  221. }
  222. } elsif ($attr && $attr =~ m/^(SUBADR[1-3])|ALLCALLADR$/i) { # weitere I2C Adressen
  223. $val = $defaultreg{$attr} unless defined($val);
  224. substr($attr,0,6,"");
  225. my $regaddr = ($attr =~ m/^l/i) ? 5 : $attr + 1;
  226. my $SUBADR = $val =~ /^0x.*$/ ? oct($val) : $val;
  227. return "I2C Address not valid" if $SUBADR > 127;
  228. Log3 $hash, 5, $hash->{NAME} . ": $confregs{$regaddr} alter Wert: ".$hash->{confregs}{$confregs{$regaddr}}." neuer Wert: ".($SUBADR << 1);
  229. $msg = I2C_PCA9685_i2cwrite($hash, $regaddr ,$SUBADR << 1) if $main::init_done && ($SUBADR << 1) != $hash->{confregs}{$confregs{$regaddr}};
  230. } elsif ($attr && $attr =~ m/^modereg1$/i) { # Mode register 1
  231. my @inp = split(/,/, $val) if defined($val);
  232. my $data = 32; # Auto increment soll immer gesetzt sein
  233. foreach (@inp) {
  234. return "wrong value: $_ for \"attr $name $attr\" use comma separated list of " . join(',', (sort { $mr1{ $a } <=> $mr1{ $b } } keys %setsP) )
  235. unless(exists($mr1{$_}));
  236. $data |= $mr1{$_};
  237. if ($main::init_done && $_ eq "EXTCLK" && ($hash->{confregs}{$confregs{0}} & $mr1{"EXTCLK"}) == 0) { #wenn externer Oszillator genutzt werden soll, zuerst den sleep mode aktivieren
  238. my $modereg1 = defined $hash->{confregs}{$confregs{0}} ? $hash->{confregs}{$confregs{0}} : $defaultreg{'modereg1'};
  239. my $modereg1mod = ( $modereg1 & 0x7F ) | $mr1{ "SLEEP" };
  240. Log3 $hash, 5, "$hash->{NAME}: sleep Mode aktivieren (Vorbereitung fuer EXTCLK)";
  241. $msg = I2C_PCA9685_i2cwrite($hash, 0 ,$modereg1mod); #sleep Mode aktivieren
  242. # $data += $mr1{"SLEEP"}; #???????? muss hier nicht deaktiviert werden?????
  243. }
  244. }
  245. if ($main::init_done && defined $hash->{confregs}{$confregs{0}} && ($hash->{confregs}{$confregs{0}} & $mr1{"EXTCLK"}) == $mr1{"EXTCLK"} && ($data & $mr1{"EXTCLK"}) == 0 ) { #reset wenn EXTCLK abgeschaltet wird
  246. $msg = I2C_PCA9685_i2cwrite($hash, 0 , $data | 0x80);
  247. }
  248. Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".$hash->{confregs}{$confregs{0}}." neuer Wert: ".$data;
  249. if ( $main::init_done && $data != $hash->{confregs}{$confregs{0}} ) {
  250. I2C_PCA9685_UpdReadings($hash, 0, $data); #schonmal in den Internals ablegen lassen (damit wärend Initialisierung mit korrekten daten gearbeitet wird... bei Frequenz z.B.)
  251. $msg = I2C_PCA9685_i2cwrite($hash, 0 , $data);
  252. }
  253. } elsif ($attr && $attr =~ m/^modereg2$/i) { #Mode register 2
  254. my @inp = split(/,/, $val) if defined($val);
  255. my $data = 0;
  256. foreach (@inp) {
  257. return "wrong value: $_ for \"attr $name $attr\" use comma separated list of " . join(',', (sort { $mr2{ $a } <=> $mr2{ $b } } keys %setsP) )
  258. unless(exists($mr2{$_}));
  259. $data += $mr2{$_};
  260. }
  261. Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".(defined($hash->{confregs}{$confregs{1}})?$hash->{confregs}{$confregs{1}}:"")." neuer Wert: ".$data;
  262. $msg = I2C_PCA9685_i2cwrite($hash, 1, $data) if $main::init_done && $data != $hash->{confregs}{$confregs{1}};
  263. } elsif ($attr && $attr eq "OnStartup") {
  264. if (defined $val) {
  265. foreach (split (/,/,$val)) {
  266. my @pair = split (/=/,$_);
  267. $msg = "wrong value: $_ for \"attr $hash->{NAME} $attr\" use comma separated <port>=on|off|0..4095|last where <port> = 0 - 15 "
  268. unless ( scalar(@pair) == 2 &&
  269. (($pair[0] =~ m/(^[0-9]|1[0-5])$/i &&
  270. ( $pair[1] eq "last" || exists($setsP{$pair[1]}) ||
  271. ( $pair[1] =~ m/^\d+$/ && $pair[1] < 4095 ) ) ) )
  272. );
  273. }
  274. }
  275. } elsif ($attr && $attr eq "extClock") {
  276. $val = defined($val) ? $val : 25;
  277. return "wrong value: $val for \"set $name $attr\" use point number"
  278. unless($val =~ m/^[1-9][0-9]*\.?[0-9]*$/);
  279. I2C_PCA9685_i2cread($hash, 254, 1); # Frequenz fuer Internal neu auslesen und berechnen
  280. }
  281. return ($msg) ? $msg : undef;
  282. }
  283. #############################################################################
  284. sub I2C_PCA9685_Set($@) { #
  285. my ($hash, $name, @rest) = @_;
  286. my $dimstep = AttrVal($name, "dimstep", "1");
  287. my $dimcount = AttrVal($name, "dimcount", "4095");
  288. my $msg;
  289. my $str = join(' ',@rest);
  290. #Log3 undef, 5, "$name: empfangen: $str";
  291. if ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))/i && index($str, ',') == -1) { # Nur ein Port
  292. my ($port, $dim, $delay) = split(' ', $str);
  293. $port =~ tr/(P|p)(ort|)//d;
  294. #Log3 undef, 5, "$name: ein Port: $port, $dim, $delay";
  295. ($msg, my $data, my $reg) = I2C_PCA9685_CalcRegs($hash, $port, $dim, $delay); # Registerinhalte berechnen
  296. $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
  297. # } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( *, *(P(ort|)((0|)[0-9]|1[0-5]))){1,} +\d+( +\d*)?/i ) { # Format P[ort]x,P[ort]y[,P..] Dimwert[ Delay]
  298. } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( *, *(P(ort|)((0|)[0-9]|1[0-5]))){1,}/i ) { # Format P[ort]x,P[ort]y[,P..] Dimwert[ Delay]
  299. Log3 undef, 5, "mehrere ports und ein wert";
  300. $str =~ tr/(P|p)(ort|)//d;
  301. my @einzel = split(',', $str);
  302. my @port;
  303. my (undef, $dim, $delay) = split(' ', $einzel[$#einzel]);
  304. for my $i (0..$#einzel){
  305. ($port[$i]) = split(' ', $einzel[$i]);
  306. }
  307. my ($data, $reg) = undef;
  308. my $j = 1;
  309. for my $i (0..$#einzel){
  310. ($msg, my $tdata, my $treg) = I2C_PCA9685_CalcRegs($hash, $port[$i], $dim, ( defined($delay) ? $delay : undef ) ); # Registerinhalte berechnen
  311. return $msg if defined($msg);
  312. Log3 $hash, 5, "$name: Port: $port[$i], Reg: $treg, Inhalt: $tdata, Rohwerte: $einzel[$i], Dimwert: $dim, Delay: ". ( defined($delay) ? ( $delay = "" ? "leer" : $delay ) : "leer" );
  313. if ( defined($data) && defined($reg) ) { # bereits Werte für Ports vorhanden
  314. $j += 1;
  315. $data .= " " . $tdata;
  316. } else {
  317. $data = $tdata;
  318. $reg = $treg;
  319. }
  320. unless ( $j < (int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4)) && $i < $#einzel && ($port[$i] + 1) == $port[$i+1]){ #wenn der naechste Port nicht der direkt Nachfolgende ist oder mehr als 8 Ports (32Bytes)
  321. $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data); # Rausschicken
  322. ($data, $reg) = undef;
  323. $j = 1;
  324. }
  325. }
  326. } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?(( ){0,3},( ){0,3}(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?){1,}( ){0,3}$/i ) { # Mehrere Ports auf versch. Werte setzen
  327. Log3 undef, 5, "mehrere ports und unterschiedliche Werte";
  328. $str =~ tr/(P|p)(ort|)//d;
  329. my @einzel = split(',', $str);
  330. my (@port, @dim, @delay);
  331. #@einzel = sort { $a <=> $b } @einzel;
  332. for my $i (0..$#einzel){
  333. ($port[$i], $dim[$i], $delay[$i]) = split(' ', $einzel[$i]);
  334. }
  335. my ($data, $reg) = undef;
  336. my $j = 1;
  337. for my $i (0..$#einzel){
  338. ($msg, my $tdata, my $treg) = I2C_PCA9685_CalcRegs($hash, $port[$i], $dim[$i], ( defined($delay[$i]) ? $delay[$i] : undef ) ); # Registerinhalte berechnen
  339. return $msg if defined($msg);
  340. Log3 $hash, 5, "$name: Port: $port[$i], Reg: $treg, Inhalt: $tdata, Rohwerte: $einzel[$i], Dimwert: $dim[$i], Delay: ". ( defined($delay[$i]) ? ( $delay[$i] =~ m/ */ ? "leer" : $delay[$i] ) : "leer" );
  341. if ( defined($data) && defined($reg) ) { # bereits Werte für Ports vorhanden
  342. $j += 1;
  343. $data .= " " . $tdata;
  344. } else {
  345. $data = $tdata;
  346. $reg = $treg;
  347. }
  348. unless ( $j < int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) && $i < $#einzel && ($port[$i] + 1) == $port[$i+1]){ #wenn der naechste Port nicht der direkt Nachfolgende ist oder mehr als 8 Ports (32Bytes)
  349. $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data); # Rausschicken
  350. ($data, $reg) = undef;
  351. $j = 1;
  352. }
  353. }
  354. } elsif ($str =~ m/(a(ll|)( ){0,3}((\d{1,4})|on|off)(( ){0,3}\d{1,4})?)( ){0,3}$/i) { # Alle Ports gleichzeitig
  355. my ($port, $dim, $delay) = split(' ', $str);
  356. $port = 61; # Portnummer auf 61 für All setzen (All Startreg ist 250)
  357. Log3 undef, 5, "$name: alle Ports: $port, $dim" . (defined $delay ? ", $delay" : "" );
  358. my ($msg, $data, $reg) = I2C_PCA9685_CalcRegs($hash, $port, $dim, $delay); # Registerinhalte berechnen
  359. $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
  360. } else {
  361. my $list = undef;
  362. foreach (0..15) {
  363. $list .= "Port" . sprintf ('%02d', $_) . ":slider,0,$dimstep,$dimcount ";
  364. }
  365. $list .= "all:slider,0,$dimstep,$dimcount";
  366. $msg = "Unknown argument $str, choose one of " . $list;
  367. }
  368. return (defined($msg) ? $msg : undef);
  369. }
  370. #############################################################################
  371. sub I2C_PCA9685_CalcRegs($$$$) { # Registerinhalte berechnen
  372. my ($hash, $port, $dim, $del) = @_;
  373. my $name = $hash->{NAME};
  374. #$port =~ tr/P(ort|)//d; #Nummer aus Port extrahieren
  375. my $dimcount = AttrVal($hash->{NAME}, "dimcount", "4095");
  376. my $data;
  377. my $msg = undef;
  378. if (defined($dim) && $dim eq "on") {
  379. $data = "0 16 0 0";
  380. } elsif (defined($dim) && $dim eq "off") {
  381. $data = "0 0 0 16";
  382. } elsif (defined($dim) && $dim =~ m/^\d+$/ && $dim >= 0 && $dim <= $dimcount) {
  383. my $delaytime = 0;
  384. if ($dimcount < 4095) { #DimmWert anpassen bei anderem Faktor
  385. $dim = int($dim * 4095 / $dimcount);
  386. }
  387. if (defined $del) { #Delaytime angegeben?
  388. $msg = "wrong delay value: \"$del\" for \"$name Port$port $dim\" use value between 0 and $dimcount"
  389. unless ($del =~ m/^\d+$/ && $del >= 0 && $del <= $dimcount);
  390. if ($dimcount < 4095) { #DelayWert anpassen bei anderem Faktor
  391. $del = int($del * 4095 / $dimcount);
  392. }
  393. $delaytime = $del
  394. } else { #...wenn nicht aus Reading holen (für all kommt immer 0 raus)
  395. $delaytime = ReadingsVal($name,'Port_d'.sprintf ('%02d', $port),"0");
  396. }
  397. unless($msg) { # nur berechnen wenn es keine Fehlermeldung gibt
  398. my $LEDx_OFF = $delaytime + $dim - (( $dim + $delaytime < 4096 ) ? 0 : 4096);
  399. if ($LEDx_OFF == $delaytime) { #beide Register dürfen nicht gleichen Inhalt haben, das entpricht "aus"
  400. $data = "0 0 0 16";
  401. } else {
  402. my @LEDx = unpack("C*", pack("S", $delaytime));
  403. push @LEDx, unpack("C*", pack("S", $LEDx_OFF)); #Array $LEDx[0] = LEDx_ON_L, $LEDx[1] = LEDx_ON_H, $LEDx[2] = LEDx_OFF_L, $LEDx[3] = LEDx_OFF_H
  404. # $data = sprintf "%01d " x 4, @LEDx;
  405. $data = sprintf "%01d %01d %01d %01d", @LEDx;
  406. }
  407. }
  408. } else {
  409. $msg = "wrong dimvalue: \"".(defined($dim)?$dim:"...")."\" for \"$name Port$port\" use one of: " .
  410. join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " 0..$dimcount";
  411. }
  412. my $reg = 6 + 4 * $port if defined $port; # Nummer des entspechenden LEDx_ON_L Registers (LED0_ON_L = 0x06) jede LED hat 4 Register
  413. return $msg, $data, $reg;
  414. }
  415. #############################################################################
  416. sub I2C_PCA9685_Get($@) { # Portwerte bei laden der Datailseite aktualisieren
  417. my ($hash, @a) = @_;
  418. unless ($hash->{IODev}->{TYPE} eq 'RPII2C') { #fuer FRM, etc. Register zurücklesen (bei RPII2C kommt bei erfolgreicher Uebertragung die Botschaft zurueck)
  419. my $reg = int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) * 4; # Anzahl moegliche 4er Registergruppen pro Lesevorgang
  420. my $n = int(64 / $reg); # Anzahl Lesevorgänge (abgerundet)
  421. foreach (0 .. ($n-1)) {
  422. I2C_PCA9685_i2cread($hash, 6 + $_ * $reg, $reg);
  423. }
  424. I2C_PCA9685_i2cread($hash, 6 + $n * $reg, $reg - ($reg * ($n+1) - 64)) if (($n+1) * $reg) > 64;
  425. } else {
  426. I2C_PCA9685_i2cread($hash, 0x6, 64);
  427. }
  428. return;
  429. }
  430. #############################################################################
  431. sub I2C_PCA9685_i2cread($$$) { # Lesebefehl an Hardware absetzen (antwort kommt in I2C_*****_I2CRec an)
  432. my ($hash, $reg, $nbyte) = @_;
  433. if (defined (my $iodev = $hash->{IODev})) {
  434. Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} read $nbyte Byte from Register $reg";
  435. CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
  436. direction => "i2cread",
  437. i2caddress => $hash->{I2C_Address},
  438. reg => $reg,
  439. nbyte => $nbyte
  440. });
  441. } else {
  442. if (AttrVal($hash->{NAME}, "dummy", 0) == 1) {
  443. Log3 $hash, 1, "attr dummy -> kann nix lesen";
  444. } else {
  445. return "no IODev assigned to '$hash->{NAME}'";
  446. } }
  447. }
  448. #############################################################################
  449. sub I2C_PCA9685_i2cwrite($$$) { # Schreibbefehl an Hardware absetzen
  450. my ($hash, $reg, $data) = @_;
  451. if (defined (my $iodev = $hash->{IODev})) {
  452. Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} write " . $data . " to Register $reg";
  453. CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
  454. direction => "i2cwrite",
  455. i2caddress => $hash->{I2C_Address},
  456. reg => $reg,
  457. data => $data,
  458. });
  459. unless ($hash->{IODev}->{TYPE} eq 'RPII2C') { #fuer FRM, etc. Register zurücklesen (bei RPII2C kommt bei erfolgreicher Uebertragung die Botschaft zurueck)
  460. my $nbyte = () = $data =~ / /gi;
  461. unless ($reg == 250) {
  462. I2C_PCA9685_i2cread($hash, $reg, $nbyte + 1);
  463. } else {
  464. #I2C_PCA9685_UpdReadings($hash, $reg, $data);
  465. my $reg = int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) * 4; # Anzahl moegliche 4er Registergruppen pro Lesevorgang
  466. my $n = int(64 / $reg); # Anzahl Lesevorgänge (abgerundet)
  467. foreach (0 .. ($n-1)) {
  468. I2C_PCA9685_i2cread($hash, 6 + $_ * $reg, $reg);
  469. }
  470. I2C_PCA9685_i2cread($hash, 6 + $n * $reg, $reg - ($reg * ($n+1) - 64)) if (($n+1) * $reg) > 64;
  471. }
  472. }
  473. return undef;
  474. } else {
  475. if (AttrVal($hash->{NAME}, "dummy", 0) == 1) {
  476. I2C_PCA9685_UpdReadings($hash, $reg, $data); # Zeile zum testen (Werte werden direkt zu I2CRec umgeleitet)
  477. } else {
  478. return "no IODev assigned to '$hash->{NAME}'";
  479. }
  480. }
  481. }
  482. #############################################################################
  483. sub I2C_PCA9685_I2CRec($@) { # vom IODev aufgerufen
  484. my ($hash, $clientmsg) = @_;
  485. my $name = $hash->{NAME};
  486. my $phash = $hash->{IODev};
  487. my $pname = $phash->{NAME};
  488. while ( my ( $k, $v ) = each %$clientmsg ) { #erzeugen von Internals fuer alle Keys in $clientmsg die mit dem physical Namen beginnen
  489. $hash->{$k} = $v if $k =~ /^$pname/ ;
  490. }
  491. if ($clientmsg->{direction} && defined($clientmsg->{reg}) && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok") {
  492. if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
  493. I2C_PCA9685_UpdReadings($hash, $clientmsg->{reg} , $clientmsg->{received});
  494. readingsSingleUpdate($hash,"state", "Ok", 1);
  495. } elsif ( $clientmsg->{direction} eq "i2cwrite" && defined($clientmsg->{data}) ) { #readings aktualisieren wenn uebertragung ok (bei FRM kommt nix zurueck)
  496. I2C_PCA9685_UpdReadings($hash, $clientmsg->{reg} , $clientmsg->{data});
  497. readingsSingleUpdate($hash,"state", "Ok", 1);
  498. } else {
  499. readingsSingleUpdate($hash,"state", "transmission error", 1);
  500. Log3 $hash, 3, "$name: failure in message from $pname";
  501. Log3 $hash, 3, (defined($clientmsg->{direction}) ? "Direction: " . $clientmsg->{direction} : "Direction: undef").
  502. (defined($clientmsg->{i2caddress}) ? " I2Caddress: " . sprintf("0x%.2X", $clientmsg->{i2caddress}) : " I2Caddress: undef").
  503. (defined($clientmsg->{reg}) ? " Register: " . sprintf("0x%.2X", $clientmsg->{reg}) : " Register: undef").
  504. (defined($clientmsg->{data}) ? " Data: " . sprintf("0x%.2X", $clientmsg->{data}) : " Data: undef").
  505. (defined($clientmsg->{received}) ? " received: " . sprintf("0x%.2X", $clientmsg->{received}) : " received: undef");
  506. }
  507. } else {
  508. readingsSingleUpdate($hash,"state", "transmission error", 1);
  509. Log3 $hash, 3, "$name: failure in message from $pname";
  510. Log3 $hash, 3, (defined($clientmsg->{direction}) ? "Direction: " . $clientmsg->{direction} : "Direction: undef").
  511. (defined($clientmsg->{i2caddress}) ? " I2Caddress: " . sprintf("0x%.2X", $clientmsg->{i2caddress}) : " I2Caddress: undef").
  512. (defined($clientmsg->{reg}) ? " Register: " . sprintf("0x%.2X", $clientmsg->{reg}) : " Register: undef").
  513. (defined($clientmsg->{data}) ? " Data: " . sprintf("0x%.2X", $clientmsg->{data}) : " Data: undef").
  514. (defined($clientmsg->{received}) ? " received: " . sprintf("0x%.2X", $clientmsg->{received}) : " received: undef");
  515. }
  516. }
  517. #############################################################################
  518. sub I2C_PCA9685_CalcVal($@) { # Readings aus Registerwerten berechnen
  519. my ($dimcount, @reginh) = @_;
  520. my $delay = undef;
  521. my $dimval;
  522. if ($reginh[1] > 15) {
  523. $dimval = "on";
  524. } elsif ($reginh[3] > 15) {
  525. $dimval = "off";
  526. } else {
  527. $delay = $reginh[1] * 256 + $reginh[0];
  528. my $temp = $reginh[3] * 256 + $reginh[2];
  529. $dimval = $temp - $delay + (( $temp > $delay ) ? 0 : 4096);
  530. if ($dimcount < 4095) { #Wert anpassen bei anderem Faktor
  531. $dimval = int($dimval * $dimcount / 4095);
  532. $delay = int($delay * $dimcount / 4095);
  533. }
  534. }
  535. return $dimval, $delay;
  536. }
  537. #############################################################################
  538. sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Readings/Internals schreiben
  539. my ($hash, $reg, $inh) = @_;
  540. my $name = $hash->{NAME};
  541. Log3 $hash, 5, "$name Received from Register $reg: $inh"; #sprintf("0x%.2X", $reg)
  542. my @reginh = split(" ", $inh);
  543. my $dimstep = AttrVal($name, "dimstep", "1");
  544. my $dimcount = AttrVal($name, "dimcount", "4095");
  545. my $delay = undef;
  546. my $dimval;
  547. readingsBeginUpdate($hash);
  548. if ($reg == 250 && @reginh == 4) { # wenn All
  549. ($dimval, $delay) = I2C_PCA9685_CalcVal($dimcount, @reginh);
  550. foreach (0..15) {
  551. readingsBulkUpdate($hash, 'Port'.sprintf('%02d', $_) , $dimval) if (ReadingsVal($name, 'Port'.sprintf('%02d', $_), "failure") ne $dimval); #nur wenn Wert geaendert
  552. readingsBulkUpdate($hash, 'Port_d'.sprintf('%02d', $_) , $delay) if (defined $delay && ReadingsVal($name, 'Port_d'.$hash->{confregs}, "failure") ne $delay); #nur wenn Wert geaendert
  553. }
  554. } elsif ( $reg < 70 && $reg > 5 && @reginh == 4) { #Wenn PortRegister
  555. my $port = sprintf ('%02d', ($reg - 6) / 4);
  556. ($dimval, $delay) = I2C_PCA9685_CalcVal($dimcount, @reginh);
  557. readingsBulkUpdate($hash, 'Port'.$port , $dimval) if (ReadingsVal($name, 'Port'.$port, "failure") ne $dimval); #nur wenn Wert geaendert
  558. readingsBulkUpdate($hash, 'Port_d'.$port , $delay) if (defined $delay && ReadingsVal($name, 'Port_d'.$port, "failure") ne $delay); #nur wenn Wert geaendert
  559. Log3 $hash, 5, "$name: lese einen Port - Reg: $reg, Inh: @reginh";
  560. } elsif ( $reg < 70 && $reg > 5 && @reginh > 4 ) { #Wenn mehrere Ports abgefragt werden
  561. for (my $i = 0; $i < @reginh; $i++) {
  562. next unless ( ($reg + $i - 2) / 4 =~ m/^\d+$/ && defined($reginh[$i + 3]) );
  563. my @regpart = ( $reginh[$i], $reginh[$i + 1], $reginh[$i + 2], $reginh[$i + 3] );
  564. my $port = sprintf ('%02d', ($reg + $i - 6) / 4);
  565. ($dimval, $delay) = I2C_PCA9685_CalcVal($dimcount, @regpart);
  566. readingsBulkUpdate($hash, 'Port'.$port , $dimval) if (ReadingsVal($name, 'Port'.$port, "failure") ne $dimval); #nur wenn Wert geaendert
  567. readingsBulkUpdate($hash, 'Port_d'.$port , $delay) if (defined $delay && ReadingsVal($name, 'Port_d'.$port, "failure") ne $delay); #nur wenn Wert geaendert
  568. Log3 $hash, 5, "$name: lese mehrere Ports - Reg: $reg, i: $i; Inh: @regpart";
  569. $i += 3;
  570. }
  571. } elsif ($reg == 254) { #wenn Frequenz Register
  572. my $clock = AttrVal($name, "extClock", 25);
  573. my $init = 1 unless defined($hash->{Frequency});
  574. $hash->{confregs}{PRESCALE} = $inh;
  575. $hash->{Frequency} = sprintf( "%.1f", $clock * 1000000 / (4096 * ($inh + 1)) ) . " Hz";
  576. I2C_PCA9685_Init2($hash) if defined($init);
  577. } elsif ( $reg >= 0 && $reg < 6 ) { #Konfigurations Register
  578. $hash->{confregs}{$confregs{$reg}} = $inh;
  579. }
  580. readingsEndUpdate($hash, 1);
  581. return;
  582. }
  583. #############################################################################
  584. 1;
  585. =pod
  586. =item device
  587. =item summary controls PWM outputs from an via I2C connected PCA9685
  588. =item summary_DE steuern der PWM Ausg&aumlnge eines &uuml;ber I2C angeschlossenen PCA9685
  589. =begin html
  590. <a name="I2C_PCA9685"></a>
  591. <h3>I2C_PCA9685</h3>
  592. (en | <a href="commandref_DE.html#I2C_PCA9685">de</a>)
  593. <ul>
  594. <a name="I2C_PCA9685"></a>
  595. Provides an interface to the PCA9685 I2C 16 channel PWM IC.
  596. The I2C messages are send through an I2C interface module like <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
  597. or <a href="#NetzerI2C">NetzerI2C</a> so this device must be defined first.<br>
  598. <b>attribute IODev must be set</b><br>
  599. <a name="I2C_PCA9685Define"></a><br>
  600. <b>Define</b>
  601. <ul>
  602. <code>define &lt;name&gt; I2C_PCA9685 &lt;I2C Address&gt; [&lt;I2C Buffer Size&gt;]</code><br>
  603. where <code>&lt;I2C Address&gt;</code> can be written as decimal value or 0xnn<br>
  604. <code>&lt;I2C Buffer Size&gt;</code> sets the maximum size of the I2C-Packet.
  605. Without this option the packet size is 30 Bytes (32 incl. Address and Register number).
  606. For RPII2C this option has no influence, cause it can deal with arbitrary packet sizes.<br>
  607. </ul>
  608. <a name="I2C_PCA9685Set"></a>
  609. <b>Set</b>
  610. <ul>
  611. <code>set &lt;name&gt; &lt;port&gt; &lt;dimvalue&gt; [&lt;delay&gt;]</code><br><br>
  612. <li>where <code>&lt;port&gt;</code> is one of Port0 to Port15<br>
  613. and <code>&lt;dimvalue&gt;</code> one of<br>
  614. <ul>
  615. <code>
  616. off<br>
  617. on<br>
  618. 0..4095<br>
  619. </code>
  620. </ul>
  621. <code>&lt;delay&gt;</code> defines the switch on time inside the PWM counting loop. It does not have an influence to the duty cycle.
  622. Default value is 0 and, possible values are 0..4095<br>
  623. </li><br>
  624. <li>
  625. It is also possible to change more than one port at the same time. Just separate them by comma.
  626. If only the last of the comma separated ports has dimvalue (and delay), all ports will set to the same values.
  627. Sequently ports will set at once (useful for multi color LED's).<br>
  628. Also P instead of Port is Possible.
  629. </li><br>
  630. <br>
  631. Examples:
  632. <ul>
  633. <code>set mod1 Port04 543</code><br>
  634. <code>set mod1 Port4 434 765</code><br>
  635. <code>set mod1 Port1, Port14 434 765</code><br>
  636. <code>set mod1 Port1 on, P14 434 765</code><br>
  637. </ul><br>
  638. </ul>
  639. <a name="I2C_PCA9685Get"></a>
  640. <b>Get</b>
  641. <ul>
  642. <code>get &lt;name&gt;</code>
  643. <br><br>
  644. refreshes all readings
  645. </ul><br>
  646. <a name="I2C_PCA9685Attr"></a>
  647. <b>Attributes</b>
  648. <ul>
  649. <li>SUBADR1,SUBADR2,SUBADR3,ALLCALLADR<br>
  650. Alternative slave addresses, if you want to control more than one PCA9685 with one define
  651. Respective flag in modereg1 must be set as well<br>
  652. Default: SUBADR1=113,SUBADR2=114,SUBADR3=116,ALLCALLADR=112, valid values: valid I2C Address <br><br>
  653. </li>
  654. <li>OnStartup<br>
  655. Comma separated list of output ports/PWM registers and their desired state after start<br>
  656. Without this atribut all output ports will set to last state<br>
  657. Default: -, valid values: &lt;port&gt;=on|off|0..4095|last where &lt;port&gt; = 0 - 15<br><br>
  658. </li>
  659. <li>prescale<br>
  660. Sets PWM Frequency. The Formula is: Fx = 25MHz/(4096 * (prescale + 1)).
  661. The corresponding frequency value is shown under internals.
  662. If provided, attribute extClock will be used for frequency calculation. Otherwise 25MHz<br>
  663. Default: 30 (200Hz for 25MHz clock), valid values: 0-255<br><br>
  664. </li>
  665. <li>modereg1<br>
  666. Comma separated list of:
  667. <ul>
  668. <li>EXTCLK<br>
  669. If set the an external connected clock will be used instead of the internal 25MHz oscillator.
  670. Use the attribute extClock to provide the external oscillater value.
  671. </li>
  672. <li>SUBADR1<br>
  673. If set the PCA9685 responds to I2C-bus SUBADR 1.
  674. </li>
  675. <li>SUBADR2<br>
  676. If set the PCA9685 responds to I2C-bus SUBADR 2.
  677. </li>
  678. <li>SUBADR3<br>
  679. If set the PCA9685 responds to I2C-bus SUBADR 3.
  680. </li>
  681. <li>ALLCALLADR<br>
  682. If set the PCA9685 responds to I2C-bus ALLCALLADR address.
  683. </li>
  684. </ul>
  685. </li>
  686. <li>modereg2<br>
  687. Comma separated list of:
  688. <ul>
  689. <li>INVRT<br>
  690. If set the Output logic state is inverted.<br>
  691. </li>
  692. <li>OCH<br>
  693. If set the outputs changes on ACK (after every byte sent).<br>
  694. Otherwise the output changes on STOP command (bus write action finished)<br>
  695. </li>
  696. <li>OUTDRV<br>
  697. If set the outputs are configured with a totem pole structure.<br>
  698. Otherwise the outputs are configured with open-drain.<br>
  699. </li>
  700. Behaviour when OE = 1 (if OE = 0 the output will act according OUTDRV configuration):
  701. <li>OUTNE0<br>
  702. If set:<br>
  703. LEDn = 1 when OUTDRV = 1<br>
  704. LEDn = high-impedance when OUTDRV = 0<br>
  705. If not set:
  706. LEDn = 0.<br>
  707. </li>
  708. <li>OUTNE1<br>
  709. LEDn = high-impedance.<br>
  710. OUTNE1 overrides OUTNE0<br><br>
  711. </li>
  712. </ul>
  713. </li>
  714. <li><a href="#IODev">IODev</a></li>
  715. <li><a href="#ignore">ignore</a></li>
  716. <li><a href="#do_not_notify">do_not_notify</a></li>
  717. <li><a href="#showtime">showtime</a></li>
  718. </ul>
  719. <br>
  720. </ul>
  721. =end html
  722. =begin html_DE
  723. <a name="I2C_PCA9685"></a>
  724. <h3>I2C_PCA9685</h3>
  725. (<a href="commandref.html#I2C_PCA9685">en</a> | de)
  726. <ul>
  727. <a name="I2C_PCA9685"></a>
  728. Erm&ouml;glicht die Verwendung eines PCA9685 I2C 16 Kanal PWM IC.
  729. I2C-Botschaften werden &uuml;ber ein I2C Interface Modul wie beispielsweise das <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
  730. oder <a href="#NetzerI2C">NetzerI2C</a> gesendet. Daher muss dieses vorher definiert werden.<br>
  731. <b>Das Attribut IODev muss definiert sein.</b><br>
  732. <a name="I2C_PCA9685Define"></a><br>
  733. <b>Define</b>
  734. <ul>
  735. <code>define &lt;name&gt; I2C_PCA9685 &lt;I2C Address&gt; [&lt;I2C Buffer Size&gt;]</code><br>
  736. Der Wert <code>&lt;I2C Address&gt;</code> ist ein zweistelliger Hex-Wert im Format 0xnn oder eine Dezimalzahl<br>
  737. <code>&lt;I2C Buffer Size&gt;</code> gibt die maximale Anzahl von Datenbytes pro I2C Datenpaket an. Nicht angegeben, wird der Wert 30 verwendet
  738. ( entspricht 32 Bytes incl. Adresse und Registernummer). RPII2C kann mit beliebig gro&szlig;en Paketl&auml;ngen umgehen, daher ist diese Option dort inaktiv.<br>
  739. </ul>
  740. <a name="I2C_PCA9685Set"></a>
  741. <b>Set</b>
  742. <ul>
  743. <code>set &lt;name&gt; &lt;port&gt; &lt;dimvalue&gt; [&lt;delay&gt;]</code><br><br>
  744. <li>Als <code>&lt;port&gt;</code> kann Port00 bis Port15 verwendet werden<br>
  745. <code>&lt;dimvalue&gt;</code> kann folgende Werte annehmen:<br>
  746. <ul>
  747. <code>
  748. off<br>
  749. on<br>
  750. 0..4095<br>
  751. </code>
  752. </ul>
  753. <code>&lt;delay&gt;</code> gibt den Wert innerhalb der Z&auml;hlschleife an, an dem der Ausgang eingeschaltet wird.
  754. Damit lassen sich die 16 Ausg&auml;nge zu unterschiedlichen Zeiten einschalten um Stromspitzen zu minimieren.
  755. Dieser Wert hat keinerlei Einfluss auf die Pulsbreite. Stardartwert ist 0, m&ouml;gliche Werte sind 0..4095<br>
  756. </li>
  757. <li>
  758. Um mehrer Ports mit einem Befehl zu &auml;ndern k&ouml;nnen mehrere Befehle per Komma getrennt eingegeben werden.
  759. Dabei kann jeder Port auf einen separaten, oder alle Ports auf den selben Wert gesettz werden.
  760. F&auml;r letzteres darf nur der letzte Befehl dimvalue (und delay) enthalten.
  761. Aufeinanerfolgene Ports werden mit einem Befehl geschrieben. So k&ouml;nnen beispielsweise multicolor LED's ohne flackern geschaltet werden.<br>
  762. Anstelle von Port kann auch einfach ein P verwendet werden.
  763. </li>
  764. <br>
  765. Examples:
  766. <ul>
  767. <code>set mod1 Port04 543</code><br>
  768. <code>set mod1 Port4 434 765</code><br>
  769. <code>set mod1 Port1, Port2, Port14 434 765</code><br>
  770. <code>set mod1 Port1 on, P14 434 765</code><br>
  771. </ul><br>
  772. </ul>
  773. <a name="I2C_PCA9685Get"></a>
  774. <b>Get</b>
  775. <ul>
  776. <code>get &lt;name&gt;</code>
  777. <br><br>
  778. Aktualisierung aller Werte
  779. </ul><br>
  780. <a name="I2C_PCA9685Attr"></a>
  781. <b>Attribute</b>
  782. <ul>
  783. <li>SUBADR1,SUBADR2,SUBADR3,ALLCALLADR<br>
  784. Alternative slave Adressen, zum kontrollieren mehrerer PCA9685 mit einem define
  785. Zus&auml;tzlich zu diesen Registern m&uuml;ssen die Passenden Bits in modereg1 gesetzt werden.<br>
  786. Standard: SUBADR1=113,SUBADR2=114,SUBADR3=116,ALLCALLADR=112, g&uuml;ltige Werte: I2C Adresse <br><br>
  787. </li>
  788. <li>OnStartup<br>
  789. Kommagetrennte Liste der Ports mit den gew&uuml;nschten Startwerten.<br>
  790. Nicht gelistete Ports werden auf en letzte state wiederhergestellt.<br>
  791. Standard: last, g&uuml;ltige Werte: &lt;port&gt;=on|off|0..4095|last wobei &lt;port&gt; = 0 - 15<br><br>
  792. </li>
  793. <li>prescale<br>
  794. PWM Frequenz setzen. Formel: Fx = 25MHz/(4096 * (prescale + 1)).
  795. Die eingestellte Frequenz wird in den Internals angezeigt.
  796. Wenn das Attribut extclock angegeben ist, wird dieses zur Frequenzberechnung verwendet. Andernfalls 25MHz.<br>
  797. Standard: 30 (200Hz f&uuml;r 25MHz clock), g&uuml;ltige Werte: 0-255<br><br>
  798. </li>
  799. <li>modereg1<br>
  800. Durch Komma getrennte Liste von:
  801. <ul>
  802. <li>EXTCLK<br>
  803. Anstelle des internen 25MHz Oszillators wird ein extern Angeschlossener verwendet.
  804. Die Frequenz des externen Oszillators kann &uuml;ber das Attribut extclock angegeben werden.
  805. </li>
  806. <li>SUBADR1<br>
  807. Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 1.
  808. </li>
  809. <li>SUBADR2<br>
  810. Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 2.
  811. </li>
  812. <li>SUBADR3<br>
  813. Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 3.
  814. </li>
  815. <li>ALLCALLADR<br>
  816. Wenn gesetzt, antwortet der PCA9685 auf I2C-bus ALLCALLADR Adresse.
  817. </li>
  818. </ul>
  819. </li>
  820. <li>modereg2<br>
  821. Durch Komma getrennte Liste von:
  822. <ul>
  823. <li>INVRT<br>
  824. Wenn gesetzt, werden die Ausg&auml;nge invertiert.<br>
  825. </li>
  826. <li>OCH<br>
  827. Wenn gesetzt, werden die Ports nach jedem ACK gesetzt (also nach jedem gesendeten Byte).<br>
  828. Andernfalls werden sie nach einem STOP Kommando gesetzt (Bus Schreibaktion fertig, also nach einem Datenpaket)<br>
  829. </li>
  830. <li>OUTDRV<br>
  831. Wenn gesetzt, werden die Ausg&auml;nge als totem pole konfiguriert.<br>
  832. Andernfalls sind sie open-drain.<br>
  833. </li>
  834. Verhalten bei OE = 1 (wenn OE = 0 verhalten sich die Ausg&auml;nge wie in OUTDRV eingestellt):
  835. <li>OUTNE0<br>
  836. Wenn gesetzt:<br>
  837. LEDn = 1 wenn OUTDRV = 1<br>
  838. LEDn = hochohmig wenn OUTDRV = 0<br>
  839. Wenn nicht gesetzt:
  840. LEDn = 0.<br>
  841. </li>
  842. <li>OUTNE1<br>
  843. LEDn = hochohmig.<br>
  844. Wenn OUTNE1 gesetzt wird OUTNE0 ignoriert.<br><br>
  845. </li>
  846. </ul>
  847. </li>
  848. <li><a href="#IODev">IODev</a></li>
  849. <li><a href="#ignore">ignore</a></li>
  850. <li><a href="#do_not_notify">do_not_notify</a></li>
  851. <li><a href="#showtime">showtime</a></li>
  852. </ul>
  853. <br>
  854. </ul>
  855. =end html_DE
  856. =cut