/***************************************************
Filename: This code perform following functions:
1. Read 3x4 matrix keypad PID3845
2. Control individual 30 servos to open or close position via I2C bus
using 2 PCA9685 drivers
Author: Nghia Tran
Date Jan 8, 2024
This code is base on examples from Adafruit for multi-servo
channels driver PCA9685
------> http://www.adafruit.com/products/815
These drivers use I2C to communicate, 2 pins are required to
interface.
****************************************************/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include "Adafruit_Keypad.h"
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40); //I2C address of board 1
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41); //I2C address of board 2
#define NUM_MUSICBOX 30
#define BUF_LEN 5
// Depending on your servo make, the pulse width min and max may vary, you
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN 400 //Actuator closed position // Servo Min: 150 This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 470 //Actuator open position // Servo Max: 600 This is the 'maximum' pulse length count (out of 4096)
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
// define your specific keypad here via PID
#define KEYPAD_PID3845 // * PID3845 3x4 Matrix Keypad
// define your pins here
// can ignore ones that don't apply
#define R1 2
#define R2 3
#define R3 4
#define R4 5
#define C1 8
#define C2 9
#define C3 10
#define C4 11
// leave this import after the above configuration
#include "keypad_config.h"
//initialize an instance of class NewKeypad
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// our servo # counter
uint8_t servonum = 0;
uint8_t boxplaying = 0;
int servo_oe1_pin = 12;
int servo_oe2_pin = 13;
uint8_t key_press = 0;
uint8_t key = 0;
uint8_t num_digit = 0;
int song_num = 0;
uint8_t key_buf[BUF_LEN];
uint8_t buf_index = 0;
boolean new_song = false;
uint8_t song_current = 0;
boolean stop_song = false;
boolean start_song = false;
void setup() {
Serial.begin(9600);
Serial.println("8 channel Servo test!");
customKeypad.begin();
pinMode(servo_oe1_pin, OUTPUT); // This pin control output enable of PCA9685 board
pinMode(servo_oe2_pin, OUTPUT); // This pin control output enable of PCA9685 board
pinMode(servo_oe1_pin, HIGH); // Disable all motors
pinMode(servo_oe2_pin, HIGH); // Disable all motors); // Disable all motors
pwm1.begin();
pwm2.begin();
/*
* In theory the internal oscillator (clock) is 25MHz but it really isn't
* that precise. You can 'calibrate' this by tweaking this number until
* you get the PWM update frequency you're expecting!
* The int.osc. for the PCA9685 chip is a range between about 23-27MHz and
* is used for calculating things like writeMicroseconds()
* Analog servos run at ~50 Hz updates, It is importaint to use an
* oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip.
* 1) Attach the oscilloscope to one of the PWM signal pins and ground on
* the I2C PCA9685 chip you are setting the value for.
* 2) Adjust setOscillatorFrequency() until the PWM update frequency is the
* expected value (50Hz for most ESCs)
* Setting the value here is specific to each individual I2C PCA9685 chip and
* affects the calculations for the PWM update frequency.
* Failure to correctly set the int.osc value will cause unexpected PWM results
*/
pwm1.setOscillatorFrequency(27000000);
pwm1.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
pwm2.setOscillatorFrequency(27000000);
pwm2.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
delay(10);
}
//********************************
void setPCA9685Enable(void){
digitalWrite(servo_oe1_pin, LOW);
digitalWrite(servo_oe2_pin, LOW);
}
//********************************
void setPCA9685Disable(void){
digitalWrite(servo_oe1_pin, HIGH);
digitalWrite(servo_oe2_pin, HIGH);
}
//*********************************
void setLockAll(void){
setPCA9685Enable();
delay(10);
for (servonum = 0; servonum < 16; servonum++){
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm1.setPWM(servonum, 0, pulselen);
}
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm2.setPWM(servonum, 0, pulselen);
}
delay(10);
}
setPCA9685Disable();
}
//*******************************************************************************
// setPlayBox
// input: box number
// execute: Move actuator to open position
// If box number from 1-15, access servo driver PCA9685 board #1, I2C address 0x40
// If box number from 16-30, access servo driver PCA9685 board #2, I2C address 0x41
//**********************************************************************************
void setPlayBox(uint8_t boxnum){
delay(100);
if(boxnum < 16){
servonum = boxnum - 1;
pwm1.setPWM(servonum, 0, SERVOMAX);
}
else if(boxnum < 31){
servonum = boxnum - 16;
pwm2.setPWM(servonum, 0, SERVOMAX);
}
delay(100);
setPCA9685Enable();
delay(100);
if(boxnum < 16){
servonum = boxnum - 1;
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm1.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
}
else if(boxnum < 31){
servonum = boxnum - 16;
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm2.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
}
else{
}
delay(500);
//setPCA9685Disable(); //Don't do this. It makes servo go crazy
delay(100);
}
//**********************************************
// SetStopBox
// input: box number
// execute: Move actuator to closed position
// If box number from 1-15, access servo driver PCA9685 board #1, I2C address 0x40
// If box number from 16-30, access servo driver PCA9685 board #2, I2C address 0x41
// If box number is 88 following by a "#", all servo move to openned positions
// If box number is 99 following by a "#", all servo move to closed positions
//**********************************************
void setStopBox(uint8_t boxnum){
delay(100);
setPCA9685Enable();
delay(100);
if(boxnum < 16){
servonum = boxnum - 1;
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm1.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
}
else if(boxnum < 31){
servonum = boxnum - 16;
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm2.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
}
// if boxnum is 99, set all motors to lock position
else if(boxnum == 99){
// Drive each servo one at a time using setPWM()
for (servonum = 0; servonum <= 15; servonum++){
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm1.setPWM(servonum, 0, pulselen);
delay(3);
}
delay(100);
Serial.println(servonum);
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm2.setPWM(servonum, 0, pulselen);
delay(3);
}
delay(100);
}
}
// if boxnum is 88, set all motors to open position
else if(boxnum == 88){
// Drive each servo one at a time using setPWM()
for (servonum = 0; servonum <= 15; servonum++){
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm1.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
delay(100);
Serial.println(servonum);
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm2.setPWM(servonum, 0, pulselen);
delay(3); //Move slow
}
delay(100);
}
}
else{
}
delay(500);
//setPCA9685Disable();
delay(100);
}
//***************************************************************
//* Main loop here
//***************************************************************
void loop() {
// put your main code here, to run repeatedly:
customKeypad.tick();
while(customKeypad.available()){
keypadEvent e = customKeypad.read();
key_press = (uint8_t)e.bit.KEY;
//Serial.println(key_press);
Serial.println((char)e.bit.KEY);
if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed");
else if(e.bit.EVENT == KEY_JUST_RELEASED){
Serial.println(" released");
if(key_press == 35){ //If key press is "#", stop play song
//Stop play
//clear key buffer
if(num_digit == 0){
for(int i = 0; i < BUF_LEN; i++){
key_buf[i] = 0;
}
}
else if (num_digit == 1){
song_num = key_buf[0] - 48;
Serial.println(song_num);
}
else if (num_digit == 2){
song_num = 10*(key_buf[0] - 48) + (key_buf[1] - 48);
Serial.println(song_num);
}
new_song = true;
stop_song = true;
start_song = false;
num_digit = 0;
}
else if(key_press == 42){ //If key press is "*", start play song
// for(int i = 0; i < BUF_LEN; i++){
// Serial.print(key_buf[i]);
// Serial.println();
// }
if (num_digit == 1){
song_num = key_buf[0] - 48;
Serial.println(song_num);
}
else if (num_digit == 2){
song_num = 10*(key_buf[0] - 48) + (key_buf[1] - 48);
Serial.println(song_num);
}
num_digit = 0;
new_song = true;
stop_song = false;
start_song = true;
}
else if(key_press >=48 && key_press <= 57){ //Key 0-9
if(num_digit == 0){
key_buf[0] = key_press;
num_digit++;
}
else if(num_digit == 1){
key_buf[1] = key_press;
num_digit++;
}
else if(num_digit >= 2){
num_digit = 2;
}
// Serial.println(num_digit);
}
}
}
if(new_song == true){
Serial.print("Song number: ");
Serial.println(song_num);
if(song_num != song_current){
if(start_song == true){
// Stop current play
//setStopBox(song_current);
Serial.print("Stop playing song: ");
Serial.println(song_current);
setStopBox(song_current);
delay(1000);
Serial.print("Star playing song: ");
Serial.println(song_num);
setPlayBox(song_num);
delay(1000);
song_current = song_num;
new_song = false;
}
else{
Serial.print("Stop playing song: ");
Serial.println(song_num);
setStopBox(song_num);
//song_current = 0;
new_song = false;
}
}
else{
Serial.print("Play same song ");
if(start_song == false){
Serial.print("Stop playing song: ");
Serial.println(song_num);
setStopBox(song_current);
song_current = 0;
}
new_song = false;
}
}
delay(30);
}
Comments
Please log in or sign up to comment.