Luteijn/Vortex: Difference between revisions
No edit summary |
No edit summary |
||
Line 407: | Line 407: | ||
The files to play can be put on the Vortex via usb, seems the little switch next to the micro-usb socket switches this between the mp3-players mass-storage and the arduino usb-serial interface. The number passed to the player is just the index into the (FAT?) table of stored songs. So, be careful of the order these are uploaded to the memory in. | The files to play can be put on the Vortex via usb, seems the little switch next to the micro-usb socket switches this between the mp3-players mass-storage and the arduino usb-serial interface. The number passed to the player is just the index into the (FAT?) table of stored songs. So, be careful of the order these are uploaded to the memory in. | ||
https://www.dfrobot.com/product-1121.html , documented at https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299 is a mini-MP3 player from DFRobot. It is controllable over serial, and might be the same one as used in the Vortex. Would be good to figure out if the 'busy' signal and/or the serial TX are connected back to the arduino somewhere in that case. Player could also be a variant but the magic numbers more or less match (although the stop command 0x16 is not in the table. The MP3-chip Part# | https://www.dfrobot.com/product-1121.html , documented at https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299 is a mini-MP3 player from DFRobot. It is controllable over serial, and might be the same one as used in the Vortex. Would be good to figure out if the 'busy' signal and/or the serial TX are connected back to the arduino somewhere in that case. Player could also be a variant but the magic numbers more or less match (although the stop command 0x16 is not in the table. | ||
The MP3-chip inside Vortex has Part# YX6100-24SS. Seems to be part of a family of serial MP3-players made by "广州悦欣电子科技有限公司" --> "Guangzhou Yue Xin Electronic Technology Co., Ltd." - website http://www.yx080.com/mp3xinpian/53-15.html has a download link on this yx6100 page but it seems to just refer us to the 5200 application Manual V1.8, which appears to be mostly compatible. The command table for the chip does include a 0x16 stop command. | |||
Also the datasheet mentions the chip can play both MP3 and WAV. YX5300-24SS is a similar part, datasheet at https://xp-dev.com/trac/arduino_antonio/export/280/arduino_antonio/trunk/EnterpriseBase/Serial%20MP3%20Player/About%20the%20Chip%20-%20YX5300/YX5300-24SS%20Datasheet%20V1.0.pdf The command table for that chip does include a 0x16 stop command. | |||
Documentation for the DFRobot miniplayer mentions the instruction format to be: | Documentation for the DFRobot miniplayer mentions the instruction format to be: | ||
Line 443: | Line 447: | ||
| checksum | | checksum | ||
| Checksum | | Checksum | ||
| accumulation and verification, doesn't include start byte. Seems to be 2 bytes from the example given in the docs, but Vortex seems to just not need it put in. example given is 7e ff 06 09 00 00 04 ff dd ef ; The | | accumulation and verification, doesn't include start byte. Seems to be 2 bytes from the example given in the docs, but Vortex seems to just not need it put in. example given is 7e ff 06 09 00 00 04 ff dd ef ; The 5200 Datasheet uses the exact same example command, and explains that you should add all the bytes, and then subtract those from 0 to get the checksum. The 5300 Datasheet also mentions "另外用户也可以直接忽视校验,参考我们的5.3.4 章节说明。" so looks like the checksum is optional if you don't care too much about corruption of the occasional command. | ||
|- | |- | ||
| $O | | $O |
Revision as of 15:30, 2 February 2018
Project "Vortex":
Project Luteijn/Vortex | |
---|---|
Status | In progress |
Contact | Luteijn |
Last Update | 2018-02-02 |
I've got four DFRobot 'Vortex' units. Basic programming via the official apps is possible, but rather limited. The WhenDo app is only available on iPad. Luckily, the internal Arduino clone can be directly programmed too. Unfortunately, not all the specs seem to be available, but there are some examples to work with, although they have a quite a bit of 'magic numbers' in them. These examples might disappear, so duplicating them here, with my own notes as available. The examples-coding is mostly done by "Andy Zhou <Andy.zhou@dfrobot.com>", although I did change some of the things to figure out what they do.
https://www.dfrobot.com/wiki/index.php/Vortex_Arduino_Coding_Tutorial_V1.0#Introduction
(Chinese page seems to have a bit better documentation, although English page might be easier to read and it is interesting to compare the differences)
http://wiki.dfrobot.com.cn/images/1/10/%E4%B8%BB%E6%9D%BF.png
What's connected to the pins
0 | Serial RX (input) |
1 | Serial TX (output) |
2 | Encoder Wheel (External Interrupt 0) (input) |
3 | Encoder Wheel (External Interrupt 1) (input) |
4 | ?? mp3 RX (input) hopefully but don't know. Doesn't seem to be it, and can't really trace where it is going. |
5 | Motor 0 Speed (PWM) (output) |
6 | Motor 1 Speed (PWM) (output) |
7 | IR decoder/detector (input) |
8 | IR led Left (output) |
9 | Motor 0 direction (H=forwards,L=reverse) (output) |
10 | Motor 1 direction (output) |
11 | MP3-player TX (output) |
12 | IR led Right (output) |
13 | GRB LED chain around body (output) |
A0 | grayscale 4 'D' (input) |
A1 | grayscale 3 'C' (input) |
A2 | grayscale 2 'B' (input) |
A3 | grayscale 1 'A' (input) |
A4 | SDA (i2c) |
A5 | SCL (i2c) |
A6 | grayscale 5 'E' (input) |
A7 | grayscale 6 'F' (input) |
i2c bus + Vcc & Gnd should be available at 4 pin rear expansion port too - need to find a suitable connector for it..
http://www.hobbytronics.co.uk/arduino-atmega328-pinout Useful diagrams to map pins to package
Motor Control
Simple 'enable' and 'direction' pins for left and right wheels. Enable can be PWM'd or just full on. This example revs up the engines with PWM.
int E1 = 5; int M1 = 9; int E2 = 6; int M2 = 10; void setup() { pinMode(M1, OUTPUT); // directional controls, High is forward, Low is backward pinMode(M2, OUTPUT); } void loop() { int value; for(value = 0 ; value <= 255; value+=5) //foreward { digitalWrite(M1,HIGH); digitalWrite(M2, HIGH); analogWrite(E1, value); //PWM Speed control analogWrite(E2, value); //PWM Speed Control delay(30); } for(value = 0 ; value <= 255; value+=5) //backward { digitalWrite(M1, LOW); digitalWrite(M2, LOW); analogWrite(E1, value); //PWM Speed control analogWrite(E2, value); //PWM Speed Control delay(30); } }
Encoders
The two external interrupts are linked to encoders that track wheel movement, so it is possible to detect the Vortext is being pushed/pulled/turned, although I don't think these things indicate which direction the robot is pushed in...
#define pinInputLeft 0 // this is the interrupt, not the pin number, D2 #define pinInputRight 1 // external int 1, D3 long leftPul,rightPul; void leftCallBack(){ leftPul++; } void rightCallBack(){ rightPul++; } void initDdevice(){ pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); noInterrupts(); attachInterrupt(pinInputLeft,leftCallBack,CHANGE); attachInterrupt(pinInputRight,rightCallBack,CHANGE); interrupts(); } void motorDebug(){ digitalWrite(5,HIGH); digitalWrite(6,HIGH); digitalWrite(9,HIGH); digitalWrite(10,HIGH); } void printPul(){ Serial.print(leftPul); Serial.print(" "); Serial.println(rightPul); leftPul = 0; rightPul = 0; } void setup() { initDdevice(); Serial.begin(9600); motorDebug(); } void loop() { printPul(); delay(500); }
Analogue Inputs
six 'grayscale' detectors are placed around the bottom of the Vortex, to be used to track a line, maybe read simple codes from the floor.
2 (a2) 3 (a1) 1 (a3) 4 (a0) 5 (a6) 6 (a7)
This is the example sketch to dump the values read by the 6 little eyes.
void setup(void){ Serial.begin(9600); } int analogBuf[6] = {'\0'}; void loop(void){ analogBuf[0] = analogRead(3); analogBuf[1] = analogRead(2); analogBuf[2] = analogRead(1); analogBuf[3] = analogRead(0); analogBuf[4] = analogRead(6); analogBuf[5] = analogRead(7); for(int i=0;i<6;i++){ Serial.print(i+1); Serial.print(": "); Serial.print(analogBuf[i]); Serial.print(" "); } Serial.println(); delay(500); }
Wonder what's connected to A4 and A5, if anything? These are used for the i2c bus! See below under the Luteijn/Vortex#Eyes section
LEDs
12 RGB (GRB!) leds can be addressed. Example from website causes Red and Green to be swapped. initialize library differently:
FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS);
IR example below uses some of the LED functionality.
IR obstacle detector
Seems to be somewhat flaky. Needs a bit more work to figure out. Also, the IR sensor is useful to read IR remote controllers or beacons. This receiver seems to work at 38kHz, but probabbly also reacts to 36-40kHz. Remote controllers often work at 36kHz. Note that 2x 8µs delay doesn't give you 38kHz, but the digitalWrite itself also induces quite some delay (3-6µs), so seems this is bringing the total period up to around the 26.something µs we'd expect.
#define NUM_LEDS 12 // Data pin that led data will be written out over #define DATA_PIN 13 CRGB leds[NUM_LEDS]; #define IR_IN 7//IR receiver pin #define L_IR 8 //left ir transmitter pin #define R_IR 12 //right ir transmitter pin int count; void leftSend38KHZ(void){//left ir transmitter sends 38kHZ pulse int i; for(i=0;i<24;i++){ digitalWrite(L_IR,LOW); delayMicroseconds(8); digitalWrite(L_IR,HIGH); delayMicroseconds(8); } } void rightSend38KHZ(void){//right ir transmitter sends 38kHZ pulse int i; for(i=0;i<24;i++){ digitalWrite(R_IR,LOW); delayMicroseconds(8); digitalWrite(R_IR,HIGH); delayMicroseconds(8); } } void pcint0Init(void){//init the interrupt PCICR |= 1 << PCIE2; PCMSK2 |= 1 << PCINT23; //pin D7 is int23 } ISR(PCINT2_vect){//IR decoder interrupt count++; } void obstacleAvoidance(void){ char i; count=0; leds[5] = CRGB::Green; FastLED.show(); for(i=0;i<20;i++){ //left transmitter sends 20 pulses leftSend38KHZ(); delayMicroseconds(600); } if(count>10){//if received a lot pulse , it means there's a obstacle leds[5] = CRGB::White; FastLED.show(); Serial.println("Left"); delay(100); } count=0; leds[3] = CRGB::Green; FastLED.show(); for(i=0;i<20;i++){//right transmitter sends 20 pulses rightSend38KHZ(); delayMicroseconds(600); } if(count>10){//if received a lot pulse , it means there's a obstacle leds[3] = CRGB::White; FastLED.show(); Serial.println("Right"); delay(100); } delay(600); } void setup(void){ delay(2000); FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS); pinMode(L_IR,OUTPUT);//init the left transmitter pin pinMode(R_IR,OUTPUT);//init the right transmitter pin pinMode(IR_IN,INPUT);//init the ir receiver pin Serial.begin(9600); leds[4] = CRGB::Blue; FastLED.show(); delay(2000); leds[4] = CRGB::Purple; FastLED.show(); noInterrupts(); pcint0Init(); interrupts(); //enable the interrupt } void loop(void){ obstacleAvoidance(); }
IRreceiver
Since DFrobot also have a 'loose' IR-receiver module in their program, decided to just see if the example sketches for those would transfer, and they do. https://www.dfrobot.com/product-366.html - A remote similar to the one pictured on the DFRobot product page actually came with one of my RTLSDR sticks, and seems to work well enough, although the range isn't great, couple of meters. With a 'proper' remote control, e.g. from a TV, the range is fine, 10m at least when pointing at unit from across the house. Might be less if using reflections to try to control a roving robot.
So, using the IRremote library you can read values from a remote controller:
#include "IRremote.h" #define IR_IN 7//IR receiver pin IRrecv irrecv(IR_IN); decode_results results; void setup(void){ Serial.begin(9600); irrecv.enableIRIn(); // Start the receiver } void loop(void){ if (irrecv.decode(&results)) { Serial.println(results.value, HEX); irrecv.resume(); // Receive the next value } }
This was already useful to read codes from the remote of the AV-receiver we have at home and then play these back via a universal remote app on the smartphone that was missing some buttons. For some reason I couldn't find the 'learn' function in the app, but could enter the codes as read by this sketch easily.
The receiver is mounted on the front, bottom. So not right between the eyes, although a spot seems to be prepared for it there too.
MP3-player
There is an MP3.player integrated in the robot. It can be controlled by sending more or less magic commands over software Serial via pin 11. Pin 2 might be connected to the player too if the example I found can be believed, but my tests so far never had anything received there, or on pin 4. Would be nice to get an 'end of song reached' or to get things like version information out. Anyway, Pin 2 is connected to one of the wheel encoders, so not likely to be the RX. It might also be co-connected to one of the relatively harmless outputs, like to the ir emitter? Will need to trace the board to find out, but initial quick look didn't immediately show anything.
The example found on the DFRobot site:
#define MP3_VOLUME 0x10 #define TX 11 #define RX 4 // ?? was 2 in example I found, but that is unlikely #include <SoftwareSerial.h> SoftwareSerial mySerial(RX, TX);// RX, TX void setup() { delay(1000); mp3Init(); mp3setVolume(30);//0~30 } void loop() { mp3player(1); delay(2000); mp3stop(); delay(1000); } void mp3Init() { mySerial.begin (9600); } void mp3setVolume(byte vol) { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x06, 0x00, 0x00, vol, 0xef}; mySerial.write(buffer, 8); delay(20); } void mp3player(byte data) { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x03, 0x00, 0x00, data, 0xef}; mySerial.write(buffer, 8); delay(20); } void mp3stop() { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x16, 0x00, 0x00, 0x00, 0xef}; mySerial.write(buffer, 8); }
The files to play can be put on the Vortex via usb, seems the little switch next to the micro-usb socket switches this between the mp3-players mass-storage and the arduino usb-serial interface. The number passed to the player is just the index into the (FAT?) table of stored songs. So, be careful of the order these are uploaded to the memory in.
https://www.dfrobot.com/product-1121.html , documented at https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299 is a mini-MP3 player from DFRobot. It is controllable over serial, and might be the same one as used in the Vortex. Would be good to figure out if the 'busy' signal and/or the serial TX are connected back to the arduino somewhere in that case. Player could also be a variant but the magic numbers more or less match (although the stop command 0x16 is not in the table.
The MP3-chip inside Vortex has Part# YX6100-24SS. Seems to be part of a family of serial MP3-players made by "广州悦欣电子科技有限公司" --> "Guangzhou Yue Xin Electronic Technology Co., Ltd." - website http://www.yx080.com/mp3xinpian/53-15.html has a download link on this yx6100 page but it seems to just refer us to the 5200 application Manual V1.8, which appears to be mostly compatible. The command table for the chip does include a 0x16 stop command.
Also the datasheet mentions the chip can play both MP3 and WAV. YX5300-24SS is a similar part, datasheet at https://xp-dev.com/trac/arduino_antonio/export/280/arduino_antonio/trunk/EnterpriseBase/Serial%20MP3%20Player/About%20the%20Chip%20-%20YX5300/YX5300-24SS%20Datasheet%20V1.0.pdf The command table for that chip does include a 0x16 stop command.
Documentation for the DFRobot miniplayer mentions the instruction format to be:
$S | Start byte 0x7e | Each command begins with 0x7e ('~') |
VER | Version information | Version seems to be 0xff from the example |
Len | the number of bytes | Start, End and Checksum are not counted, |
CMD | Commands | See command table. |
Feedback | Command feedback | 1: feedback, 0: no feedback ; need to test what this does, might mean 'echo' |
Para1 | Parameter 1 | Query high data byte |
Para2 | Parameter 2 | Query low data byte |
checksum | Checksum | accumulation and verification, doesn't include start byte. Seems to be 2 bytes from the example given in the docs, but Vortex seems to just not need it put in. example given is 7e ff 06 09 00 00 04 ff dd ef ; The 5200 Datasheet uses the exact same example command, and explains that you should add all the bytes, and then subtract those from 0 to get the checksum. The 5300 Datasheet also mentions "另外用户也可以直接忽视校验,参考我们的5.3.4 章节说明。" so looks like the checksum is optional if you don't care too much about corruption of the occasional command. |
$O | End byte | End of command is signaled with 0xEF |
CMD | Function Description | Parameters (16 bit) | compared with YX5300 info |
---|---|---|---|
0x01 | Next | ||
0x02 | Previous | ||
0x03 | Specific track | 0-2999 but example is only using low byte. also track 0 doesn't seem to do anything? | Indicates 1-255 are the valid tracks only. |
0x04 | Volume up | ||
0x05 | Volume down | ||
0x06 | Set Volume | 0-30 (10 is already quite loud!) | |
0x07 | Specify EQ(0/1/2/3/4/5/) | Normal/Pop/Rock/Jazz/Classic/Base. | Reserved in the 5300's command list. |
0x08 | Specify playback mode (0/1/2/3) | Repeat/folder repeat/single repeat/random | See 3.4.3; this explains the argument is the song to play in a loop - may have been changed for 6100 |
0x09 | Select source (0/1/2/3/4) | U/TF/AUX/SLEEP/FLASH | See 3.4.4; specifies 1 as U, 2 as TF, 4 as PC, 5 FLASH and 6 SLEEP |
0x0a | Enter into standby - low power loss | Sleep - Low power consumption 10MA (obviously mA or µA, not MA, is meant) | |
0x0b | Normal working | Wake up from sleep | |
0x0c | reset module | chip reset | |
0x0d | Playback | Play - seems to be contrast to suspend/pause | |
0x0e | Pause | Suspended | |
0x0f | Specify folder to playback | 1~10(need to set by user) | see 3.4.5 - DH: represents the name of the folder, the default support for 99 files, 01 - 99 named DL: represents the track, the default maximum of 255 songs, that is, 0x01 ~ 0xFF |
0x10 | Volume adjust set | DH=1:open volume adjust DL: set volume gain 0~31 | not present in command table |
0x11 | Repeat play | 1:start repeat play 0: stop play | not present in command table |
0x16 | not in the table | example mentions it as a stop command | Stop |
0x17 | not in the table | FLASH only, see 3.4.7 (but is in section 3.4.6), select folder to loop. | |
0x18 | not in the table | Reserved | |
0x19 | not in the table | See 3.4.8 (but is in section 3.4.7), select loop current track mode | |
0x21 | not in the table | See 3.4.9 (3.4.8), set DAC to High-Z mode (1) or on (0) so you can use the amp for something else. | |
0x22 | not in the table | See 3.4.10 (section 3.4.9 doesn't exist), Set volume and song to play in one command (H:volume L:track) | |
0x3C | STAY | Reserved | |
0x3D | STAY | Reserved | |
0x3E | STAY | Reserved | |
0x3F | Send initialization parameters | 0-0x0F (each bit represent one device of the low-four bits) | Seems to be reporting which storage devices are currently online (see section 3.5.1) |
0x40 | Returns an error, request retransmission | Probably this is a response to a command meaning Error Encountered. | |
0x41 | Answer | Probably this is a response to a query and just means Accepted. | |
0x42 | Query Status | See 3.4.10 (actually 3.5.2) - explains that this will return which storage is used and if it's playing, stopped or paused. The storage could also be 'SLEEP' to indicate sleeping? | |
Code to calculate the checksum from the Library supporting the miniplayer:
uint16_t DFRobotDFPlayerMini::calculateCheckSum(uint8_t *buffer){ uint16_t sum = 0; for (int i=Stack_Version; i<Stack_CheckSum; i++) { sum += buffer[i]; } return -sum; }
but this doesn't seem to be needed.
Eyes
The 'Eyes' are connected over i2c. The daughterboard they are on features an STM8S103K3 (see http://www.st.com/en/microcontrollers/stm8s103-105.html ) and 2x HC595 (shift registers). Besides 35 predefined eye patterns, it is also possible to upload your own eye patterns.
The default eyes can be set as follows:
#include <Wire.h> #define I2C_LED_ADDRESS 0b1100000 #define I2C_WRITE 0x00 uint8_t serial=0; void setup(){ Wire.begin(); // join i2c bus (address optional for master) defined_eyes(6,1); delay(2000); } void loop(){ defined_eyes(1,serial); serial++; if(serial>=35) serial=0; delay(250); } void defined_eyes(uint8_t color,uint8_t serial) { Wire.beginTransmission(I2C_LED_ADDRESS << 1 | I2C_WRITE); // transmit to device #4 // (I suppose they mean 0x40, although eyes seem to also respond on 0xC0 which is what is defined above, and 0x20) Wire.write(color&0x07); // color bits: 1 blue, 2 green, 4 red Wire.write(serial); //preset eyes 0~34 Wire.endTransmission(); // stop transmitting }
void custom_eyes(uint8_t color, uint8_t eyeline[10]){ uint8_t index; // right eye left eye //1 2 3 4 5 25 24 23 22 21 //6 7 8 9 10 20 19 18 17 16 //11 12 13 14 15 15 14 13 12 11 //16 17 18 19 20 10 9 8 7 6 //21 22 23 24 25 5 4 3 2 1 Wire.beginTransmission(I2C_LED_ADDRESS << 1 | I2C_WRITE); // transmit to device #4 Wire.write(0x55); // color 55=custom eyes follow Wire.write(0xAA); // ?? AA=color followed by 10 bytes, each defining one line // other values cause eyes to light up in multiple colors, needs more work Wire.write(color&0x7); //color 1-B,2-G,4-R of foreground for (index=0;index<10;index++) { Wire.write(eyeline[index]); } Wire.endTransmission(); // stop transmitting void example_eyes() { /* left eye of robot (right for onlooker) */ Wire.write(0x1f); // bottom row, all bits lit Wire.write(0x1e); // 10 9 8 7 on, 6 off Wire.write(0x1c); Wire.write(0x18); Wire.write(0x10); /* right eye of robot (left for onlooker) */ Wire.write(0x1f); // top row all 5 bits lit Wire.write(0x0f); // leds 6,7,8,9 on 10 off Wire.write(0x07); // 11,12,13 on, 14,15 off Wire.write(0x03); Wire.write(0x01); }
KITT-scanner / Cylon
#include <Wire.h> #include <SoftwareSerial.h> #include <IRremote.h> #define MTX (11) #define MRX (4) // Song number for "By your command"-sample #define BYC (30) // Song number for Warble #define Warble (31) #define IR_IN (7) #define I2C_LED_ADDRESS 0x80 bool left=1; decode_results results; SoftwareSerial mp3(MRX,MTX); IRrecv irrecv(IR_IN); short command=0; uint8_t eyes[10]={0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; void setup(){ Wire.begin(); // join i2c bus (address optional for master) mp3Init(); irrecv.enableIRIn(); // Start the receiver delay(2000); delay(100); mp3setVolume(10);//0~255, but 30 is already quite loud! delay(50); mp3player(Warble); delay(50); mp3repeat(2); // repeat once delay(50); mp3player(BYC); delay(3000); mp3setVolume(8);//0~255, but 30 is already quite loud! delay(50); mp3player(Warble); delay(50); mp3repeat(0); // repeat forever delay(50); } void lscroll_eyes(uint8_t * eyes ){ uint8_t i; eyes[2]=(uint8_t)(eyes[2]<<1); eyes[7]=(uint8_t)(eyes[7]<<1); } void rscroll_eyes(uint8_t * eyes ){ uint8_t i; eyes[2]=(uint8_t)(eyes[2]>>1); eyes[7]=(uint8_t)(eyes[7]>>1); } void custom_eyes(uint8_t color, uint8_t eyeline[10]){ uint8_t index; Wire.beginTransmission(I2C_LED_ADDRESS); // 0x4 preshifted to 0x8 and lsb set to 0 for write Wire.write(0x55); // register 55=?custom eyes Wire.write(0xAA); // ?? AA=color followed by 10 bytes, each defining one line Wire.write(color&0x7); //color 1-B,2-G,4-R for (index=0;index<10;index++) { Wire.write(eyeline[index]); } Wire.endTransmission(); // stop transmitting } void loop(){ // 1 2 4 8 10 '20' 10 8 4 2 1 if (left) {lscroll_eyes(eyes);} else if (!left) {rscroll_eyes(eyes);} custom_eyes(4,eyes); if (eyes[7]==0x1) {left=1;} else if (eyes[2]==0x1) {left=1;} else if (left && eyes[2]>=0x10) {eyes[2]=0;eyes[7]=0x20;left=0;} else if (left && eyes[7]>=0x10) {eyes[7]=0;eyes[2]=0x20;left=0;} if (irrecv.decode(&results)){ if (command) { command=0; } else{ command=34; // adjust to match sample length mp3player(BYC); delay(50); } irrecv.resume(); } else { if (command) { command--; if (!command){ mp3player(Warble); delay(50); mp3repeat(0); // repeat forever } else { delay(80); } } else { delay(80); } } } void mp3Init() { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x0C, 0x00, 0x00, 0x00, 0xef}; mp3.begin(9600); delay(100); mp3.write(buffer, 8); delay(100); } void mp3setVolume(byte vol) { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x06, 0x00, 0x00, vol, 0xef}; mp3.write(buffer, 8); } void mp3player(byte data) { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x03, 0x00, 0x00, data, 0xef}; mp3.write(buffer, 8); } void mp3repeat(byte data) { uint8_t buffer[] = {0x7e, 0xff, 0x06, 0x08, 0x00, 0x00, data, 0xef}; mp3.write(buffer, 8); }
i2c
There might be more stuff connected to the i2c already, I plan to do some tests to find out. Would be nice if e.g. the flash of the mp3 player or some other expansion was already there.
Regardless of what's there already, Vortex seems to be designed to be extended over i2c, and could be a nice platform to do some experiments/demo's with.
Here's a simple scanning sketch, looks like only 0x40 has something connected, and that would be the eye-display.
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println("\nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 0; address < 128; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.print(" ("); Serial.print(address,DEC); Serial.println("d) !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.print(" ("); Serial.print(address,DEC); Serial.println("d) !"); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); delay(5000); // wait 5 seconds for next scan }