Prueba 1

Dependencies:   FRDM_MMA8451Q MODSERIAL mbed

main.cpp

Committer:
esjimenezro
Date:
2014-07-01
Revision:
1:f1cf6444beba
Parent:
0:64bf61ea2ead

File content as of revision 1:f1cf6444beba:

#include "mbed.h"
#include "MODSERIAL.h"
#include "MMA8451Q.h"
#define MMA8451_I2C_ADDRESS (0x1d<<1)

// Se configuran los puertos de conexión del acelerometro y TX Rx serial.
MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
MODSERIAL xbee(PTC4, PTC3);     // tx, rx


// Definición de los botones del control de Xbox
#define A 0x01
#define X 0x04
#define Y 0x08
#define B 0x02
#define LB 0x10 
#define RB 0x20
#define Back 0x40
#define Start 0x80
#define Back_A 0x41
#define Back_B 0x42


// Factores de conversión de los análogos
#define F_LT_RT 0.000030637
#define F_analog 0.000015258
#define F_arrows 0.003174603

// Definición de el periodo de las señales PWM
#define P_M 20.0
#define P_S1 20.0
#define P_S2 20.0

// Salidas PWM
PwmOut Motor(PTD4);             // Puerto PWM para manejar el motor Brushless
PwmOut Direc(PTA12);            // Puerto PWM para manejar el servo de direccion
PwmOut Elev(PTA4);              // Puerto PWM para manejar el servo de elevacion

// Variables para el acelerometro
float datosZ;
float datosX;
float datosY;
float angleXZ;
float angleYZ;

// Ciclos de dureza PWM
float p1;                     
float p2;
float p3;
float p1a;
float p2a;
float p3a;

// Variables del control de xbox
float LT;
float RT;
float Med_M;
float Med_S1;
float Med_S2;
float C_In;
float C_S2;
float C_Stop;
float C_Load;
float T_In;
float T_Load;
float T_Stop;
float T_S2;
float T_PWM;
int I_cont;
int cont;
int Inicio;

// Interrupciones
Ticker envioTask;               // Tarea programada para que se envíen datos cada determinado tiempo
Ticker pwmTask;                 // Tarea programada para que se actualice el PWM cada determinado tiempo

// Banderas para avisar cuando llega un dato nuevo o se va a escribir un valor en el pwm
char datoNuevo;
char pwmNuevo;


/*Definición de funciones*/
void TxSend(void);              // Funcion de interrupción
void WaitPWM(void);             // Funcion de interrupción
void xbeeRead(void);            // Funcion de lectura de paquetes
void xbeeSend(void);            // Funcion de escritura de paquetes
void initPWM(void);             // Funcion de inicialización de los PWM


void AcCurve(void);             // Funcion de aceleración del motor principal (sin carga)
void AcLoadCurve(void);         // Funcion de aceleración del motor principal (con carga)
void StopCurve(void);           // Funcion de parada


// Definicion de los datos fijos de la trama de envio
int trama[17]={0x7E,0x00,0x11,0x10,0x01,0x00,0x13,0xA2,0x00,0x40,0xB5,0xE7,0x51,0xFF,0xFE,0x00,0x00}; 

int i;

int entrada[8];                 // Definicion de los datos utiles que se enviaran 

// Declaracion de los datos utiles recibidos
int d1,d2,d3,d4,d5,d6,d7,d8,d9;

// Declaracion de los analogos
int Left_Xaxis,Left_Yaxis,LT_RT,Arrows;

int V[24]; //Se nombra un vector que tendrá los datos que se sumarán para calcular el valor del checksum
                /*El tamaño de este depende del número de datos útiles, para:
                1 dato  17
                2 datos 18
                3 datos 19
                4 datos 20
                5 datos 21
                     .
                     .
                     .
                */

int baudrate; //Se denomina un baudrate (bits/segundo) de 57600

DigitalOut status(PTA17); //  Led de estado

/*************************************************************************
FUNCIÓN: main()
PROPÓSITO:  ESTA ES LA FUNCIÓN PRINCIPAL DEL PROGRAMA
**************************************************************************/

int main() {
    
    // Inicializacion de datos del acelerometro
    datosZ = 0;
    datosX = 0;
    datosY = 0;
    
    // Inicializacion de ciclos de dureza
    p1 = 0;                     
    p2 = 0;
    p3 = 0;
    p1a = 0;
    p2a = 0;
    p3a = 0;
    
    // Inicializacion de datos del control del xbox
    I_cont = 0;
    cont = 0;
    Inicio = 0;
    Med_M = 0;
    Med_S1 = 0;
    Med_S2 = 0;
    datoNuevo = 0;
    pwmNuevo = 0;
    
    // Valor del BaudRate
    baudrate = 19200;
    xbee.baud(baudrate);
    
    initPWM();

    trama[2]=0x16;      // Este valor es del número de datos desde luego de la longitud hasta antes del checksum,
                        // en este caso son 3 datos y se tiene una longitud de 17 datos= 0x11
/* 
La longitud varía según el número de datos útiles a enviar, para:
1 dato  0F
2 datos 10
3 datos 11
4 datos 12
5 datos 13
    .
    .
    .
*/

    envioTask.attach_us(&TxSend, 250000);    
    pwmTask.attach_us(&WaitPWM, 100000); 
    
    
    while(1) {
        
        status = !status;
    
        xbeeRead();     //Leer datos que llegan del control 
        
        switch(d1) {         //El dato número 1 (d1) contiene los valores discretos más importantes del control 
            case LB:          //Si el dato1 es L1 (0x40) el barco debe frenar    
                p1=(1.0/P_M);
                break;
            case RB:          //Si el dato1 es R1 (0x80) el barco debe acelerar al máximo
                p1=(Med_M-1.0)+(Med_M);
                break;
            case X:
                p3=(Med_S2/P_S2);
                break;
            case Y:
                p2=((Med_S1+0.03)/P_S1);
                break;
            default:
                Left_Xaxis = ((unsigned int)d2 << 8) | (unsigned int) d3; //Concatena el dato 2 (d2) y el dato 3 (d3) para obtener A1_EjeX
    
                if ((Left_Xaxis<=32000)|(Left_Xaxis>=33000)){ 
                    p2=(1.0/P_S1)+(F_analog*Left_Xaxis)*((Med_S1-1.0)*(2.0/P_S1));
                }else {
                    p2=((Med_S1+0.03)/P_S1);
                }
    //Left_Yaxis = ((unsigned int)d4 << 8) | (unsigned int) d5; //Concatena el dato 4 (d4) y el dato 5 (d5) para obtener A1_EjeY
    
    //p3=0.05+(0.00001625*A1_Y)*0.05;
    
                LT_RT = ((unsigned int)d6 << 8) | (unsigned int) d7; //Concatena el dato 6 (d6) y el dato 7 (d7) para obtener A2_EjeX
        
                Arrows = ((unsigned int)d8 << 8) | (unsigned int) d9; //Concatena el dato 8 (d8) y el dato 9 (d9) para obtener A2_EjeY
    
                break;
        }

        /////////////Tareas lentas///////////////////////

        //Envío de datos
        if(datoNuevo){           
            xbeeSend();
            datoNuevo = 0;
        }

        //Actualización del valor de PWM        
        if (pwmNuevo){    
            if ((Inicio==0)&&(d1==Back_A)){
                AcCurve();
            }else if ((Inicio==0)&&(d1==Back_B)){
                AcLoadCurve();
            }else if ((Inicio==1)&&(d1==Start)){
                StopCurve(); Inicio=0;
            }else if (Inicio==1){
                //LT y RT vienen en un valor que va desde 128 hasta 65408. LT va desde 32768 hasta 65408 y RT va desde 128 hasta 32768.
                // Con este if se identifica si se presionó LT y RT. Para luego escalar a valores desde 0 hasta 1
                if (LT_RT>32768){
                    LT=(-1*LT_RT+65536)*F_LT_RT;p1=((LT*(Med_M-1.0))+1.0)/P_M; //p1 se escala desde 1 a 1,6 para el freno
                }                  
                else if (LT_RT<32768){
                    RT=(-1*LT_RT+32768)*F_LT_RT;p1=((RT*(Med_M-1.0))+(Med_M))/P_M; //p1 se escala desde 1,6 a 2,2 para la aceleración
                }      
                else if (LT_RT==32768){
                    p1=(Med_M/P_M);
                }                                  //p1 es 1,6 si no presiona ni LT ni RT
            }     
        
            if (cont<=10){
                p2=Med_S1/P_S1; p3=1.5/P_S2; cont++;
            }else {
                cont=12;
            }
         
            if (p1 != p1a) {
                Motor.write(p1);
            }
        
            if (p2 != p2a) {
                Direc.write(p2);
            }
        
            C_S2 = (Med_S2-1.05555)*(T_PWM/T_S2);
               
            if ((Arrows==315)|(Arrows==0)|(Arrows==45)){
                p3=p3+C_S2/P_S2;
            }else if ((Arrows==225)|(Arrows==180)|(Arrows==135)) {
                p3=p3-C_S2/P_S2;
            }
        
            if(p3 <= 1.05555/P_S2){
                p3 = 1.05555/P_S2;
            }
            if(p3 >= 1.94444/P_S2){
                p3 = 1.94444/P_S2;
            }
        
            if (p3 != p3a) {
                Elev.write(p3);
            }
        
            p1a = p1;
            p2a = p2;
            p3a = p3;
        
            datosX = acc.getAccX();             // datos a almacenar
            datosY = acc.getAccY();             // datos a almacenar
            datosZ = acc.getAccZ();             // datos a almacenar
        
            pwmNuevo = 0;               
        }
    }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*************************************************************************
FUNCIÓN: initPWM()
PROPÓSITO:  Inicializar los PWM
**************************************************************************/

void initPWM(void){
    Motor.period_ms(P_M);
    Motor.write(1.0/P_M);
    Direc.period_ms(P_S1);
    Direc.write(Med_S1/P_S1);
    Elev.period_ms(P_S2);
    Elev.write(Med_S2/P_S2);
    wait(0.2);
}

/*************************************************************************
FUNCIÓN: AcCurve(void)
PROPÓSITO:  Función de aceleración del motor a partir de velocidad cero
**************************************************************************/
void AcCurve(void){   
    C_In=(Med_M-1.0)*(T_PWM/T_In);
    
    p1=(1.0/P_M);
    Motor.write(p1);
    wait(0.250);
                    
    for (int ii=0;ii<=ceil(T_In/T_PWM);ii++){
        if (p1 < (Med_M/P_M)) {
            p1 = p1 + C_In/P_M; 
            Motor.write(p1);
            wait(T_PWM);
        }else if (p1 >= (Med_M/P_M)){
            p1 = Med_M/P_M; 
        }
    }
    Inicio = 1;
}
                   
/*************************************************************************
FUNCIÓN: AcLoadCurve(void)
PROPÓSITO:  Función de aceleración del motor a partir de velocidad cero
**************************************************************************/


void AcLoadCurve(void){       
    C_Load=(Med_M-1.0)*(T_PWM/T_Load);
    
    p1=(1.0/P_M);
    Motor.write(p1);
    wait(0.250);
                    
    for (int ii=0;ii<=ceil(T_Load/T_PWM);ii++){
        if (p1 < (Med_M/P_M)) {
            p1=p1+C_Load/P_M; Motor.write(p1); wait(T_PWM);
        }else if (p1 >= (Med_M/P_M)){
            p1=Med_M/P_M;
        }
    }
                    
    Inicio=1;
}

/*************************************************************************
FUNCIÓN: StopCurve(void)
PROPÓSITO: función de parada del motor. 
**************************************************************************/
 
void StopCurve(void){    
    C_Stop=(Med_M-1.0)*(T_PWM/T_Stop);
    
    for (int ii=0;ii<=ceil(T_Stop/T_PWM);ii++){
        if (p1 > 1.0/P_M) {
            p1=p1-C_Stop/P_M; Motor.write(p1); wait(T_PWM);
        }else if (p1 <= 1.0/P_M){
            p1=1.0/P_M;
        }
    }
}

/*************************************************************************
FUNCIÓN: xbeeRead()
PROPÓSITO:  ESCRIBIR UN PAQUETE DE DATOS API EN EL XBEE CON LOS DATOS ÚTILES
**************************************************************************/
 

void xbeeSend(void){
    int checksum=0x00;          //Se inicializa el cálculo del checksum por cada iteración

    for (i=3;i<=24;i++){
        //Se nombra un nuevo vector con los datos que va desde luego de la longitud (3) hasta antes del checksum (19)
        if(i<=16){
            V[i]=trama[i]; //El número de datos de los datos fijos de la trama de envío es 17, y la longitud es el dato 2
                           //por ende el condicional tomaría desde 3-16
        }else if((i>16) && (i<=24)){
            V[i]=entrada[i-17];  //El número de datos útiles a enviar es de 3, estos corresponderían a las posiciones 17,18 y 19
                                 // Si se envían 4 datos útiles la condición sería hasta 20, 5 datos útil iría hasta 21...
        }                                              
        checksum=checksum+V[i];  //Se suma desde el dato siguiente a la longitud de la trama hasta el último dato útil a enviar
    }

    // FORMULA CHECKSUM
    checksum=0xFF-checksum;         //Se realiza la operación para la fórmula del ckecksum

    // Primero se comprueba que el puerto esté libre para escribir
    if (xbee.writeable()){
        for (i=0;i<=16;i++){
            xbee.putc(trama[i]); //Envía todos los datos fijos de la trama de envío
        }
        xbee.printf("%c%c%c%c%c%c%c%c%c", entrada[0], entrada[1],entrada[2],entrada[3],entrada[4], entrada[5],entrada[6],entrada[7],checksum);//Envía el resto de datos (datos variables) de la trama de envío        
    }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*************************************************************************
FUNCIÓN: xbeeRead()
PROPÓSITO:  LEER UN PAQUETE DE DATOS DEL XBee Y SACAR DATOS ÚTILES
**************************************************************************/
void xbeeRead(){
    char packetFound = 0;                  //Esta variable, indicará si se ha encontrado un paquete o no.
    char thisByte;                         //Esta variable tomará valores de la trama de datos recibida
     
    if(xbee.rxBufferGetCount() == 0){       //Si en el Buffer no ha llegado ningún dato, el programa volverá a leerlo
         return;
     }
    while(xbee.rxBufferGetCount() > 14){   //Si llegaron más de 14 palabras al buffer, compruebe que sea la trama correcta 
        thisByte = xbee.getc();             //Toma el primer valor de la trama recibida. 
        if(thisByte == 0x7E){               //Si el primer dato de la trama es 0x7E, continúe...
            thisByte =  xbee.getc();        //Toma el MSB de la longitud
            thisByte =  xbee.getc();        //Toma el LSB de la longitud
            thisByte =  xbee.getc();        //Toma el tipo de paquete
        if(thisByte == 0x90){           //Si recibió que el paquete es de tipo: Rx (0x90), continúe...
            // packet is rx type
            packetFound = 1;            //Se indica que se encontró la trama de recepción
            break;                      //Si se ubica la trama, se sale del ciclo while
        }
    }
}
                                                
    if(packetFound == 1){                 // Se encontró un paquete, entonces se toman los siguientes 11 datos. 
                                          // Estos 11 datos van hasta un dato antes del primer dato útil     
        
        for(int j = 1; j >= 11; j++){
            thisByte =  xbee.getc();
        }    
        
        // Luego de contar los 11 datos, se comienzan a tomar los datos útiles. En este caso son 3 
        thisByte =  xbee.getc();       
        d1 =  thisByte;
        thisByte =  xbee.getc();       
        d2 =  thisByte;
        thisByte =  xbee.getc();       
        d3 =  thisByte;
        thisByte =  xbee.getc();       
        d4 =  thisByte;
        thisByte =  xbee.getc();       
        d5 =  thisByte;
        thisByte =  xbee.getc();       
        d6 =  thisByte;
        thisByte =  xbee.getc();       
        d7 =  thisByte;
        thisByte =  xbee.getc();       
        d8 =  thisByte;
        thisByte =  xbee.getc();       
        d9 =  thisByte;
    }        
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// ISR -> Interrupt service routine - para tomar dato y hacer parpadeo (DEBE SER RAPIDA)
void TxSend(void){
    angleXZ = atan((datosX)/(datosZ));
    angleXZ = angleXZ*(57.2958);
    
    angleYZ = atan((datosY)/(datosZ));
    angleYZ = angleYZ*(57.2958);
    
    char * b1 = (char *) &angleXZ;
    char * b2 = (char *) &angleYZ;

    entrada[0]= b1[3];
    entrada[1]= b1[2];
    entrada[2]= b1[1];
    entrada[3]= b1[0];
    entrada[4]= b2[3];
    entrada[5]= b2[2];
    entrada[6]= b2[1];
    entrada[7]= b2[0];    
    
    datoNuevo = 1; // Indicamos que tenemos un dato nuevo
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// ISR -> Interrupción para la actualización del PWM
void WaitPWM(void){   
    pwmNuevo = 1; // Indicamos que tenemos un dato nuevo
}