├── CAD ├── Bug.f3d └── Bug.step ├── Code └── Bug │ ├── BluetoothHandle.h │ ├── Bug.ino │ ├── Buzzer.cpp │ ├── Buzzer.h │ ├── Emakefun_MS_PWMServoDriver.cpp │ ├── Emakefun_MS_PWMServoDriver.h │ ├── Emakefun_MotorDriver.cpp │ ├── Emakefun_MotorDriver.h │ ├── IRremote.cpp │ ├── IRremote.h │ ├── Keymap.cpp │ ├── PS2X_lib.cpp │ ├── PS2X_lib.h │ ├── PinChangeInt.h │ ├── Protocol.h │ ├── ProtocolParser.cpp │ ├── ProtocolParser.h │ ├── RGBLed.cpp │ ├── RGBLed.h │ ├── SmartCar.cpp │ ├── SmartCar.h │ ├── Sounds.h │ ├── debug.cpp │ ├── debug.h │ ├── keymap.h │ ├── nRF24L01.cpp │ └── nRF24L01.h ├── LICENSE ├── README.md └── STLs ├── Body (Qty 1).stl ├── Drive Wheel (Qty 2).stl ├── Idle Wheel (Qty 2).stl ├── Lid (Qty 1).stl ├── TPU Tread (Qty 2).stl └── Wheel Brace (Qty 2).stl /CAD/Bug.f3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshuaStanleyRobotics/Bug/0fb50739de4e51ffd094ff89c9dffecbf4db93b3/CAD/Bug.f3d -------------------------------------------------------------------------------- /Code/Bug/BluetoothHandle.h: -------------------------------------------------------------------------------- 1 | #ifndef _BUTTON_H_ 2 | #define _BUTTON_H_ 3 | 4 | //These are our button constantst 5 | 6 | #define BT_L2 0x0001 7 | #define BT_START 0x0002 8 | #define BT_PAD_RIGHT 0x0004 9 | #define BT_PAD_UP 0x0008 10 | #define BT_PAD_LEFT 0x0010 11 | #define BT_PAD_DOWN 0x0020 12 | #define BT_R1 0x0040 13 | #define BT_L1 0x0080 14 | #define BT_SELECT 0x0100 15 | #define BT_R2 0x0200 16 | #define BT_L3 0x0400 17 | #define BT_R3 0x0800 18 | #define BT_GREEN 0x1000 19 | #define BT_RED 0x2000 20 | #define BT_BLUE 0x4000 21 | #define BT_PINK 0x8000 22 | #define BT_TRIANGLE 0x1000 23 | #define BT_CIRCLE 0x2000 24 | #define BT_CROSS 0x4000 25 | #define BT_SQUARE 0x8000 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Code/Bug/Bug.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Description: This program is for controlling Bug. It recieves commands from the robot remote and uses those commands to determine how to drive Bug's motors. 3 | 4 | Components: The required components are an Arduino Uno, Emakefun Motor Driver Shield, NRF24L01 module, 2x DC 3-6V Gearbox Motors, Ultrasonic Distance Sensor, and a 2 Cell Lipo Battery. 5 | All components are wired to their dedicated connections on the Emakefun Shield. 6 | */ 7 | 8 | #include "Emakefun_MotorDriver.h" //Include library for Emakefun Motor Driver Shield 9 | Emakefun_MotorDriver mMotorDriver = Emakefun_MotorDriver(0x60, MOTOR_DRIVER_BOARD_V5); 10 | Emakefun_DCMotor *left = mMotorDriver.getMotor(M2); //Define Motors and Servos 11 | Emakefun_DCMotor *right = mMotorDriver.getMotor(M4); 12 | 13 | #include //Include library for NRF24L01 Radio Transceiver 14 | RF24 radio(10, 9); 15 | const byte chan[6] = "00007"; 16 | byte data[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 17 | 18 | #include 19 | int buzzer = A0; 20 | 21 | int trig = A2; //Define pins for Ultrasonic Distance Sensor 22 | int echo = A3; 23 | 24 | long xDir = 0; //Variables for requested speed and directions from remote 25 | long yDir = 0; 26 | double spd = 0; 27 | 28 | void setup() { 29 | Serial.begin(9600); 30 | 31 | radio.begin(); //Begin radio communication 32 | radio.openReadingPipe(1, chan); 33 | radio.setPALevel(RF24_PA_MIN); 34 | radio.startListening(); 35 | 36 | mMotorDriver.begin(50); //Initialize Motor Driver 37 | 38 | pinMode(trig, OUTPUT); //Set mode of Ultrasonic Distance Sensor pins 39 | pinMode(echo, INPUT); 40 | 41 | delay(1000); 42 | } 43 | 44 | void loop() { 45 | if (radio.available()) { 46 | radio.read(&data, sizeof(data)); //Read in radio data if available 47 | 48 | if (data[4] == 0) xDir = 0; //Steering controlled by left to right motion of right joystick 49 | else xDir = map(data[4], 1, 255, -255, 255); 50 | 51 | if (data[1] == 0) yDir = 0; //Forward and reverse controlled by front to back motion of left joystick 52 | else yDir = map(data[1], 1, 255, -255, 255); 53 | 54 | spd = map(data[9], 0, 255, 25, 100); //Driving speed controlled by right potentiometer 55 | spd = spd / 100; 56 | } 57 | 58 | 59 | if (yDir == 0) { //Logic for driving motors from directions commanded 60 | if (xDir == 0) { 61 | left->run(BRAKE); 62 | right->run(BRAKE); 63 | } 64 | else if (xDir > 0) { 65 | left->setSpeed(xDir * spd); 66 | left->run(FORWARD); 67 | right->setSpeed(xDir * spd * 0.6); 68 | right->run(BACKWARD); 69 | } 70 | else { 71 | left->setSpeed(-xDir * spd); 72 | left->run(BACKWARD); 73 | right->setSpeed(-xDir * spd * 0.6); 74 | right->run(FORWARD); 75 | } 76 | } 77 | else if (yDir > 0) { 78 | if (xDir > 0) { 79 | left->setSpeed(yDir * spd); 80 | left->run(FORWARD); 81 | right->setSpeed((yDir - ((xDir * yDir) / 255))*spd * 0.6); 82 | right->run(FORWARD); 83 | } 84 | else { 85 | left->setSpeed((yDir + ((xDir * yDir) / 255))*spd); 86 | left->run(FORWARD); 87 | right->setSpeed(yDir * spd * 0.6); 88 | right->run(FORWARD); 89 | } 90 | } 91 | else { 92 | if (xDir > 0) { 93 | left->setSpeed(-yDir * spd); 94 | left->run(BACKWARD); 95 | right->setSpeed((-yDir + ((xDir * yDir) / 255))*spd * 0.6); 96 | right->run(BACKWARD); 97 | } 98 | else { 99 | left->setSpeed((-yDir - ((xDir * yDir) / 255))*spd); 100 | left->run(BACKWARD); 101 | right->setSpeed(-yDir * spd * 0.6); 102 | right->run(BACKWARD); 103 | } 104 | } 105 | 106 | 107 | if (data[6]) NewTone(buzzer, 440); //Activate horn (buzzer) if right joystick is pressed 108 | else noNewTone(buzzer); 109 | 110 | int distance = Ping(); //Perform function to get distance from Ultrasonic Distance Sensor 111 | Serial.println(distance); 112 | 113 | delay(10); 114 | } 115 | 116 | int Ping() { //Function to return distance indicated by sensor in inches 117 | long duration, inches; 118 | digitalWrite(trig, LOW); 119 | delayMicroseconds(2); 120 | digitalWrite(trig, HIGH); //Sends out pulse 121 | delayMicroseconds(5); 122 | digitalWrite(trig, LOW); 123 | duration = pulseIn(echo, HIGH); //Measures how long it take for the pulse to return 124 | inches = duration / 74 / 2; //Calculates how many inches sound would travel in this time and divides by 2 for round trip 125 | inches = constrain(inches, 0, 120); //Limits readouts to be from 0 to 120 inches 126 | return inches; //Returns the distance in inches 127 | } 128 | -------------------------------------------------------------------------------- /Code/Bug/Buzzer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Buzzer.h" 3 | #include 4 | 5 | uint8_t buzzer_pin; 6 | 7 | #ifdef ME_PORT_DEFINED 8 | /** 9 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 10 | * Buzzer pins are used and initialized here. 11 | * \param[in] 12 | * None 13 | */ 14 | Buzzer::Buzzer() 15 | { 16 | buzzer_pin = 9; 17 | } 18 | 19 | /** 20 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 21 | * If the hardware serial was selected, we will used the hardware serial. 22 | * \param[in] 23 | * port - RJ25 port from PORT_1 to M2 24 | */ 25 | Buzzer::Buzzer(uint8_t port):MePort(port) 26 | { 27 | buzzer_pin = port; 28 | } 29 | 30 | /** 31 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 32 | * you can set any slot for the buzzer device. 33 | * \param[in] 34 | * port - RJ25 port from PORT_1 to M2 35 | * \param[in] 36 | * slot - SLOT1 or SLOT2 37 | */ 38 | Buzzer::Buzzer(uint8_t port, uint8_t slot):MePort(port) 39 | { 40 | buzzer_pin = s2; 41 | if(slot == SLOT2) 42 | { 43 | buzzer_pin = s2; 44 | } 45 | else 46 | { 47 | buzzer_pin = s1; 48 | } 49 | } 50 | #else // ME_PORT_DEFINED 51 | /** 52 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 53 | * \param[in] 54 | * switchPin - arduino port for buzzer detect pin. 55 | */ 56 | Buzzer::Buzzer(int pin) 57 | { 58 | buzzer_pin = pin; 59 | } 60 | #endif // ME_PORT_DEFINED 61 | 62 | /** 63 | * \par Function 64 | * setpin 65 | * \par Description 66 | * Reset the buzzer available pin by its arduino port. 67 | * \param[in] 68 | * pin - arduino port for buzzer detect pin. 69 | * \par Output 70 | * None 71 | * \par Return 72 | * None 73 | * \par Others 74 | * None 75 | */ 76 | void Buzzer::setpin(int pin) 77 | { 78 | buzzer_pin = pin; 79 | } 80 | 81 | /** 82 | * \par Function 83 | * tone 84 | * \par Description 85 | * Playing the tones. 86 | * \param[in] 87 | * pin - Which pin on board that buzzer is connecting to. 88 | * \param[in] 89 | * frequency - The speed of buzzer's tone play. 90 | * \param[in] 91 | * duration - Time of a tone play. 92 | * \par Output 93 | * None 94 | * \Return 95 | * None. 96 | * \par Others 97 | * Frequency (in hertz) and duration (in milliseconds). 98 | */ 99 | void Buzzer::tone(int pin, uint16_t frequency, uint32_t duration) 100 | { 101 | buzzer_pin = pin; 102 | int period = 1000000L / frequency; 103 | int pulse = period / 2; 104 | pinMode(buzzer_pin, OUTPUT); 105 | for (long i = 0; i < duration * 1000L; i += period) 106 | { 107 | digitalWrite(buzzer_pin, HIGH); 108 | delayMicroseconds(pulse); 109 | digitalWrite(buzzer_pin, LOW); 110 | delayMicroseconds(pulse); 111 | wdt_reset(); 112 | } 113 | } 114 | 115 | /** 116 | * \par Function 117 | * tone 118 | * \par Description 119 | * Playing the tones. 120 | * \param[in] 121 | * frequency - The speed of buzzer's tone play. 122 | * \param[in] 123 | * duration - Time of a tone play. 124 | * \par Output 125 | * None 126 | * \Return 127 | * None. 128 | * \par Others 129 | * Frequency (in hertz) and duration (in milliseconds). 130 | */ 131 | void Buzzer::tone(uint16_t frequency, uint32_t duration) 132 | { 133 | int period = 1000000L / frequency; 134 | int pulse = period / 2; 135 | pinMode(buzzer_pin, OUTPUT); 136 | for (long i = 0; i < duration * 1000L; i += period) 137 | { 138 | digitalWrite(buzzer_pin, HIGH); 139 | delayMicroseconds(pulse); 140 | digitalWrite(buzzer_pin, LOW); 141 | delayMicroseconds(pulse); 142 | wdt_reset(); 143 | } 144 | } 145 | 146 | void Buzzer::_tone (float noteFrequency, long noteDuration, int silentDuration) 147 | { 148 | 149 | // tone(10,261,500); 150 | // delay(500); 151 | 152 | if(silentDuration==0){silentDuration=1;} 153 | 154 | tone(buzzer_pin, noteFrequency, noteDuration); 155 | delay(noteDuration); //milliseconds to microseconds 156 | //noTone(PIN_Buzzer); 157 | delay(silentDuration); 158 | } 159 | 160 | 161 | void Buzzer::bendTones(float initFrequency, float finalFrequency, float prop, long noteDuration, int silentDuration){ 162 | 163 | //Examples: 164 | // bendTones (880, 2093, 1.02, 18, 1); 165 | // bendTones (note_A5, note_C7, 1.02, 18, 0); 166 | 167 | if(silentDuration==0){silentDuration=1;} 168 | 169 | if(initFrequency < finalFrequency) 170 | { 171 | for (int i=initFrequency; ifinalFrequency; i=i/prop) { 178 | _tone(i, noteDuration, silentDuration); 179 | } 180 | } 181 | } 182 | 183 | /** 184 | * \par Function 185 | * noTone 186 | * \par Description 187 | * Do not playing the tones. 188 | * \param[in] 189 | * pin - Which pin on board that buzzer is connecting to. 190 | * \par Output 191 | * None 192 | * \Return 193 | * None. 194 | * \par Others 195 | * None 196 | */ 197 | void Buzzer::noTone(int pin) 198 | { 199 | buzzer_pin = pin; 200 | pinMode(buzzer_pin, OUTPUT); 201 | digitalWrite(buzzer_pin, LOW); 202 | } 203 | 204 | /** 205 | * \par Function 206 | * noTone 207 | * \par Description 208 | * Do not playing the tones. 209 | * \param[in] 210 | * None 211 | * \par Output 212 | * None 213 | * \Return 214 | * None. 215 | * \par Others 216 | * None 217 | */ 218 | void Buzzer::noTone() 219 | { 220 | pinMode(buzzer_pin, OUTPUT); 221 | digitalWrite(buzzer_pin, LOW); 222 | } 223 | -------------------------------------------------------------------------------- /Code/Bug/Buzzer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \par Copyright (C), 2012-2016, MakeBlock 3 | * \class Buzzer 4 | * \brief Driver for Me Buzzer module. 5 | * @file Buzzer.h 6 | * @author MakeBlock 7 | * @version V1.0.0 8 | * @date 2015/11/09 9 | * @brief Header for Buzzer.cpp module 10 | * 11 | * \par Copyright 12 | * This software is Copyright (C), 2012-2016, MakeBlock. Use is subject to license \n 13 | * conditions. The main licensing options available are GPL V2 or Commercial: \n 14 | * 15 | * \par Open Source Licensing GPL V2 16 | * This is the appropriate option if you want to share the source code of your \n 17 | * application with everyone you distribute it to, and you also want to give them \n 18 | * the right to share who uses it. If you wish to use this software under Open \n 19 | * Source Licensing, you must contribute all your source code to the open source \n 20 | * community in accordance with the GPL Version 2 when your application is \n 21 | * distributed. See http://www.gnu.org/copyleft/gpl.html 22 | * 23 | * \par Description 24 | * This file is a drive for Me Buzzer device, The Me Buzzer inherited the 25 | * MeSerial class from SoftwareSerial. 26 | * 27 | * \par Method List: 28 | * 29 | * 1. void Buzzer::setpin(int pin); 30 | * 2. void Buzzer::tone(int pin, uint16_t frequency, uint32_t duration); 31 | * 3. void Buzzer::tone(uint16_t frequency, uint32_t duration) 32 | * 4. void Buzzer::noTone(int pin); 33 | * 5. void Buzzer::noTone(); 34 | * 35 | * \par History: 36 | *
 37 |  * ``         `
40 | * 41 | * @example BuzzerTest.ino 42 | */ 43 | #ifndef Buzzer_H 44 | #define Buzzer_H 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #ifdef ME_PORT_DEFINED 51 | #include "MePort.h" 52 | #endif // ME_PORT_DEFINED 53 | 54 | /** 55 | * Class: Buzzer 56 | * \par Description 57 | * Declaration of Class Buzzer. 58 | */ 59 | 60 | #ifdef ME_PORT_DEFINED 61 | class Buzzer : public MePort 62 | #else 63 | class Buzzer 64 | #endif 65 | 66 | { 67 | public: 68 | #ifdef ME_PORT_DEFINED 69 | /** 70 | * Alternate Constructor which can call your own function to map the buzzer to arduino port, 71 | * no pins are used or initialized here. 72 | * \param[in] 73 | * None 74 | */ 75 | Buzzer(); 76 | 77 | /** 78 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 79 | * If the hardware serial was selected, we will used the hardware serial. 80 | * \param[in] 81 | * port - RJ25 port from PORT_1 to M2 82 | */ 83 | Buzzer(uint8_t port); 84 | 85 | /** 86 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 87 | * you can set any slot for the buzzer device. 88 | * \param[in] 89 | * port - RJ25 port from PORT_1 to M2 90 | * \param[in] 91 | * slot - SLOT1 or SLOT2 92 | */ 93 | Buzzer(uint8_t port, uint8_t slot); 94 | #else // ME_PORT_DEFINED 95 | /** 96 | * Alternate Constructor which can call your own function to map the Buzzer to arduino port, 97 | * \param[in] 98 | * switchPin - arduino port for buzzer detect pin. 99 | */ 100 | Buzzer(int pin); 101 | #endif // ME_PORT_DEFINED 102 | /** 103 | * \par Function 104 | * setpin 105 | * \par Description 106 | * Reset the buzzer available pin by its arduino port. 107 | * \param[in] 108 | * pin - arduino port for buzzer detect pin. 109 | * \par Output 110 | * None 111 | * \par Return 112 | * None 113 | * \par Others 114 | * None 115 | */ 116 | void setpin(int pin); 117 | 118 | /** 119 | * \par Function 120 | * tone 121 | * \par Description 122 | * Playing the tones. 123 | * \param[in] 124 | * pin - Which pin on board that buzzer is connecting to. 125 | * \param[in] 126 | * frequency - The speed of buzzer's tone play. 127 | * \param[in] 128 | * duration - Time of a tone play. 129 | * \par Output 130 | * None 131 | * \Return 132 | * None. 133 | * \par Others 134 | * Frequency (in hertz) and duration (in milliseconds). 135 | */ 136 | void tone(int pin, uint16_t frequency, uint32_t duration); 137 | 138 | /** 139 | * \par Function 140 | * tone 141 | * \par Description 142 | * Playing the tones. 143 | * \param[in] 144 | * frequency - The speed of buzzer's tone play. 145 | * \param[in] 146 | * duration - Time of a tone play. 147 | * \par Output 148 | * None 149 | * \Return 150 | * None. 151 | * \par Others 152 | * Frequency (in hertz) and duration (in milliseconds). 153 | */ 154 | void tone(uint16_t frequency, uint32_t duration = 0); 155 | 156 | /** 157 | * \par Function 158 | * noTone 159 | * \par Description 160 | * Do not playing the tones. 161 | * \param[in] 162 | * pin - Which pin on board that buzzer is connecting to. 163 | * \par Output 164 | * None 165 | * \Return 166 | * None. 167 | * \par Others 168 | * None 169 | */ 170 | 171 | void _tone(float noteFrequency, long noteDuration, int silentDuration); 172 | void bendTones(float initFrequency, float finalFrequency, float prop, long noteDuration, int silentDuration); 173 | 174 | void noTone(int pin); 175 | 176 | /** 177 | * \par Function 178 | * noTone 179 | * \par Description 180 | * Do not playing the tones. 181 | * \param[in] 182 | * None 183 | * \par Output 184 | * None 185 | * \Return 186 | * None. 187 | * \par Others 188 | * None 189 | */ 190 | void noTone(); 191 | }; 192 | #endif 193 | -------------------------------------------------------------------------------- /Code/Bug/Emakefun_MS_PWMServoDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "Emakefun_MS_PWMServoDriver.h" 2 | #include 3 | #if defined(ARDUINO_SAM_DUE) 4 | #define WIRE Wire1 5 | #else 6 | #define WIRE Wire 7 | #endif 8 | 9 | Emakefun_MS_PWMServoDriver::Emakefun_MS_PWMServoDriver(uint8_t addr) { 10 | _i2caddr = addr; 11 | } 12 | 13 | void Emakefun_MS_PWMServoDriver::begin(void) { 14 | WIRE.begin(); 15 | reset(); 16 | } 17 | 18 | 19 | void Emakefun_MS_PWMServoDriver::reset(void) { 20 | write8(PCA9685_MODE1, 0x0); 21 | } 22 | 23 | void Emakefun_MS_PWMServoDriver::setPWMFreq(float freq) { 24 | //Serial.print("Attempting to set freq "); 25 | //Serial.println(freq); 26 | 27 | freq *= 0.9; // Correct for overshoot in the frequency setting (see issue #11). 28 | 29 | float prescaleval = 25000000; 30 | prescaleval /= 4096; 31 | prescaleval /= freq; 32 | prescaleval -= 1; 33 | //Serial.print("Estimated pre-scale: "); Serial.println(prescaleval); 34 | uint8_t prescale = floor(prescaleval + 0.5); 35 | //Serial.print("Final pre-scale: "); Serial.println(prescale); 36 | 37 | uint8_t oldmode = read8(PCA9685_MODE1); 38 | uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep 39 | write8(PCA9685_MODE1, newmode); // go to sleep 40 | write8(PCA9685_PRESCALE, prescale); // set the prescaler 41 | write8(PCA9685_MODE1, oldmode); 42 | delay(5); 43 | write8(PCA9685_MODE1, oldmode | 0xa1); // This sets the MODE1 register to turn on auto increment. 44 | // This is why the beginTransmission below was not working. 45 | // Serial.print("Mode now 0x"); Serial.println(read8(PCA9685_MODE1), HEX); 46 | } 47 | 48 | void Emakefun_MS_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) { 49 | //Serial.print("Setting PWM "); Serial.print(num); Serial.print(": "); Serial.print(on); Serial.print("->"); Serial.println(off); 50 | 51 | WIRE.beginTransmission(_i2caddr); 52 | #if ARDUINO >= 100 53 | WIRE.write(LED0_ON_L+4*num); 54 | WIRE.write(on); 55 | WIRE.write(on>>8); 56 | WIRE.write(off); 57 | WIRE.write(off>>8); 58 | #else 59 | WIRE.send(LED0_ON_L+4*num); 60 | WIRE.send((uint8_t)on); 61 | WIRE.send((uint8_t)(on>>8)); 62 | WIRE.send((uint8_t)off); 63 | WIRE.send((uint8_t)(off>>8)); 64 | #endif 65 | WIRE.endTransmission(); 66 | } 67 | 68 | uint8_t Emakefun_MS_PWMServoDriver::read8(uint8_t addr) { 69 | WIRE.beginTransmission(_i2caddr); 70 | #if ARDUINO >= 100 71 | WIRE.write(addr); 72 | #else 73 | WIRE.send(addr); 74 | #endif 75 | WIRE.endTransmission(); 76 | 77 | WIRE.requestFrom((uint8_t)_i2caddr, (uint8_t)1); 78 | #if ARDUINO >= 100 79 | return WIRE.read(); 80 | #else 81 | return WIRE.receive(); 82 | #endif 83 | } 84 | 85 | void Emakefun_MS_PWMServoDriver::write8(uint8_t addr, uint8_t d) { 86 | WIRE.beginTransmission(_i2caddr); 87 | #if ARDUINO >= 100 88 | WIRE.write(addr); 89 | WIRE.write(d); 90 | #else 91 | WIRE.send(addr); 92 | WIRE.send(d); 93 | #endif 94 | WIRE.endTransmission(); 95 | } 96 | -------------------------------------------------------------------------------- /Code/Bug/Emakefun_MS_PWMServoDriver.h: -------------------------------------------------------------------------------- 1 | #ifndef _Emakefun_MS_PWMServoDriver_H 2 | #define _Emakefun_MS_PWMServoDriver_H 3 | 4 | #if ARDUINO >= 100 5 | #include "Arduino.h" 6 | #else 7 | #include "WProgram.h" 8 | #endif 9 | 10 | #define PCA9685_SUBADR1 0x2 11 | #define PCA9685_SUBADR2 0x3 12 | #define PCA9685_SUBADR3 0x4 13 | 14 | #define PCA9685_MODE1 0x0 15 | #define PCA9685_PRESCALE 0xFE 16 | 17 | #define LED0_ON_L 0x6 18 | #define LED0_ON_H 0x7 19 | #define LED0_OFF_L 0x8 20 | #define LED0_OFF_H 0x9 21 | 22 | #define ALLLED_ON_L 0xFA 23 | #define ALLLED_ON_H 0xFB 24 | #define ALLLED_OFF_L 0xFC 25 | #define ALLLED_OFF_H 0xFD 26 | 27 | 28 | class Emakefun_MS_PWMServoDriver { 29 | public: 30 | Emakefun_MS_PWMServoDriver(uint8_t addr = 0x40); 31 | void begin(void); 32 | void reset(void); 33 | void setPWMFreq(float freq); 34 | void setPWM(uint8_t num, uint16_t on, uint16_t off); 35 | 36 | private: 37 | uint8_t _i2caddr; 38 | 39 | uint8_t read8(uint8_t addr); 40 | void write8(uint8_t addr, uint8_t d); 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Code/Bug/Emakefun_MotorDriver.cpp: -------------------------------------------------------------------------------- 1 | #if (ARDUINO >= 100) 2 | #include "PinChangeInt.h" 3 | #include "Arduino.h" 4 | #else 5 | #include "WProgram.h" 6 | #endif 7 | #include 8 | 9 | #include "Emakefun_MotorDriver.h" 10 | #include "Emakefun_MS_PWMServoDriver.h" 11 | #if defined(ARDUINO_SAM_DUE) 12 | #define WIRE Wire1 13 | #else 14 | #define WIRE Wire 15 | #endif 16 | 17 | #if (MICROSTEPS == 8) 18 | uint8_t microstepcurve[] = {0, 50, 98, 142, 180, 212, 236, 250, 255}; 19 | #elif (MICROSTEPS == 16) 20 | uint8_t microstepcurve[] = {0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255}; 21 | #endif 22 | 23 | Emakefun_MotorDriver::Emakefun_MotorDriver(uint8_t addr, uint8_t version) { 24 | _version = version; 25 | _addr = addr; 26 | _pwm = Emakefun_MS_PWMServoDriver(_addr); 27 | } 28 | 29 | void Emakefun_MotorDriver::begin(uint16_t freq) { 30 | // init PWM w/_freq 31 | WIRE.begin(); 32 | _pwm.begin(); 33 | _freq = freq; 34 | _pwm.setPWMFreq(_freq); // This is the maximum PWM frequency 35 | for (uint8_t i = 0; i < 16; i++) 36 | _pwm.setPWM(i, 0, 0); 37 | } 38 | 39 | void Emakefun_MotorDriver::setPWM(uint8_t pin, uint16_t value) { 40 | if (value > 4095) { 41 | _pwm.setPWM(pin, 4096, 0); 42 | } else 43 | _pwm.setPWM(pin, 0, value); 44 | } 45 | void Emakefun_MotorDriver::setPin(uint8_t pin, boolean value) { 46 | if (value == LOW) 47 | _pwm.setPWM(pin, 0, 0); 48 | else 49 | _pwm.setPWM(pin, 4096, 0); 50 | } 51 | 52 | Emakefun_DCMotor *Emakefun_MotorDriver::getMotor(uint8_t num) { 53 | if (num > 4) return NULL; 54 | num--; 55 | if (dcmotors[num].motornum == 0) { 56 | // not init'd yet! 57 | dcmotors[num].motornum = num; 58 | dcmotors[num].MC = this; 59 | uint8_t pwm, in1, in2; 60 | if (num == 0) { 61 | if (_version == MOTOR_DRIVER_BOARD_V3) { 62 | pwm = 8; in2 = 9; in1 = 10; 63 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 64 | pwm = 8; in1 = 10; 65 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 66 | in1 = 8; in2 = 10; 67 | } 68 | } else if (num == 1) { 69 | if (_version == MOTOR_DRIVER_BOARD_V3) { 70 | pwm = 13; in2 = 12; in1 = 11; 71 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 72 | pwm = 13; in1 = 11; 73 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 74 | in1 = 11; in2 = 13; 75 | } 76 | } else if (num == 2) { 77 | if (_version == MOTOR_DRIVER_BOARD_V3) { 78 | pwm = 2; in2 = 3; in1 = 4; 79 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 80 | pwm = 2; in1 = 4; 81 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 82 | in1 = 4; in2 = 2; 83 | } 84 | } else if (num == 3) { 85 | if (_version == MOTOR_DRIVER_BOARD_V3) { 86 | pwm = 7; in2 = 6; in1 = 5; 87 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 88 | pwm = 7; in1 = 5; 89 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 90 | in1 = 5; in2 = 7; 91 | } 92 | } 93 | dcmotors[num].PWMpin = pwm; 94 | dcmotors[num].IN1pin = in1; 95 | dcmotors[num].IN2pin = in2; 96 | } 97 | 98 | return &dcmotors[num]; 99 | } 100 | 101 | 102 | void Emakefun_EncoderMotor::EncoderCallback1(void) 103 | { 104 | (CallBack[0])(); 105 | } 106 | 107 | void Emakefun_EncoderMotor::EncoderCallback2(void) 108 | { 109 | (CallBack[1])(); 110 | } 111 | 112 | Emakefun_EncoderMotor::Emakefun_EncoderMotor(void) { 113 | MC = NULL; 114 | encodernum = 0; 115 | ENCODER1pin = ENCODER2pin = 0; 116 | PWMpin = IN1pin = IN2pin = 0; 117 | 118 | } 119 | 120 | void Emakefun_EncoderMotor::init(FuncPtr encoder_fun) { 121 | pinMode(ENCODER1pin, INPUT); 122 | CallBack[encodernum] = encoder_fun; 123 | if (encodernum == 0) { 124 | #if ARDUINO > 10609 125 | attachPinChangeInterrupt(ENCODER1pin, *(FuncPtr )(&EncoderCallback1), CHANGE); 126 | #else 127 | attachPinChangeInterrupt(ENCODER1pin, *(FuncPtr )(&Emakefun_EncoderMotor::EncoderCallback1), CHANGE); 128 | #endif 129 | } else if (encodernum == 1) { 130 | #if ARDUINO > 10609 131 | attachPinChangeInterrupt(ENCODER1pin, *(FuncPtr )(&EncoderCallback2), CHANGE); 132 | #else 133 | attachPinChangeInterrupt(ENCODER1pin, *(FuncPtr )(&Emakefun_EncoderMotor::EncoderCallback2), CHANGE); 134 | #endif 135 | } 136 | } 137 | 138 | Emakefun_EncoderMotor *Emakefun_MotorDriver::getEncoderMotor(uint8_t num) { 139 | if (num > 2) return NULL; 140 | num--; 141 | if (encoder[num].encodernum == 0) { 142 | // not init'd yet! 143 | encoder[num].encodernum = num; 144 | encoder[num].MC = this; 145 | uint8_t pwm, in1, in2; 146 | uint8_t encoder1pin, encoder2pin; 147 | if (num == 0) { 148 | if (_version == MOTOR_DRIVER_BOARD_V3) { 149 | pwm = 8; in2 = 9; in1 = 10; 150 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 151 | pwm = 8; in1 = 10; 152 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 153 | in1 = 8; in2 = 10; 154 | } 155 | encoder1pin = 3; encoder2pin = 2; 156 | 157 | } else if (num == 1) { 158 | if (_version == MOTOR_DRIVER_BOARD_V3) { 159 | pwm = 13; in2 = 12; in1 = 11; 160 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 161 | pwm = 13; in1 = 11; 162 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 163 | in1 = 11; in2 = 13; 164 | } 165 | encoder1pin = 7; encoder2pin = 4; 166 | } 167 | // for mega2560 168 | /* else if (num == 2) { 169 | if (_version == MOTOR_DRIVER_BOARD_V3) { 170 | pwm = 2; in2 = 3; in1 = 4; 171 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 172 | pwm = 2; in1 = 4; 173 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 174 | in1 = 4; in2 = 2; 175 | } 176 | } else if (num == 3) { 177 | if (_version == MOTOR_DRIVER_BOARD_V3) { 178 | pwm = 7; in2 = 6; in1 = 5; 179 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 180 | pwm = 7; in1 = 5; 181 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 182 | in1 = 5; in2 = 7; 183 | } 184 | } 185 | */ 186 | encoder[num].PWMpin = pwm; 187 | encoder[num].IN1pin = in1; 188 | encoder[num].IN2pin = in2; 189 | encoder[num].ENCODER1pin = encoder1pin; 190 | encoder[num].ENCODER2pin = encoder2pin; 191 | } 192 | return &encoder[num]; 193 | } 194 | 195 | void Emakefun_EncoderMotor::run(uint8_t cmd) { 196 | switch (cmd) { 197 | case FORWARD: 198 | if (MC->_version != MOTOR_DRIVER_BOARD_V4) MC->setPin(IN2pin, LOW); 199 | if (MC->_version == MOTOR_DRIVER_BOARD_V5) { 200 | MC->setPWM(IN1pin, DcSpeed); 201 | } else { 202 | MC->setPin(IN1pin, HIGH); 203 | } 204 | break; 205 | case BACKWARD: 206 | MC->setPin(IN1pin, LOW); 207 | if (MC->_version == MOTOR_DRIVER_BOARD_V5) { 208 | MC->setPWM(IN2pin, DcSpeed); 209 | } else if (MC->_version == MOTOR_DRIVER_BOARD_V3) { 210 | MC->setPin(IN2pin, HIGH); 211 | } 212 | break; 213 | case BRAKE: 214 | if (MC->_version != MOTOR_DRIVER_BOARD_V5) { 215 | MC->setPWM(PWMpin, 0); 216 | } 217 | if (MC->_version != MOTOR_DRIVER_BOARD_V4) MC->setPin(IN2pin, HIGH); 218 | MC->setPin(IN1pin, HIGH); 219 | break; 220 | case RELEASE: 221 | if (MC->_version == 4) { 222 | MC->setPin(IN1pin, LOW); 223 | } else { 224 | MC->setPin(IN1pin, LOW); 225 | MC->setPin(IN2pin, LOW); 226 | } 227 | break; 228 | } 229 | } 230 | 231 | void Emakefun_EncoderMotor::setSpeed(uint8_t speed) { 232 | if (MC->_version == 5) { 233 | DcSpeed = (speed * 16); 234 | } else { 235 | MC->setPWM(PWMpin, speed * 16); 236 | } 237 | } 238 | 239 | Emakefun_StepperMotor *Emakefun_MotorDriver::getStepper(uint16_t steps, uint8_t num) { 240 | if (num > 2) return NULL; 241 | 242 | num--; 243 | 244 | if (steppers[num].steppernum == 0) { 245 | // not init'd yet! 246 | steppers[num].steppernum = num; 247 | steppers[num].revsteps = steps; 248 | steppers[num].MC = this; 249 | uint8_t pwma, pwmb, ain1, ain2, bin1, bin2; 250 | if (num == 0) { 251 | if (_version == MOTOR_DRIVER_BOARD_V3) { 252 | pwma = 8; ain2 = 9; ain1 = 10; 253 | pwmb = 13; bin2 = 12; bin1 = 11; 254 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 255 | pwma = 8; ain1 = 10; 256 | pwmb = 13; bin1 = 11; 257 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 258 | ain1 = 8; ain2 = 10; 259 | bin1 = 13; bin2 = 11; 260 | } 261 | } else if (num == 1) { 262 | if (_version == MOTOR_DRIVER_BOARD_V3) { 263 | pwma = 2; ain2 = 3; ain1 = 4; 264 | pwmb = 7; bin2 = 6; bin1 = 5; 265 | } else if (_version == MOTOR_DRIVER_BOARD_V4) { 266 | pwma = 2; ain1 = 4; 267 | pwmb = 7; bin1 = 5; 268 | 269 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 270 | ain1 = 2; ain2 = 4; 271 | bin1 = 7; bin2 = 5; 272 | } 273 | } 274 | steppers[num].PWMApin = pwma; 275 | steppers[num].PWMBpin = pwmb; 276 | steppers[num].AIN1pin = ain1; 277 | steppers[num].AIN2pin = ain2; 278 | steppers[num].BIN1pin = bin1; 279 | steppers[num].BIN2pin = bin2; 280 | } 281 | return &steppers[num]; 282 | } 283 | 284 | Emakefun_Servo *Emakefun_MotorDriver::getServo(uint8_t num) { 285 | if (num > 8) return NULL; 286 | 287 | num--; 288 | 289 | if (servos[num].servonum == 0) { 290 | // not init'd yet! 291 | servos[num].servonum = num; 292 | servos[num].MC = this; 293 | uint8_t pwm; 294 | if (num == 0) { 295 | pwm = 0; 296 | } else if (num == 1) { 297 | pwm = 1; 298 | } else if (num == 2) { 299 | if (_version == MOTOR_DRIVER_BOARD_V4) { 300 | pwm = 3; 301 | } else { 302 | pwm = 14; 303 | } 304 | } else if (num == 3) { 305 | if (_version == MOTOR_DRIVER_BOARD_V4) { 306 | pwm = 6; 307 | } else { 308 | pwm = 15; 309 | } 310 | } 311 | if (_version == MOTOR_DRIVER_BOARD_V4 || _version == MOTOR_DRIVER_BOARD_V5) { 312 | if (num == 4) { 313 | pwm = 9; 314 | } else if (num == 5) { 315 | pwm = 12; 316 | } else if (num == 6) { 317 | if (_version == MOTOR_DRIVER_BOARD_V4) { 318 | pwm = 14; 319 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 320 | pwm = 3; 321 | } 322 | } else if (num == 7) { 323 | if (_version == MOTOR_DRIVER_BOARD_V4) { 324 | pwm = 15; 325 | } else if (_version == MOTOR_DRIVER_BOARD_V5) { 326 | pwm = 6; 327 | } 328 | } 329 | servos[num].PWMpin = pwm; 330 | } 331 | } 332 | return &servos[num]; 333 | } 334 | 335 | /****************************************** 336 | SERVOS 337 | ******************************************/ 338 | 339 | Emakefun_Servo::Emakefun_Servo(void) { 340 | MC = NULL; 341 | servonum = 0; 342 | PWMpin = 0; 343 | currentAngle = 0; 344 | } 345 | 346 | void Emakefun_Servo::setServoPulse(double pulse) { 347 | double pulselength; 348 | pulselength = 1000000; // 1,000,000 us per second 349 | pulselength /= 50; // 50 Hz 350 | pulselength /= 4096; // 12 bits of resolution 351 | pulse *= 1000; 352 | pulse /= pulselength; 353 | MC->setPWM(PWMpin, pulse); 354 | } 355 | void Emakefun_Servo::writeServo(uint8_t angle) { 356 | double pulse; 357 | pulse = 0.5 + angle / 90.0; 358 | setServoPulse(pulse); 359 | currentAngle = angle; 360 | /* if (n > 1) { 361 | currentAngle[n-12]=angle; 362 | }else{ 363 | currentAngle[n]=angle; 364 | } */ 365 | } 366 | 367 | uint8_t Emakefun_Servo::readDegrees() { 368 | return currentAngle; 369 | } 370 | 371 | /****************************************** 372 | MOTORS 373 | ******************************************/ 374 | 375 | Emakefun_DCMotor::Emakefun_DCMotor(void) { 376 | MC = NULL; 377 | motornum = 0; 378 | PWMpin = IN1pin = IN2pin = 0; 379 | } 380 | 381 | void Emakefun_DCMotor::run(uint8_t cmd) { 382 | #ifdef MOTORDEBUG 383 | #endif 384 | switch (cmd) { 385 | case FORWARD: 386 | if (MC->_version != MOTOR_DRIVER_BOARD_V4) MC->setPin(IN2pin, LOW); 387 | if (MC->_version == MOTOR_DRIVER_BOARD_V5) { 388 | MC->setPWM(IN1pin, DcSpeed); 389 | } else { 390 | MC->setPin(IN1pin, HIGH); 391 | } 392 | break; 393 | case BACKWARD: 394 | MC->setPin(IN1pin, LOW); 395 | if (MC->_version == MOTOR_DRIVER_BOARD_V5) { 396 | MC->setPWM(IN2pin, DcSpeed); 397 | } else { 398 | MC->setPin(IN2pin, HIGH); 399 | } 400 | break; 401 | case BRAKE: 402 | if (MC->_version != MOTOR_DRIVER_BOARD_V5) { 403 | MC->setPWM(PWMpin, 0); 404 | } 405 | if (MC->_version != MOTOR_DRIVER_BOARD_V4) MC->setPin(IN2pin, HIGH); 406 | MC->setPin(IN1pin, HIGH); 407 | break; 408 | case RELEASE: 409 | if (MC->_version == 4) { 410 | MC->setPin(IN1pin, LOW); 411 | } else { 412 | MC->setPin(IN1pin, LOW); 413 | MC->setPin(IN2pin, LOW); 414 | } 415 | break; 416 | } 417 | } 418 | 419 | void Emakefun_DCMotor::setSpeed(uint8_t speed) { 420 | if (MC->_version == 5) { 421 | DcSpeed = (speed * 16); 422 | } else { 423 | MC->setPWM(PWMpin, speed * 16); 424 | } 425 | } 426 | 427 | /****************************************** 428 | STEPPERS 429 | ******************************************/ 430 | Emakefun_StepperMotor::Emakefun_StepperMotor(void) { 431 | revsteps = steppernum = currentstep = 0; 432 | } 433 | void Emakefun_StepperMotor::setSpeed(uint16_t rpm) { 434 | //Serial.println("steps per rev: "); Serial.println(revsteps); 435 | //Serial.println("RPM: "); Serial.println(rpm); 436 | usperstep = 60000000 / ((uint32_t)revsteps * (uint32_t)rpm); 437 | } 438 | 439 | void Emakefun_StepperMotor::release(void) { 440 | 441 | MC->setPin(AIN1pin, LOW); 442 | MC->setPin(BIN1pin, LOW); 443 | if (MC->_version != 4) { 444 | MC->setPin(AIN2pin, LOW); 445 | MC->setPin(BIN2pin, LOW); 446 | } 447 | if (MC->_version != 5) { 448 | MC->setPWM(PWMApin, 0); 449 | MC->setPWM(PWMBpin, 0); 450 | } 451 | } 452 | 453 | void Emakefun_StepperMotor::step(uint16_t steps, uint8_t dir, uint8_t style) { 454 | uint32_t uspers = usperstep; 455 | uint8_t ret = 0; 456 | if (MC->_version == 4) style = DOUBLE; 457 | if (style == INTERLEAVE) { 458 | uspers /= 2; 459 | } 460 | else if (style == MICROSTEP) { 461 | uspers /= MICROSTEPS; 462 | steps *= MICROSTEPS; 463 | #ifdef MOTORDEBUG 464 | Serial.print("steps = "); Serial.println(steps, DEC); 465 | #endif 466 | } 467 | while (steps--) { 468 | //Serial.println("step!"); Serial.println(uspers); 469 | ret = onestep(dir, style); 470 | delayMicroseconds(uspers); 471 | //yield(); // required for ESP8266 472 | } 473 | } 474 | 475 | uint8_t Emakefun_StepperMotor::onestep(uint8_t dir, uint8_t style) { 476 | uint8_t a, b, c, d; 477 | uint8_t ocrb, ocra; 478 | 479 | ocra = ocrb = 255; 480 | 481 | // next determine what sort of stepping procedure we're up to 482 | if (style == SINGLE) { 483 | if ((currentstep / (MICROSTEPS / 2)) % 2) { // we're at an odd step, weird 484 | if (dir == FORWARD) { 485 | currentstep += MICROSTEPS / 2; 486 | } 487 | else { 488 | currentstep -= MICROSTEPS / 2; 489 | } 490 | } else { // go to the next even step 491 | if (dir == FORWARD) { 492 | currentstep += MICROSTEPS; 493 | } 494 | else { 495 | currentstep -= MICROSTEPS; 496 | } 497 | } 498 | } else if (style == DOUBLE) { 499 | if (! (currentstep / (MICROSTEPS / 2) % 2)) { // we're at an even step, weird 500 | if (dir == FORWARD) { 501 | currentstep += MICROSTEPS / 2; 502 | } else { 503 | currentstep -= MICROSTEPS / 2; 504 | } 505 | } else { // go to the next odd step 506 | if (dir == FORWARD) { 507 | currentstep += MICROSTEPS; 508 | } else { 509 | currentstep -= MICROSTEPS; 510 | } 511 | } 512 | } else if (style == INTERLEAVE) { 513 | if (dir == FORWARD) { 514 | currentstep += MICROSTEPS / 2; 515 | } else { 516 | currentstep -= MICROSTEPS / 2; 517 | } 518 | } 519 | if (style == MICROSTEP) { 520 | if (dir == FORWARD) { 521 | currentstep++; 522 | } else { 523 | // BACKWARDS 524 | currentstep--; 525 | } 526 | currentstep += MICROSTEPS * 4; 527 | currentstep %= MICROSTEPS * 4; 528 | 529 | ocra = ocrb = 0; 530 | if ( (currentstep >= 0) && (currentstep < MICROSTEPS)) { 531 | ocra = microstepcurve[MICROSTEPS - currentstep]; 532 | ocrb = microstepcurve[currentstep]; 533 | } else if ( (currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS * 2)) { 534 | ocra = microstepcurve[currentstep - MICROSTEPS]; 535 | ocrb = microstepcurve[MICROSTEPS * 2 - currentstep]; 536 | } else if ( (currentstep >= MICROSTEPS * 2) && (currentstep < MICROSTEPS * 3)) { 537 | ocra = microstepcurve[MICROSTEPS * 3 - currentstep]; 538 | ocrb = microstepcurve[currentstep - MICROSTEPS * 2]; 539 | } else if ( (currentstep >= MICROSTEPS * 3) && (currentstep < MICROSTEPS * 4)) { 540 | ocra = microstepcurve[currentstep - MICROSTEPS * 3]; 541 | ocrb = microstepcurve[MICROSTEPS * 4 - currentstep]; 542 | } 543 | } 544 | currentstep += MICROSTEPS * 4; 545 | currentstep %= MICROSTEPS * 4; 546 | #ifdef MOTORDEBUG 547 | Serial.print("current step: "); Serial.println(currentstep, DEC); 548 | Serial.print(" pwmA = "); Serial.print(ocra, DEC); 549 | Serial.print(" pwmB = "); Serial.println(ocrb, DEC); 550 | #endif 551 | if (MC->_version != 5) { 552 | MC->setPWM(PWMApin, ocra * 16); 553 | MC->setPWM(PWMBpin, ocrb * 16); 554 | } 555 | // release all 556 | uint8_t latch_state = 0; // all motor pins to 0 557 | //Serial.println(step, DEC); 558 | if (style == MICROSTEP) { 559 | if ((currentstep >= 0) && (currentstep < MICROSTEPS)) 560 | latch_state |= 0x03; 561 | if ((currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS * 2)) 562 | latch_state |= 0x06; 563 | if ((currentstep >= MICROSTEPS * 2) && (currentstep < MICROSTEPS * 3)) 564 | latch_state |= 0x0C; 565 | if ((currentstep >= MICROSTEPS * 3) && (currentstep < MICROSTEPS * 4)) 566 | latch_state |= 0x09; 567 | } else { 568 | switch (currentstep / (MICROSTEPS / 2)) { 569 | case 0: 570 | latch_state |= 0x1; // energize coil 1 only 571 | break; 572 | case 1: 573 | latch_state |= 0x3; // energize coil 1+2 574 | break; 575 | case 2: 576 | latch_state |= 0x2; // energize coil 2 only 577 | break; 578 | case 3: 579 | latch_state |= 0x6; // energize coil 2+3 580 | break; 581 | case 4: 582 | latch_state |= 0x4; // energize coil 3 only 583 | break; 584 | case 5: 585 | latch_state |= 0xC; // energize coil 3+4 586 | break; 587 | case 6: 588 | latch_state |= 0x8; // energize coil 4 only 589 | break; 590 | case 7: 591 | latch_state |= 0x9; // energize coil 1+4 592 | break; 593 | } 594 | } 595 | #ifdef MOTORDEBUG 596 | Serial.print("Latch: 0x"); Serial.println(latch_state, HEX); 597 | #endif 598 | if (MC->_version == 3) { 599 | if (latch_state & 0x1) { 600 | MC->setPin(AIN2pin, HIGH); 601 | } else { 602 | MC->setPin(AIN2pin, LOW); 603 | } 604 | if (latch_state & 0x2) { 605 | MC->setPin(BIN1pin, HIGH); 606 | } else { 607 | MC->setPin(BIN1pin, LOW); 608 | } 609 | if (latch_state & 0x4) { 610 | MC->setPin(AIN1pin, HIGH); 611 | } else { 612 | MC->setPin(AIN1pin, LOW); 613 | } 614 | if (latch_state & 0x8) { 615 | MC->setPin(BIN2pin, HIGH); 616 | } else { 617 | MC->setPin(BIN2pin, LOW); 618 | } 619 | } else if (MC->_version == 4) { 620 | if (latch_state & 0x1) { 621 | MC->setPin(AIN1pin, HIGH); 622 | } 623 | if (latch_state & 0x2) { 624 | MC->setPin(BIN1pin, HIGH); 625 | } 626 | if (latch_state & 0x4) { 627 | MC->setPin(AIN1pin, LOW); 628 | } 629 | if (latch_state & 0x8) { 630 | MC->setPin(BIN1pin, LOW); 631 | } 632 | } else if (MC->_version == 5) { 633 | if (latch_state & 0x1) { 634 | MC->setPin(AIN2pin, LOW); 635 | } else { 636 | MC->setPWM(AIN2pin, ocra * 16); 637 | } 638 | if (latch_state & 0x2) { 639 | MC->setPin(BIN1pin, LOW); 640 | } else { 641 | MC->setPWM(BIN1pin, ocrb * 16); 642 | } 643 | if (latch_state & 0x4) { 644 | MC->setPin(AIN1pin, LOW); 645 | } else { 646 | MC->setPWM(AIN1pin, ocra * 16); 647 | } 648 | if (latch_state & 0x8) { 649 | MC->setPin(BIN2pin, LOW); 650 | } else { 651 | MC->setPWM(BIN2pin, ocrb * 16); 652 | } 653 | } 654 | return currentstep; 655 | } 656 | 657 | /****************************************** 658 | SENSOR 659 | ******************************************/ 660 | 661 | Emakefun_Sensor::Emakefun_Sensor(void) { 662 | MC = NULL; 663 | mIrRecv = NULL; 664 | mPs2x = NULL; 665 | mBuzzer = NULL; 666 | mRgb = NULL; 667 | mNrf24L01 = NULL; 668 | IrPin = BuzzerPin = RgbPin = EchoPin = TrigPin = 0; 669 | Ps2xClkPin = Ps2xCmdPin = Ps2xAttPin = Ps2xDatPin = 0; 670 | P1 = P2 = P3 = P4 = P5 = 0; 671 | } 672 | 673 | void Emakefun_Sensor::SetRgbColor(E_RGB_INDEX index , long Color) 674 | { 675 | if (index == E_RGB_ALL) { 676 | mRgb->setColor(0, Color); 677 | } else { 678 | mRgb->setColor(index, Color); 679 | } 680 | mRgb->show(); 681 | } 682 | 683 | void Emakefun_Sensor::Sing(byte songName) 684 | { 685 | switch (songName) { 686 | case S_connection: 687 | mBuzzer->_tone(note_E5, 50, 30); 688 | mBuzzer->_tone(note_E6, 55, 25); 689 | mBuzzer->_tone(note_A6, 60, 10); 690 | // _tone(9, 394); 691 | break; 692 | 693 | case S_disconnection: 694 | mBuzzer->_tone(note_E5, 50, 30); 695 | mBuzzer->_tone(note_A6, 55, 25); 696 | mBuzzer->_tone(note_E6, 50, 10); 697 | break; 698 | 699 | case S_buttonPushed: 700 | mBuzzer->bendTones (note_E6, note_G6, 1.03, 20, 2); 701 | delay(30); 702 | mBuzzer->bendTones (note_E6, note_D7, 1.04, 10, 2); 703 | break; 704 | 705 | case S_mode1: 706 | mBuzzer->bendTones (note_E6, note_A6, 1.02, 30, 10); //1318.51 to 1760 707 | break; 708 | 709 | case S_mode2: 710 | mBuzzer->bendTones (note_G6, note_D7, 1.03, 30, 10); //1567.98 to 2349.32 711 | break; 712 | 713 | case S_mode3: 714 | mBuzzer->_tone(note_E6, 50, 100); //D6 715 | mBuzzer->_tone(note_G6, 50, 80); //E6 716 | mBuzzer->_tone(note_D7, 300, 0); //G6 717 | break; 718 | 719 | case S_surprise: 720 | mBuzzer->bendTones(800, 2150, 1.02, 10, 1); 721 | mBuzzer->bendTones(2149, 800, 1.03, 7, 1); 722 | break; 723 | 724 | case S_OhOoh: 725 | mBuzzer->bendTones(880, 2000, 1.04, 8, 3); //A5 = 880 726 | delay(200); 727 | 728 | for (int i = 880; i < 2000; i = i * 1.04) { 729 | mBuzzer->_tone(note_B5, 5, 10); 730 | } 731 | break; 732 | 733 | case S_OhOoh2: 734 | mBuzzer->bendTones(1880, 3000, 1.03, 8, 3); 735 | delay(200); 736 | 737 | for (int i = 1880; i < 3000; i = i * 1.03) { 738 | mBuzzer->_tone(note_C6, 10, 10); 739 | } 740 | break; 741 | 742 | case S_cuddly: 743 | mBuzzer->bendTones(700, 900, 1.03, 16, 4); 744 | mBuzzer->bendTones(899, 650, 1.01, 18, 7); 745 | break; 746 | 747 | case S_sleeping: 748 | mBuzzer->bendTones(100, 500, 1.04, 10, 10); 749 | delay(500); 750 | mBuzzer->bendTones(400, 100, 1.04, 10, 1); 751 | break; 752 | 753 | case S_happy: 754 | mBuzzer->bendTones(1500, 2500, 1.05, 20, 8); 755 | mBuzzer->bendTones(2499, 1500, 1.05, 25, 8); 756 | break; 757 | 758 | case S_superHappy: 759 | mBuzzer->bendTones(2000, 6000, 1.05, 8, 3); 760 | delay(50); 761 | mBuzzer->bendTones(5999, 2000, 1.05, 13, 2); 762 | break; 763 | 764 | case S_happy_short: 765 | mBuzzer->bendTones(1500, 2000, 1.05, 15, 8); 766 | delay(100); 767 | mBuzzer->bendTones(1900, 2500, 1.05, 10, 8); 768 | break; 769 | 770 | case S_sad: 771 | mBuzzer->bendTones(880, 669, 1.02, 20, 200); 772 | break; 773 | 774 | case S_confused: 775 | mBuzzer->bendTones(1000, 1700, 1.03, 8, 2); 776 | mBuzzer->bendTones(1699, 500, 1.04, 8, 3); 777 | mBuzzer->bendTones(1000, 1700, 1.05, 9, 10); 778 | break; 779 | 780 | case S_fart1: 781 | mBuzzer->bendTones(1600, 3000, 1.02, 2, 15); 782 | break; 783 | 784 | case S_fart2: 785 | mBuzzer->bendTones(2000, 6000, 1.02, 2, 20); 786 | break; 787 | 788 | case S_fart3: 789 | mBuzzer->bendTones(1600, 4000, 1.02, 2, 20); 790 | mBuzzer->bendTones(4000, 3000, 1.02, 2, 20); 791 | break; 792 | 793 | case S_didi: 794 | mBuzzer->_tone(note_C7, 50, 100); 795 | delay(110); 796 | mBuzzer->_tone(note_C6, 50, 100); 797 | break; 798 | } 799 | 800 | } 801 | 802 | uint16_t Emakefun_Sensor::GetUltrasonicDistance(void) 803 | { 804 | uint16_t FrontDistance; 805 | digitalWrite(TrigPin, LOW); 806 | delayMicroseconds(2); 807 | digitalWrite(TrigPin, HIGH); 808 | delayMicroseconds(10); 809 | digitalWrite(TrigPin, LOW); 810 | FrontDistance = pulseIn(EchoPin, HIGH) / 58.00; 811 | return FrontDistance; 812 | } 813 | 814 | /* 815 | Nrf24l Emakefun_MotorDriver::GetNrf24L01() { 816 | Serial.println("E_NRF24L01 in"); 817 | if (sensors.mNrf24L01 == NULL) { 818 | sensors.mNrf24L01 = new Nrf24l(NRF24L01_CE, NRF24L01_CSN); 819 | sensors.mNrf24L01->spi = &MirfHardwareSpi; 820 | sensors.mNrf24L01->init(); 821 | sensors.mNrf24L01->setRADDR((byte *)"MotorDriver"); 822 | sensors.mNrf24L01->payload = 1; 823 | sensors.mNrf24L01->channel = 90; //Set the used channel 824 | sensors.mNrf24L01->config(); 825 | } 826 | Serial.println("Got E_NRF24L01"); 827 | return sensors.mNrf24L01; 828 | 829 | } */ 830 | 831 | 832 | int Emakefun_Sensor::GetNrf24L01(char *RxaddrName) { 833 | mNrf24L01->setRADDR((byte *)RxaddrName); 834 | delay(10); 835 | if (mNrf24L01->dataReady()) { 836 | mNrf24L01->getData((byte *) &GetNrfData); 837 | return GetNrfData; 838 | } else { 839 | return NULL; 840 | } 841 | } 842 | 843 | void Emakefun_Sensor::sendNrf24l01(char *TxaddrName, int SendNrfData) { 844 | mNrf24L01->setTADDR((byte *)TxaddrName); 845 | mNrf24L01->send((byte *)&SendNrfData); 846 | while (mNrf24L01->isSending()) delay(1); //Until you send successfully, exit the loop 847 | #ifdef MOTORDEBUG 848 | Serial.print("Send success:"); 849 | Serial.println(SendNrfData); 850 | #endif 851 | delay(1000); 852 | } 853 | 854 | void *Emakefun_MotorDriver::getSensor(E_SENSOR_INDEX n) 855 | { 856 | //Serial.print("E_SENSOR_INDEX is "); 857 | //Serial.println(n); 858 | if (n == E_RGB) { 859 | if (sensors.mRgb == NULL) { 860 | sensors.RgbPin = RGB_PIN; 861 | pinMode(RGB_PIN, OUTPUT); 862 | sensors.mRgb = new RGBLed(RGB_PIN, 2); 863 | } 864 | return sensors.mRgb; 865 | } 866 | if (n == E_IR) { 867 | if (sensors.mIrRecv == NULL) { 868 | sensors.IrPin = IR_PIN; 869 | pinMode(IR_PIN, INPUT); 870 | sensors.mIrRecv = new IRremote (IR_PIN); 871 | sensors.mIrRecv->begin(); // Initialize the infrared receiver 872 | } 873 | return sensors.mIrRecv; 874 | } 875 | if (n == E_BUZZER) { 876 | if (sensors.mBuzzer == NULL) { 877 | sensors.BuzzerPin = BUZZER_PIN; 878 | if (_version == 3) sensors.BuzzerPin = 9; 879 | sensors.mBuzzer = new Buzzer(sensors.BuzzerPin); 880 | } 881 | return sensors.mBuzzer; 882 | } 883 | if (n == E_PS2X) { 884 | // Serial.println("E_PS2X in"); 885 | int error = 0; 886 | if (sensors.mPs2x == NULL) { 887 | sensors.mPs2x = new PS2X(); 888 | sensors.Ps2xClkPin = PS2_CLK; 889 | sensors.Ps2xCmdPin = PS2_CMD; 890 | sensors.Ps2xAttPin = PS2_SEL; 891 | sensors.Ps2xDatPin = PS2_DAT; 892 | error = sensors.mPs2x->config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, false, false); 893 | if (error == 0) { 894 | Serial.println("Found Controller, configured successful"); 895 | } else { 896 | Serial.println("Connect Faile"); 897 | } 898 | } 899 | return sensors.mPs2x; 900 | } 901 | if (n == E_NRF24L01) { 902 | 903 | if (sensors.mNrf24L01 == NULL) { 904 | 905 | sensors.mNrf24L01 = new Nrf24l(NRF24L01_CE, NRF24L01_CSN); 906 | sensors.mNrf24L01->init(); 907 | sensors.mNrf24L01->setRADDR((byte *)"MotorDriver"); 908 | sensors.mNrf24L01->payload = 12; 909 | sensors.mNrf24L01->channel = 90; //Set the used channel 910 | sensors.mNrf24L01->config(); 911 | } 912 | // Serial.println("Got E_NRF24L01"); 913 | return sensors.mNrf24L01; 914 | } 915 | if (n == E_ULTRASONIC) { 916 | // Serial.println("E_ULTRASONIC"); 917 | sensors.EchoPin = ECHO_PIN; 918 | sensors.TrigPin = TRIG_PIN; 919 | pinMode(ECHO_PIN, INPUT); 920 | pinMode(TRIG_PIN, OUTPUT); 921 | return NULL; 922 | } 923 | sensors.MC = this; 924 | return &sensors; 925 | } 926 | 927 | /* 928 | Emakefun_Sensor *Emakefun_MotorDriver::getSensor() 929 | { 930 | sensors.MC = this; 931 | return &sensors; 932 | } */ 933 | -------------------------------------------------------------------------------- /Code/Bug/Emakefun_MotorDriver.h: -------------------------------------------------------------------------------- 1 | #ifndef _Emakefun_MotorDriver_h_ 2 | #define _Emakefun_MotorDriver_h_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Emakefun_MS_PWMServoDriver.h" 8 | #include "IRremote.h" 9 | #include "PS2X_lib.h" //for v1.6 10 | #include "Buzzer.h" 11 | #include "RGBLed.h" 12 | #include "Sounds.h" 13 | #include "nRF24L01.h" 14 | //#define MOTORDEBUG 15 | 16 | #define MOTOR_DRIVER_BOARD_V3 3 17 | #define MOTOR_DRIVER_BOARD_V4 4 18 | #define MOTOR_DRIVER_BOARD_V5 5 19 | 20 | #define MICROSTEPS 16 // 8 or 16 21 | 22 | #define MOTOR1_A 2 23 | #define MOTOR1_B 3 24 | #define MOTOR2_A 1 25 | #define MOTOR2_B 4 26 | #define MOTOR3_A 5 27 | #define MOTOR3_B 7 28 | #define MOTOR4_A 0 29 | #define MOTOR4_B 6 30 | 31 | #define M1 1 32 | #define M2 2 33 | #define M3 3 34 | #define M4 4 35 | 36 | #define FORWARD 1 37 | #define BACKWARD 2 38 | #define BRAKE 3 39 | #define RELEASE 4 40 | 41 | #define SINGLE 1 42 | #define DOUBLE 2 43 | #define INTERLEAVE 3 44 | #define MICROSTEP 4 45 | 46 | #define RGB_PIN A1 47 | #define ECHO_PIN A3 48 | #define TRIG_PIN A2 49 | #define IR_PIN 8 50 | 51 | #if (MOTOR_DRIVER_BOARD_VER == 3) 52 | #define BUZZER_PIN 9 53 | #else 54 | #define BUZZER_PIN A0 55 | #endif 56 | 57 | #define PS2_DAT 12 58 | #define PS2_CMD 11 59 | #define PS2_SEL 10 60 | #define PS2_CLK 13 61 | 62 | #define NRF24L01_CE 10 63 | #define NRF24L01_CSN 9 64 | 65 | #define NRF_NAME "m" 66 | #define NRF_DATA_LEN 12 67 | 68 | #define UL_LIMIT_MIN 16 69 | #define UL_LIMIT_MID 20 70 | #define UL_LIMIT_MAX 500 71 | 72 | typedef enum 73 | { 74 | E_RGB = 0, 75 | E_IR = 1, 76 | E_BUZZER = 2, 77 | E_PS2X = 3, 78 | E_NRF24L01 = 4, 79 | E_ULTRASONIC = 5, 80 | E_EXTERN_PIN = 6, 81 | E_SENSOR_MAX, 82 | } E_SENSOR_INDEX; 83 | 84 | typedef void (*FuncPtr)(void); 85 | 86 | class Emakefun_MotorDriver; 87 | 88 | class Emakefun_Sensor 89 | { 90 | public: 91 | Emakefun_Sensor(void); 92 | friend class Emakefun_MotorDriver; 93 | IRremote *mIrRecv; 94 | PS2X *mPs2x; 95 | Buzzer *mBuzzer; 96 | RGBLed *mRgb; 97 | Nrf24l *mNrf24L01; 98 | void SetRgbColor(E_RGB_INDEX index, long Color); 99 | void Sing(byte songName); 100 | uint16_t GetUltrasonicDistance(void); 101 | int GetNrf24L01(char *RxaddrName); 102 | void sendNrf24l01(char *TxaddrName,int SendNrfData); 103 | private: 104 | uint8_t IrPin; // Infrared remoter pin 105 | uint8_t BuzzerPin; // Buzzer pin 106 | uint8_t RgbPin; // Rgb pin 107 | uint8_t EchoPin,TrigPin; 108 | uint8_t Ps2xClkPin, Ps2xCmdPin, Ps2xAttPin, Ps2xDatPin; // for Ps2 remoter 109 | uint8_t P1, P2, P3, P4, P5; // for Infrared tracing pin 110 | int GetNrfData,SendNrfData; 111 | Emakefun_MotorDriver *MC; 112 | }; 113 | 114 | class Emakefun_DCMotor 115 | { 116 | public: 117 | Emakefun_DCMotor(void); 118 | friend class Emakefun_MotorDriver; 119 | void run(uint8_t); 120 | void setSpeed(uint8_t); 121 | 122 | private: 123 | uint8_t PWMpin, IN1pin, IN2pin; 124 | int DcSpeed; 125 | Emakefun_MotorDriver *MC; 126 | uint8_t motornum; 127 | 128 | }; 129 | 130 | class Emakefun_EncoderMotor { 131 | public: 132 | Emakefun_EncoderMotor(void); 133 | friend class Emakefun_MotorDriver; 134 | void run(uint8_t); 135 | void setSpeed(uint8_t); 136 | void release(void); 137 | void init(FuncPtr encoder_fun); 138 | void EncoderCallback1(void); 139 | void EncoderCallback2(void); 140 | static FuncPtr CallBack[2]; 141 | private: 142 | uint8_t PWMpin, IN1pin, IN2pin; 143 | uint8_t ENCODER1pin, ENCODER2pin; 144 | uint8_t pluse; 145 | int DcSpeed; 146 | Emakefun_MotorDriver *MC; 147 | uint8_t encodernum; 148 | }; 149 | 150 | class Emakefun_StepperMotor { 151 | public: 152 | Emakefun_StepperMotor(void); 153 | friend class Emakefun_MotorDriver; 154 | void step(uint16_t steps, uint8_t dir, uint8_t style = SINGLE); 155 | void setSpeed(uint16_t); 156 | uint8_t onestep(uint8_t dir, uint8_t style); 157 | void release(void); 158 | uint32_t usperstep; 159 | 160 | private: 161 | uint8_t PWMApin, AIN1pin, AIN2pin; 162 | uint8_t PWMBpin, BIN1pin, BIN2pin; 163 | uint16_t revsteps; // # steps per revolution 164 | uint8_t currentstep; 165 | Emakefun_MotorDriver *MC; 166 | uint8_t steppernum; 167 | }; 168 | 169 | class Emakefun_Servo 170 | { 171 | public: 172 | Emakefun_Servo(void); 173 | friend class Emakefun_MotorDriver; 174 | void setServoPulse(double pulse); 175 | void writeServo(uint8_t angle); 176 | uint8_t readDegrees(); 177 | private: 178 | uint8_t PWMpin; 179 | Emakefun_MotorDriver *MC; 180 | uint8_t servonum, currentAngle; 181 | }; 182 | 183 | class Emakefun_MotorDriver 184 | { 185 | public: 186 | Emakefun_MotorDriver(uint8_t addr = 0x60, uint8_t version = 4); 187 | uint8_t _version; 188 | void begin(uint16_t freq = 1600); 189 | void setPWM(uint8_t pin, uint16_t val); 190 | void setPin(uint8_t pin, boolean val); 191 | Emakefun_DCMotor *getMotor(uint8_t n); 192 | Emakefun_StepperMotor *getStepper(uint16_t steps, uint8_t n); 193 | Emakefun_EncoderMotor *getEncoderMotor(uint8_t num); 194 | Emakefun_Servo *getServo(uint8_t n); 195 | //Emakefun_Sensor *getSensor(); 196 | void *getSensor(E_SENSOR_INDEX n); 197 | private: 198 | 199 | uint8_t _addr; 200 | uint16_t _freq; 201 | Emakefun_DCMotor dcmotors[4]; 202 | Emakefun_EncoderMotor encoder[2]; 203 | Emakefun_StepperMotor steppers[2]; 204 | Emakefun_MS_PWMServoDriver _pwm; 205 | #if (MOTOR_DRIVER_BOARD_VER == 3) 206 | Emakefun_Servo servos[4]; 207 | #else 208 | Emakefun_Servo servos[8]; 209 | #endif 210 | Emakefun_Sensor sensors; 211 | }; 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /Code/Bug/IRremote.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "IRremote.h" 3 | #include "Keymap.h" 4 | // Provides ISR 5 | #ifndef __AVR_ATmega32U4__ 6 | #include 7 | 8 | volatile irparams_t irparams; 9 | bool MATCH(uint8_t measured_ticks, uint8_t desired_us) 10 | { 11 | // Serial.print(measured_ticks);Serial.print(",");Serial.println(desired_us); 12 | return(measured_ticks >= desired_us - (desired_us>>2)-1 && measured_ticks <= desired_us + (desired_us>>2)+1); 13 | } 14 | 15 | ISR(TIMER_INTR_NAME) 16 | { 17 | // Serial.println("ISR"); 18 | //Serial.println(millis()); 19 | uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); 20 | // uint32_t new_time = micros(); 21 | // uint8_t timer = (new_time - irparams.lastTime)>>6; 22 | irparams.timer++; // One more 50us tick 23 | if (irparams.rawlen >= RAWBUF) 24 | { 25 | // Buffer overflow 26 | irparams.rcvstate = STATE_STOP; 27 | } 28 | switch(irparams.rcvstate) 29 | { 30 | case STATE_IDLE: // In the middle of a gap 31 | if (irdata == MARK) 32 | { 33 | irparams.rawlen = 0; 34 | irparams.timer = 0; 35 | irparams.rcvstate = STATE_MARK; 36 | } 37 | break; 38 | case STATE_MARK: // timing MARK 39 | if (irdata == SPACE) 40 | { 41 | // MARK ended, record time 42 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; 43 | irparams.timer = 0; 44 | irparams.rcvstate = STATE_SPACE; 45 | } 46 | break; 47 | case STATE_SPACE: // timing SPACE 48 | if (irdata == MARK) 49 | { 50 | // SPACE just ended, record it 51 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; 52 | irparams.timer = 0; 53 | irparams.rcvstate = STATE_MARK; 54 | } 55 | else 56 | { // SPACE 57 | if (irparams.timer > GAP_TICKS) 58 | { 59 | // big SPACE, indicates gap between codes 60 | // Mark current code as ready for processing 61 | // Switch to STOP 62 | // Don't reset timer; keep counting space width 63 | irparams.rcvstate = STATE_STOP; 64 | irparams.lastTime = millis(); 65 | } 66 | } 67 | break; 68 | case STATE_STOP: // waiting, measuring gap 69 | if(millis() - irparams.lastTime > 120) 70 | { 71 | irparams.rawlen = 0; 72 | irparams.timer = 0; 73 | irparams.rcvstate = STATE_IDLE; 74 | } 75 | else if (irdata == MARK) 76 | { 77 | // reset gap timer 78 | irparams.timer = 0; 79 | } 80 | break; 81 | } 82 | // irparams.lastTime = new_time; 83 | } 84 | 85 | /** 86 | * Alternate Constructor which can call your own function to map the IR to arduino port, 87 | * no pins are used or initialized here. 88 | * \param[in] 89 | * None 90 | */ 91 | IRremote::IRremote(int pin) 92 | { 93 | pinMode(pin,INPUT); 94 | irparams.recvpin = pin; 95 | // attachInterrupt(INT0, irISR, CHANGE); 96 | 97 | irDelayTime = 0; 98 | irIndex = 0; 99 | irRead = 0; 100 | irReady = false; 101 | irBuffer = ""; 102 | irPressed = false; 103 | begin(); 104 | } 105 | 106 | /** 107 | * \par Function 108 | * begin 109 | * \par Description 110 | * Initialize interrupt. 111 | * \param[in] 112 | * None 113 | * \par Output 114 | * None 115 | * \par Return 116 | * None 117 | * \par Others 118 | * None 119 | */ 120 | void IRremote::begin() 121 | { 122 | cli(); 123 | // setup pulse clock timer interrupt 124 | //Prescale /8 (16M/8 = 0.5 microseconds per tick) 125 | // Therefore, the timer interval can range from 0.5 to 128 microseconds 126 | // depending on the reset value (255 to 0) 127 | TIMER_CONFIG_NORMAL(); 128 | 129 | //Timer2 Overflow Interrupt Enable 130 | TIMER_ENABLE_INTR; 131 | 132 | // TIMER_RESET; 133 | 134 | sei(); // enable interrupts 135 | 136 | // initialize state machine variables 137 | irparams.rawlen = 0; 138 | irparams.rcvstate = STATE_IDLE; 139 | } 140 | 141 | /** 142 | * \par Function 143 | * end 144 | * \par Description 145 | * Close the interrupt. 146 | * \param[in] 147 | * None 148 | * \par Output 149 | * None 150 | * \par Return 151 | * None 152 | * \par Others 153 | * None 154 | */ 155 | void IRremote::end() 156 | { 157 | EIMSK &= ~(1 << INT0); 158 | } 159 | 160 | /** 161 | * \par Function 162 | * decode 163 | * \par Description 164 | * Decodes the received IR message. 165 | * \param[in] 166 | * None 167 | * \par Output 168 | * None 169 | * \par Return 170 | * Returns 0 if no data ready, 1 if data ready. 171 | * \par Others 172 | * Results of decoding are stored in results. 173 | */ 174 | ErrorStatus IRremote::decode() 175 | { 176 | rawbuf = irparams.rawbuf; 177 | rawlen = irparams.rawlen; 178 | if (irparams.rcvstate != STATE_STOP) 179 | { 180 | return ERROR; 181 | } 182 | 183 | if (decodeNEC()) 184 | { 185 | begin(); 186 | return SUCCESS; 187 | } 188 | begin(); 189 | return ERROR; 190 | } 191 | 192 | /** 193 | * \par Function 194 | * decodeNEC 195 | * \par Description 196 | * Decodes NEC the received IR message. 197 | * \param[in] 198 | * None 199 | * \par Output 200 | * None 201 | * \par Return 202 | * Returns ERROR if decode NEC no done, SUCCESS if decode NEC done. 203 | * \par Others 204 | * Results of decode NEC. 205 | */ 206 | // NECs have a repeat only 4 items long 207 | ErrorStatus IRremote::decodeNEC() 208 | { 209 | static unsigned long repeat_value = 0xFFFFFFFF; 210 | static byte repeta_time = 0; 211 | uint32_t data = 0; 212 | int offset = 0; // Skip first space 213 | // Initial mark 214 | if (!MATCH(rawbuf[offset], NEC_HDR_MARK/50)) 215 | { 216 | return ERROR; 217 | } 218 | offset++; 219 | // Check for repeat 220 | if (rawlen == 3 && 221 | MATCH(rawbuf[offset], NEC_RPT_SPACE/50) && 222 | MATCH(rawbuf[offset+1], NEC_BIT_MARK/50)) 223 | { 224 | rawbuf[offset] = 0; 225 | rawbuf[offset+1] = 0; 226 | repeta_time++; 227 | // if(repeta_time > 1) { 228 | repeta_time = 0; 229 | bits = 0; 230 | value = repeat_value; 231 | // Serial.println("REPEAT"); 232 | decode_type = NEC; 233 | return SUCCESS; 234 | // } 235 | } 236 | if (rawlen < (2 * NEC_BITS + 3)) 237 | { 238 | return ERROR; 239 | } 240 | // Initial space 241 | if (!MATCH(rawbuf[offset], NEC_HDR_SPACE/50)) 242 | { 243 | return ERROR; 244 | } 245 | rawbuf[offset] = 0; 246 | offset++; 247 | for (int i = 0; i < NEC_BITS; i++) 248 | { 249 | if (!MATCH(rawbuf[offset], NEC_BIT_MARK/50)) 250 | { 251 | return ERROR; 252 | } 253 | rawbuf[offset] = 0; 254 | offset++; 255 | if (MATCH(rawbuf[offset], NEC_ONE_SPACE/50)) 256 | { 257 | //data = (data << 1) | 1; 258 | data = (data >> 1) | 0x80000000; 259 | } 260 | else if (MATCH(rawbuf[offset], NEC_ZERO_SPACE/50)) 261 | { 262 | //data <<= 1; 263 | data >>= 1; 264 | } 265 | else 266 | { 267 | return ERROR; 268 | } 269 | offset++; 270 | } 271 | // Success 272 | bits = NEC_BITS; 273 | value = data; 274 | repeat_value = data; 275 | decode_type = NEC; 276 | repeta_time = 0; 277 | return SUCCESS; 278 | } 279 | 280 | /** 281 | * \par Function 282 | * mark 283 | * \par Description 284 | * Sends an IR mark for the specified number of microseconds. 285 | * \param[in] 286 | * us - THe time of a PWM. 287 | * \par Output 288 | * None 289 | * \par Return 290 | * None 291 | * \par Others 292 | * None 293 | */ 294 | void IRremote::mark(uint16_t us) 295 | { 296 | // Sends an IR mark for the specified number of microseconds. 297 | // The mark output is modulated at the PWM frequency. 298 | TIMER_ENABLE_PWM; // Enable pin 3 PWM output 299 | delayMicroseconds(us); 300 | } 301 | 302 | /** 303 | * \par Function 304 | * space 305 | * \par Description 306 | * Sends an IR mark for the specified number of microseconds. 307 | * \param[in] 308 | * us - THe time of a PWM. 309 | * \par Output 310 | * None 311 | * \par Return 312 | * None 313 | * \par Others 314 | * None 315 | */ 316 | /* Leave pin off for time (given in microseconds) */ 317 | void IRremote::space(uint16_t us) 318 | { 319 | // Sends an IR space for the specified number of microseconds. 320 | // A space is no output, so the PWM output is disabled. 321 | TIMER_DISABLE_PWM; // Disable pin 3 PWM output 322 | delayMicroseconds(us); 323 | } 324 | 325 | /** 326 | * \par Function 327 | * enableIROut 328 | * \par Description 329 | * Enable an IR for the specified number of khz. 330 | * \param[in] 331 | * us - THe time of a INTR. 332 | * \par Output 333 | * None 334 | * \par Return 335 | * None 336 | * \par Others 337 | * None 338 | */ 339 | void IRremote::enableIROut(uint8_t khz) 340 | { 341 | TIMER_DISABLE_INTR; //Timer2 disable Interrupt 342 | TIMER_CONFIG_KHZ(khz); 343 | } 344 | 345 | /** 346 | * \par Function 347 | * enableIRIn 348 | * \par Description 349 | * Enable an IR to write in. 350 | * \param[in] 351 | * None 352 | * \par Output 353 | * None 354 | * \par Return 355 | * None 356 | * \par Others 357 | * None 358 | */ 359 | // initialization 360 | void IRremote::enableIRIn() { 361 | cli(); 362 | // setup pulse clock timer interrupt 363 | //Prescale /8 (16M/8 = 0.5 microseconds per tick) 364 | // Therefore, the timer interval can range from 0.5 to 128 microseconds 365 | // depending on the reset value (255 to 0) 366 | TIMER_CONFIG_NORMAL(); 367 | 368 | //Timer2 Overflow Interrupt Enable 369 | TIMER_ENABLE_INTR; 370 | 371 | //TIMER_RESET; 372 | 373 | sei(); // enable interrupts 374 | 375 | // initialize state machine variables 376 | irparams.rcvstate = STATE_IDLE; 377 | irparams.rawlen = 0; 378 | 379 | // set pin modes 380 | pinMode(irparams.recvpin, INPUT); 381 | } 382 | 383 | /** 384 | * \par Function 385 | * sendRaw 386 | * \par Description 387 | * Send the length of data with hz. 388 | * \param[in] 389 | * buf[] - The data's buffer. 390 | * \param[in] 391 | * len - The data's length. 392 | * \param[in] 393 | * hz - The hz for sending data. 394 | * \par Output 395 | * None 396 | * \par Return 397 | * None 398 | * \par Others 399 | * None 400 | */ 401 | void IRremote::sendRaw(unsigned int buf[], int len, uint8_t hz) 402 | { 403 | enableIROut(hz); 404 | for (int i = 0; i < len; i++) 405 | { 406 | if (i & 1) 407 | { 408 | space(buf[i]); 409 | } 410 | else 411 | { 412 | mark(buf[i]); 413 | } 414 | } 415 | space(0); // Just to be sure 416 | } 417 | 418 | /** 419 | * \par Function 420 | * getString 421 | * \par Description 422 | * Get string in a INTR. 423 | * \param[in] 424 | * None 425 | * \par Output 426 | * None 427 | * \par Return 428 | * Return the result in a IRQ. 429 | * \par Others 430 | * None 431 | */ 432 | String IRremote::getString() 433 | { 434 | if(decode()) 435 | { 436 | irRead = ((value >> 8) >> 8) & 0xff; 437 | if(irRead == 0xa || irRead == 0xd) 438 | { 439 | irIndex = 0; 440 | irReady = true; 441 | } 442 | else 443 | { 444 | irBuffer += irRead; 445 | irIndex++; 446 | } 447 | irDelayTime = millis(); 448 | } 449 | else 450 | { 451 | if(irRead > 0) 452 | { 453 | if(millis() - irDelayTime > 100) 454 | { 455 | irPressed = false; 456 | irRead = 0; 457 | irDelayTime = millis(); 458 | Pre_Str = ""; 459 | } 460 | } 461 | } 462 | if(irReady) 463 | { 464 | irReady = false; 465 | String s = String(irBuffer); 466 | Pre_Str = s; 467 | irBuffer = ""; 468 | return s; 469 | } 470 | return Pre_Str; 471 | } 472 | 473 | /** 474 | * \par Function 475 | * getCode 476 | * \par Description 477 | * Get the reading code. 478 | * \param[in] 479 | * None 480 | * \par Output 481 | * None 482 | * \par Return 483 | * Return the result of reading. 484 | * \par Others 485 | * None 486 | */ 487 | unsigned char IRremote::getCode() 488 | { 489 | irIndex = 0; 490 | loop(); 491 | return irRead; 492 | } 493 | String IRremote::getKeyMap(byte keycode, byte ir_type) 494 | { 495 | byte i; 496 | ST_KEY_MAP *irkeymap = normal_ir_keymap; 497 | if (ir_type == IR_TYPE_EM) irkeymap = em_ir_keymap; 498 | for (i = 0; i < KEY_MAX; i++) { 499 | if (irkeymap[i].keycode == keycode) 500 | return irkeymap[i].keyname; 501 | } 502 | return ""; 503 | } 504 | 505 | byte IRremote::getIrKey(byte keycode, byte ir_type) 506 | { 507 | byte i; 508 | ST_KEY_MAP *irkeymap = normal_ir_keymap; 509 | if (ir_type == IR_TYPE_EM) irkeymap = em_ir_keymap; 510 | for (i = 0; i < KEY_MAX; i++) { 511 | if (irkeymap[i].keycode == keycode) 512 | return i; 513 | } 514 | return 0xFF; 515 | } 516 | /** 517 | * \par Function 518 | * sendString 519 | * \par Description 520 | * Send data. 521 | * \param[in] 522 | * s - The string you want to send. 523 | * \par Output 524 | * None 525 | * \par Return 526 | * None 527 | * \par Others 528 | * None 529 | */ 530 | void IRremote::sendString(String s) 531 | { 532 | unsigned long l; 533 | uint8_t data; 534 | s.concat('\n'); 535 | for(int i = 0;i < s.length();i++) 536 | { 537 | data = s.charAt(i); 538 | l = 0x0000ffff & (uint8_t)(~data); 539 | l = l << 8; 540 | l = l + ((uint8_t)data); 541 | l = l << 16; 542 | l = l | 0x000000ff; 543 | sendNEC(l,32); 544 | delay(20); 545 | } 546 | enableIRIn(); 547 | } 548 | 549 | /** 550 | * \par Function 551 | * sendString 552 | * \par Description 553 | * Send data. 554 | * \param[in] 555 | * v - The string you want to send. 556 | * \par Output 557 | * None 558 | * \par Return 559 | * None 560 | * \par Others 561 | * None 562 | */ 563 | void IRremote::sendString(float v) 564 | { 565 | dtostrf(v,5, 8, floatString); 566 | sendString(floatString); 567 | } 568 | 569 | /** 570 | * \par Function 571 | * sendNEC 572 | * \par Description 573 | * Send NEC. 574 | * \param[in] 575 | * data - The data you want to send. 576 | * \param[in] 577 | * nbits - The data bit you want to send. 578 | * \par Output 579 | * None 580 | * \par Return 581 | * None 582 | * \par Others 583 | * None 584 | */ 585 | void IRremote::sendNEC(unsigned long data, int nbits) 586 | { 587 | 588 | enableIROut(38); 589 | mark(NEC_HDR_MARK); 590 | space(NEC_HDR_SPACE); 591 | for (int i = 0; i < nbits; i++) 592 | { 593 | if (data & 1) 594 | { 595 | mark(NEC_BIT_MARK); 596 | space(NEC_ONE_SPACE); 597 | } 598 | else 599 | { 600 | mark(NEC_BIT_MARK); 601 | space(NEC_ZERO_SPACE); 602 | } 603 | data >>= 1; 604 | } 605 | mark(NEC_BIT_MARK); 606 | space(0); 607 | } 608 | 609 | /** 610 | * \par Function 611 | * loop 612 | * \par Description 613 | * A circle of operation. 614 | * \param[in] 615 | * None 616 | * \par Output0 617 | * None 618 | * \par Return 619 | * None 620 | * \par Others 621 | * None 622 | */ 623 | void IRremote::loop() 624 | { 625 | if(decode()) 626 | { 627 | irRead = ((value >> 8) >> 8) & 0xff; 628 | irPressed = true; 629 | if(irRead == 0xa || irRead == 0xd) 630 | { 631 | irIndex = 0; 632 | irReady = true; 633 | } 634 | else 635 | { 636 | irBuffer += irRead; 637 | irIndex++; 638 | if(irIndex > 64) 639 | { 640 | irIndex = 0; 641 | irBuffer = ""; 642 | } 643 | } 644 | irDelayTime = millis(); 645 | } 646 | else 647 | { 648 | if(irRead > 0) 649 | { 650 | // Serial.println(millis() - irDelayTime); 651 | if(millis() - irDelayTime > 0) 652 | { 653 | irPressed = false; 654 | irRead = 0; 655 | irDelayTime = millis(); 656 | } 657 | } 658 | } 659 | // Serial.println(irRead, HEX); 660 | } 661 | 662 | /** 663 | * \par Function 664 | * keyPressed 665 | * \par Description 666 | * Press key. 667 | * \param[in] 668 | * None 669 | * \par Output 670 | * None 671 | * \par Return 672 | * Return you the pressed key or not. 673 | * \par Others 674 | * None 675 | */ 676 | boolean IRremote::keyPressed(unsigned char r) 677 | { 678 | 679 | irIndex = 0; 680 | loop(); 681 | return irRead == r; 682 | } 683 | #endif // !defined(__AVR_ATmega32U4__) 684 | -------------------------------------------------------------------------------- /Code/Bug/IRremote.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef IRremote_h 3 | #define IRremote_h 4 | 5 | /* Includes ------------------------------------------------------------------*/ 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef ME_PORT_DEFINED 11 | #endif // ME_PORT_DEFINED 12 | #ifndef __AVR_ATmega32U4__ 13 | #define MARK 0 14 | #define SPACE 1 15 | #define NEC_BITS 32 16 | #define USECPERTICK 50 // microseconds per clock interrupt tick 17 | #define RAWBUF 80 // Length of raw duration buffer 18 | 19 | typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus; 20 | 21 | #define NEC_HDR_MARK 9000 22 | #define NEC_HDR_SPACE 4500 23 | #define NEC_BIT_MARK 560 24 | #define NEC_ONE_SPACE 1600 25 | #define NEC_ZERO_SPACE 560 26 | #define NEC_RPT_SPACE 2250 27 | #define NEC_RPT_PERIOD 110000 28 | 29 | 30 | #define _GAP 5000 // Minimum map between transmissions 31 | 32 | // receiver states 33 | #define STATE_IDLE 2 34 | #define STATE_MARK 3 35 | #define STATE_SPACE 4 36 | #define STATE_STOP 5 37 | 38 | 39 | // Values for decode_type 40 | #define NEC 1 41 | #define SONY 2 42 | #define RC5 3 43 | #define RC6 4 44 | #define DISH 5 45 | #define SHARP 6 46 | #define PANASONIC 7 47 | #define JVC 8 48 | #define SANYO 9 49 | #define MITSUBISHI 10 50 | #define SAMSUNG 11 51 | #define LG 12 52 | #define UNKNOWN -1 53 | 54 | #define TOPBIT 0x80000000 55 | 56 | 57 | #ifdef F_CPU 58 | #define SYSCLOCK F_CPU // main Arduino clock 59 | #else 60 | #define SYSCLOCK 16000000 // main Arduino clock 61 | #endif 62 | 63 | 64 | #define _GAP 5000 // Minimum map between transmissions 65 | #define GAP_TICKS (_GAP/USECPERTICK) 66 | 67 | 68 | #define TIMER_DISABLE_INTR (TIMSK2 = 0) 69 | #define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1)) 70 | #define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1))) 71 | #define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A)) 72 | #define TIMER_DISABLE_INTR (TIMSK2 = 0) 73 | #define TIMER_INTR_NAME TIMER2_COMPA_vect 74 | #define TIMER_CONFIG_KHZ(val) ({ \ 75 | const uint8_t pwmval = F_CPU / 2000 / (val); \ 76 | TCCR2A = _BV(WGM20); \ 77 | TCCR2B = _BV(WGM22) | _BV(CS20); \ 78 | OCR2A = pwmval; \ 79 | OCR2B = pwmval / 3; \ 80 | }) 81 | 82 | #define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) 83 | #if (TIMER_COUNT_TOP < 256) 84 | #define TIMER_CONFIG_NORMAL() ({ \ 85 | TCCR2A = _BV(WGM21); \ 86 | TCCR2B = _BV(CS20); \ 87 | OCR2A = TIMER_COUNT_TOP; \ 88 | TCNT2 = 0; \ 89 | }) 90 | #else 91 | #define TIMER_CONFIG_NORMAL() ({ \ 92 | TCCR2A = _BV(WGM21); \ 93 | TCCR2B = _BV(CS21); \ 94 | OCR2A = TIMER_COUNT_TOP / 8; \ 95 | TCNT2 = 0; \ 96 | }) 97 | #endif 98 | 99 | // information for the interrupt handler 100 | typedef struct { 101 | uint8_t recvpin; // pin for IR data from detector 102 | volatile uint8_t rcvstate; // state machine 103 | volatile uint32_t lastTime; 104 | unsigned int timer; // 105 | volatile uint8_t rawbuf[RAWBUF]; // raw data 106 | volatile uint8_t rawlen; // counter of entries in rawbuf 107 | } irparams_t; 108 | 109 | 110 | class IRremote 111 | { 112 | public: 113 | 114 | IRremote(int pin); 115 | ErrorStatus decode(); 116 | void begin(); 117 | void end(); 118 | void loop(); 119 | boolean keyPressed(unsigned char r); 120 | // void resume(); 121 | 122 | int8_t decode_type; // NEC, SONY, RC5, UNKNOWN 123 | unsigned long value; // Decoded value 124 | uint8_t bits; // Number of bits in decoded value 125 | volatile uint8_t *rawbuf; // Raw intervals in .5 us ticks 126 | int rawlen; // Number of records in rawbuf. 127 | String getString(); 128 | unsigned char getCode(); 129 | String getKeyMap(byte keycode, byte ir_type = 1); 130 | byte getIrKey(byte keycode, byte ir_type = 1); 131 | void sendString(String s); 132 | void sendString(float v); 133 | void sendNEC(unsigned long data, int nbits); 134 | void sendRaw(unsigned int buf[], int len, uint8_t hz); 135 | void enableIROut(uint8_t khz); 136 | void enableIRIn(); 137 | void mark(uint16_t us); 138 | void space(uint16_t us); 139 | private: 140 | ErrorStatus decodeNEC(); 141 | int16_t irIndex; 142 | char irRead; 143 | char floatString[5]; 144 | boolean irReady; 145 | boolean irPressed; 146 | String irBuffer; 147 | String Pre_Str; 148 | double irDelayTime; 149 | }; 150 | #endif // !__AVR_ATmega32U4__ 151 | #endif 152 | -------------------------------------------------------------------------------- /Code/Bug/Keymap.cpp: -------------------------------------------------------------------------------- 1 | #include "Keymap.h" 2 | 3 | ST_KEY_MAP normal_ir_keymap[18] = { 4 | {"1", 0x45}, 5 | {"2", 0x46}, 6 | {"3", 0x47}, 7 | {"4", 0x44}, 8 | {"5", 0x40}, 9 | {"6", 0x43}, 10 | {"7", 0x07}, 11 | {"8", 0x15}, 12 | {"9", 0x09}, 13 | {"0", 0x19}, 14 | {"*", 0x16}, 15 | {"#", 0x0D}, 16 | {"up", 0x18}, 17 | {"down", 0x52}, 18 | {"ok", 0x1C}, 19 | {"left", 0x08}, 20 | {"right", 0x5A} 21 | }; 22 | 23 | ST_KEY_MAP em_ir_keymap[21] = { 24 | {"A", 0x45}, 25 | {"B", 0x46}, 26 | {"C", 0x47}, 27 | {"D", 0x44}, 28 | {"up", 0x40}, 29 | {"+", 0x43}, 30 | {"left", 0x07}, 31 | {"ok", 0x15}, 32 | {"right", 0x09}, 33 | {"0", 0x16}, 34 | {"down", 0x19}, 35 | {"-", 0x0d}, 36 | {"1", 0x0c}, 37 | {"2", 0x18}, 38 | {"3", 0x5e}, 39 | {"4", 0x08}, 40 | {"5", 0x1c}, 41 | {"6", 0x5A}, 42 | {"7", 0x42}, 43 | {"8", 0x52}, 44 | {"9", 0x4A} 45 | }; 46 | -------------------------------------------------------------------------------- /Code/Bug/PS2X_lib.cpp: -------------------------------------------------------------------------------- 1 | #include "PS2X_lib.h" 2 | #include 3 | #include 4 | #include 5 | //#include 6 | #if defined(__SAM3X8E__) 7 | #include // For the Due 8 | #else 9 | #include // For anything else before the Due 10 | #endif 11 | #if ARDUINO > 22 12 | #include "Arduino.h" 13 | #else 14 | #include "WProgram.h" 15 | #include "pins_arduino.h" 16 | #endif 17 | 18 | static byte enter_config[] = {0x01, 0x43, 0x00, 0x01, 0x00}; 19 | static byte set_mode[] = {0x01, 0x44, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}; 20 | static byte set_bytes_large[] = {0x01, 0x4F, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00}; 21 | static byte exit_config[] = {0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A}; 22 | static byte enable_rumble[] = {0x01, 0x4D, 0x00, 0x00, 0x01}; 23 | static byte type_read[] = {0x01, 0x45, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A}; 24 | 25 | /****************************************************************************************/ 26 | boolean PS2X::NewButtonState() { 27 | return ((last_buttons ^ buttons) > 0); 28 | } 29 | 30 | /****************************************************************************************/ 31 | boolean PS2X::NewButtonState(unsigned int button) { 32 | return (((last_buttons ^ buttons) & button) > 0); 33 | } 34 | 35 | /****************************************************************************************/ 36 | boolean PS2X::ButtonPressed(unsigned int button) { 37 | return (NewButtonState(button) & Button(button)); 38 | } 39 | 40 | /****************************************************************************************/ 41 | boolean PS2X::ButtonReleased(unsigned int button) { 42 | return ((NewButtonState(button)) & ((~last_buttons & button) > 0)); 43 | } 44 | 45 | /****************************************************************************************/ 46 | boolean PS2X::Button(uint16_t button) { 47 | return ((~buttons & button) > 0); 48 | } 49 | 50 | /****************************************************************************************/ 51 | unsigned int PS2X::ButtonDataByte() { 52 | return (~buttons); 53 | } 54 | 55 | /****************************************************************************************/ 56 | byte PS2X::Analog(byte button) { 57 | return PS2data[button]; 58 | } 59 | uint16_t PS2X::LeftHart(void) 60 | { 61 | LY = float ((PS2data[PSS_LY]) - 127) / 127; 62 | LX = float ((PS2data[PSS_LX]) - 127) / 127; 63 | if ((-0.1 <= LX) && (LX <= 0.1) && (-0.1 <= LY) && (LY <= 0.1)) { 64 | return 0xFFF; 65 | } else { 66 | if ((LX > 0) && (LY > 0)) { 67 | LeftAngle = 360 - (atan(LY / LX) * 58); 68 | } else if ((LX < 0) && (LY > 0)) { 69 | LeftAngle = 180 + (abs(atan(LY / LX) * 58)); 70 | } else if ((LX < 0) && (LY < 0)) { 71 | LeftAngle = 180 - (abs(atan(LY / LX) * 58)) ; 72 | } else if ((LX > 0) && (LY < 0)) { 73 | LeftAngle = abs(atan(LY / LX) * 58); 74 | } 75 | return LeftAngle; 76 | } 77 | } 78 | uint16_t PS2X::RightHart(void) 79 | { 80 | float RY = float ((PS2data[PSS_RY]) - 127) / 127; 81 | float RX = float ((PS2data[PSS_RX]) - 127) / 127; 82 | if ((-0.1 <= RX) && (RX <= 0.1) && (-0.1 <= RY) && (RY <= 0.1)) { 83 | return 0xFFF; 84 | } else { 85 | if ((RX > 0) && (RY > 0)) { 86 | RightAngle = 360 - (atan(RY / RX) * 58); 87 | } else if ((RX < 0) && (RY > 0)) { 88 | RightAngle = 180 + (abs(atan(RY / RX) * 58)); 89 | } else if ((RX < 0) && (RY < 0)) { 90 | RightAngle = 180 - (abs(atan(RY / RX) * 58)) ; 91 | } else if ((RX > 0) && (RY < 0)) { 92 | RightAngle = abs(atan(RY / RX) * 58); 93 | } 94 | return RightAngle; 95 | } 96 | } 97 | /****************************************************************************************/ 98 | unsigned char PS2X::_gamepad_shiftinout (char byte) { 99 | unsigned char tmp = 0; 100 | for (unsigned char i = 0; i < 8; i++) { 101 | if (CHK(byte, i)) CMD_SET(); 102 | else CMD_CLR(); 103 | 104 | CLK_CLR(); 105 | delayMicroseconds(CTRL_CLK); 106 | 107 | //if(DAT_CHK()) SET(tmp,i); 108 | if (DAT_CHK()) bitSet(tmp, i); 109 | 110 | CLK_SET(); 111 | #if CTRL_CLK_HIGH 112 | delayMicroseconds(CTRL_CLK_HIGH); 113 | #endif 114 | } 115 | CMD_SET(); 116 | delayMicroseconds(CTRL_BYTE_DELAY); 117 | return tmp; 118 | } 119 | 120 | /****************************************************************************************/ 121 | void PS2X::read_gamepad() { 122 | read_gamepad(false, 0x00); 123 | } 124 | 125 | /****************************************************************************************/ 126 | boolean PS2X::read_gamepad(boolean motor1, byte motor2) { 127 | double temp = millis() - last_read; 128 | 129 | if (temp > 1500) //waited to long 130 | reconfig_gamepad(); 131 | 132 | if (temp < read_delay) //waited too short 133 | delay(read_delay - temp); 134 | 135 | if (motor2 != 0x00) 136 | motor2 = map(motor2, 0, 255, 0x40, 0xFF); //noting below 40 will make it spin 137 | 138 | char dword[9] = {0x01, 0x42, 0, motor1, motor2, 0, 0, 0, 0}; 139 | byte dword2[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 140 | 141 | // Try a few times to get valid data... 142 | for (byte RetryCnt = 0; RetryCnt < 5; RetryCnt++) { 143 | CMD_SET(); 144 | CLK_SET(); 145 | ATT_CLR(); // low enable joystick 146 | 147 | delayMicroseconds(CTRL_BYTE_DELAY); 148 | //Send the command to send button and joystick data; 149 | for (int i = 0; i < 9; i++) { 150 | PS2data[i] = _gamepad_shiftinout(dword[i]); 151 | } 152 | 153 | if (PS2data[1] == 0x79) { //if controller is in full data return mode, get the rest of data 154 | for (int i = 0; i < 12; i++) { 155 | PS2data[i + 9] = _gamepad_shiftinout(dword2[i]); 156 | } 157 | } 158 | 159 | ATT_SET(); // HI disable joystick 160 | // Check to see if we received valid data or not. 161 | // We should be in analog mode for our data to be valid (analog == 0x7_) 162 | if ((PS2data[1] & 0xf0) == 0x70) 163 | break; 164 | 165 | // If we got to here, we are not in analog mode, try to recover... 166 | reconfig_gamepad(); // try to get back into Analog mode. 167 | delay(read_delay); 168 | } 169 | 170 | // If we get here and still not in analog mode (=0x7_), try increasing the read_delay... 171 | if ((PS2data[1] & 0xf0) != 0x70) { 172 | if (read_delay < 10) 173 | read_delay++; // see if this helps out... 174 | } 175 | 176 | #ifdef PS2X_COM_DEBUG 177 | Serial.println("OUT:IN"); 178 | for (int i = 0; i < 9; i++) { 179 | Serial.print(dword[i], HEX); 180 | Serial.print(":"); 181 | Serial.print(PS2data[i], HEX); 182 | Serial.print(" "); 183 | } 184 | for (int i = 0; i < 12; i++) { 185 | Serial.print(dword2[i], HEX); 186 | Serial.print(":"); 187 | Serial.print(PS2data[i + 9], HEX); 188 | Serial.print(" "); 189 | } 190 | Serial.println(""); 191 | #endif 192 | 193 | last_buttons = buttons; //store the previous buttons states 194 | 195 | #if defined(__AVR__) 196 | buttons = *(uint16_t*)(PS2data + 3); //store as one value for multiple functions 197 | #else 198 | buttons = (uint16_t)(PS2data[4] << 8) + PS2data[3]; //store as one value for multiple functions 199 | #endif 200 | last_read = millis(); 201 | return ((PS2data[1] & 0xf0) == 0x70); // 1 = OK = analog mode - 0 = NOK 202 | } 203 | 204 | /****************************************************************************************/ 205 | byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat) { 206 | return config_gamepad(clk, cmd, att, dat, false, false); 207 | } 208 | 209 | /****************************************************************************************/ 210 | byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble) { 211 | 212 | byte temp[sizeof(type_read)]; 213 | 214 | #ifdef __AVR__ 215 | _clk_mask = digitalPinToBitMask(clk); 216 | _clk_oreg = portOutputRegister(digitalPinToPort(clk)); 217 | _cmd_mask = digitalPinToBitMask(cmd); 218 | _cmd_oreg = portOutputRegister(digitalPinToPort(cmd)); 219 | _att_mask = digitalPinToBitMask(att); 220 | _att_oreg = portOutputRegister(digitalPinToPort(att)); 221 | _dat_mask = digitalPinToBitMask(dat); 222 | _dat_ireg = portInputRegister(digitalPinToPort(dat)); 223 | #else 224 | uint32_t lport; // Port number for this pin 225 | _clk_mask = digitalPinToBitMask(clk); 226 | lport = digitalPinToPort(clk); 227 | _clk_lport_set = portOutputRegister(lport) + 2; 228 | _clk_lport_clr = portOutputRegister(lport) + 1; 229 | 230 | _cmd_mask = digitalPinToBitMask(cmd); 231 | lport = digitalPinToPort(cmd); 232 | _cmd_lport_set = portOutputRegister(lport) + 2; 233 | _cmd_lport_clr = portOutputRegister(lport) + 1; 234 | 235 | _att_mask = digitalPinToBitMask(att); 236 | lport = digitalPinToPort(att); 237 | _att_lport_set = portOutputRegister(lport) + 2; 238 | _att_lport_clr = portOutputRegister(lport) + 1; 239 | 240 | _dat_mask = digitalPinToBitMask(dat); 241 | _dat_lport = portInputRegister(digitalPinToPort(dat)); 242 | #endif 243 | 244 | pinMode(clk, OUTPUT); //configure ports 245 | pinMode(att, OUTPUT); 246 | pinMode(cmd, OUTPUT); 247 | pinMode(dat, INPUT_PULLUP); 248 | 249 | CMD_SET(); // SET(*_cmd_oreg,_cmd_mask); 250 | delay(5); 251 | CLK_SET(); 252 | delay(5); 253 | //new error checking. First, read gamepad a few times to see if it's talking 254 | read_gamepad(); 255 | delay(50); 256 | read_gamepad(); 257 | 258 | //see if it talked - see if mode came back. 259 | //If still anything but 41, 73 or 79, then it's not talking 260 | if (PS2data[1] != 0x41 && PS2data[1] != 0x73 && PS2data[1] != 0x79) { 261 | #ifdef PS2X_DEBUG 262 | Serial.println("Controller mode not matched or no controller found"); 263 | Serial.print("Expected 0x41, 0x73 or 0x79, but got "); 264 | Serial.println(PS2data[1], HEX); 265 | #endif 266 | return 1; //return error code 1 267 | } 268 | 269 | //try setting mode, increasing delays if need be. 270 | read_delay = 1; 271 | 272 | for (int y = 0; y <= 10; y++) { 273 | sendCommandString(enter_config, sizeof(enter_config)); //start config run 274 | 275 | //read type 276 | delayMicroseconds(CTRL_BYTE_DELAY); 277 | 278 | CMD_SET(); 279 | CLK_SET(); 280 | ATT_CLR(); // low enable joystick 281 | 282 | delayMicroseconds(CTRL_BYTE_DELAY); 283 | 284 | for (int i = 0; i < 9; i++) { 285 | temp[i] = _gamepad_shiftinout(type_read[i]); 286 | } 287 | 288 | ATT_SET(); // HI disable joystick 289 | 290 | controller_type = temp[3]; 291 | 292 | sendCommandString(set_mode, sizeof(set_mode)); 293 | if (rumble) { 294 | sendCommandString(enable_rumble, sizeof(enable_rumble)); 295 | en_Rumble = true; 296 | } 297 | if (pressures) { 298 | sendCommandString(set_bytes_large, sizeof(set_bytes_large)); 299 | en_Pressures = true; 300 | } 301 | sendCommandString(exit_config, sizeof(exit_config)); 302 | 303 | read_gamepad(); 304 | 305 | if (pressures) { 306 | if (PS2data[1] == 0x79) 307 | break; 308 | if (PS2data[1] == 0x73) 309 | return 3; 310 | } 311 | 312 | if (PS2data[1] == 0x73) 313 | break; 314 | 315 | if (y == 10) { 316 | #ifdef PS2X_DEBUG 317 | Serial.println("Controller not accepting commands"); 318 | Serial.print("mode stil set at"); 319 | Serial.println(PS2data[1], HEX); 320 | #endif 321 | return 2; //exit function with error 322 | } 323 | read_delay += 1; //add 1ms to read_delay 324 | } 325 | return 0; //no error if here 326 | } 327 | 328 | /****************************************************************************************/ 329 | void PS2X::sendCommandString(byte string[], byte len) { 330 | #ifdef PS2X_COM_DEBUG 331 | byte temp[len]; 332 | ATT_CLR(); // low enable joystick 333 | delayMicroseconds(CTRL_BYTE_DELAY); 334 | 335 | for (int y = 0; y < len; y++) 336 | temp[y] = _gamepad_shiftinout(string[y]); 337 | 338 | ATT_SET(); //high disable joystick 339 | delay(read_delay); //wait a few 340 | 341 | Serial.println("OUT:IN Configure"); 342 | for (int i = 0; i < len; i++) { 343 | Serial.print(string[i], HEX); 344 | Serial.print(":"); 345 | Serial.print(temp[i], HEX); 346 | Serial.print(" "); 347 | } 348 | Serial.println(""); 349 | #else 350 | ATT_CLR(); // low enable joystick 351 | for (int y = 0; y < len; y++) 352 | _gamepad_shiftinout(string[y]); 353 | ATT_SET(); //high disable joystick 354 | delay(read_delay); //wait a few 355 | #endif 356 | } 357 | 358 | /****************************************************************************************/ 359 | byte PS2X::readType() { 360 | /* 361 | byte temp[sizeof(type_read)]; 362 | 363 | sendCommandString(enter_config, sizeof(enter_config)); 364 | 365 | delayMicroseconds(CTRL_BYTE_DELAY); 366 | 367 | CMD_SET(); 368 | CLK_SET(); 369 | ATT_CLR(); // low enable joystick 370 | 371 | delayMicroseconds(CTRL_BYTE_DELAY); 372 | 373 | for (int i = 0; i<9; i++) { 374 | temp[i] = _gamepad_shiftinout(type_read[i]); 375 | } 376 | 377 | sendCommandString(exit_config, sizeof(exit_config)); 378 | 379 | if(temp[3] == 0x03) 380 | return 1; 381 | else if(temp[3] == 0x01) 382 | return 2; 383 | 384 | return 0; 385 | */ 386 | 387 | if (controller_type == 0x03) 388 | return 1; 389 | else if (controller_type == 0x01) 390 | return 2; 391 | else if (controller_type == 0x0C) 392 | return 3; //2.4G Wireless Dual Shock PS2 Game Controller 393 | 394 | return 0; 395 | } 396 | 397 | /****************************************************************************************/ 398 | void PS2X::enableRumble() { 399 | sendCommandString(enter_config, sizeof(enter_config)); 400 | sendCommandString(enable_rumble, sizeof(enable_rumble)); 401 | sendCommandString(exit_config, sizeof(exit_config)); 402 | en_Rumble = true; 403 | } 404 | 405 | /****************************************************************************************/ 406 | bool PS2X::enablePressures() { 407 | sendCommandString(enter_config, sizeof(enter_config)); 408 | sendCommandString(set_bytes_large, sizeof(set_bytes_large)); 409 | sendCommandString(exit_config, sizeof(exit_config)); 410 | 411 | read_gamepad(); 412 | read_gamepad(); 413 | 414 | if (PS2data[1] != 0x79) 415 | return false; 416 | 417 | en_Pressures = true; 418 | return true; 419 | } 420 | 421 | /****************************************************************************************/ 422 | void PS2X::reconfig_gamepad() { 423 | sendCommandString(enter_config, sizeof(enter_config)); 424 | sendCommandString(set_mode, sizeof(set_mode)); 425 | if (en_Rumble) 426 | sendCommandString(enable_rumble, sizeof(enable_rumble)); 427 | if (en_Pressures) 428 | sendCommandString(set_bytes_large, sizeof(set_bytes_large)); 429 | sendCommandString(exit_config, sizeof(exit_config)); 430 | } 431 | 432 | /****************************************************************************************/ 433 | #ifdef __AVR__ 434 | inline void PS2X::CLK_SET(void) { 435 | register uint8_t old_sreg = SREG; 436 | cli(); 437 | *_clk_oreg |= _clk_mask; 438 | SREG = old_sreg; 439 | } 440 | 441 | inline void PS2X::CLK_CLR(void) { 442 | register uint8_t old_sreg = SREG; 443 | cli(); 444 | *_clk_oreg &= ~_clk_mask; 445 | SREG = old_sreg; 446 | } 447 | 448 | inline void PS2X::CMD_SET(void) { 449 | register uint8_t old_sreg = SREG; 450 | cli(); 451 | *_cmd_oreg |= _cmd_mask; // SET(*_cmd_oreg,_cmd_mask); 452 | SREG = old_sreg; 453 | } 454 | 455 | inline void PS2X::CMD_CLR(void) { 456 | register uint8_t old_sreg = SREG; 457 | cli(); 458 | *_cmd_oreg &= ~_cmd_mask; // SET(*_cmd_oreg,_cmd_mask); 459 | SREG = old_sreg; 460 | } 461 | 462 | inline void PS2X::ATT_SET(void) { 463 | register uint8_t old_sreg = SREG; 464 | cli(); 465 | *_att_oreg |= _att_mask ; 466 | SREG = old_sreg; 467 | } 468 | 469 | inline void PS2X::ATT_CLR(void) { 470 | register uint8_t old_sreg = SREG; 471 | cli(); 472 | *_att_oreg &= ~_att_mask; 473 | SREG = old_sreg; 474 | } 475 | 476 | inline bool PS2X::DAT_CHK(void) { 477 | return (*_dat_ireg & _dat_mask) ? true : false; 478 | } 479 | 480 | #else 481 | // On pic32, use the set/clr registers to make them atomic... 482 | inline void PS2X::CLK_SET(void) { 483 | *_clk_lport_set |= _clk_mask; 484 | } 485 | 486 | inline void PS2X::CLK_CLR(void) { 487 | *_clk_lport_clr |= _clk_mask; 488 | } 489 | 490 | inline void PS2X::CMD_SET(void) { 491 | *_cmd_lport_set |= _cmd_mask; 492 | } 493 | 494 | inline void PS2X::CMD_CLR(void) { 495 | *_cmd_lport_clr |= _cmd_mask; 496 | } 497 | 498 | inline void PS2X::ATT_SET(void) { 499 | *_att_lport_set |= _att_mask; 500 | } 501 | 502 | inline void PS2X::ATT_CLR(void) { 503 | *_att_lport_clr |= _att_mask; 504 | } 505 | 506 | inline bool PS2X::DAT_CHK(void) { 507 | return (*_dat_lport & _dat_mask) ? true : false; 508 | } 509 | 510 | #endif 511 | -------------------------------------------------------------------------------- /Code/Bug/PS2X_lib.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | * Super amazing PS2 controller Arduino Library v1.8 3 | * details and example sketch: 4 | * http://www.billporter.info/?p=240 5 | * 6 | * Original code by Shutter on Arduino Forums 7 | * 8 | * Revamped, made into lib by and supporting continued development: 9 | * Bill Porter 10 | * www.billporter.info 11 | * 12 | * Contributers: 13 | * Eric Wetzel (thewetzel@gmail.com) 14 | * Kurt Eckhardt 15 | * 16 | * Lib version history 17 | * 0.1 made into library, added analog stick support. 18 | * 0.2 fixed config_gamepad miss-spelling 19 | * added new functions: 20 | * NewButtonState(); 21 | * NewButtonState(unsigned int); 22 | * ButtonPressed(unsigned int); 23 | * ButtonReleased(unsigned int); 24 | * removed 'PS' from begining of ever function 25 | * 1.0 found and fixed bug that wasn't configuring controller 26 | * added ability to define pins 27 | * added time checking to reconfigure controller if not polled enough 28 | * Analog sticks and pressures all through 'ps2x.Analog()' function 29 | * added: 30 | * enableRumble(); 31 | * enablePressures(); 32 | * 1.1 33 | * added some debug stuff for end user. Reports if no controller found 34 | * added auto-increasing sentence delay to see if it helps compatibility. 35 | * 1.2 36 | * found bad math by Shutter for original clock. Was running at 50kHz, not the required 500kHz. 37 | * fixed some of the debug reporting. 38 | * 1.3 39 | * Changed clock back to 50kHz. CuriousInventor says it's suppose to be 500kHz, but doesn't seem to work for everybody. 40 | * 1.4 41 | * Removed redundant functions. 42 | * Fixed mode check to include two other possible modes the controller could be in. 43 | * Added debug code enabled by compiler directives. See below to enable debug mode. 44 | * Added button definitions for shapes as well as colors. 45 | * 1.41 46 | * Some simple bug fixes 47 | * Added Keywords.txt file 48 | * 1.5 49 | * Added proper Guitar Hero compatibility 50 | * Fixed issue with DEBUG mode, had to send serial at once instead of in bits 51 | * 1.6 52 | * Changed config_gamepad() call to include rumble and pressures options 53 | * This was to fix controllers that will only go into config mode once 54 | * Old methods should still work for backwards compatibility 55 | * 1.7 56 | * Integrated Kurt's fixes for the interrupts messing with servo signals 57 | * Reorganized directory so examples show up in Arduino IDE menu 58 | * 1.8 59 | * Added Arduino 1.0 compatibility. 60 | * 1.9 61 | * Kurt - Added detection and recovery from dropping from analog mode, plus 62 | * integreated Chipkit (pic32mx...) support 63 | * 64 | * 65 | * 66 | *This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. 67 | This program is distributed in the hope that it will be useful, 68 | but WITHOUT ANY WARRANTY; without even the implied warranty of 69 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 70 | GNU General Public License for more details. 71 | 72 | * 73 | ******************************************************************/ 74 | 75 | // $$$$$$$$$$$$ DEBUG ENABLE SECTION $$$$$$$$$$$$$$$$ 76 | // to debug ps2 controller, uncomment these two lines to print out debug to uart 77 | //#define PS2X_DEBUG 78 | //#define PS2X_COM_DEBUG 79 | 80 | #ifndef PS2X_lib_h 81 | #define PS2X_lib_h 82 | 83 | #if ARDUINO > 22 84 | #include "Arduino.h" 85 | #else 86 | #include "WProgram.h" 87 | #endif 88 | 89 | #include 90 | #include 91 | #include 92 | #ifdef __AVR__ 93 | // AVR 94 | #include 95 | #define CTRL_CLK 4 96 | #define CTRL_BYTE_DELAY 3 97 | #else 98 | // Pic32... 99 | #include 100 | #define CTRL_CLK 5 101 | #define CTRL_CLK_HIGH 5 102 | #define CTRL_BYTE_DELAY 4 103 | #endif 104 | 105 | //These are our button constants 106 | #define PSB_SELECT 0x0001 107 | #define PSB_L3 0x0002 108 | #define PSB_R3 0x0004 109 | #define PSB_START 0x0008 110 | #define PSB_PAD_UP 0x0010 111 | #define PSB_PAD_RIGHT 0x0020 112 | #define PSB_PAD_DOWN 0x0040 113 | #define PSB_PAD_LEFT 0x0080 114 | #define PSB_L2 0x0100 115 | #define PSB_R2 0x0200 116 | #define PSB_L1 0x0400 117 | #define PSB_R1 0x0800 118 | #define PSB_GREEN 0x1000 119 | #define PSB_RED 0x2000 120 | #define PSB_BLUE 0x4000 121 | #define PSB_PINK 0x8000 122 | #define PSB_TRIANGLE 0x1000 123 | #define PSB_CIRCLE 0x2000 124 | #define PSB_CROSS 0x4000 125 | #define PSB_SQUARE 0x8000 126 | 127 | //Guitar button constants 128 | #define UP_STRUM 0x0010 129 | #define DOWN_STRUM 0x0040 130 | #define STAR_POWER 0x0100 131 | #define GREEN_FRET 0x0200 132 | #define YELLOW_FRET 0x1000 133 | #define RED_FRET 0x2000 134 | #define BLUE_FRET 0x4000 135 | #define ORANGE_FRET 0x8000 136 | #define WHAMMY_BAR 8 137 | 138 | //These are stick values 139 | #define PSS_RX 5 140 | #define PSS_RY 6 141 | #define PSS_LX 7 142 | #define PSS_LY 8 143 | 144 | //These are analog buttons 145 | #define PSAB_PAD_RIGHT 9 146 | #define PSAB_PAD_UP 11 147 | #define PSAB_PAD_DOWN 12 148 | #define PSAB_PAD_LEFT 10 149 | #define PSAB_L2 19 150 | #define PSAB_R2 20 151 | #define PSAB_L1 17 152 | #define PSAB_R1 18 153 | #define PSAB_GREEN 13 154 | #define PSAB_RED 14 155 | #define PSAB_BLUE 15 156 | #define PSAB_PINK 16 157 | #define PSAB_TRIANGLE 13 158 | #define PSAB_CIRCLE 14 159 | #define PSAB_CROSS 15 160 | #define PSAB_SQUARE 16 161 | 162 | #define SET(x,y) (x|=(1<:set ts=4 sw=4 sts=4 11 | // ...that's: ESCAPE key, colon key, then 12 | // "s-e-t SPACE key t-s = 4 SPACE key s-w = 4 SPACE key s-t-s = 4" 13 | 14 | 15 | /* 16 | VERSIONS found in moved to RELEASE_NOTES. 17 | 18 | See the README file for the License and more details. 19 | */ 20 | 21 | #ifndef PinChangeInt_h 22 | #define PinChangeInt_h 23 | 24 | #include "stddef.h" 25 | 26 | // Maurice Beelen, nms277, Akesson Karlpetter, and Orly Andico 27 | // sent in fixes to work with Arduino >= version 1.0 28 | #include 29 | #include 30 | #include // cbi and sbi defined here 31 | 32 | #undef DEBUG 33 | 34 | /* 35 | * Theory: For the IO pins covered by Pin Change Interrupts 36 | * (== all of them on the Atmega168/328, and a subset on the Atmega2560), 37 | * the PCINT corresponding to the pin must be enabled and masked, and 38 | * an ISR routine provided. Since PCINTs are per port, not per pin, the ISR 39 | * must use some logic to actually implement a per-pin interrupt service. 40 | */ 41 | 42 | /* Pin to interrupt map, ATmega328: 43 | * D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2 44 | * D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0 45 | * A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1 46 | */ 47 | 48 | #undef INLINE_PCINT 49 | #define INLINE_PCINT 50 | // Thanks to cserveny...@gmail.com for MEGA support! 51 | #if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__ 52 | #define __USE_PORT_JK 53 | // Mega does not have PORTA, C or D 54 | #define NO_PORTA_PINCHANGES 55 | #define NO_PORTC_PINCHANGES 56 | #define NO_PORTD_PINCHANGES 57 | #if ((defined(NO_PORTB_PINCHANGES) && defined(NO_PORTJ_PINCHANGES)) || \ 58 | (defined(NO_PORTJ_PINCHANGES) && defined(NO_PORTK_PINCHANGES)) || \ 59 | (defined(NO_PORTK_PINCHANGES) && defined(NO_PORTB_PINCHANGES))) 60 | #define INLINE_PCINT inline 61 | #endif 62 | #else 63 | #define NO_PORTJ_PINCHANGES 64 | #define NO_PORTK_PINCHANGES 65 | #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 66 | #ifndef NO_PORTA_PINCHANGES 67 | #define __USE_PORT_A 68 | #endif 69 | #else 70 | #define NO_PORTA_PINCHANGES 71 | #endif 72 | // if defined only D .OR. only C .OR. only B .OR. only A, then inline it 73 | #if ( (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES)) || \ 74 | (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \ 75 | (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \ 76 | (defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) ) 77 | #define INLINE_PCINT inline 78 | #endif 79 | #endif 80 | 81 | // Provide drop in compatibility with Chris J. Kiick's PCInt project at 82 | // http://www.arduino.cc/playground/Main/PcInt 83 | #define PCdetachInterrupt(pin) PCintPort::detachInterrupt(pin) 84 | #define PCattachInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, userFunc,mode) 85 | #define PCgetArduinoPin() PCintPort::getArduinoPin() 86 | 87 | typedef void (*PCIntvoidFuncPtr)(void); 88 | 89 | class PCintPort { 90 | public: 91 | // portB=PCintPort(2, 1,PCMSK1); 92 | // index: portInputReg(*portInputRegister(index)), 93 | // pcindex: PCICRbit(1 << pcindex) 94 | // maskReg: portPCMask(maskReg) 95 | PCintPort(int index,int pcindex, volatile uint8_t& maskReg) : 96 | portInputReg(*portInputRegister(index)), 97 | portPCMask(maskReg), 98 | PCICRbit(1 << pcindex), 99 | portRisingPins(0), 100 | portFallingPins(0), 101 | firstPin(NULL) 102 | #ifdef PINMODE 103 | ,intrCount(0) 104 | #endif 105 | { 106 | #ifdef FLASH 107 | ledsetup(); 108 | #endif 109 | } 110 | volatile uint8_t& portInputReg; 111 | static int8_t attachInterrupt(uint8_t pin, PCIntvoidFuncPtr userFunc, int mode); 112 | static void detachInterrupt(uint8_t pin); 113 | INLINE_PCINT void PCint(); 114 | static volatile uint8_t curr; 115 | #ifndef NO_PIN_NUMBER 116 | static volatile uint8_t arduinoPin; 117 | #endif 118 | #ifndef NO_PIN_STATE 119 | static volatile uint8_t pinState; 120 | #endif 121 | #ifdef PINMODE 122 | static volatile uint8_t pinmode; 123 | static volatile uint8_t s_portRisingPins; 124 | static volatile uint8_t s_portFallingPins; 125 | static volatile uint8_t s_lastPinView; 126 | static volatile uint8_t s_pmask; 127 | static volatile char s_PORT; 128 | static volatile uint8_t s_changedPins; 129 | static volatile uint8_t s_portRisingPins_nCurr; 130 | static volatile uint8_t s_portFallingPins_nNCurr; 131 | static volatile uint8_t s_currXORlastPinView; 132 | volatile uint8_t intrCount; 133 | static volatile uint8_t s_count; 134 | static volatile uint8_t pcint_multi; 135 | static volatile uint8_t PCIFRbug; 136 | #endif 137 | #ifdef FLASH 138 | static void ledsetup(void); 139 | #endif 140 | 141 | protected: 142 | class PCintPin { 143 | public: 144 | PCintPin() : 145 | PCintFunc((PCIntvoidFuncPtr)NULL), 146 | mode(0) {} 147 | PCIntvoidFuncPtr PCintFunc; 148 | uint8_t mode; 149 | uint8_t mask; 150 | uint8_t arduinoPin; 151 | PCintPin* next; 152 | }; 153 | void enable(PCintPin* pin, PCIntvoidFuncPtr userFunc, uint8_t mode); 154 | int8_t addPin(uint8_t arduinoPin,PCIntvoidFuncPtr userFunc, uint8_t mode); 155 | volatile uint8_t& portPCMask; 156 | const uint8_t PCICRbit; 157 | volatile uint8_t portRisingPins; 158 | volatile uint8_t portFallingPins; 159 | volatile uint8_t lastPinView; 160 | PCintPin* firstPin; 161 | }; 162 | 163 | #ifndef LIBCALL_PINCHANGEINT // LIBCALL_PINCHANGEINT *********************************************** 164 | volatile uint8_t PCintPort::curr=0; 165 | #ifndef NO_PIN_NUMBER 166 | volatile uint8_t PCintPort::arduinoPin=0; 167 | #endif 168 | #ifndef NO_PIN_STATE 169 | volatile uint8_t PCintPort::pinState=0; 170 | #endif 171 | #ifdef PINMODE 172 | volatile uint8_t PCintPort::pinmode=0; 173 | volatile uint8_t PCintPort::s_portRisingPins=0; 174 | volatile uint8_t PCintPort::s_portFallingPins=0; 175 | volatile uint8_t PCintPort::s_lastPinView=0; 176 | volatile uint8_t PCintPort::s_pmask=0; 177 | volatile char PCintPort::s_PORT='x'; 178 | volatile uint8_t PCintPort::s_changedPins=0; 179 | volatile uint8_t PCintPort::s_portRisingPins_nCurr=0; 180 | volatile uint8_t PCintPort::s_portFallingPins_nNCurr=0; 181 | volatile uint8_t PCintPort::s_currXORlastPinView=0; 182 | volatile uint8_t PCintPort::s_count=0; 183 | volatile uint8_t PCintPort::pcint_multi=0; 184 | volatile uint8_t PCintPort::PCIFRbug=0; 185 | #endif 186 | 187 | #ifdef FLASH 188 | #define PINLED 13 189 | volatile uint8_t *led_port; 190 | uint8_t led_mask; 191 | uint8_t not_led_mask; 192 | boolean ledsetup_run=false; 193 | void PCintPort::ledsetup(void) { 194 | if (! ledsetup_run) { 195 | led_port=portOutputRegister(digitalPinToPort(PINLED)); 196 | led_mask=digitalPinToBitMask(PINLED); 197 | not_led_mask=led_mask^0xFF; 198 | pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW); 199 | ledsetup_run=true; 200 | } 201 | }; 202 | #endif 203 | 204 | // 205 | // ATMEGA 644 206 | // 207 | #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino, Mosquino uino bobino bonanafannafofino, me my momino... 208 | 209 | #ifndef NO_PORTA_PINCHANGES 210 | PCintPort portA=PCintPort(1, 0,PCMSK0); // port PA==1 (from Arduino.h, Arduino version 1.0) 211 | #endif 212 | #ifndef NO_PORTB_PINCHANGES 213 | PCintPort portB=PCintPort(2, 1,PCMSK1); // port PB==2 (from Arduino.h, Arduino version 1.0) 214 | #endif 215 | #ifndef NO_PORTC_PINCHANGES 216 | PCintPort portC=PCintPort(3, 2,PCMSK2); // port PC==3 (also in pins_arduino.c, Arduino version 022) 217 | #endif 218 | #ifndef NO_PORTD_PINCHANGES 219 | PCintPort portD=PCintPort(4, 3,PCMSK3); // port PD==4 220 | #endif 221 | 222 | #else // others 223 | 224 | #ifndef NO_PORTB_PINCHANGES 225 | PCintPort portB=PCintPort(2, 0,PCMSK0); // port PB==2 (from Arduino.h, Arduino version 1.0) 226 | #endif 227 | #ifndef NO_PORTC_PINCHANGES // note: no PORTC on MEGA 228 | PCintPort portC=PCintPort(3, 1,PCMSK1); // port PC==3 (also in pins_arduino.c, Arduino version 022) 229 | #endif 230 | #ifndef NO_PORTD_PINCHANGES // note: no PORTD on MEGA 231 | PCintPort portD=PCintPort(4, 2,PCMSK2); // port PD==4 232 | #endif 233 | 234 | #endif // defined __AVR_ATmega644__ 235 | 236 | #ifdef __USE_PORT_JK 237 | #ifndef NO_PORTJ_PINCHANGES 238 | PCintPort portJ=PCintPort(10,1,PCMSK1); // port PJ==10 239 | #endif 240 | #ifndef NO_PORTK_PINCHANGES 241 | PCintPort portK=PCintPort(11,2,PCMSK2); // port PK==11 242 | #endif 243 | #endif // USE_PORT_JK 244 | 245 | static PCintPort *lookupPortNumToPort( int portNum ) { 246 | PCintPort *port = NULL; 247 | 248 | switch (portNum) { 249 | #ifndef NO_PORTA_PINCHANGES 250 | case 1: 251 | port=&portA; 252 | break; 253 | #endif 254 | #ifndef NO_PORTB_PINCHANGES 255 | case 2: 256 | port=&portB; 257 | break; 258 | #endif 259 | #ifndef NO_PORTC_PINCHANGES 260 | case 3: 261 | port=&portC; 262 | break; 263 | #endif 264 | #ifndef NO_PORTD_PINCHANGES 265 | case 4: 266 | port=&portD; 267 | break; 268 | #endif 269 | #ifdef __USE_PORT_JK 270 | 271 | #ifndef NO_PORTJ_PINCHANGES 272 | case 10: 273 | port=&portJ; 274 | break; 275 | #endif 276 | 277 | #ifndef NO_PORTK_PINCHANGES 278 | case 11: 279 | port=&portK; 280 | break; 281 | #endif 282 | 283 | #endif // __USE_PORT_JK 284 | } 285 | 286 | return port; 287 | } 288 | 289 | 290 | void PCintPort::enable(PCintPin* p, PCIntvoidFuncPtr userFunc, uint8_t mode) { 291 | // Enable the pin for interrupts by adding to the PCMSKx register. 292 | // ...The final steps; at this point the interrupt is enabled on this pin. 293 | p->mode=mode; 294 | p->PCintFunc=userFunc; 295 | #ifndef NO_PORTJ_PINCHANGES 296 | // A big shout out to jrhelbert for this fix! Thanks!!! 297 | if ((p->arduinoPin == 14) || (p->arduinoPin == 15)) { 298 | portPCMask |= (p->mask << 1); // PORTJ's PCMSK1 is a little odd... 299 | } 300 | else { 301 | portPCMask |= p->mask; 302 | } 303 | #else 304 | portPCMask |= p->mask; 305 | #endif 306 | if ((p->mode == RISING) || (p->mode == CHANGE)) portRisingPins |= p->mask; 307 | if ((p->mode == FALLING) || (p->mode == CHANGE)) portFallingPins |= p->mask; 308 | PCICR |= PCICRbit; 309 | } 310 | 311 | int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t mode) 312 | { 313 | PCintPin* tmp; 314 | 315 | tmp=firstPin; 316 | // Add to linked list, starting with firstPin. If pin already exists, just enable. 317 | if (firstPin != NULL) { 318 | do { 319 | if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); } 320 | if (tmp->next == NULL) break; 321 | tmp=tmp->next; 322 | } while (true); 323 | } 324 | 325 | // Create pin p: fill in the data. 326 | PCintPin* p=new PCintPin; 327 | if (p == NULL) return(-1); 328 | p->arduinoPin=arduinoPin; 329 | p->mode = mode; 330 | p->next=NULL; 331 | p->mask = digitalPinToBitMask(arduinoPin); // the mask 332 | 333 | if (firstPin == NULL) firstPin=p; 334 | else tmp->next=p; // NOTE that tmp cannot be NULL. 335 | 336 | #ifdef DEBUG 337 | Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC); 338 | int addr = (int) p; 339 | Serial.print(" instance addr: "); Serial.println(addr, HEX); 340 | Serial.print("userFunc addr: "); Serial.println((int)p->PCintFunc, HEX); 341 | #endif 342 | 343 | enable(p, userFunc, mode); 344 | #ifdef DEBUG 345 | Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC), Serial.print (" pin stored: "); 346 | int addr = (int) p; 347 | Serial.print(" instance addr: "); Serial.println(addr, HEX); 348 | #endif 349 | return(1); 350 | } 351 | 352 | /* 353 | * attach an interrupt to a specific pin using pin change interrupts. 354 | */ 355 | int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode) 356 | { 357 | PCintPort *port; 358 | uint8_t portNum = digitalPinToPort(arduinoPin); 359 | if ((portNum == NOT_A_PORT) || (userFunc == NULL)) return(-1); 360 | 361 | port=lookupPortNumToPort(portNum); 362 | // Added by GreyGnome... must set the initial value of lastPinView for it to be correct on the 1st interrupt. 363 | // ...but even then, how do you define "correct"? Ultimately, the user must specify (not provisioned for yet). 364 | port->lastPinView=port->portInputReg; 365 | #ifdef DEBUG 366 | Serial.print("attachInterrupt- pin: "); Serial.println(arduinoPin, DEC); 367 | #endif 368 | // map pin to PCIR register 369 | return(port->addPin(arduinoPin,userFunc,mode)); 370 | } 371 | 372 | void PCintPort::detachInterrupt(uint8_t arduinoPin) 373 | { 374 | PCintPort *port; 375 | PCintPin* current; 376 | uint8_t mask; 377 | uint8_t portNum = digitalPinToPort(arduinoPin); 378 | if (portNum == NOT_A_PORT) return; 379 | port=lookupPortNumToPort(portNum); 380 | mask=digitalPinToBitMask(arduinoPin); 381 | current=port->firstPin; 382 | while (current) { 383 | if (current->mask == mask) { // found the target 384 | uint8_t oldSREG = SREG; 385 | cli(); // disable interrupts 386 | #ifndef NO_PORTJ_PINCHANGES 387 | // A big shout out to jrhelbert for this fix! Thanks!!! 388 | if ((arduinoPin == 14) || (arduinoPin == 15)) { 389 | port->portPCMask &= ~(mask << 1); // PORTJ's PCMSK1 is a little odd... 390 | } 391 | else { 392 | port->portPCMask &= ~mask; // disable the mask entry. 393 | } 394 | #else 395 | port->portPCMask &= ~mask; // disable the mask entry. 396 | #endif 397 | if (port->portPCMask == 0) PCICR &= ~(port->PCICRbit); 398 | port->portRisingPins &= ~current->mask; port->portFallingPins &= ~current->mask; 399 | // TODO: This is removed until we can add code that frees memory. 400 | // Note that in the addPin() function, above, we do not define a new pin if it was 401 | // once already defined. 402 | // ... ... 403 | // Link the previous' next to the found next. Then remove the found. 404 | //if (prev != NULL) prev->next=current->next; // linked list skips over current. 405 | //else firstPin=current->next; // at the first pin; save the new first pin 406 | SREG = oldSREG; // Restore register; reenables interrupts 407 | return; 408 | } 409 | current=current->next; 410 | } 411 | } 412 | 413 | // common code for isr handler. "port" is the PCINT number. 414 | // there isn't really a good way to back-map ports and masks to pins. 415 | void PCintPort::PCint() { 416 | 417 | #ifdef FLASH 418 | if (*led_port & led_mask) *led_port&=not_led_mask; 419 | else *led_port|=led_mask; 420 | #endif 421 | #ifndef DISABLE_PCINT_MULTI_SERVICE 422 | uint8_t pcifr; 423 | while (true) { 424 | #endif 425 | // get the pin states for the indicated port. 426 | #ifdef PINMODE 427 | PCintPort::s_lastPinView=lastPinView; 428 | intrCount++; 429 | PCintPort::s_count=intrCount; 430 | #endif 431 | uint8_t changedPins = (PCintPort::curr ^ lastPinView) & 432 | ((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr )); 433 | 434 | #ifdef PINMODE 435 | PCintPort::s_currXORlastPinView=PCintPort::curr ^ lastPinView; 436 | PCintPort::s_portRisingPins_nCurr=portRisingPins & PCintPort::curr; 437 | PCintPort::s_portFallingPins_nNCurr=portFallingPins & ~PCintPort::curr; 438 | #endif 439 | lastPinView = PCintPort::curr; 440 | 441 | PCintPin* p = firstPin; 442 | while (p) { 443 | // Trigger interrupt if the bit is high and it's set to trigger on mode RISING or CHANGE 444 | // Trigger interrupt if the bit is low and it's set to trigger on mode FALLING or CHANGE 445 | if (p->mask & changedPins) { 446 | #ifndef NO_PIN_STATE 447 | PCintPort::pinState=PCintPort::curr & p->mask ? HIGH : LOW; 448 | #endif 449 | #ifndef NO_PIN_NUMBER 450 | PCintPort::arduinoPin=p->arduinoPin; 451 | #endif 452 | #ifdef PINMODE 453 | PCintPort::pinmode=p->mode; 454 | PCintPort::s_portRisingPins=portRisingPins; 455 | PCintPort::s_portFallingPins=portFallingPins; 456 | PCintPort::s_pmask=p->mask; 457 | PCintPort::s_changedPins=changedPins; 458 | #endif 459 | p->PCintFunc(); 460 | } 461 | p=p->next; 462 | } 463 | #ifndef DISABLE_PCINT_MULTI_SERVICE 464 | pcifr = PCIFR & PCICRbit; 465 | if (pcifr == 0) break; 466 | PCIFR |= PCICRbit; 467 | #ifdef PINMODE 468 | PCintPort::pcint_multi++; 469 | if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here! 470 | #endif 471 | PCintPort::curr=portInputReg; 472 | } 473 | #endif 474 | } 475 | 476 | #ifndef NO_PORTA_PINCHANGES 477 | ISR(PCINT0_vect) { 478 | #ifdef PINMODE 479 | PCintPort::s_PORT='A'; 480 | #endif 481 | PCintPort::curr = portA.portInputReg; 482 | portA.PCint(); 483 | } 484 | #define PORTBVECT PCINT1_vect 485 | #define PORTCVECT PCINT2_vect 486 | #define PORTDVECT PCINT3_vect 487 | #else 488 | #define PORTBVECT PCINT0_vect_em 489 | #define PORTCVECT PCINT1_vect_em 490 | #define PORTDVECT PCINT2_vect_em 491 | #endif 492 | 493 | #ifndef NO_PORTB_PINCHANGES 494 | ISR(PORTBVECT) { 495 | #ifdef PINMODE 496 | PCintPort::s_PORT='B'; 497 | #endif 498 | PCintPort::curr = portB.portInputReg; 499 | portB.PCint(); 500 | } 501 | #endif 502 | 503 | #ifndef NO_PORTC_PINCHANGES 504 | ISR(PORTCVECT) { 505 | #ifdef PINMODE 506 | PCintPort::s_PORT='C'; 507 | #endif 508 | PCintPort::curr = portC.portInputReg; 509 | portC.PCint(); 510 | } 511 | #endif 512 | 513 | #ifndef NO_PORTD_PINCHANGES 514 | ISR(PORTDVECT){ 515 | #ifdef PINMODE 516 | PCintPort::s_PORT='D'; 517 | #endif 518 | PCintPort::curr = portD.portInputReg; 519 | portD.PCint(); 520 | } 521 | #endif 522 | 523 | #ifdef __USE_PORT_JK 524 | #ifndef NO_PORTJ_PINCHANGES 525 | ISR(PCINT1_vect) { 526 | #ifdef PINMODE 527 | PCintPort::s_PORT='J'; 528 | #endif 529 | PCintPort::curr = portJ.portInputReg; 530 | portJ.PCint(); 531 | } 532 | #endif 533 | 534 | #ifndef NO_PORTK_PINCHANGES 535 | ISR(PCINT2_vect){ 536 | #ifdef PINMODE 537 | PCintPort::s_PORT='K'; 538 | #endif 539 | PCintPort::curr = portK.portInputReg; 540 | portK.PCint(); 541 | } 542 | #endif 543 | 544 | #endif // __USE_PORT_JK 545 | 546 | #ifdef GET_PCINT_VERSION 547 | uint16_t getPCIntVersion () { 548 | return ((uint16_t) PCINT_VERSION); 549 | } 550 | #endif // GET_PCINT_VERSION 551 | #endif // #ifndef LIBCALL_PINCHANGEINT ************************************************************* 552 | #endif // #ifndef PinChangeInt_h ******************************************************************* 553 | -------------------------------------------------------------------------------- /Code/Bug/Protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOCOL_H_ 2 | #define _PROTOCOL_H_ 3 | #include "Arduino.h" 4 | 5 | #define PROTOCOL_START_CODE 0xAA 6 | #define PROTOCOL_END_CODE 0x55 7 | 8 | typedef enum 9 | { 10 | E_BATTERY = 1, 11 | E_LED, 12 | E_BUZZER_MODE, 13 | E_INFO, 14 | E_ROBOT_CONTROL_DIRECTION, 15 | E_ROBOT_CONTROL_SPEED, 16 | E_TEMPERATURE, 17 | E_INFRARED_TRACKING, 18 | E_ULTRASONIC_MODE, 19 | E_INFRARED_REMOTE, 20 | E_INFRARED_AVOIDANCE, 21 | E_CONTROL_MODE, //12 22 | E_BUTTON = 13, 23 | E_LED_MAXTRIX, 24 | E_CMD_LINE, 25 | E_VERSION, 26 | E_UPGRADE, 27 | E_PHOTORESISTOR, 28 | E_SERVER_DEGREE, 29 | E_CONTOROL_CODE_MAX, 30 | } E_CONTOROL_FUNC; 31 | 32 | typedef enum 33 | { 34 | E_SMARTCAR = 0, 35 | E_HUMMER_BOT, 36 | E_AURORA_RACING, 37 | E_PANTHER_TANK, 38 | E_BEETLE_BOT, 39 | E_BALANCE_CAR, 40 | E_OTTO, 41 | E_QUADCOPTER, 42 | E_HELLO_BOT, 43 | E_MIRAGE_TANK, 44 | E_4WD, 45 | E_MECANUMCAR, 46 | E_TYPE_MAX, 47 | } E_TYPE; 48 | 49 | typedef struct 50 | { 51 | byte start_code ; // 8bit 0xAA 52 | byte len; // protocol data length 53 | E_TYPE type; 54 | byte addr; 55 | byte function; // 8 bit 56 | byte *data; // n bit 57 | uint16_t sum; // check sum 16bit 58 | byte end_code; // 8bit 0x55 59 | } ST_PROTOCOL; 60 | 61 | #endif // _PROTOCOL_H_ 62 | -------------------------------------------------------------------------------- /Code/Bug/ProtocolParser.cpp: -------------------------------------------------------------------------------- 1 | #include "Protocol.h" 2 | #include "ProtocolParser.h" 3 | //#define DEBUG_LEVEL DEBUG_LEVEL_ALL 4 | #include "debug.h" 5 | 6 | #if ARDUINO > 10609 7 | ProtocolParser::ProtocolParser(byte startcode = PROTOCOL_START_CODE, byte endcode = PROTOCOL_END_CODE) 8 | #else 9 | ProtocolParser::ProtocolParser(byte startcode , byte endcode ) 10 | #endif 11 | { 12 | m_recv_flag = false; 13 | m_send_success = false; 14 | m_StartCode = startcode; 15 | m_EndCode = endcode; 16 | m_pHeader = buffer; // protocol header 17 | protocol_data_len = 0; // protocol->data length 18 | m_PackageLength = 0; // recevie all package length 19 | m_CheckSum = 0x0000; 20 | m_RecvDataIndex = 0; 21 | for (int i = 0; i < BUFFER_SIZE; i++) { 22 | buffer[i] = 0; 23 | } 24 | } 25 | 26 | ProtocolParser::~ProtocolParser(void) 27 | { 28 | m_pHeader = NULL; 29 | } 30 | 31 | bool ProtocolParser::ParserPackage(byte *data = NULL) 32 | { 33 | unsigned int check_sum = 0; 34 | if (m_recv_flag) { 35 | m_recv_flag = false; 36 | if( data != NULL) { 37 | m_pHeader = data; 38 | } else { 39 | m_pHeader = buffer; 40 | } 41 | recv->start_code = buffer[0]; 42 | recv->len = buffer[1]; 43 | for (byte i = 1; i < m_PackageLength - 3; i++) { 44 | check_sum += buffer[i]; 45 | } 46 | if ((check_sum & 0xFFFF) != GetCheckSum()) { 47 | DEBUG_ERR("check sum error \n"); 48 | for (int i = 0; i < m_PackageLength; i++) { 49 | DEBUG_LOG(DEBUG_LEVEL_ERR, "0x%x ", buffer[i]); 50 | } 51 | return false ; 52 | } 53 | recv->function = buffer[4]; 54 | recv->data = &buffer[5]; 55 | protocol_data_len = m_PackageLength - 8; 56 | recv->end_code = buffer[m_PackageLength-1]; 57 | DEBUG_LOG(DEBUG_LEVEL_INFO, "\nRecevPackage end \n"); 58 | return true; 59 | } 60 | return false; 61 | } 62 | 63 | bool ProtocolParser::RecevData(void) 64 | { 65 | // DEBUG_LOG(DEBUG_LEVEL_INFO, "RecevData start \n"); 66 | static bool avilable = false; 67 | static byte preRecvLen = 0; 68 | byte dat; 69 | while (Serial.available() > 0) { 70 | dat = Serial.read(); 71 | // DEBUG_LOG(DEBUG_LEVEL_INFO, "\n"); 72 | // Serial.println(dat, HEX); 73 | delay(2); 74 | if (avilable == false && dat == m_StartCode) { 75 | memset(buffer, 0, BUFFER_SIZE); 76 | preRecvLen = 0; 77 | m_pHeader = buffer; 78 | *m_pHeader++ = dat; 79 | m_RecvDataIndex = 0; 80 | avilable = true; 81 | // Serial.println(dat, HEX); 82 | DEBUG_LOG(DEBUG_LEVEL_INFO, "aviable\n"); 83 | // arduino_printf("aviable \n"); 84 | continue; 85 | } 86 | if (avilable) { 87 | if (dat == m_EndCode && preRecvLen == m_RecvDataIndex) { 88 | avilable = false; 89 | *m_pHeader = dat; 90 | // m_RecvDataIndex++; 91 | m_PackageLength = preRecvLen + 2; 92 | m_recv_flag = true; 93 | DEBUG_LOG(DEBUG_LEVEL_INFO, "RecevData end \n"); 94 | return true; 95 | } else { 96 | //Serial.println(dat, HEX); 97 | *m_pHeader++ = dat; 98 | m_RecvDataIndex++; 99 | if (m_RecvDataIndex == 1) { 100 | preRecvLen = dat; 101 | if (preRecvLen > BUFFER_SIZE-2) goto error; 102 | DEBUG_LOG(DEBUG_LEVEL_INFO, "preRecvLen = %d\n", preRecvLen); 103 | } 104 | // arduino_printf("prelen= %d Index =%d \n",preRecvLen, m_RecvDataIndex); 105 | if ((m_RecvDataIndex > preRecvLen) && (preRecvLen != 0)) { 106 | for (int i = m_RecvDataIndex; i > 0; i--) { 107 | //DEBUG_LOG(DEBUG_LEVEL_ERR, "%x ", buffer[i]); 108 | if (buffer[i] == m_StartCode) { 109 | m_pHeader = &buffer[i]; 110 | preRecvLen = buffer[i+1]; 111 | m_RecvDataIndex -= i; 112 | continue; 113 | } 114 | } 115 | DEBUG_LOG(DEBUG_LEVEL_ERR, "preRecvLen \r\n"); 116 | goto error; 117 | } 118 | 119 | if (m_RecvDataIndex >= BUFFER_SIZE - 1) { 120 | for (int i = 0; i < BUFFER_SIZE; i++) { 121 | DEBUG_LOG(DEBUG_LEVEL_ERR, "%x ", buffer[i]); 122 | } 123 | DEBUG_LOG(DEBUG_LEVEL_ERR, "buffer is over\r\n"); 124 | goto error; 125 | } 126 | } 127 | } 128 | } 129 | return avilable; 130 | error : 131 | preRecvLen = 0; 132 | m_pHeader = buffer; 133 | avilable = false; 134 | m_recv_flag = false; 135 | return false; 136 | } 137 | 138 | bool ProtocolParser::RecevData(byte *data, size_t len) 139 | { 140 | DEBUG_LOG(DEBUG_LEVEL_INFO, "RecevData start \n"); 141 | bool avilable = false; 142 | if (data == NULL || len > BUFFER_SIZE) 143 | { 144 | DEBUG_ERR("len > BUFFER_SIZE \n"); 145 | return false; 146 | } 147 | m_PackageLength = 0; 148 | memset(buffer, 0, BUFFER_SIZE); 149 | m_pHeader = buffer; 150 | 151 | while (len--) { 152 | if(!avilable && *data == m_StartCode) { 153 | avilable = true; 154 | } 155 | 156 | if (avilable) { 157 | if ((*m_pHeader = *data) == m_EndCode) { 158 | m_recv_flag = true; 159 | m_PackageLength++; 160 | DEBUG_LOG(DEBUG_LEVEL_INFO, "%x ", *m_pHeader); 161 | //Serial.println("m_PackageLength "); 162 | //Serial.print(m_PackageLength); 163 | break; 164 | } 165 | DEBUG_LOG(DEBUG_LEVEL_INFO, "%x ", *m_pHeader); 166 | m_pHeader++; 167 | m_PackageLength++; 168 | } 169 | data++; 170 | } 171 | DEBUG_LOG(DEBUG_LEVEL_INFO, "\nRecevPackage done\n"); 172 | return true; 173 | } 174 | 175 | 176 | E_TYPE ProtocolParser::GetRobotType(void) 177 | { 178 | return (E_TYPE)recv->type; 179 | } 180 | 181 | uint8_t ProtocolParser::GetRobotAddr(void) 182 | { 183 | return recv->addr; 184 | } 185 | 186 | E_CONTOROL_FUNC ProtocolParser::GetRobotControlFun(void) 187 | { 188 | return (E_CONTOROL_FUNC)recv->function; 189 | } 190 | 191 | int ProtocolParser::GetRobotSpeed(void) 192 | { 193 | if (recv->function == E_ROBOT_CONTROL_SPEED ) { 194 | return (int)(*(recv->data)); 195 | } else { 196 | return 0; 197 | } 198 | } 199 | 200 | int ProtocolParser::GetRobotDegree(void) 201 | { 202 | if (recv->function == E_ROBOT_CONTROL_DIRECTION ) { 203 | return ((int)(*(recv->data)<< 8) | (int)(*(recv->data+1))); 204 | } else { 205 | return 0; 206 | } 207 | } 208 | 209 | E_BUZZER_TYPE ProtocolParser::GetBuzzerMode(void) 210 | { 211 | if (recv->function == E_BUZZER_MODE) { 212 | return (E_BUZZER_TYPE)(*(recv->data)); 213 | } else { 214 | return E_BUZZER_TYPE_MAX; 215 | } 216 | } 217 | 218 | uint16_t ProtocolParser::GetBuzzerNote(void) 219 | { 220 | uint16_t note; 221 | if (recv->function == E_BUZZER_MODE) { 222 | note = (*(recv->data + 1) << 8) | (*(recv->data + 2)); 223 | return note; 224 | } 225 | } 226 | 227 | uint8_t ProtocolParser::GetBuzzerSound(void) 228 | { 229 | if (recv->function == E_BUZZER_MODE) { 230 | return *(recv->data + 1) << 8; 231 | } 232 | } 233 | 234 | ST_MUSIC_TYPE ProtocolParser::GetBuzzerMusic(void) 235 | { 236 | ST_MUSIC_TYPE music; 237 | if (recv->function == E_BUZZER_MODE) { 238 | music.note = (*(recv->data + 1) << 8) |(*(recv->data + 2)); 239 | music.beat = (E_MUSIC_BEAT)*(recv->data + 3); 240 | } 241 | return music; 242 | } 243 | 244 | int ProtocolParser::GetServoDegree(void) 245 | { 246 | if (recv->function == E_SERVER_DEGREE ) { 247 | return (uint8_t)(*(recv->data+1)); 248 | } else { 249 | return 0; 250 | } 251 | } 252 | 253 | int ProtocolParser::GetServoDegreeNum(void) 254 | { 255 | if (recv->function == E_SERVER_DEGREE ) { 256 | return (uint8_t)(*(recv->data)); 257 | } else { 258 | return 0; 259 | } 260 | } 261 | 262 | uint16_t ProtocolParser::GetBluetoothButton() { 263 | if (recv->function == E_BUTTON) { 264 | return (uint16_t)(*(recv->data)<< 8) | (uint16_t)(*(recv->data+1)); 265 | } 266 | return 0xFFFF; 267 | } 268 | 269 | bool ProtocolParser::GetBluetoothButton(uint16_t Button) { 270 | if (GetBluetoothButton() == Button) { 271 | return true; 272 | } 273 | return false; 274 | } 275 | 276 | long ProtocolParser::GetRgbValue(void) 277 | { 278 | if (recv->function == E_LED) { 279 | long value = ((long)(*(recv->data+2))<< 16 | (long)(*(recv->data+1))<< 8 | (long)(*(recv->data))); 280 | return value; 281 | } else { 282 | return 0; 283 | } 284 | } 285 | 286 | byte ProtocolParser::GetRgbEffect(void) 287 | { 288 | if (recv->function == E_LED) { 289 | return (byte)(*(recv->data + 3)); 290 | } else { 291 | return 0; 292 | } 293 | } 294 | 295 | byte ProtocolParser::GetRgbMode(void) 296 | { 297 | if (recv->function == E_LED) { 298 | if (recv->len == 9) { 299 | return 1; 300 | } else { 301 | return 0; 302 | } 303 | } 304 | } 305 | 306 | byte* ProtocolParser::GetCmdLine(void) 307 | { 308 | if (recv->function == E_CMD_LINE) { 309 | return (byte *)recv->data; 310 | } else { 311 | return NULL; 312 | } 313 | } 314 | 315 | uint8_t ProtocolParser::GetProtocolDataLength(void) 316 | { 317 | return protocol_data_len; 318 | } 319 | 320 | uint8_t ProtocolParser::GetPackageLength(void) 321 | { 322 | return m_PackageLength; 323 | } 324 | 325 | E_SMARTCAR_CONTROL_MODE ProtocolParser::GetControlMode(void) 326 | { 327 | if (((E_CONTOROL_FUNC)recv->function) == E_CONTROL_MODE) { 328 | return (E_SMARTCAR_CONTROL_MODE)(*(recv->data)); 329 | } else { 330 | return (E_SMARTCAR_CONTROL_MODE)0; 331 | } 332 | } 333 | 334 | uint16_t ProtocolParser::GetCheckSum(void) 335 | { 336 | return ((buffer[m_PackageLength - 3] << 8 ) | buffer[m_PackageLength - 2]); 337 | } 338 | 339 | // len : protocol data length 340 | bool ProtocolParser::SendPackage(ST_PROTOCOL *send_dat,int len) 341 | { 342 | if( send_dat == NULL || len > BUFFER_SIZE) { 343 | DEBUG_ERR("SendPackage error"); 344 | return false; 345 | } 346 | unsigned short checksum = 0; 347 | byte *p_data = &buffer[5]; 348 | protocol_data_len = len; 349 | buffer[0] = send_dat->start_code; 350 | buffer[1] = send_dat->len; 351 | buffer[2] = send_dat->type; 352 | buffer[3] = send_dat->addr; 353 | buffer[4] = send_dat->function; 354 | checksum = buffer[1] + buffer[2] + buffer[3] + buffer[4]; 355 | 356 | // Serial.println(*send_dat->data); 357 | // Serial.println(*(send_dat->data + 1 )); 358 | for(int i = 0; i < len; i++) { 359 | *(p_data+i) = *(send_dat->data + i); 360 | // Serial.println(*(p_data+i) ); 361 | checksum += *(send_dat->data + i); 362 | } 363 | *(p_data + len) = (checksum >> 8) & 0xFF; 364 | *(p_data + len + 1) = checksum & 0xFF; 365 | *(p_data + len + 2) = send_dat->end_code; 366 | 367 | Serial.write(buffer,len+8); 368 | Serial.flush(); 369 | delay(100); 370 | return true; 371 | } 372 | -------------------------------------------------------------------------------- /Code/Bug/ProtocolParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOCOLPARSER_H_ 2 | #define _PROTOCOLPARSER_H_ 3 | #include "Arduino.h" 4 | #include "Protocol.h" 5 | #include 6 | #include "Sounds.h" 7 | #include"SmartCar.h" 8 | #include 9 | 10 | #define BUFFER_SIZE 32 11 | 12 | class ProtocolParser 13 | { 14 | public: 15 | ProtocolParser(byte header = PROTOCOL_START_CODE, byte end = PROTOCOL_END_CODE); 16 | ~ProtocolParser(); 17 | bool RecevData(byte *data, size_t len); 18 | bool RecevData(void); 19 | bool ParserPackage(byte *data = NULL); 20 | E_TYPE GetRobotType(void); 21 | uint8_t GetRobotAddr(void); 22 | E_CONTOROL_FUNC GetRobotControlFun(void); 23 | int GetRobotSpeed(void); 24 | int GetRobotDegree(void); 25 | int GetServoDegree(void); 26 | int GetServoDegreeNum(void); 27 | uint16_t GetBluetoothButton(); 28 | bool GetBluetoothButton(uint16_t Button); 29 | E_BUZZER_TYPE GetBuzzerMode(void); 30 | uint16_t GetBuzzerNote(void); 31 | uint8_t GetBuzzerSound(void); 32 | ST_MUSIC_TYPE GetBuzzerMusic(void); 33 | long GetRgbValue(void); 34 | byte GetRgbEffect(void); 35 | byte GetRgbMode(void); 36 | byte* GetCmdLine(void); 37 | bool SendPackage(ST_PROTOCOL *send_dat, int len); 38 | E_SMARTCAR_CONTROL_MODE GetControlMode(void); 39 | uint8_t GetProtocolDataLength(void); 40 | 41 | private: 42 | byte buffer[BUFFER_SIZE]; 43 | byte m_StartCode, m_EndCode; 44 | ST_PROTOCOL *recv; 45 | uint8_t protocol_data_len; 46 | bool m_recv_flag, m_send_success; // recevive flag 47 | byte *m_pHeader; // protocol header 48 | uint8_t m_PackageLength; // recevie package length 49 | uint16_t m_CheckSum; 50 | uint8_t m_RecvDataIndex; // get recevie data index 51 | char GetHeader(size_t index); 52 | uint8_t GetPackageLength(void); 53 | uint16_t GetCheckSum(void); // get package check sum 54 | }; 55 | 56 | #endif // _PROTOCOLPARSER_H_ 57 | -------------------------------------------------------------------------------- /Code/Bug/RGBLed.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RGBLed.h" 3 | 4 | /** 5 | * Alternate Constructor which can call your own function to map the RGBLed to arduino port, 6 | * it will assigned the LED display buffer and initialization the GPIO of LED lights. You can 7 | * set any arduino digital pin for the LED data PIN, The default number of light strips is 32. 8 | * \param[in] 9 | * port - arduino port 10 | */ 11 | RGBLed::RGBLed(uint8_t port) 12 | { 13 | pinMask = digitalPinToBitMask(port); 14 | ws2812_port = portOutputRegister(digitalPinToPort(port) ); 15 | // set pinMode OUTPUT */ 16 | pinMode(port, OUTPUT); 17 | setNumber(DEFAULT_MAX_LED_NUMBER); 18 | } 19 | 20 | /** 21 | * Alternate Constructor which can call your own function to map the RGBLed to arduino port, 22 | * it will assigned the LED display buffer and initialization the GPIO of LED lights. You can 23 | * set any arduino digital pin for the LED data PIN, and reset the LED number by this constructor. 24 | * \param[in] 25 | * port - arduino port 26 | * \param[in] 27 | * led_num - The LED number 28 | */ 29 | RGBLed::RGBLed(uint8_t port, uint8_t led_num) 30 | { 31 | pinMask = digitalPinToBitMask(port); 32 | ws2812_port = portOutputRegister(digitalPinToPort(port) ); 33 | brightness = 255; 34 | // set pinMode OUTPUT */ 35 | pinMode(port, OUTPUT); 36 | setNumber(led_num); 37 | } 38 | 39 | /** 40 | * \par Function 41 | * setpin 42 | * \par Description 43 | * Reset the LED available data PIN by its arduino port. 44 | * \param[in] 45 | * port - arduino port(should digital pin) 46 | * \par Output 47 | * None 48 | * \return 49 | * None 50 | * \par Others 51 | * None 52 | */ 53 | void RGBLed::setpin(uint8_t port) 54 | { 55 | setColor(0,0,0,0); 56 | fillPixelsBak(0, 0, 0); 57 | pinMask = digitalPinToBitMask(port); 58 | ws2812_port = portOutputRegister(digitalPinToPort(port) ); 59 | pinMode(port, OUTPUT); 60 | // _port = 0; 61 | // _slot = SLOT2; 62 | } 63 | 64 | /** 65 | * \par Function 66 | * setNumber 67 | * \par Description 68 | * Assigned the LED display buffer by the LED number 69 | * \param[in] 70 | * num_leds - The LED number you used 71 | * \par Output 72 | * None 73 | * \return 74 | * None 75 | * \par Others 76 | * None 77 | */ 78 | void RGBLed::setNumber(uint8_t num_leds) 79 | { 80 | count_led = num_leds; 81 | pixels = (uint8_t*)malloc(count_led * 3); 82 | if(!pixels) 83 | { 84 | printf("There is not enough space!\r\n"); 85 | } 86 | for(int16_t i = 0; i < count_led * 3; i++) 87 | { 88 | pixels[i] = 0; 89 | } 90 | 91 | pixels_bak = (uint8_t*)malloc(count_led * 3); 92 | if(!pixels_bak) 93 | { 94 | printf("There is not enough space!\r\n"); 95 | } 96 | for(int16_t i = 0; i < count_led * 3; i++) 97 | { 98 | pixels_bak[i] = 0; 99 | } 100 | } 101 | 102 | /** 103 | * \par Function 104 | * getColorAt 105 | * \par Description 106 | * Get the LED color value from its index 107 | * \param[in] 108 | * index - The LED index number you want to read its value 109 | * \par Output 110 | * None 111 | * \return 112 | * The LED color value, include the R,G,B 113 | * \par Others 114 | * The index value from 1 to the max 115 | */ 116 | cRGB RGBLed::getColorAt(uint8_t index) 117 | { 118 | cRGB px_value; 119 | 120 | if(index < count_led) 121 | { 122 | uint8_t tmp; 123 | tmp = (index-1) * 3; 124 | 125 | px_value.g = pixels[tmp]; 126 | px_value.r = pixels[tmp + 1]; 127 | px_value.b = pixels[tmp + 2]; 128 | } 129 | return(px_value); 130 | } 131 | 132 | /** 133 | * \par Function 134 | * getNumber 135 | * \par Description 136 | * Get the LED number you can light it. 137 | * \par Output 138 | * None 139 | * \return 140 | * The total number of LED's 141 | * \par Others 142 | * The index value from 1 to the max 143 | */ 144 | uint8_t RGBLed::getNumber(void) 145 | { 146 | return(count_led); 147 | } 148 | 149 | /** 150 | * \par Function 151 | * fillPixelsBak 152 | * \par Description 153 | * fill the LED color data to pixels_bak. 154 | * \param[in] 155 | * red - Red values 156 | * \param[in] 157 | * green - green values 158 | * \param[in] 159 | * blue - blue values 160 | * \par Output 161 | * None 162 | * \return 163 | * None 164 | * \par Others 165 | * None 166 | */ 167 | void RGBLed::fillPixelsBak(uint8_t red, uint8_t green, uint8_t blue) 168 | { 169 | for(int16_t i = 0; i < count_led; i++) 170 | { 171 | uint8_t tmp = i * 3; 172 | pixels_bak[tmp] = green; 173 | pixels_bak[tmp + 1] = red; 174 | pixels_bak[tmp + 2] = blue; 175 | } 176 | } 177 | 178 | /** 179 | * \par Function 180 | * setColorAt 181 | * \par Description 182 | * Set the LED color for any LED. 183 | * \param[in] 184 | * index - The LED index number you want to set its color 185 | * \param[in] 186 | * red - Red values 187 | * \param[in] 188 | * green - green values 189 | * \param[in] 190 | * blue - blue values 191 | * \par Output 192 | * None 193 | * \return 194 | * TRUE: Successful implementation 195 | * FALSE: Wrong execution 196 | * \par Others 197 | * The index value from 0 to the max. 198 | */ 199 | bool RGBLed::setColorAt(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) 200 | { 201 | if(index < count_led) 202 | { 203 | uint8_t tmp = index * 3; 204 | if(brightness) { // See notes in setBrightness() 205 | red = (red * brightness) >> 8; 206 | green = (green * brightness) >> 8; 207 | blue = (blue * brightness) >> 8; 208 | } 209 | pixels[tmp] = green; 210 | pixels[tmp + 1] = red; 211 | pixels[tmp + 2] = blue; 212 | return(true); 213 | } 214 | return(false); 215 | } 216 | 217 | /** 218 | * \par Function 219 | * setColor 220 | * \par Description 221 | * Set the LED color for any LED. 222 | * \param[in] 223 | * index - The LED index number you want to set its color 224 | * \param[in] 225 | * red - Red values 226 | * \param[in] 227 | * green - green values 228 | * \param[in] 229 | * blue - blue values 230 | * \par Output 231 | * None 232 | * \return 233 | * TRUE: Successful implementation 234 | * FALSE: Wrong execution 235 | * \par Others 236 | * The index value from 1 to the max, if you set the index 0, all the LED will be lit 237 | */ 238 | bool RGBLed::setColor(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) 239 | { 240 | if(index == 0) 241 | { 242 | for(int16_t i = 0; i < count_led; i++) 243 | { 244 | setColorAt(i,red,green,blue); 245 | } 246 | return(true); 247 | } 248 | else 249 | { 250 | setColorAt(index-1,red,green,blue); 251 | } 252 | return(false); 253 | } 254 | 255 | /** 256 | * \par Function 257 | * setColor 258 | * \par Description 259 | * Set the LED color for all LED. 260 | * \param[in] 261 | * red - Red values 262 | * \param[in] 263 | * green - green values 264 | * \param[in] 265 | * blue - blue values 266 | * \par Output 267 | * None 268 | * \return 269 | * TRUE: Successful implementation 270 | * FALSE: Wrong execution 271 | * \par Others 272 | * All the LED will be lit. 273 | */ 274 | bool RGBLed::setColor(uint8_t red, uint8_t green, uint8_t blue) 275 | { 276 | return(setColor(0, red, green, blue)); 277 | } 278 | 279 | /** 280 | * \par Function 281 | * setColor 282 | * \par Description 283 | * Set the LED color for any LED. 284 | * \param[in] 285 | * value - the LED color defined as long type, for example (white) = 0xFFFFFF 286 | * \par Output 287 | * None 288 | * \return 289 | * TRUE: Successful implementation 290 | * FALSE: Wrong execution 291 | * \par Others 292 | * The index value from 1 to the max, if you set the index 0, all the LED will be lit 293 | */ 294 | bool RGBLed::setColor(uint8_t index, long value) 295 | { 296 | uint8_t red = (value & 0xff0000) >> 16; 297 | uint8_t green = (value & 0xff00) >> 8; 298 | uint8_t blue = value & 0xff; 299 | 300 | if(index == 0) 301 | { 302 | return(setColor(0, red, green, blue)); 303 | } else if(index <= count_led) { 304 | return(setColor(index, red, green, blue)); 305 | } 306 | return(false); 307 | } 308 | 309 | /* 310 | This routine writes an array of bytes with RGB values to the Dataout pin 311 | using the fast 800kHz clockless WS2811/2812 protocol. 312 | */ 313 | /* Timing in ns */ 314 | #define w_zeropulse (350) 315 | #define w_onepulse (900) 316 | #define w_totalperiod (1250) 317 | 318 | /* Fixed cycles used by the inner loop */ 319 | #define w_fixedlow (3) 320 | #define w_fixedhigh (6) 321 | #define w_fixedtotal (10) 322 | 323 | /* Insert NOPs to match the timing, if possible */ 324 | #define w_zerocycles ( ( (F_CPU / 1000) * w_zeropulse) / 1000000) 325 | #define w_onecycles ( ( (F_CPU / 1000) * w_onepulse + 500000) / 1000000) 326 | #define w_totalcycles ( ( (F_CPU / 1000) * w_totalperiod + 500000) / 1000000) 327 | 328 | /* w1 - nops between rising edge and falling edge - low */ 329 | #define w1 (w_zerocycles - w_fixedlow) 330 | /* w2 nops between fe low and fe high */ 331 | #define w2 (w_onecycles - w_fixedhigh - w1) 332 | /* w3 nops to complete loop */ 333 | #define w3 (w_totalcycles - w_fixedtotal - w1 - w2) 334 | 335 | #if w1 > 0 336 | #define w1_nops w1 337 | #else 338 | #define w1_nops 0 339 | #endif 340 | 341 | /* 342 | The only critical timing parameter is the minimum pulse length of the "0" 343 | Warn or throw error if this timing can not be met with current F_CPU settings. 344 | */ 345 | #define w_lowtime ( (w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000) 346 | #if w_lowtime > 550 347 | #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" 348 | #elif w_lowtime > 450 349 | #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." 350 | #warning "Please consider a higher clockspeed, if possible" 351 | #endif 352 | 353 | #if w2 > 0 354 | #define w2_nops w2 355 | #else 356 | #define w2_nops 0 357 | #endif 358 | 359 | #if w3 > 0 360 | #define w3_nops w3 361 | #else 362 | #define w3_nops 0 363 | #endif 364 | 365 | #define w_nop1 "nop \n\t" 366 | #define w_nop2 "rjmp .+0 \n\t" 367 | #define w_nop4 w_nop2 w_nop2 368 | #define w_nop8 w_nop4 w_nop4 369 | #define w_nop16 w_nop8 w_nop8 370 | 371 | /** 372 | * \par Function 373 | * rgbled_sendarray_mask 374 | * \par Description 375 | * Set the LED color for any LED. 376 | * \param[in] 377 | * *data - the LED color store memory address 378 | * \param[in] 379 | * datlen - the data length need to be transmitted. 380 | * \param[in] 381 | * maskhi - the gpio pin mask 382 | * \param[in] 383 | * *port - the gpio port address 384 | * \par Output 385 | * None 386 | * \return 387 | * TRUE: Successful implementation 388 | * FALSE: Wrong execution 389 | * \par Others 390 | * None 391 | */ 392 | void RGBLed::rgbled_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t maskhi, uint8_t *port) 393 | { 394 | uint8_t curbyte, ctr, masklo; 395 | uint8_t oldSREG = SREG; 396 | cli(); // Disables all interrupts 397 | 398 | masklo = *port & ~maskhi; 399 | maskhi = *port | maskhi; 400 | 401 | while(datlen--) 402 | { 403 | curbyte = *data++; 404 | 405 | asm volatile ( 406 | " ldi %0,8 \n\t" 407 | "loop%=: \n\t" 408 | " st X,%3 \n\t" // '1' [02] '0' [02] - re 409 | #if (w1_nops & 1) 410 | w_nop1 411 | #endif 412 | #if (w1_nops & 2) 413 | w_nop2 414 | #endif 415 | #if (w1_nops & 4) 416 | w_nop4 417 | #endif 418 | #if (w1_nops & 8) 419 | w_nop8 420 | #endif 421 | #if (w1_nops & 16) 422 | w_nop16 423 | #endif 424 | " sbrs %1,7 \n\t" // '1' [04] '0' [03] 425 | " st X,%4 \n\t" // '1' [--] '0' [05] - fe-low 426 | " lsl %1 \n\t" // '1' [05] '0' [06] 427 | #if (w2_nops & 1) 428 | w_nop1 429 | #endif 430 | #if (w2_nops & 2) 431 | w_nop2 432 | #endif 433 | #if (w2_nops & 4) 434 | w_nop4 435 | #endif 436 | #if (w2_nops & 8) 437 | w_nop8 438 | #endif 439 | #if (w2_nops & 16) 440 | w_nop16 441 | #endif 442 | " brcc skipone%= \n\t" /* '1' [+1] '0' [+2] - */ 443 | " st X,%4 \n\t" /* '1' [+3] '0' [--] - fe-high */ 444 | "skipone%=: " /* '1' [+3] '0' [+2] - */ 445 | 446 | #if (w3_nops & 1) 447 | w_nop1 448 | #endif 449 | #if (w3_nops & 2) 450 | w_nop2 451 | #endif 452 | #if (w3_nops & 4) 453 | w_nop4 454 | #endif 455 | #if (w3_nops & 8) 456 | w_nop8 457 | #endif 458 | #if (w3_nops & 16) 459 | w_nop16 460 | #endif 461 | 462 | " dec %0 \n\t" // '1' [+4] '0' [+3] 463 | " brne loop%=\n\t" // '1' [+5] '0' [+4] 464 | : "=&d" (ctr) 465 | : "r" (curbyte), "x" (port), "r" (maskhi), "r" (masklo) 466 | ); 467 | } 468 | 469 | SREG = oldSREG; 470 | } 471 | 472 | void RGBLed::setBrightness(uint8_t b) { 473 | static uint8_t oldBrightness = 0; 474 | uint8_t newBrightness = b + 1; 475 | uint16_t scale = 0; 476 | if(newBrightness != brightness) { // Compare against prior value 477 | // Brightness has changed -- re-scale existing data in RAM 478 | uint8_t c, 479 | *ptr = pixels, 480 | oldBrightness = brightness - 1; // De-wrap old brightness value 481 | uint16_t scale; 482 | if(oldBrightness == 0) scale = 0; // Avoid /0 483 | else if(b == 255) scale = 65535 / oldBrightness; 484 | else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; 485 | for(uint16_t i=0; i < (3 * count_led); i++) { 486 | c = *ptr; 487 | *ptr++ = (c * scale) >> 8; 488 | } 489 | brightness = newBrightness; 490 | } 491 | } 492 | 493 | /** 494 | * \par Function 495 | * show 496 | * \par Description 497 | * Transmission the data to WS2812 498 | * \par Output 499 | * None 500 | * \return 501 | * None 502 | * \par Others 503 | * None 504 | */ 505 | void RGBLed::show(void) 506 | { 507 | if(memcmp(pixels_bak,pixels,3 * count_led) != 0) 508 | { 509 | rgbled_sendarray_mask(pixels, 3 * count_led, pinMask, (uint8_t*)ws2812_port); 510 | memcpy(pixels_bak,pixels,3 * count_led); 511 | delayMicroseconds(500); 512 | } 513 | } 514 | 515 | void RGBLed::SetRgbColor(E_RGB_INDEX index , long Color) 516 | { 517 | if (index == E_RGB_ALL) { 518 | setColor(0, Color); 519 | } else { 520 | setColor(index, Color); 521 | } 522 | show(); 523 | } 524 | 525 | 526 | /** 527 | * Destructor which can call your own function, it will release the LED buffer 528 | */ 529 | RGBLed::~RGBLed(void) 530 | { 531 | free(pixels); 532 | pixels = NULL; 533 | free(pixels_bak); 534 | pixels_bak = NULL; 535 | } 536 | -------------------------------------------------------------------------------- /Code/Bug/RGBLed.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RGBLed_h 3 | #define RGBLed_h 4 | #include 5 | 6 | #define DEFAULT_MAX_LED_NUMBER (32) 7 | 8 | #define RGB_RED 0xFF0000 9 | #define RGB_GREEN 0x00FF00 10 | #define RGB_BLUE 0x0000FF 11 | #define RGB_YELLOW 0xFFFF00 12 | #define RGB_PURPLE 0xFF00FF 13 | #define RGB_ORANGE 0xFFA500 14 | #define RGB_INDIGO 0x4b0082 15 | #define RGB_VIOLET 0x8a2be2 16 | #define RGB_WHITE 0xFFFFFF 17 | #define RGB_BLACK 0 18 | 19 | typedef enum 20 | { 21 | E_RGB_ALL = 0, 22 | E_RGB_RIGHT = 1, 23 | E_RGB_LEFT = 2 24 | } E_RGB_INDEX; 25 | 26 | /// @brief Class for RGB Led Module 27 | struct cRGB 28 | { 29 | uint8_t g; 30 | uint8_t r; 31 | uint8_t b; 32 | }; 33 | 34 | /** 35 | * Class: RGBLed 36 | * 37 | * \par Description 38 | * Declaration of Class RGBLed 39 | */ 40 | 41 | class RGBLed 42 | { 43 | public: 44 | 45 | /** 46 | * Alternate Constructor which can call your own function to map the RGBLed to arduino port, 47 | * it will assigned the LED display buffer and initialization the GPIO of LED lights. You can 48 | * set any arduino digital pin for the LED data PIN, The default number of light strips is 32. 49 | * \param[in] 50 | * port - arduino port 51 | */ 52 | RGBLed(uint8_t port); 53 | 54 | /** 55 | * Alternate Constructor which can call your own function to map the RGBLed to arduino port, 56 | * it will assigned the LED display buffer and initialization the GPIO of LED lights. You can 57 | * set any slot for the LED data PIN, and reset the LED numberby this constructor. 58 | * \param[in] 59 | * port - arduino port 60 | * \param[in] 61 | * led_num - The LED number 62 | */ 63 | RGBLed(uint8_t port, uint8_t led_num); 64 | 65 | /** 66 | * Destructor which can call your own function, it will release the LED buffer 67 | */ 68 | ~RGBLed(void); 69 | 70 | /** 71 | * \par Function 72 | * setpin 73 | * \par Description 74 | * Reset the LED available data PIN by its arduino port. 75 | * \param[in] 76 | * port - arduino port(should digital pin) 77 | * \par Output 78 | * None 79 | * \return 80 | * None 81 | * \par Others 82 | * None 83 | */ 84 | void setpin(uint8_t port); 85 | 86 | /** 87 | * \par Function 88 | * getNumber 89 | * \par Description 90 | * Get the LED number you can light it. 91 | * \par Output 92 | * None 93 | * \return 94 | * The total number of LED's 95 | * \par Others 96 | * The index value from 1 to the max 97 | */ 98 | uint8_t getNumber(void); 99 | 100 | /** 101 | * \par Function 102 | * getColorAt 103 | * \par Description 104 | * Get the LED color value from its index 105 | * \param[in] 106 | * index - The LED index number you want to read its value 107 | * \par Output 108 | * None 109 | * \return 110 | * The LED color value, include the R,G,B 111 | * \par Others 112 | * The index value from 1 to the max 113 | */ 114 | cRGB getColorAt(uint8_t index); 115 | 116 | /** 117 | * \par Function 118 | * fillPixelsBak 119 | * \par Description 120 | * fill the LED color data to pixels_bak. 121 | * \param[in] 122 | * red - Red values 123 | * \param[in] 124 | * green - green values 125 | * \param[in] 126 | * blue - blue values 127 | * \par Output 128 | * None 129 | * \return 130 | * None 131 | * \par Others 132 | * None 133 | */ 134 | void fillPixelsBak(uint8_t red, uint8_t green, uint8_t blue); 135 | 136 | /** 137 | * \par Function 138 | * setColorAt 139 | * \par Description 140 | * Set the LED color for any LED. 141 | * \param[in] 142 | * index - The LED index number you want to set its color 143 | * \param[in] 144 | * red - Red values 145 | * \param[in] 146 | * green - green values 147 | * \param[in] 148 | * blue - blue values 149 | * \par Output 150 | * None 151 | * \return 152 | * TRUE: Successful implementation 153 | * FALSE: Wrong execution 154 | * \par Others 155 | * The index value from 0 to the max. 156 | */ 157 | bool setColorAt(uint8_t index, uint8_t red, uint8_t green, uint8_t blue); 158 | 159 | /** 160 | * \par Function 161 | * setColor 162 | * \par Description 163 | * Set the LED color for any LED. 164 | * \param[in] 165 | * index - The LED index number you want to set its color 166 | * \param[in] 167 | * red - Red values 168 | * \param[in] 169 | * green - green values 170 | * \param[in] 171 | * blue - blue values 172 | * \par Output 173 | * None 174 | * \return 175 | * TRUE: Successful implementation 176 | * FALSE: Wrong execution 177 | * \par Others 178 | * The index value from 1 to the max, if you set the index 0, all the LED will be lit 179 | */ 180 | bool setColor(uint8_t index, uint8_t red, uint8_t green, uint8_t blue); 181 | 182 | /** 183 | * \par Function 184 | * setColor 185 | * \par Description 186 | * Set the LED color for all LED. 187 | * \param[in] 188 | * red - Red values 189 | * \param[in] 190 | * green - green values 191 | * \param[in] 192 | * blue - blue values 193 | * \par Output 194 | * None 195 | * \return 196 | * TRUE: Successful implementation 197 | * FALSE: Wrong execution 198 | * \par Others 199 | * All the LED will be lit. 200 | */ 201 | bool setColor(uint8_t red, uint8_t green, uint8_t blue); 202 | 203 | /** 204 | * \par Function 205 | * setColor 206 | * \par Description 207 | * Set the LED color for any LED. 208 | * \param[in] 209 | * value - the LED color defined as long type, for example (white) = 0xFFFFFF 210 | * \par Output 211 | * None 212 | * \return 213 | * TRUE: Successful implementation 214 | * FALSE: Wrong execution 215 | * \par Others 216 | * The index value from 1 to the max, if you set the index 0, all the LED will be lit 217 | */ 218 | bool setColor(uint8_t index, long value); 219 | 220 | /** 221 | * \par Function 222 | * setNumber 223 | * \par Description 224 | * Assigned the LED display buffer by the LED number 225 | * \param[in] 226 | * num_leds - The LED number you used 227 | * \par Output 228 | * None 229 | * \return 230 | * None 231 | * \par Others 232 | * None 233 | */ 234 | void setNumber(uint8_t num_led); 235 | 236 | /** 237 | * \par Function 238 | * show 239 | * \par Description 240 | * Transmission the data to WS2812 241 | * \par Output 242 | * None 243 | * \return 244 | * None 245 | * \par Others 246 | * None 247 | */ 248 | void show(void); 249 | void setBrightness(uint8_t b); 250 | void SetRgbColor(E_RGB_INDEX index, long Color); 251 | 252 | private: 253 | uint16_t count_led; 254 | uint8_t *pixels; 255 | uint8_t *pixels_bak; 256 | uint8_t brightness; 257 | 258 | /** 259 | * \par Function 260 | * rgbled_sendarray_mask 261 | * \par Description 262 | * Set the LED color for any LED. 263 | * \param[in] 264 | * *data - the LED color store memory address 265 | * \param[in] 266 | * datlen - the data length need to be transmitted. 267 | * \param[in] 268 | * maskhi - the gpio pin mask 269 | * \param[in] 270 | * *port - the gpio port address 271 | * \par Output 272 | * None 273 | * \return 274 | * TRUE: Successful implementation 275 | * FALSE: Wrong execution 276 | * \par Others 277 | * None 278 | */ 279 | void rgbled_sendarray_mask(uint8_t *array, uint16_t length, uint8_t pinmask, uint8_t *port); 280 | 281 | const volatile uint8_t *ws2812_port; 282 | volatile uint8_t *ws2812_port_reg; 283 | uint8_t pinMask; 284 | }; 285 | #endif 286 | -------------------------------------------------------------------------------- /Code/Bug/SmartCar.cpp: -------------------------------------------------------------------------------- 1 | #include "SmartCar.h" 2 | #include "debug.h" 3 | 4 | #if ARDUINO > 10609 5 | SmartCar::SmartCar(String name, byte type, byte addr, E_SMARTCAR_CONTROL_MODE control_mode = E_BLUETOOTH_CONTROL) 6 | #else 7 | SmartCar::SmartCar(String name, byte type, byte addr, E_SMARTCAR_CONTROL_MODE control_mode) 8 | #endif 9 | { 10 | SmartCarName = name; 11 | SmartCarType = (E_TYPE)type; 12 | Addr = addr; 13 | mControlMode = control_mode; 14 | mStatus = E_STOP; 15 | BatteryValue = 0; 16 | Temperature = 0; 17 | Speed = 0 ; 18 | Degree = 0; 19 | } 20 | 21 | SmartCar::~SmartCar(void) 22 | { 23 | 24 | } 25 | 26 | #if ARDUINO > 10609 27 | void SmartCar::SetControlMode(E_SMARTCAR_CONTROL_MODE mode=0) 28 | #else 29 | void SmartCar::SetControlMode(E_SMARTCAR_CONTROL_MODE mode) 30 | #endif 31 | { 32 | if (mode < E_SMARTCAR_CONTROL_MAX && mode >= 0) 33 | mControlMode = mode; 34 | } 35 | 36 | E_SMARTCAR_CONTROL_MODE SmartCar::GetControlMode(void) 37 | { 38 | return mControlMode; 39 | } 40 | 41 | void SmartCar::SetSpeed(int8_t s) 42 | { 43 | // DEBUG_LOG(DEBUG_LEVEL_INFO, "SetSpeed =%d \n", s); 44 | if (s > 100) { 45 | Speed = 100; 46 | return; 47 | } else if (s < 0) { 48 | Speed = 0; 49 | return; 50 | } 51 | Speed = s; 52 | } 53 | 54 | int SmartCar::GetSpeed(void) 55 | { 56 | return Speed; 57 | } 58 | 59 | #if ARDUINO > 10609 60 | void SmartCar::SpeedUp(int8_t Duration = 5) 61 | #else 62 | void SmartCar::SpeedUp(int8_t Duration) 63 | #endif 64 | { 65 | SetSpeed(Speed + Duration); 66 | mStatus = E_SPEED_UP; 67 | } 68 | 69 | #if ARDUINO > 10609 70 | void SmartCar::SpeedDown(int8_t Duration = 5) 71 | #else 72 | void SmartCar::SpeedDown(int8_t Duration ) 73 | #endif 74 | { 75 | SetSpeed(Speed - Duration); 76 | mStatus = E_SPEED_DOWN; 77 | } 78 | 79 | #if ARDUINO > 10609 80 | void SmartCar::SetStatus(E_SMARTCAR_STATUS status=0) 81 | #else 82 | void SmartCar::SetStatus(E_SMARTCAR_STATUS status) 83 | #endif 84 | { 85 | mStatus = status; 86 | } 87 | 88 | E_SMARTCAR_STATUS SmartCar::GetStatus(void) 89 | { 90 | return mStatus; 91 | } 92 | 93 | uint8_t SmartCar::GetBattery(void) 94 | { 95 | return BatteryValue; 96 | } 97 | 98 | uint8_t SmartCar::GetTemperature(void) 99 | { 100 | return Temperature; 101 | } 102 | -------------------------------------------------------------------------------- /Code/Bug/SmartCar.h: -------------------------------------------------------------------------------- 1 | #ifndef _SMART_CAR_H_ 2 | #define _SMART_CAR_H_ 3 | #include "Arduino.h" 4 | #include "Protocol.h" 5 | #include 6 | 7 | typedef enum 8 | { 9 | E_BLUETOOTH_CONTROL = 0, 10 | E_INFRARED_REMOTE_CONTROL, 11 | E_INFRARED_TRACKING_MODE, 12 | E_INFRARED_AVOIDANCE_MODE, 13 | E_ULTRASONIC_AVOIDANCE, 14 | E_PS2_REMOTE_CONTROL, 15 | E_NRF24L01_CONTROL, 16 | E_ULTRASONIC_INFRARED_AVOIDANCE, 17 | E_PIANO_MODE, 18 | E_RGB_MODE, 19 | E_LED_MAXTRIX_MODE, 20 | E_CMD_LINE_MODE, 21 | E_LIGHT_SEEKING_MODE, 22 | E_ULTRASONIC_FOLLOW_MODE, 23 | E_SMARTCAR_CONTROL_MAX, 24 | } E_SMARTCAR_CONTROL_MODE; 25 | 26 | typedef enum 27 | { 28 | E_FORWARD = 0, 29 | E_BACK, 30 | E_LEFT, 31 | E_RIGHT, 32 | E_RIGHT_ROTATE, 33 | E_LEFT_ROTATE, 34 | E_STOP, 35 | E_RUNNING, 36 | E_SPEED_UP, 37 | E_SPEED_DOWN, 38 | E_LOW_POWER, 39 | } E_SMARTCAR_STATUS; 40 | 41 | class SmartCar { 42 | 43 | private : 44 | String SmartCarName; 45 | E_TYPE SmartCarType; 46 | byte Addr; 47 | E_SMARTCAR_CONTROL_MODE mControlMode; 48 | E_SMARTCAR_STATUS mStatus; 49 | public : 50 | SmartCar(String name, byte type, byte addr, E_SMARTCAR_CONTROL_MODE control_mode = E_BLUETOOTH_CONTROL); 51 | ~SmartCar(); 52 | uint8_t BatteryValue; 53 | uint8_t Temperature; 54 | byte Speed ; 55 | int Degree; 56 | void Move(int directions); 57 | void GoForward(void); 58 | void GoBack(void); 59 | void TurnLeft(void); 60 | void TurnRight(void); 61 | void KeepStop(void); 62 | void Drive(int degree); 63 | void SetSpeed(int8_t s); 64 | void SpeedUp(int8_t Duration = 5); 65 | void SpeedDown(int8_t Duration = 5); 66 | int GetSpeed(void); 67 | void SetControlMode(E_SMARTCAR_CONTROL_MODE mode); 68 | void SetStatus(E_SMARTCAR_STATUS status); 69 | E_SMARTCAR_CONTROL_MODE GetControlMode(void); 70 | E_SMARTCAR_STATUS GetStatus(void); 71 | uint8_t GetBattery(void); 72 | uint8_t GetTemperature(void); 73 | }; 74 | #endif // _SMART_CAR_H_ 75 | -------------------------------------------------------------------------------- /Code/Bug/Sounds.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOUNDS_H_ 2 | #define _SOUNDS_H_ 3 | 4 | typedef enum { 5 | E_NOTE, 6 | E_SOUND, 7 | E_MUSIC, 8 | E_BUZZER_TYPE_MAX, 9 | }E_BUZZER_TYPE; 10 | 11 | typedef enum { 12 | E_BEAT_8_1, 13 | E_BEAT_4_1, 14 | E_BEAT_2_1, 15 | E_BEAT_1, 16 | E_BEAT_2, 17 | E_BEAT_4 18 | }E_MUSIC_BEAT; 19 | 20 | typedef struct { 21 | uint16_t note; 22 | E_MUSIC_BEAT beat; 23 | }ST_MUSIC_TYPE; 24 | 25 | //*********************************************************************************** 26 | //*********************************SOUNDS DEFINES************************************ 27 | //*********************************************************************************** 28 | 29 | 30 | // Reference: This list was adapted from the table located here: 31 | // http://www.phy.mtu.edu/~suits/notefreqs.html 32 | #define note_C0 16.35 //C0 33 | #define note_Db0 17.32 //C#0/Db0 34 | #define note_D0 18.35 //D0 35 | #define note_Eb0 19.45 //D#0/Eb0 36 | #define note_E0 20.6 //E0 37 | #define note_F0 21.83 //F0 38 | #define note_Gb0 23.12 //F#0/Gb0 39 | #define note_G0 24.5 //G0 40 | #define note_Ab0 25.96 //G#0/Ab0 41 | #define note_A0 27.5 //A0 42 | #define note_Bb0 29.14 //A#0/Bb0 43 | #define note_B0 30.87 //B0 44 | #define note_C1 32.7 //C1 45 | #define note_Db1 34.65 //C#1/Db1 46 | #define note_D1 36.71 //D1 47 | #define note_Eb1 38.89 //D#1/Eb1 48 | #define note_E1 41.2 //E1 49 | #define note_F1 43.65 //F1 50 | #define note_Gb1 46.25 //F#1/Gb1 51 | #define note_G1 49 //G1 52 | #define note_Ab1 51.91 //G#1/Ab1 53 | #define note_A1 55 //A1 54 | #define note_Bb1 58.27 //A#1/Bb1 55 | #define note_B1 61.74 //B1 56 | #define note_C2 65.41 //C2 (Middle C) 57 | #define note_Db2 69.3 //C#2/Db2 58 | #define note_D2 73.42 //D2 59 | #define note_Eb2 77.78 //D#2/Eb2 60 | #define note_E2 82.41 //E2 61 | #define note_F2 87.31 //F2 62 | #define note_Gb2 92.5 //F#2/Gb2 63 | #define note_G2 98 //G2 64 | #define note_Ab2 103.83 //G#2/Ab2 65 | #define note_A2 110 //A2 66 | #define note_Bb2 116.54 //A#2/Bb2 67 | #define note_B2 123.47 //B2 68 | #define note_C3 130.81 //C3 69 | #define note_Db3 138.59 //C#3/Db3 70 | #define note_D3 146.83 //D3 71 | #define note_Eb3 155.56 //D#3/Eb3 72 | #define note_E3 164.81 //E3 73 | #define note_F3 174.61 //F3 74 | #define note_Gb3 185 //F#3/Gb3 75 | #define note_G3 196 //G3 76 | #define note_Ab3 207.65 //G#3/Ab3 77 | #define note_A3 220 //A3 78 | #define note_Bb3 233.08 //A#3/Bb3 79 | #define note_B3 246.94 //B3 80 | #define note_C4 261.63 //C4 81 | #define note_Db4 277.18 //C#4/Db4 82 | #define note_D4 293.66 //D4 83 | #define note_Eb4 311.13 //D#4/Eb4 84 | #define note_E4 329.63 //E4 85 | #define note_F4 349.23 //F4 86 | #define note_Gb4 369.99 //F#4/Gb4 87 | #define note_G4 392 //G4 88 | #define note_Ab4 415.3 //G#4/Ab4 89 | #define note_A4 440 //A4 90 | #define note_Bb4 466.16 //A#4/Bb4 91 | #define note_B4 493.88 //B4 92 | #define note_C5 523.25 //C5 93 | #define note_Db5 554.37 //C#5/Db5 94 | #define note_D5 587.33 //D5 95 | #define note_Eb5 622.25 //D#5/Eb5 96 | #define note_E5 659.26 //E5 97 | #define note_F5 698.46 //F5 98 | #define note_Gb5 739.99 //F#5/Gb5 99 | #define note_G5 783.99 //G5 100 | #define note_Ab5 830.61 //G#5/Ab5 101 | #define note_A5 880 //A5 102 | #define note_Bb5 932.33 //A#5/Bb5 103 | #define note_B5 987.77 //B5 104 | #define note_C6 1046.5 //C6 105 | #define note_Db6 1108.73 //C#6/Db6 106 | #define note_D6 1174.66 //D6 107 | #define note_Eb6 1244.51 //D#6/Eb6 108 | #define note_E6 1318.51 //E6 109 | #define note_F6 1396.91 //F6 110 | #define note_Gb6 1479.98 //F#6/Gb6 111 | #define note_G6 1567.98 //G6 112 | #define note_Ab6 1661.22 //G#6/Ab6 113 | #define note_A6 1760 //A6 114 | #define note_Bb6 1864.66 //A#6/Bb6 115 | #define note_B6 1975.53 //B6 116 | #define note_C7 2093 //C7 117 | #define note_Db7 2217.46 //C#7/Db7 118 | #define note_D7 2349.32 //D7 119 | #define note_Eb7 2489.02 //D#7/Eb7 120 | #define note_E7 2637.02 //E7 121 | #define note_F7 2793.83 //F7 122 | #define note_Gb7 2959.96 //F#7/Gb7 123 | #define note_G7 3135.96 //G7 124 | #define note_Ab7 3322.44 //G#7/Ab7 125 | #define note_A7 3520 //A7 126 | #define note_Bb7 3729.31 //A#7/Bb7 127 | #define note_B7 3951.07 //B7 128 | #define note_C8 4186.01 //C8 129 | #define note_Db8 4434.92 //C#8/Db8 130 | #define note_D8 4698.64 //D8 131 | #define note_Eb8 4978.03 //D#8/Eb8 132 | 133 | #define S_connection 0 134 | #define S_disconnection 1 135 | #define S_buttonPushed 2 136 | #define S_mode1 3 137 | #define S_mode2 4 138 | #define S_mode3 5 139 | #define S_surprise 6 140 | #define S_OhOoh 7 141 | #define S_OhOoh2 8 142 | #define S_cuddly 9 143 | #define S_sleeping 10 144 | #define S_happy 11 145 | #define S_superHappy 12 146 | #define S_happy_short 13 147 | #define S_sad 14 148 | #define S_confused 15 149 | #define S_fart1 16 150 | #define S_fart2 17 151 | #define S_fart3 18 152 | #define S_didi 19 153 | 154 | #endif /* _SOUNDS_H_ */ 155 | -------------------------------------------------------------------------------- /Code/Bug/debug.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | #include"stdio.h" 4 | #include"stdlib.h" 5 | 6 | void arduino_printf(char *fmt ,...) 7 | { 8 | va_list v_arg; 9 | char string[128]; 10 | va_start(v_arg,fmt); 11 | vsprintf(string,fmt,v_arg); 12 | Serial.print(string); 13 | } 14 | -------------------------------------------------------------------------------- /Code/Bug/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H_ 2 | #define _DEUBG_H_ 3 | 4 | #ifndef DEBUG_LEVEL 5 | #define DEBUG_LEVEL 0xFF 6 | #endif 7 | 8 | void arduino_printf(char *fmt ,...); 9 | 10 | #define DEBUG_LEVEL_INFO 0x0001 11 | #define DEBUG_LEVEL_WRN 0x0002 12 | #define DEBUG_LEVEL_ERR 0x0003 13 | #define DEBUG_LEVEL_RED 0x0004 14 | #define DEBUG_LEVEL_ALL 0x0000 15 | 16 | #define DEBUG_LOG(level, fmt, ...) \ 17 | do{\ 18 | if(level >= DEBUG_LEVEL ){\ 19 | arduino_printf(fmt, ##__VA_ARGS__);}\ 20 | }while(0) 21 | 22 | #define DEBUG_ERR(fmt, ...) \ 23 | do{\ 24 | arduino_printf("[Error][%s:%s:%d]",__FILE__,__FUNCTION__,__LINE__);\ 25 | arduino_printf(fmt, ##__VA_ARGS__);\ 26 | }while(0) 27 | 28 | #define DEBUG_RED(flag, fmt, ...) \ 29 | do{\ 30 | if(DEBUG_LEVEL & DEBUG_LEVEL_RED){\ 31 | arduino_printf("[[30\33m");\ 32 | arduino_printf(fmt,##__VA_ARGS__);}\ 33 | arduino_printf("\033[0m");\ 34 | }while(0) 35 | 36 | #endif /* _DEBUG_ */ 37 | -------------------------------------------------------------------------------- /Code/Bug/keymap.h: -------------------------------------------------------------------------------- 1 | #ifndef _KEYMAY_H_ 2 | #define _KEYMAY_H_ 3 | #include 4 | #define KEY_MAX 21 5 | typedef struct 6 | { 7 | String keyname; 8 | byte keycode; 9 | }ST_KEY_MAP; 10 | 11 | #define IR_TYPE_NORMAL 1 12 | #define IR_TYPE_EM 2 13 | 14 | typedef enum { 15 | IR_KEYCODE_1 = 0, 16 | IR_KEYCODE_2, 17 | IR_KEYCODE_3, 18 | IR_KEYCODE_4, 19 | IR_KEYCODE_5, 20 | IR_KEYCODE_6, 21 | IR_KEYCODE_7, 22 | IR_KEYCODE_8, 23 | IR_KEYCODE_9, 24 | IR_KEYCODE_0, 25 | IR_KEYCODE_STAR, // * 26 | IR_KEYCODE_POUND, // # 27 | IR_KEYCODE_UP, 28 | IR_KEYCODE_DOWN, 29 | IR_KEYCODE_OK, 30 | IR_KEYCODE_LEFT, 31 | IR_KEYCODE_RIGHT, 32 | }E_NORMAL_IR_KEYCODE; 33 | 34 | typedef enum { 35 | EM_IR_KEYCODE_A = 0, 36 | EM_IR_KEYCODE_B, 37 | EM_IR_KEYCODE_C, 38 | EM_IR_KEYCODE_D, 39 | EM_IR_KEYCODE_UP, 40 | EM_IR_KEYCODE_PLUS, 41 | EM_IR_KEYCODE_LEFT, 42 | EM_IR_KEYCODE_OK, 43 | EM_IR_KEYCODE_RIGHT, 44 | EM_IR_KEYCODE_0, 45 | EM_IR_KEYCODE_DOWN, 46 | EM_IR_KEYCODE_REDUCE, 47 | EM_IR_KEYCODE_1, 48 | EM_IR_KEYCODE_2, 49 | EM_IR_KEYCODE_3, 50 | EM_IR_KEYCODE_4, 51 | EM_IR_KEYCODE_5, 52 | EM_IR_KEYCODE_6, 53 | EM_IR_KEYCODE_7, 54 | EM_IR_KEYCODE_8, 55 | }E_EM_IR_KEYCODE; 56 | 57 | extern ST_KEY_MAP normal_ir_keymap[]; 58 | extern ST_KEY_MAP em_ir_keymap[]; 59 | #endif /* _KEYMAY_H_ */ 60 | -------------------------------------------------------------------------------- /Code/Bug/nRF24L01.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Mirf 3 | 4 | Additional bug fixes and improvements 5 | 11/03/2011: 6 | Switched spi library. 7 | 07/13/2010: 8 | Added example to read a register 9 | 11/12/2009: 10 | Fix dataReady() to work correctly 11 | Renamed keywords to keywords.txt ( for IDE ) and updated keyword list 12 | Fixed client example code to timeout after one second and try again 13 | when no response received from server 14 | By: Nathan Isburgh 15 | $Id: mirf.cpp 67 2010-07-13 13:25:53Z nisburgh $ 16 | 17 | 18 | An Ardunio port of: 19 | http://www.tinkerer.eu/AVRLib/nRF24L01 20 | 21 | Significant changes to remove depencence on interupts and auto ack support. 22 | 23 | Aaron Shrimpton 24 | 25 | */ 26 | 27 | /* 28 | Copyright (c) 2007 Stefan Engelke 29 | 30 | Permission is hereby granted, free of charge, to any person 31 | obtaining a copy of this software and associated documentation 32 | files (the "Software"), to deal in the Software without 33 | restriction, including without limitation the rights to use, copy, 34 | modify, merge, publish, distribute, sublicense, and/or sell copies 35 | of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be 39 | included in all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 42 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 43 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 44 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 45 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 46 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 48 | DEALINGS IN THE SOFTWARE. 49 | 50 | $Id: mirf.cpp 67 2010-07-13 13:25:53Z nisburgh $ 51 | */ 52 | 53 | #include "nRF24L01.h" 54 | // Defines for setting the MiRF registers for transmitting or receiving mode 55 | 56 | 57 | uint8_t MirfHardwareSpiDriver::transfer(uint8_t data) { 58 | return SPI.transfer(data); 59 | } 60 | 61 | void MirfHardwareSpiDriver::begin() { 62 | SPI.begin(); 63 | SPI.setDataMode(SPI_MODE0); 64 | SPI.setClockDivider(SPI_2XCLOCK_MASK); 65 | } 66 | 67 | void MirfHardwareSpiDriver::end() { 68 | } 69 | 70 | //MirfHardwareSpiDriver MirfHardwareSpi; 71 | 72 | Nrf24l::Nrf24l(uint8_t cs_pin, uint8_t csn_pin) 73 | { 74 | cePin = cs_pin; 75 | csnPin = csn_pin; 76 | channel = 1; 77 | payload = 16; 78 | spi = new MirfHardwareSpiDriver(); 79 | } 80 | 81 | void Nrf24l::transferSync(uint8_t *dataout, uint8_t *datain, uint8_t len) { 82 | uint8_t i; 83 | for (i = 0; i < len; i++) { 84 | datain[i] = spi->transfer(dataout[i]); 85 | } 86 | } 87 | 88 | void Nrf24l::transmitSync(uint8_t *dataout, uint8_t len) { 89 | uint8_t i; 90 | for (i = 0; i < len; i++) { 91 | spi->transfer(dataout[i]); 92 | } 93 | } 94 | 95 | void Nrf24l::init() 96 | // Initializes pins to communicate with the MiRF module 97 | // Should be called in the early initializing phase at startup. 98 | { 99 | pinMode(cePin, OUTPUT); 100 | pinMode(csnPin, OUTPUT); 101 | ceLow(); 102 | csnHi(); 103 | // Initialize spi module 104 | spi->begin(); 105 | 106 | } 107 | 108 | 109 | void Nrf24l::config() 110 | // Sets the important registers in the MiRF module and powers the module 111 | // in receiving mode 112 | // NB: channel and payload must be set now. 113 | { 114 | // Set RF channel 115 | configRegister(RF_CH, channel); 116 | 117 | // Set length of incoming payload 118 | configRegister(RX_PW_P0, payload); 119 | configRegister(RX_PW_P1, payload); 120 | 121 | // Start receiver 122 | powerUpRx(); 123 | flushRx(); 124 | } 125 | 126 | void Nrf24l::setRADDR(uint8_t * adr) 127 | // Sets the receiving address 128 | { 129 | ceLow(); 130 | writeRegister(RX_ADDR_P1, adr, mirf_ADDR_LEN); 131 | ceHi(); 132 | } 133 | 134 | void Nrf24l::setTADDR(uint8_t * adr) 135 | // Sets the transmitting address 136 | { 137 | /* 138 | RX_ADDR_P0 must be set to the sending addr for auto ack to work. 139 | */ 140 | 141 | writeRegister(RX_ADDR_P0, adr, mirf_ADDR_LEN); 142 | writeRegister(TX_ADDR, adr, mirf_ADDR_LEN); 143 | } 144 | 145 | extern bool Nrf24l::dataReady() 146 | // Checks if data is available for reading 147 | { 148 | // See note in getData() function - just checking RX_DR isn't good enough 149 | uint8_t status = getStatus(); 150 | 151 | // We can short circuit on RX_DR, but if it's not set, we still need 152 | // to check the FIFO for any pending packets 153 | if ( status & (1 << RX_DR) ) return 1; 154 | return !rxFifoEmpty(); 155 | } 156 | 157 | extern bool Nrf24l::rxFifoEmpty() { 158 | uint8_t fifoStatus; 159 | 160 | readRegister(FIFO_STATUS, &fifoStatus, sizeof(fifoStatus)); 161 | return (fifoStatus & (1 << RX_EMPTY)); 162 | } 163 | 164 | 165 | 166 | extern void Nrf24l::getData(uint8_t * data) 167 | // Reads payload bytes into data array 168 | { 169 | csnLow(); // Pull down chip select 170 | spi->transfer( R_RX_PAYLOAD ); // Send cmd to read rx payload 171 | transferSync(data, data, payload); // Read payload 172 | csnHi(); // Pull up chip select 173 | // NVI: per product spec, p 67, note c: 174 | // "The RX_DR IRQ is asserted by a new packet arrival event. The procedure 175 | // for handling this interrupt should be: 1) read payload through SPI, 176 | // 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more 177 | // payloads available in RX FIFO, 4) if there are more data in RX FIFO, 178 | // repeat from step 1)." 179 | // So if we're going to clear RX_DR here, we need to check the RX FIFO 180 | // in the dataReady() function 181 | configRegister(STATUS, (1 << RX_DR)); // Reset status register 182 | } 183 | 184 | void Nrf24l::configRegister(uint8_t reg, uint8_t value) 185 | // Clocks only one byte into the given MiRF register 186 | { 187 | csnLow(); 188 | spi->transfer(W_REGISTER | (REGISTER_MASK & reg)); 189 | spi->transfer(value); 190 | csnHi(); 191 | } 192 | 193 | void Nrf24l::readRegister(uint8_t reg, uint8_t * value, uint8_t len) 194 | // Reads an array of bytes from the given start position in the MiRF registers. 195 | { 196 | csnLow(); 197 | spi->transfer(R_REGISTER | (REGISTER_MASK & reg)); 198 | transferSync(value, value, len); 199 | csnHi(); 200 | } 201 | 202 | void Nrf24l::writeRegister(uint8_t reg, uint8_t * value, uint8_t len) 203 | // Writes an array of bytes into inte the MiRF registers. 204 | { 205 | csnLow(); 206 | spi->transfer(W_REGISTER | (REGISTER_MASK & reg)); 207 | transmitSync(value, len); 208 | csnHi(); 209 | } 210 | 211 | 212 | void Nrf24l::send(uint8_t * value) 213 | // Sends a data package to the default address. Be sure to send the correct 214 | // amount of bytes as configured as payload on the receiver. 215 | { 216 | uint8_t status; 217 | status = getStatus(); 218 | 219 | while (PTX) { 220 | status = getStatus(); 221 | 222 | if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) { 223 | PTX = 0; 224 | break; 225 | } 226 | } // Wait until last paket is send 227 | 228 | ceLow(); 229 | 230 | powerUpTx(); // Set to transmitter mode , Power up 231 | 232 | csnLow(); // Pull down chip select 233 | spi->transfer( FLUSH_TX ); // Write cmd to flush tx fifo 234 | csnHi(); // Pull up chip select 235 | 236 | csnLow(); // Pull down chip select 237 | spi->transfer( W_TX_PAYLOAD ); // Write cmd to write payload 238 | transmitSync(value, payload); // Write payload 239 | csnHi(); // Pull up chip select 240 | 241 | ceHi(); // Start transmission 242 | } 243 | 244 | /** 245 | isSending. 246 | 247 | Test if chip is still sending. 248 | When sending has finished return chip to listening. 249 | 250 | */ 251 | 252 | bool Nrf24l::isSending() { 253 | uint8_t status; 254 | if (PTX) { 255 | status = getStatus(); 256 | 257 | /* 258 | if sending successful (TX_DS) or max retries exceded (MAX_RT). 259 | */ 260 | 261 | if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) { 262 | powerUpRx(); 263 | return false; 264 | } 265 | 266 | return true; 267 | } 268 | return false; 269 | } 270 | 271 | uint8_t Nrf24l::getStatus() { 272 | uint8_t rv; 273 | readRegister(STATUS, &rv, 1); 274 | return rv; 275 | } 276 | 277 | void Nrf24l::powerUpRx() { 278 | PTX = 0; 279 | ceLow(); 280 | configRegister(CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (1 << PRIM_RX) ) ); 281 | ceHi(); 282 | configRegister(STATUS, (1 << TX_DS) | (1 << MAX_RT)); 283 | } 284 | 285 | void Nrf24l::flushRx() { 286 | csnLow(); 287 | spi->transfer( FLUSH_RX ); 288 | csnHi(); 289 | } 290 | 291 | void Nrf24l::powerUpTx() { 292 | PTX = 1; 293 | configRegister(CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) ) ); 294 | } 295 | 296 | void Nrf24l::ceHi() { 297 | digitalWrite(cePin, HIGH); 298 | } 299 | 300 | void Nrf24l::ceLow() { 301 | digitalWrite(cePin, LOW); 302 | } 303 | 304 | void Nrf24l::csnHi() { 305 | digitalWrite(csnPin, HIGH); 306 | } 307 | 308 | void Nrf24l::csnLow() { 309 | digitalWrite(csnPin, LOW); 310 | } 311 | 312 | void Nrf24l::powerDown() { 313 | ceLow(); 314 | configRegister(CONFIG, mirf_CONFIG ); 315 | } 316 | -------------------------------------------------------------------------------- /Code/Bug/nRF24L01.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007 Stefan Engelke 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, copy, 8 | modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | 24 | $Id$ 25 | */ 26 | 27 | //#include "MirfSpiDriver.h" 28 | 29 | #ifndef __MIRF_HARDWARE_SPI_DRIVER 30 | #define __MIRF_HARDWARE_SPI_DRIVER 31 | 32 | #include 33 | 34 | class MirfHardwareSpiDriver { 35 | 36 | public: 37 | virtual uint8_t transfer(uint8_t data); 38 | virtual void begin(); 39 | virtual void end(); 40 | }; 41 | 42 | //extern MirfHardwareSpiDriver MirfHardwareSpi; 43 | 44 | #endif 45 | 46 | #ifndef _NRF24L01_H_ 47 | #define _NRF24L01_H_ 48 | 49 | #include 50 | 51 | //#include "MirfHardwareSpiDriver.h" 52 | 53 | // Nrf24l settings 54 | /* Memory Map */ 55 | #define CONFIG 0x00 56 | #define EN_AA 0x01 57 | #define EN_RXADDR 0x02 58 | #define SETUP_AW 0x03 59 | #define SETUP_RETR 0x04 60 | #define RF_CH 0x05 61 | #define RF_SETUP 0x06 62 | #define STATUS 0x07 63 | #define OBSERVE_TX 0x08 64 | #define CD 0x09 65 | #define RX_ADDR_P0 0x0A 66 | #define RX_ADDR_P1 0x0B 67 | #define RX_ADDR_P2 0x0C 68 | #define RX_ADDR_P3 0x0D 69 | #define RX_ADDR_P4 0x0E 70 | #define RX_ADDR_P5 0x0F 71 | #define TX_ADDR 0x10 72 | #define RX_PW_P0 0x11 73 | #define RX_PW_P1 0x12 74 | #define RX_PW_P2 0x13 75 | #define RX_PW_P3 0x14 76 | #define RX_PW_P4 0x15 77 | #define RX_PW_P5 0x16 78 | #define FIFO_STATUS 0x17 79 | 80 | /* Bit Mnemonics */ 81 | #define MASK_RX_DR 6 82 | #define MASK_TX_DS 5 83 | #define MASK_MAX_RT 4 84 | #define EN_CRC 3 85 | #define CRCO 2 86 | #define PWR_UP 1 87 | #define PRIM_RX 0 88 | #define ENAA_P5 5 89 | #define ENAA_P4 4 90 | #define ENAA_P3 3 91 | #define ENAA_P2 2 92 | #define ENAA_P1 1 93 | #define ENAA_P0 0 94 | #define ERX_P5 5 95 | #define ERX_P4 4 96 | #define ERX_P3 3 97 | #define ERX_P2 2 98 | #define ERX_P1 1 99 | #define ERX_P0 0 100 | #define AW 0 101 | #define ARD 4 102 | #define ARC 0 103 | #define PLL_LOCK 4 104 | #define RF_DR 3 105 | #define RF_PWR 1 106 | #define LNA_HCURR 0 107 | #define RX_DR 6 108 | #define TX_DS 5 109 | #define MAX_RT 4 110 | #define RX_P_NO 1 111 | #define TX_FULL 0 112 | #define PLOS_CNT 4 113 | #define ARC_CNT 0 114 | #define TX_REUSE 6 115 | #define FIFO_FULL 5 116 | #define TX_EMPTY 4 117 | #define RX_FULL 1 118 | #define RX_EMPTY 0 119 | 120 | /* Instruction Mnemonics */ 121 | #define R_REGISTER 0x00 122 | #define W_REGISTER 0x20 123 | #define REGISTER_MASK 0x1F 124 | #define R_RX_PAYLOAD 0x61 125 | #define W_TX_PAYLOAD 0xA0 126 | #define FLUSH_TX 0xE1 127 | #define FLUSH_RX 0xE2 128 | #define REUSE_TX_PL 0xE3 129 | #define NOP 0xFF 130 | 131 | #define mirf_ADDR_LEN 5 132 | #define mirf_CONFIG ((1<