Matrix of Several 16-channel PWM Shields

Hello,

I have 56 motors sm-s4315r and using 4 Adafruit 16-channel PWM/Servo Shield for control them.
How can I create a matrix of all the addresses and pins? I have 56 motors and 56 buttons as limit switches, I want to use a matrix of buttons and send numbers of motors which should stop. Like button 47 is pressed which is equivalent to motor 47, so do pwm_D.setPWM(11, 0, 0) for example.

Also it's needed to run a few specific motors from the received command. Like I get command "run_1" and thats mean that the motors 34,1,3,67 (pwm_D.setPWM(11, 0, 500), pwm_C.setPWM(7, 0, 500),pwm_B.setPWM(16, 0, 500),pwm_A.setPWM(1, 0, 500)) shoud turn on and when their buttons was pressed turn off.

Or maybe here is another solution?
Thanks

Start by considering the use of arrays to hold the motor and switch numbers so you can iterate through the switches and determine which, if any, are pressed and respond by sending commands to the appropriate motor.

well, for now my code looks like that, and I can't figure out how to assign addresses with pins to the number of motor

#include <Keypad.h>
#include "led.h"
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm_A = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm_B = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver pwm_C = Adafruit_PWMServoDriver(0x42);
Adafruit_PWMServoDriver pwm_D = Adafruit_PWMServoDriver(0x44);


const byte ROWS = 6; //four rows
const byte COLS = 9; //three columns


unsigned char keys[ROWS][COLS] = {
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}
};

byte rowPins[ROWS] = {34, 32, 30, 28, 26, 24}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {53, 51, 49, 47, 45, 43, 41, 39, 37}; //connect to the column pinouts of the kpd

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// In led.h we have defined four variables for each motor.
// They are: motorPin, startTime, interval, and onOff.

const unsigned int numMOTORs = 54;
MOTOR motor[numMOTORs];   // so let's make an array of 56 of them.


unsigned int num;
int incomingNum;

void setup() {
 Serial.begin(9600);
 Serial1.begin(9600);

 pwm_A.begin();
 pwm_A.setPWMFreq(1600);  // This is the maximum PWM frequency

 pwm_B.begin();
 pwm_B.setPWMFreq(1600);  // This is the maximum PWM frequency

 pwm_C.begin();
 pwm_C.setPWMFreq(1600);  // This is the maximum PWM frequency

 pwm_D.begin();
 pwm_D.setPWMFreq(1600);  // This is the maximum PWM frequency

 uint8_t twbrbackup = TWBR;
 // must be changed after calling Wire.begin() (inside pwm.begin())
 TWBR = 12; // upgrade to 400KHz!

 for (uint8_t pwmnum = 0; pwmnum < 16; pwmnum++) {
   pwm_A.setPWM(pwmnum, 0, 0);
   pwm_B.setPWM(pwmnum, 0, 0);
   pwm_C.setPWM(pwmnum, 0, 0);
   pwm_D.setPWM(pwmnum, 0, 0);
 }
}



void loop()
{
 if (Serial1.available() > 0) {
   // read the incoming byte:
   incomingNum = Serial1.read();
   Serial.print(Serial1.read());
   // say what you got:
   Serial.print("I received: ");
   Serial.println(incomingNum);
 }
 /* Set the brightness to a medium values */
 char key = keypad.getKey();

 // In this block we will turn on a selected motor by pressing a key.

 if (key)
 {
   num = keypad.key[0].kcode;           // Map key code to motor num.
   motor[num].onOff = OFF;                 // Update the LED onOff status.
   // Send your motor 'on command' from here.
   // Turn the motor OFF.
   Serial.print(num);
  // pwm_A.setPWM(num, 0, OFF);
   key != keypad.getKey();
 }

 // In this block we will scan through the entire motors array and
 // decide if there are any motors that need to be turned off.
 if (incomingNum == 2) {
   motor[num].startTime = millis();
   for (num = 0; num < numMOTORs; num++)
   {
     if ( (motor[num].onOff == ON) && ( (millis() - motor[num].startTime) > motor[num].interval) )
     {
       motor[num].onOff = ON;             // Update the LED onOff status.
      // pwm_A.setPWM(num, 0, ON);
      Serial.print(motor[num].pin);
     }
   }
 }
 
 switch (incomingNum) {
   case 1: //figure is touched
     pwm_A.setPWM(1, 0, ON);
     pwm_B.setPWM(2, 0, ON);
     pwm_C.setPWM(4, 0, ON);
     pwm_B.setPWM(10, 0, ON);
     pwm_A.setPWM(12, 0, ON);
     pwm_B.setPWM(7, 0, ON);
     pwm_D.setPWM(2, 0, ON);
     break;
   case 2: //figure is released
     pwm_A.setPWM(1, 0, ON);
     pwm_B.setPWM(2, 0, ON);
     pwm_C.setPWM(4, 0, ON);
     pwm_B.setPWM(10, 0, ON);
     pwm_A.setPWM(12, 0, ON);
     pwm_B.setPWM(7, 0, ON);
     pwm_D.setPWM(2, 0, ON);
 }
}
#include "motor.h"

// default constructor intializes timer.
MOTOR::MOTOR() {
  interval = 350;   // milliseconds
}
#include "Arduino.h"    // for digitalRead, digitalWrite, etc.

#ifndef _MOTOR_H_
#define _MOTOR_H_

#define  ON 500
#define OFF 0

class MOTOR {
public:
    // members
    unsigned int pin;           // Assigned pin number
    unsigned long startTime;    // Starting milliseconds for the interval.
    unsigned long interval;     // motor is on for xNumber of milliseconds.
    boolean onOff;              // Keep track when motor is ON or OFF.

    // methods
    MOTOR();

private:
        
};

#endif
unsigned char keys[ROWS][COLS] = {
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'},
 {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}
};

Regardless of which key is actually pressed, return 'x'. Well, that will certainly make it easy to know what to do. Just do it!

I replaced it with pins numbers but what to do with adresses?)

unsigned int keys[ROWS][COLS] = {
  {1,  1,  2, 13, 14,  9, 10,  5,  6},
  {2,  3,  4, 15, 16, 11, 12,  7,  8},
  {3,  5,  6,  1,  2, 12, 14,  9, 10},
  {4,  7,  8,  3,  4, 15, 16, 11, 12},
  {5,  9, 10,  5,  6,  1,  2, 13, 14},
  {6, 11, 12,  7,  8,  3,  4, 15, 16}
};

Why are the pin numbers repeated in the array ? Is not each switch connected to a separate pin ?

Because I have four shilds with sixteen pins, so the pin numbers repeat but with different addresses

I replaced it with pins numbers but what to do with adresses?)

Why? You want to know what row and column the selection happens in. Make the values in the array reflect that. You can use any values you like, but 11, 12, 13 across and 11, 21, 31 down (in the first column) will make it very easy to figure out which row and column were impacted.

I'm not sure that I correctly understood you, or how to use it.

In my first code key are numbered from 0, 1, 2 ... 51, 52,53 and I maped a number of key to a number of the motor, but the problem was that I did not know how to assigne adress and pin to this number. I know where my key in an array placed and the motor aswell. But how I should send the command?
pwm(adress).SetPWM(pin number from 0 to 16, 0 (same everywhere), 500(same everywhere));

It seems that now you offer replaced numbers with another numbers)

I don't understand what you mean by address and how that relates to pwm(address).SetPWM().

Is pwm() a function?

Sorry for dump explanation).Here is about adresses

And in the begining I declare them for 4 shilds:
Adafruit_PWMServoDriver pwm_A = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm_B = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver pwm_C = Adafruit_PWMServoDriver(0x42);
Adafruit_PWMServoDriver pwm_D = Adafruit_PWMServoDriver(0x44);

Those are not addresses. They are names. The names are gone when the code gets compiled. You need to create an array of Adafruit_PWMServoDriver objects, so you can reference them by index.

Adafruit_PWMServoDriver drivers[] = 
{
   Adafruit_PWMServoDriver(0x40),
   Adafruit_PWMServoDriver(0x41),
   Adafruit_PWMServoDriver(0x42),
   Adafruit_PWMServoDriver(0x44)
};

Then, the keys array should have values that look like drivers index * 16 + pin number.

That makes it easy to use the value - index = val / 16 and pin number = val % 16.

Hooray! Thit part works perfect! Thanks!

But now I have another problem.
I have books that open and shut by the motors. Initially, they are closed. When I resive command: 1, 2, 3 .. the appropriate group of books should start moving and stop when they click the switchs button. In this position, they are open. When I get a command 11, 12, 13 ... appropriate groups of books as well start moving and stop after ~ 380 milliseconds. And now they a closed.

It works, but some books of group periodically confused. I mean, when they have to be closed for some reason they are open and vice versa. Or if I Receive a few commands at the same time some books of group suddenly don't stopped. Why is this happening? Where is the mistake?

My code attached

motorMatrix.ino (14.7 KB)