/* * Project Name : ledLightShow * File Name : ledLightShow.c * Object : This example shows how to use Sensory's FluentChip libraries, to train VRStamp to learn 4 keywords from a speaker, and then to recognize them when they are spoken again from the same speaker To be used with mikroElektronika Easy-VRStamp development board. * Author : Bruno Gavand brunog@micro-examples.com * see more details on http://www.micro-examples.com/ * Date : May 13, 2007 * Release : V1.0 * IDE : mikroE RSC4X mikroC compiler V2 * Guaranty : None, use it at your own risks * * MCU settings : RSC4128, 14.32 Mhz, 0 wait state * Memory model : small * * Extra tools : Phyton assembler and linker Project SE V1.10.06 * Sensory's FluentChip library V2.0.14 * * Dev. Board : mikroElektronika Easy-VRStamp V1.21 * * Easy-VRStamp settings : * * J1, Power : USB or EXT * J2, Buttons : to GND * J3, P0 : no resistor * J4, P1 : no resistor * J5, P2 : no resistor * J6, DAC/PWM : DAC * J7, ADC/PWM : DAC * J8, Mic Gain : MEDIUM * J9, Mic : On-Board * J10, Mic : On-Board * SW1.0, P0 LEDs : OFF * SW1.1, P1 LEDs : ON * SW1.2, P2 LEDs : ON * SW1.3 : NC * SW1.4, P0.0 RX : OFF * SW1.5, P0.1 TX : OFF * SW1.6, P0.2 SDA : OFF * SW1.7, P0.7 SCL : OFF * SW2.0 to SW2.7 : OFF * CN1, Ext Power : * CN2, USB : * CN3, RS232 : NC * CN4, Speaker out : to On-Board Speaker * CN5, LCD : NC * CN6, CF MEM CARD : NC * CN7, Ext. Mic : NC * CN10, PORT0 : NC * CN11, PORT1 : NC * CN12, PORT2 : NC * * Instruction for use : This programm will allow a user to control a LED light show by voice, after a learning phase. The user will have to train the system with four keywords : - the first keyword will start the animation - the second keyword will slow the animation - the third keyword will speed the animation - the fourth keyword will exit the animation Buttons : P0.0 : start keyword 1 training (start animation, for example : "Start !") P0.1 : start keyword 2 training (slow animation, for example : "Slow !") P0.2 : start keyword 3 training (fast animation, for example : "Fast !") P0.3 : start keyword 4 training (exit animation, for example : "Exit !") P0.6 : enters recognition mode and starts LED light show LEDs: P1.0 : on if keyword 1 is trained, off otherwise, blinks during training P1.1 : on if keyword 2 is trained, off otherwise, blinks during training P1.2 : on if keyword 3 is trained, off otherwise, blinks during training P1.3 : on if keyword 4 is trained, off otherwise, blinks during training P1.6 : on when system is fully trained, off otherwise, blinks during recognition mode P2 : LED light show
After power-up : train a keyword by pressing the corresponding button, then : - say the keyword after the prompt beep - repeat the same keyword after the prompt beep when all keywords have been trained (P1.0 to P1.3 LEDs ON), press P0.6 to enter recognition mode. when keyword 4 (exit animation) is recognized, the program exit recognition mode. * */
#include "string.h"
/* * FluentChip library definitions */ #include
/* * QS4 Files */ #include "qs4/ledLightShow.h"
/********************************** * MACRO DEFINITIONS AND CONSTANTS **********************************/ /* * I/O definitions */ #define BUTTON_PORT (p0in & BUTTON_MASK) // buttons #define STATUS_PORT p1out // status PORT #define SHOW_PORT p2out // light show PORT
/* * Button masks */ #define BUTTON_MASK 0b01101111 // button port bit mask #define BUTTON_LEARN_CHANGE (0b11111110 & BUTTON_MASK) // learn keyword for change #define BUTTON_LEARN_SLOW (0b11111101 & BUTTON_MASK) // learn keyword for slow #define BUTTON_LEARN_FAST (0b11111011 & BUTTON_MASK) // learn keyword for fast #define BUTTON_LEARN_STOP (0b11110111 & BUTTON_MASK) // learn keyword for stop #define BUTTON_RECOGNIZE (0b10111111 & BUTTON_MASK) // start recognition
/* * TIMER 3 control definitions * see RSC4128 datasheet for details on tmr3 control register */ #define T3_IRQ 0x10 // IRQ flag
/* * other definitions */ #define NB_CMD 4 // number of commands #define NB_LEDS 8 // number of status LEDs #define STATUS_LED 6 // status led number #define MAX_RETRY 3 // abort training after 3 mismatchs #define SHORT_TIMEOUT 5 // listening timeout during learning phase #define LONG_TIMEOUT 20 // listening timeout during recognition
#define BASE_TMPLT (long)sizeof(CONF_STRUCT) // template offset, leave place for configuration structure in EEPROM
#define MAX_SPEED 8
/************************************* * LOCAL FUNCTION PROTOTYPES *************************************/ void learnWord(char s) ; void recognizeWord(void);
/************************************* * VARIABLE DEFINITIONS *************************************/ long firstTmplt ; // offset of first voice template in memory
/* * LED animation */ uchar shiftLed = 0 ; // animation enable flag uchar ledCtr ; // pattern index uchar speedCtr = 0 ; // speed prescaler const uchar ledAnim[5][64] = // LED patterns { { 1, 2, 4, 8, 16, 32, 64, 128, 64, 32, 16, 8, 4, 2, 0 }, { ~1, ~2, ~4, ~8, ~16, ~32, ~64, ~128, ~64, ~32, ~16, ~8, ~4, ~2, 0 }, { 0b10000001, 0b01000010, 0b00100100, 0b00011000, 0b00100100, 0b01000010, 0 }, { 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00000100, 0b00000010, 0b00000001, 0b10000001, 0b01000001, 0b00100001, 0b00010001, 0b00001001, 0b00000101, 0b00000011, 0b10000011, 0b01000011, 0b00100011, 0b00010011, 0b00001011, 0b00000111, 0b10000111, 0b01000111, 0b00100111, 0b00010111, 0b00001111, 0b10001111, 0b01001111, 0b00101111, 0b00011111, 0b10011111, 0b01011111, 0b00111111, 0b10111111, 0b01111111, 0b11111111, 0 }, 0 // last pattern must be empty } ;
/* * configuration structure definition */ typedef struct { uchar magic[32] ; // magic string uchar learnFlags ; // 0x0f when all of the 4 keywords are trained uchar dc[NB_LEDS] ; // duty cycle to blink status LEDs uchar speed ; // animation speed uchar anim ; // animation number } CONF_STRUCT ;
CONF_STRUCT confStruct ; // configuration structure const uchar *magicString = "www.micro-examples.com" ; // magic string
PARAMETERPASS res ; // parameters passing structure, needed by Fluentchip functions
/* * messages sound index table */ const uchar msgTbl[NB_CMD] = { SND_change_animation, SND_slow_animation, SND_speed_animation, SND_stop_animation } ;
uchar cnt ; // status LEDs duty cycle counter
/******************************************** * ISR : TIMER 3 overflow ********************************************/ #pragma interrupt 4 tmr3_isr // tmr3 isr is on vector #4 void tmr3_isr(void) { uchar i ; uchar mask = 0b00000001 ; // LED status mask if(shiftLed) // if animation enabled { speedCtr++ ; // increment prescaler if(speedCtr >= confStruct.speed) // time has come ? { if(ledAnim[confStruct.anim][ledCtr] == 0) // check if last step is reached { ledCtr = 0 ; // back to start } SHOW_PORT = ledAnim[confStruct.anim][ledCtr++] ; // load animation step speedCtr = 0 ; // reset prescaler } }
cnt++ ; // increment duty cycle counter cnt &= 15 ; // only 16 steps for(i = 0 ; i < NB_LEDS ; i++) // for all status LEDs { if(confStruct.dc[i] > cnt) // light the LED depending on its duty cycle { STATUS_PORT |= mask ; // on } else { STATUS_PORT &= mask ^ 0xff ; // off } mask <<= 1 ; // next LED }
irq = ~T3_IRQ ; // clear tm3 irq flag }
/**************************************** * FUNCTIONS ****************************************/
/* * write configuration structure to EEPROM */ void writeConfig(uchar clear) { uchar i ; uchar *ptr = (uchar *)&confStruct ; // get pointer
if(clear) // clear before saving ? { memset(&confStruct, 0, sizeof(CONF_STRUCT)) ; // clear structure confStruct.speed = MAX_SPEED / 2 ; // set default animation speed } strcpy(confStruct.magic, magicString) ; // set magic string
for(i = 0 ; i < sizeof(CONF_STRUCT) ; i++) // write all bytes { _SeepWriteByte(i, *ptr++) ; } }
/* * read confguration structure from EEPROM */ void readConfig() { uchar i ; uchar *ptr = (uchar *)&confStruct ; // get pointer
for(i = 0 ; i < sizeof(CONF_STRUCT) ; i++) // read all bytes { *ptr++ = _SeepReadByte(i) ; } if(strcmp(confStruct.magic, magicString) != 0) // check magic string { /* * bad magic string : the EEPROM content does not belong to us, just ignore it */ writeConfig(1) ; } }
/* * learn a new keyword for slot #slot */ void learnWord(char slot) { uchar retry = MAX_RETRY ; // number of retries before giving up uchar lfMask ; // learn flag mask uchar err = 0 ; // error counter confStruct.dc[slot] = 7 ; // blink LED lfMask = 1 << slot ; // shift slot number to get mask
/* * prompt user to speak */ _PlaySnd(SND_say_keyword, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; _PlaySnd(msgTbl[slot], (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ;
_PutTmpltListBase(firstTmplt) ; // define template start
switch(_MakeTmpltWs(SETUP_TIMEOUT, 2, 2)) // record keyword, first time { case ERR_OK: // record is sucessful _PutTmplt(slot) ; // save pattern in #slot number do { /* * prompt user to repeat the keyword */ _PlaySnd(SND_repeat, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ;
confStruct.dc[slot] = 11 ; // change LED blinking duty cycle
switch(_MakeTmpltWs(SETUP_TIMEOUT, 2, 2)) // record keyword again { case ERR_OK: // new record is successful _GetTmplt(slot) ; // read the previous template into internal memory _PutTmplt(slot) ; // put the new template to external memory, // so that successive tries are made with last records
switch(_TrainSd(slot, SD_DEF_LEVEL, 12, &res)) // compare & average templates { case ERR_OK: // training is successful _PutTmplt(slot) ; // store the averaged template to the set #slot retry = 0 ; // no retry needed err = 0 ; // no error break; default: // training is not successful err++ ; // increment error counter retry-- ; // one try less } break ;
default: // record is not successful retry = 0 ; // no other try err++ ; // set error flag } } while(retry) ; // loop if needed break;
default: // first record is not successful err++ ; // increment error counter retry = 0 ; // no other try }
if(err) // if an error occured { confStruct.dc[slot] = 0 ; // clear keyword LED confStruct.dc[STATUS_LED] = 0 ; // clear trained status LED _PlaySnd(SND_try_again, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play the sound "try again" } else // learning is successful { confStruct.learnFlags |= lfMask ; // set keyword flag in learnFlags confStruct.dc[slot] = 255 ; // light keyword LED
_PlaySnd(SND_thank_you, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play the sound "thank you"
if(confStruct.learnFlags == 0x0f) // check for all keywords to be ready { confStruct.dc[STATUS_LED] = 255 ; // yes, light trained status LED _PlaySnd(SND_ready, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play the sound "ready" } else { confStruct.dc[STATUS_LED] = 0 ; // not fully trained, clear the status LED } }
writeConfig(0) ; // save to EEPROM }
/* * voice controled LED light show */ void recognizeWord(void) { uchar ret ; // recognition return code if((confStruct.learnFlags & 0x0f) != 0x0f) // check if all keywords are trained { _PlaySnd(SND_not_trained, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // no, play "not trained" sound return ; // return to caller }
confStruct.dc[STATUS_LED] = 7 ; // blink status LED shiftLed = 1 ; // enable animation
_PlaySnd(SND_listening, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play "listening" sound
_PutTmpltListBase(firstTmplt); // define template start
do { ret = _RecogSd(NB_CMD, SD_DEF_LEVEL, LONG_TIMEOUT, 2, 2, &res); // record and compare to the four templates
switch(ret) // test return code { case ERR_OK: // a pattern is recognized switch(res.pp_b) // best pattern number is in pp_b struct member of res { case 0: // pattern is keyword to change the animation confStruct.anim++ ; // next animation if(ledAnim[confStruct.anim][0] == 0) { confStruct.anim = 0 ; // back to first animation } ledCtr = 0 ; // first LED pattern break ; case 1: // pattern is keyword to slow the animation if(confStruct.speed < MAX_SPEED) { confStruct.speed += 2 ; // increment scaler } break ; case 2: // pattern is keyword to speed the animaition if(confStruct.speed > 1) { confStruct.speed -= 2 ; // decrement scaler } break ; case 3: shiftLed = 0 ; break ; // patter is keyword to stop the animation }
_PlaySnd(SND_ok, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play "ok" sound
writeConfig(0) ; // store configuration to EEPROM break; case ERR_DATACOL_TIMEOUT: // just loop on timeout break ; default: // an error has occured _PlaySnd(SND_error, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play "error" sound break ; } } while(ret || (res.pp_b != 3)) ; // loop if an error occured, or if exit has not been requested
SHOW_PORT = 0 ; // turn off LEDS animation
confStruct.dc[STATUS_LED] = 255 ; // turn on status LED }
/* * main loop */ void main(void) { uchar btn ; // button
/* * I/O configuration, see RSC4128 datasheet */ p0ctla &= 0b10010000 ; // full port 0 as input, except EEPROM I²C lines p0ctlb &= 0b10010000 ; p0out = 0 ; p0in = 0 ;
p1ctla = 0xff ; // full port 1 as output p1ctlb = 0xff ; p1out = 0 ; p1in = 0 ;
p2ctla = 0xff ; // full port 2 as output p2ctlb = 0xff ; p2out = 0 ; p2in = 0 ;
firstTmplt = BASE_TMPLT ; // template offset is constant because we are using external EEPROM if(BUTTON_PORT == BUTTON_RECOGNIZE) { writeConfig(1) ; } else { readConfig() ; // read configuration }
_InitCollection() ; // initialize system for audio block collection /* * timer 3 configuration */ t3Ctl = 0x87 ; // start timer 3 with prescaler t3r = 0 ; // no reload value irq = ~T3_IRQ ; // clear any pending timer 3 IRQ imr = T3_IRQ ; // enable timer 3 interrupt _sti_() ; // interrupt enable
_PlaySnd(SND_welcome, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play the "welcome" sound
for(;;) // forever loop { if((btn = BUTTON_PORT) != BUTTON_MASK) // a key is pressed ? { while(BUTTON_PORT != BUTTON_MASK) ; // yes, wait for release
switch(btn) // test button { case BUTTON_LEARN_CHANGE : learnWord(0) ; break ; // learn keyword #1 case BUTTON_LEARN_SLOW : learnWord(1) ; break ; // learn keyword #2 case BUTTON_LEARN_FAST : learnWord(2) ; break ; // learn keyword #3 case BUTTON_LEARN_STOP : learnWord(3) ; break ; // learn keyword #4 case BUTTON_RECOGNIZE : recognizeWord() ; break ; // start keyword recognition for LED animation control } } } } |