Microcontroladores PIC en Linux.
¿Quieres reaccionar a este mensaje? Regístrate en el foro con unos pocos clics o inicia sesión para continuar.

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

2 participantes

Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por maigke Vie 17 Sep 2010 - 8:32

Buenas noches a todos (Aquí en Mx es de madrugada)

Bien en esta ocasion les presento un codigo que es original de RedPIc, y que gracias a la lógica que el presenta en su sitio, he aprendido bastante. Pues bien, aqui esta el código que el nos presenta para controlar 8 servomotores con una sola interrupcion del timer1 a 16 bits, pero con las siguientes modificaciones:

-- El pic es un 18F2550
-- El lenguaje claro que es SDCC y pues así lo hace libre esto.
-- El oscilador es a 20MHz, pero basado en el proyecto Pinguino se establece que el micro trabaje a 12MIPS.
-- Tome algunos ejemplos de como trabaja el proyecto Pinguino de Jean - Pierre Mandon.
-- Aun el micro no entiende lo que le mandes por el puerto paralelo serial (andaba medio dormido). cyclops pero ya mero

sin mas preambulos, les muestro el código, que digamoslo así, es casí una copia fiel, pero con sus bueno retoques, algo importante, no se la causa del por que el SDCC no trabaja bien con las operaciones de 16bits, así que tuve que hacer algunos ajustes, así que tuve que gastar aun mas recursos de los que ya de por si SDCC requiere. posterior les presento algunas pantallas.

Espero sus notas y comentarios:, por cierto este post, se puede ligar al de GAMBAS + pic16f628 + puerto serial. Wink

Código:

/* ----------------------------------------------------------------------- */
/* Plantilla generada por Piklab */
/*
La configuracion del micro nos permite trabajar un con XT de 20MHZ
y pero usar el PLL con el propósito de alcanzar los 12MIPS
*/
#include <pic18f2550.h>
#include <delay.h>
#include <uart18f2550.c>
/* ----------------------------------------------------------------------- */
/* Bits de configuración: adapte los parámetros a su necesidad */
code char at __CONFIG1L CONFIG1L = _PLLDIV_DIVIDE_BY_5__20MHZ_INPUT__1L & _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L & _USBPLL_CLOCK_SRC_FROM_96MHZ_PLL_2_1L;
code char at __CONFIG1H CONFIG1H = _OSC_HS__HS_PLL__USB_HS_1H & _FCMEN_ON_1H & _IESO_ON_1H;
code char at __CONFIG2L CONFIG2L = _PUT_ON_2L & _BODEN_ON_2L & _BODENV_4_2V_2L & _VREGEN_ON_2L;
code char at __CONFIG2H CONFIG2H = _WDT_DISABLED_CONTROLLED_2H & _WDTPS_1_32768_2H;
code char at __CONFIG3H CONFIG3H = _CCP2MUX_RC1_3H & _PBADEN_PORTB_4_0__CONFIGURED_AS_DIGITAL_I_O_ON_RESET_3H & _LPT1OSC_ON_3H & _MCLRE_MCLR_OFF_RE3_ON_3H;
code char at __CONFIG4L CONFIG4L = _STVR_ON_4L & _LVP_OFF_4L & _ENHCPU_OFF_4L & _BACKBUG_OFF_4L;
code char at __CONFIG5L CONFIG5L = _CP_0_OFF_5L & _CP_1_OFF_5L & _CP_2_OFF_5L & _CP_3_OFF_5L;
code char at __CONFIG5H CONFIG5H = _CPB_OFF_5H;
code char at __CONFIG6L CONFIG6L = _WRT_0_OFF_6L & _WRT_1_OFF_6L & _WRT_2_OFF_6L & _WRT_3_OFF_6L;
code char at __CONFIG6H CONFIG6H = _WRTC_OFF_6H & _WRTB_OFF_6H;
code char at __CONFIG7L CONFIG7L = _EBTR_0_OFF_7L & _EBTR_1_OFF_7L & _EBTR_2_OFF_7L & _EBTR_3_OFF_7L;
code char at __CONFIG7H CONFIG7H = _EBTRB_OFF_7H;

//Definiciones de servos
#define SERVO1 LATBbits.LATB0
#define SERVO2 LATBbits.LATB1
#define SERVO3 LATBbits.LATB2
#define SERVO4 LATBbits.LATB3
#define SERVO5 LATBbits.LATB4
#define SERVO6 LATBbits.LATB5
#define SERVO7 LATBbits.LATB6
#define SERVO8 LATBbits.LATB7

#define CSERVO1 TRISBbits.TRISB0
#define CSERVO2 TRISBbits.TRISB1
#define CSERVO3 TRISBbits.TRISB2
#define CSERVO4 TRISBbits.TRISB3
#define CSERVO5 TRISBbits.TRISB4
#define CSERVO6 TRISBbits.TRISB5
#define CSERVO7 TRISBbits.TRISB6
#define CSERVO8 TRISBbits.TRISB7

typedef enum{false = 0, true = 1} boolean;

//Constantes para la definición de ventanas
const unsigned Ticks4WindowH = 0x75;
const unsigned Ticks4WindowL = 0x2F;
const unsigned Ticks4CenterH = 0x46;
const unsigned Ticks4CenterL = 0x4F;
const unsigned Ticks4MinimumH = 0x17;
const unsigned Ticks4MinimumL = 0x6F;
const unsigned Ticks4MaximumH = 0x6B;
const unsigned Ticks4MaximumL = 0xCF;
static unsigned int Ticks4NextInterruptH = 0xCF;
static unsigned int Ticks4NextInterruptL = 0x2C;

static unsigned short Servo_PWMH[8];
static unsigned short Servo_PWML[8];
static unsigned short Servo_Idx = 0;
 
#define SERVO1_ON true
#define SERVO2_ON false
#define SERVO3_ON false
#define SERVO4_ON false
#define SERVO5_ON false
#define SERVO6_ON false
#define SERVO7_ON false
#define SERVO8_ON false

//definicion de teclas
#define INTRO 0x0D
#define RETROCESO 0x08
#define ESCAPE 0x1B

unsigned short flag_Phase;
unsigned short j=0xFF;

/*Seccion para la comunicacion en serial*/

#define  lenbuff 10

unsigned char xbuff=0x00;
unsigned char cbuff[lenbuff];
char rcvchar=0x00;
unsigned char flagcommand = 0;


//Prototipos
void init_board(void);
void EnableTimer1Interrupt();
void Tmr1Carga(unsigned char high, unsigned char low);
void delay_ms(int milis);
void delay_us(int milis);


//Sección de interrupciones

static void isr_Tmr1() interrupt 1    //Esta es una interrupcion de alta prioridad
{
   PIE1bits.RCIE=0;  //deshabilitamos la interrupcion del puerto serie
   if(flag_Phase == 1)
   {
      if(Servo_Idx == 0 && SERVO1_ON) {SERVO1 = 1;}
      if(Servo_Idx == 1 && SERVO2_ON) {SERVO2 = 1;}
      if(Servo_Idx == 2 && SERVO3_ON) {SERVO3 = 1;}
      if(Servo_Idx == 3 && SERVO4_ON) {SERVO4 = 1;}
      if(Servo_Idx == 4 && SERVO5_ON) {SERVO5 = 1;}
      if(Servo_Idx == 5 && SERVO6_ON) {SERVO6 = 1;}
      if(Servo_Idx == 6 && SERVO7_ON) {SERVO7 = 1;}
      if(Servo_Idx == 7 && SERVO8_ON) {SERVO8 = 1;}
      Ticks4NextInterruptH = 0xFF - Servo_PWMH[Servo_Idx];
      Ticks4NextInterruptL = 0xFF - Servo_PWML[Servo_Idx];
      Tmr1Carga(Ticks4NextInterruptH,Ticks4NextInterruptL);
   }
   
   if(flag_Phase == 0)
   {
      if(Servo_Idx == 0 && SERVO1_ON) {SERVO1 = 0;}
      if(Servo_Idx == 1 && SERVO2_ON) {SERVO2 = 0;}
      if(Servo_Idx == 2 && SERVO3_ON) {SERVO3 = 0;}
      if(Servo_Idx == 3 && SERVO4_ON) {SERVO4 = 0;}
      if(Servo_Idx == 4 && SERVO5_ON) {SERVO5 = 0;}
      if(Servo_Idx == 5 && SERVO6_ON) {SERVO6 = 0;}
      if(Servo_Idx == 6 && SERVO7_ON) {SERVO7 = 0;}
      if(Servo_Idx == 7 && SERVO8_ON) {SERVO8 = 0;}
      Ticks4NextInterruptH = 0xFF - Ticks4WindowH;
      Ticks4NextInterruptL = 0xFF - Ticks4WindowL;
      
      if(Ticks4NextInterruptL + Servo_PWML[Servo_Idx] > 0xFF)
      {
         Ticks4NextInterruptL = Ticks4NextInterruptL + Servo_PWML[Servo_Idx];
         Ticks4NextInterruptH = Ticks4NextInterruptH + Servo_PWMH[Servo_Idx] + 1;
      }
      else
      {
         Ticks4NextInterruptL = Ticks4NextInterruptL + Servo_PWML[Servo_Idx];
         Ticks4NextInterruptH = Ticks4NextInterruptH + Servo_PWMH[Servo_Idx];
      }
      Tmr1Carga(Ticks4NextInterruptH,Ticks4NextInterruptL);
      if(++Servo_Idx > 7 ) Servo_Idx = 0;
   }
   if(++flag_Phase > 1) flag_Phase = 0;
   //Esta instruccion se esta ejecutando cada 13ms con un xtal de 20MHz   
    LATBbits.LATB7^=1; //complementamos el valor del bit RB7
//   RB7^=1;  <- dice que no se puede así
    PIR1bits.TMR1IF=0; //limpiamos la bandera de interrupcion
    PIE1bits.RCIE=1;  //habilitamos la interrupcion del puerto serie
    //Carga el timer para 1ms
    //Tmr1Carga(0xD1,0x1F);    //TMR1 = FFFF - FF00
}


static void isr_Serial() interrupt 2  //Esta es una interrupcion de baja prioridad
{
   PIR1bits.RCIF=0;
   rcvchar=RCREG;
   Printf(rcvchar);
}

//Funcion Principal
void main() {
//declaracion de variables
int i=0;
int button_down=1;
int valTimer=0;

RCONbits.IPEN=1; //interrupciones por prioridad habilitadas

init_board();
Print_str("Dispositivo inicializado");
Printf(INTRO);
Print_str("PIC18F2550 en SDCC");
Printf(INTRO);


for (i=0;i<9;i++)
{
   Servo_PWMH[i] = Ticks4MaximumH;
   Servo_PWML[i] = Ticks4MaximumL;
}
EnableTimer1Interrupt();
while (true)
{
}
}

void init_board(void) {
ADCON1=0x7; // PORTA used for digital I/O
TRISAbits.TRISA4=true; // configure PORTA4 for input (pushbutton)

/* Configuramos las salidas de los servomotores*/
CSERVO1 = false;
CSERVO2 = false;
CSERVO3 = false;
CSERVO4 = false;
CSERVO5 = false;
CSERVO6 = false;
CSERVO7 = false;
CSERVO8 = false;

//Configuramos la comunicacion serial --rutina de jean Pierre Mandon
setup_UART(B57600);
}

void EnableTimer1Interrupt()
{
   TMR1H=0xFF;
   TMR1L=0x00;    //TMR1 = FFFF - FF00
   T1CON=1;        //Timer1 preescaler 1 interno, carga de 8 bits
   PIE1bits.TMR1IE=1;
   INTCONbits.PEIE=1;
   INTCONbits.GIE=1;
}

void Tmr1Carga(unsigned char high, unsigned char low)
{
   TMR1H=high;
   TMR1L=low;
}
      
void delay_ms(int milis){
delay1ktcy(5*milis);
}

void delay_us(int milis){
delay10tcy(1*milis);
}


Y esta es la rutina de comunicacion serial de Jean Pierre que use
Código:

// UART Library for PIC 18F2550
// SDCC version / small device c compiler
// written by Jean-Pierre MANDON 2008 jp.mandon@free.fr
// www.pictec.org
/*
  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 2, or (at your option) any
  later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

  In other words, you are welcome to use, share and improve this program.
  You are forbidden to forbid anyone else to use, share and improve
  what you give them.  Help stamp out software-hoarding!
*/
// this program is intended for an oscillator frequency of 20 Mhz


// SPBRG value for FOSC 20 Mhz

#define B300            1,0,0x27,0x0F
#define B1200            1,0,0x09,0xC3
#define B2400            1,0,0x04,0xE1
#define B4800          1,0,0x02,0x70
#define B9600            0,0,0x00,0x4D
#define B19200          0,0,0x00,0x26
#define B57600          1,1,0x00,0xCF
#define B115200          1,1,0x00,0x67

// local definition UART.C

#define BUFFER 128                      // rx buffer length
char rx[BUFFER];                        // this is the buffer
unsigned char wpointer,rpointer;        // write and read pointer

#define charreceived (wpointer!=rpointer)
#define SERIAL

typedef struct
{
unsigned int
hhigh4:4,
hlow4:4,
lhigh4:4,
llow4:4;
} bitfield;

// setup PIC UART

void setup_UART(unsigned char brg16,unsigned char brgh,unsigned char highbyte,unsigned char lowbyte)
{
TXSTAbits.BRGH=brgh&1;                   // set BRGH bit
BAUDCONbits.BRG16=brg16&1;      // set 16 bits SPBRG
SPBRGH=highbyte;                        // set UART speed SPBRGH
SPBRG=lowbyte;            // set UART speed SPBRGL
RCSTA=0x90;                            // set RCEN and SPEN
BAUDCONbits.RCIDL=1;         // set receive active
PIE1bits.RCIE=1;                        // enable interrupt on RX
INTCONbits.PEIE=1;                      // enable peripheral interrupts
IPR1bits.RCIP=0;                        // define low priority for RX interrupt
wpointer=1;                            // initialize write pointer
rpointer=1;                            // initialize read pointer
TXSTAbits.TXEN=1;                      // enable TX
INTCONbits.GIE=1;
}

// UART write char

void Printf(unsigned char caractere)
{
while (!TXSTAbits.TRMT);
TXREG=caractere;              // yes, send char
}

// rxint is called by interruption service routine

void rxint(void)
{
char caractere;
unsigned char newwp;

    PIR1bits.RCIF=0;                  // clear RX interrupt flag
    caractere=RCREG;                  // take received char
    if (wpointer!=BUFFER-1)            // if not last place in buffer
   newwp=wpointer+1;              // place=place+1
    else
   newwp=1;                        // else place=1

    if (rpointer!=newwp)              // if read pointer!=write pointer
   rx[wpointer++]=caractere;      // store received char

    if (wpointer==BUFFER)              // if write pointer=length buffer
    wpointer=1;                    // write pointer = 1
}


// get char

unsigned char getch()
{
unsigned char caractere=0;

if (charreceived)
    {
    caractere=rx[rpointer++];
    if (rpointer==BUFFER)
   rpointer=1;
    }
return(caractere);
}

// clear rx buffer

void clear_buffer(void) {
wpointer=1;
rpointer=1;
}

// write a string on the UART

void Print_str(const char* text)
{
unsigned char i=0;
while ( text[i] != 0 )
    Printf( text[i++] );
}

// convert 16 bits binary value  to DEC and send it on the UART

void Print_dec(unsigned int valeur)
{
unsigned char result;
unsigned char zero=1;


result=valeur/10000;
if (result!=0)  {
      Printf(result+0x30);
      zero=0;
      }
valeur=valeur%10000;
result=valeur/1000;
if (result!=0)  {
      Printf(result+0x30);
      zero=0;
      }
else if (zero==0) Printf('0');
valeur=valeur%1000;
result=valeur/100;
if (result!=0)  {
      Printf(result+0x30);
      zero=0;
      }
else if (zero==0) Printf('0');
valeur=valeur%100;
result=valeur/10;
if (result!=0)  {
      Printf(result+0x30);
      zero=0;
      }
else if (zero==0) Printf('0');
result=valeur%10;
Printf(result+0x30);
}

// convert 16 bits binary value to HEX and send it on the UART

void Print_hex(unsigned int valeur)
{
  const char hexa[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

Printf(hexa[(valeur>>12)&0x000F]);
Printf(hexa[(valeur>>8)&0x000F]);
Printf(hexa[(valeur>>4)&0x000F]);
Printf(hexa[valeur&0x000F]);
}

// convert 16 bits binary value to byte and send it on the UART

void Print_byte(unsigned int valeur)
{
unsigned int result;
result=valeur;
Printf(result);
}


alien

Referencias


http://picmania.garcia-cuervo.net/picc.php#COMBUF232
http://picmania.garcia-cuervo.net/picc_servos_x_8.php
http://sdcc.sourceforge.net/doc/sdccman.pdf
http://pinguino.walii.es/archives/161
http://karoshi.auic.es/index.php?topic=1689.0
http://jpmandon.blogspot.com/


Última edición por maigke el Mar 21 Sep 2010 - 10:41, editado 1 vez
maigke
maigke
Asiduo del Foro
Asiduo del Foro

Mensajes : 210
Fecha de inscripción : 12/04/2009
Edad : 46
Localización : Mexico

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por maigke Dom 19 Sep 2010 - 14:45

Bueno después de mucho trabajar, por fin creo que ya funca esta versión del programa realizado por Redpic, pero en SDCC, como características tiene las siguientes:

* Comunicación por el puerto RS232 a 57600bps, pero puede aumentarse a 115200bps
* La forma de control de los servos es secuencial, lo que no permite mover dos servos de forma simultánea.
* El formato de instrucción es [servo][valor en grados][velocidad]
-Para servo usamos un byte char [a|b|c|d|e|f]
-Para valor en grados usamos tres bytes ejemplos [090] [001] [175] 90°, 1°, y 175° respectivamente
* Envia códigos de error cuando son suministrados los datos por el puerto serial
Códigos de mensajes de error
0 -- Buffer lleno Se han enviado demasiados caracteres
1 -- turnPLus error no puedo mover servo seleccionado
2 -- turnMinus error no puedo mover servo seleccionado
3 -- commandProcess error o puedo elegir ese servo

Cuando el proceso termina satisfactoriamente se manda la cadena "ok"

Para definir los servos a mover, usamos las siguientes macros definidas al inicio del código

//Definiciones de servos
#define SERVO1 LATBbits.LATB0
#define SERVO2 LATBbits.LATB1
#define SERVO3 LATBbits.LATB2
#define SERVO4 LATBbits.LATB3
#define SERVO5 LATBbits.LATB4
#define SERVO6 LATBbits.LATB5
#define SERVO7 LATBbits.LATB6
#define SERVO8 LATBbits.LATB7

#define CSERVO1 TRISBbits.TRISB0
#define CSERVO2 TRISBbits.TRISB1
#define CSERVO3 TRISBbits.TRISB2
#define CSERVO4 TRISBbits.TRISB3
#define CSERVO5 TRISBbits.TRISB4
#define CSERVO6 TRISBbits.TRISB5
#define CSERVO7 TRISBbits.TRISB6
#define CSERVO8 TRISBbits.TRISB7

Una característica mas, es que no es necesario usar los 8 pines como salida, sino que podemos elegir mediante el "bit"
boolean SERVO1_ON = true;
boolean SERVO2_ON = true;
boolean SERVO3_ON = true;
boolean SERVO4_ON = true;
boolean SERVO5_ON = true;
boolean SERVO6_ON = true;
boolean SERVO7_ON = true;
boolean SERVO8_ON = true;

Si necesitamos usar dos servos, un servo o los 8, como gustes Very Happy, (Esto tambien es original del código de RedPIC)
Código:

/* ----------------------------------------------------------------------- */
/* Plantilla generada por Piklab */
/*
La configuracion del micro nos permite trabajar un con XT de 20MHZ
y pero usar el PLL con el propósito de alcanzar los 12MIPS

Códigos de mensajes de error
0 -- Buffer lleno  Se han enviado demasiados caracteres
1 -- turnPLus error  no puedo mover servo seleccionado
2 -- turnMinus error no puedo mover servo seleccionado
3 -- commandProcess error o puedo elegir ese servo

ok -- Proceso terminado correctamente
*/
#include <pic18f2550.h>
#include <delay.h>
#include <uart18f2550.c>
#include <stdlib.h>
#include <string.h>
/* ----------------------------------------------------------------------- */
/* Bits de configuración: adapte los parámetros a su necesidad */
code char at __CONFIG1L CONFIG1L = _PLLDIV_DIVIDE_BY_5__20MHZ_INPUT__1L & _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L & _USBPLL_CLOCK_SRC_FROM_96MHZ_PLL_2_1L;
code char at __CONFIG1H CONFIG1H = _OSC_HS__HS_PLL__USB_HS_1H & _FCMEN_ON_1H & _IESO_ON_1H;
code char at __CONFIG2L CONFIG2L = _PUT_ON_2L & _BODEN_ON_2L & _BODENV_4_2V_2L & _VREGEN_ON_2L;
code char at __CONFIG2H CONFIG2H = _WDT_DISABLED_CONTROLLED_2H & _WDTPS_1_32768_2H;
code char at __CONFIG3H CONFIG3H = _CCP2MUX_RC1_3H & _PBADEN_PORTB_4_0__CONFIGURED_AS_DIGITAL_I_O_ON_RESET_3H & _LPT1OSC_ON_3H & _MCLRE_MCLR_OFF_RE3_ON_3H;
code char at __CONFIG4L CONFIG4L = _STVR_ON_4L & _LVP_OFF_4L & _ENHCPU_OFF_4L & _BACKBUG_OFF_4L;
code char at __CONFIG5L CONFIG5L = _CP_0_OFF_5L & _CP_1_OFF_5L & _CP_2_OFF_5L & _CP_3_OFF_5L;
code char at __CONFIG5H CONFIG5H = _CPB_OFF_5H;
code char at __CONFIG6L CONFIG6L = _WRT_0_OFF_6L & _WRT_1_OFF_6L & _WRT_2_OFF_6L & _WRT_3_OFF_6L;
code char at __CONFIG6H CONFIG6H = _WRTC_OFF_6H & _WRTB_OFF_6H;
code char at __CONFIG7L CONFIG7L = _EBTR_0_OFF_7L & _EBTR_1_OFF_7L & _EBTR_2_OFF_7L & _EBTR_3_OFF_7L;
code char at __CONFIG7H CONFIG7H = _EBTRB_OFF_7H;

//Definiciones de servos
#define SERVO1 LATBbits.LATB0
#define SERVO2 LATBbits.LATB1
#define SERVO3 LATBbits.LATB2
#define SERVO4 LATBbits.LATB3
#define SERVO5 LATBbits.LATB4
#define SERVO6 LATBbits.LATB5
#define SERVO7 LATBbits.LATB6
#define SERVO8 LATBbits.LATB7

#define CSERVO1 TRISBbits.TRISB0
#define CSERVO2 TRISBbits.TRISB1
#define CSERVO3 TRISBbits.TRISB2
#define CSERVO4 TRISBbits.TRISB3
#define CSERVO5 TRISBbits.TRISB4
#define CSERVO6 TRISBbits.TRISB5
#define CSERVO7 TRISBbits.TRISB6
#define CSERVO8 TRISBbits.TRISB7

typedef enum{false = 0, true = 1} boolean;  //para definir variables booleanas

//boolean tuza = true;  este es solo un ejemplo
//Constantes para la definición de ventanas
const unsigned Ticks4WindowH = 0x75;
const unsigned Ticks4WindowL = 0x2F;
const unsigned Ticks4CenterH = 0x46;
const unsigned Ticks4CenterL = 0x4F;
const unsigned Ticks4MinimumH = 0x17;
const unsigned Ticks4MinimumL = 0x6F;
const unsigned Ticks4MaximumH = 0x6B;
const unsigned Ticks4MaximumL = 0xCF;
static unsigned int Ticks4NextInterruptH = 0xCF;
static unsigned int Ticks4NextInterruptL = 0x2C;


const unsigned Ticks4Window = 0x752F;
const unsigned Ticks4Minimum = 0x176F;
const unsigned Ticks4Center = 0x464F;
const unsigned Ticks4Maximum = 0x6BCF;
static unsigned int Ticks4NextInterrupt = 0xCF2C;
static unsigned int Servo_PWM[8];
static unsigned int tempom=0x0000;
static unsigned int tempo=0x0000;
static unsigned int tempol;
static unsigned int tempoh;

static unsigned int Servo_PWMH[8];
static unsigned int Servo_PWML[8];
static unsigned short Servo_Idx = 0;
 
boolean SERVO1_ON = true;
boolean SERVO2_ON = true;
boolean SERVO3_ON = true;
boolean SERVO4_ON = true;
boolean SERVO5_ON = true;
boolean SERVO6_ON = true;
boolean SERVO7_ON = true;
boolean SERVO8_ON = true;

//definicion de teclas
#define INTRO 0x0D
#define RETROCESO 0x08
#define ESCAPE 0x1B

boolean flag_Phase;
unsigned short j=0xFF;
unsigned int posI;

/*Seccion para la comunicacion en serial*/

#define  lenbuff 10

unsigned char xbuff=0x00;
unsigned char cbuff[lenbuff];
char rcvchar=0x00;
boolean flagcommand = false;

//variables para timers
   unsigned char CounterA;
   unsigned char CounterB;

//Prototipos
void init_board(void);
void EnableTimer1Interrupt(void);
void Tmr1Carga(unsigned char high, unsigned char low);
void initBuff(void);
void add2cbuff(unsigned char c);
void echosel(char c);
void command_process(void);
void delay_ms(int milis);
void delay_us(int milis);
unsigned int SelectServo(unsigned char Servo);
void turnPlus(int vueltas, unsigned char vel, unsigned char Servo);
void turnMinus(int vueltas, unsigned char vel,unsigned char Servo);

//Sección de interrupciones

static void isr_Tmr1() interrupt 1    //Esta es una interrupcion de alta prioridad
{
   PIE1bits.RCIE=0;  //deshabilitamos la interrupcion del puerto serie
   if(flag_Phase == 1)
   {
      if(Servo_Idx == 0 && SERVO1_ON) {SERVO1 = 1;}
      if(Servo_Idx == 1 && SERVO2_ON) {SERVO2 = 1;}
      if(Servo_Idx == 2 && SERVO3_ON) {SERVO3 = 1;}
      if(Servo_Idx == 3 && SERVO4_ON) {SERVO4 = 1;}
      if(Servo_Idx == 4 && SERVO5_ON) {SERVO5 = 1;}
      if(Servo_Idx == 5 && SERVO6_ON) {SERVO6 = 1;}
      if(Servo_Idx == 6 && SERVO7_ON) {SERVO7 = 1;}
      if(Servo_Idx == 7 && SERVO8_ON) {SERVO8 = 1;}
      Ticks4NextInterruptH = 0xFF - Servo_PWMH[Servo_Idx];
      Ticks4NextInterruptL = 0xFF - Servo_PWML[Servo_Idx];
      Tmr1Carga(Ticks4NextInterruptH,Ticks4NextInterruptL);
   }
   
   if(flag_Phase == 0)
   {
      if(Servo_Idx == 0 && SERVO1_ON) {SERVO1 = 0;}
      if(Servo_Idx == 1 && SERVO2_ON) {SERVO2 = 0;}
      if(Servo_Idx == 2 && SERVO3_ON) {SERVO3 = 0;}
      if(Servo_Idx == 3 && SERVO4_ON) {SERVO4 = 0;}
      if(Servo_Idx == 4 && SERVO5_ON) {SERVO5 = 0;}
      if(Servo_Idx == 5 && SERVO6_ON) {SERVO6 = 0;}
      if(Servo_Idx == 6 && SERVO7_ON) {SERVO7 = 0;}
      if(Servo_Idx == 7 && SERVO8_ON) {SERVO8 = 0;}
      Ticks4NextInterruptH = 0xFF - Ticks4WindowH;
      Ticks4NextInterruptL = 0xFF - Ticks4WindowL;
      
      if(Ticks4NextInterruptL + Servo_PWML[Servo_Idx] > 0xFF)
      {
         Ticks4NextInterruptL = Ticks4NextInterruptL + Servo_PWML[Servo_Idx];
         Ticks4NextInterruptH = Ticks4NextInterruptH + Servo_PWMH[Servo_Idx] + 1;
      }
      else
      {
         Ticks4NextInterruptL = Ticks4NextInterruptL + Servo_PWML[Servo_Idx];
         Ticks4NextInterruptH = Ticks4NextInterruptH + Servo_PWMH[Servo_Idx];
      }
      Tmr1Carga(Ticks4NextInterruptH, Ticks4NextInterruptL);
      if(++Servo_Idx > 7 ) Servo_Idx = 0;
   }
   if(++flag_Phase > 1) flag_Phase = 0;
   
   //Esta instruccion se esta ejecutando cada 13ms con un xtal de 20MHz   
    LATBbits.LATB7^=1; //complementamos el valor del bit RB7
    PIR1bits.TMR1IF=0; //limpiamos la bandera de interrupcion
    PIE1bits.RCIE=1;  //habilitamos la interrupcion del puerto serie
}


static void isr_Serial() interrupt 2  //Esta es una interrupcion de baja prioridad
{
   PIR1bits.RCIF=0;
   rcvchar=RCREG;
   add2cbuff(rcvchar);
   echosel(rcvchar);
}

//Funcion Principal
void main() {
//declaracion de variables
int i=0;
int button_down=1;
int valTimer=0;

RCONbits.IPEN=1; //interrupciones por prioridad habilitadas
init_board();
Print_str("Dispositivo inicializado");
Printf(INTRO);
Print_str("PIC18F2550 en SDCC");
Printf(INTRO);
delay_ms(500); //tiempo de espera
initBuff();

for (i=0;i<9;i++)
{
   Servo_PWMH[i] = Ticks4CenterH;
   Servo_PWML[i] = Ticks4CenterL;
}

EnableTimer1Interrupt();
tempo = Ticks4Center;
tempoh = tempo & 0xFF00;
tempol = tempo & 0x00FF;
Tmr1Carga(tempoh, tempol);
posI = Ticks4Center;

      


while (true)
{
   if(flagcommand)  //si ya presionaste enter
   {
   command_process();
   }
}
}

void init_board(void) {
   flagcommand= false;
ADCON1=0x7; // PORTA used for digital I/O
TRISAbits.TRISA4=true; // configure PORTA4 for input (pushbutton)

/* Configuramos las salidas de los servomotores*/
CSERVO1 = false;
CSERVO2 = false;
CSERVO3 = false;
CSERVO4 = false;
CSERVO5 = false;
CSERVO6 = false;
CSERVO7 = false;
CSERVO8 = false;

//Configuramos la comunicacion serial --rutina de jean Pierre Mandon
setup_UART(B57600);
}

void EnableTimer1Interrupt(void)
{
   T1CON=1;        //Timer1 preescaler 1 interno, carga de 8 bits
   PIE1bits.TMR1IE=1;
   INTCONbits.PEIE=1;
   INTCONbits.GIE=1;
}

void Tmr1Carga(unsigned char high, unsigned char low)
{
   TMR1H=high;
   TMR1L=low;
}
      
//Funcion de vaciado del buffer
void initBuff(void){
   int i;
   for (i=0; i< lenbuff;i++){
      cbuff[i]=0x0;
   }xbuff=0x00;
}

//agrega un caracter mas al buffer, o realiza un acción
void add2cbuff(unsigned char c)
{
   if(xbuff<lenbuff){  //Añade caracteres al buffer mientras no se llene el buffer
      switch(c){
         case INTRO: //Enter  --> Habilita flag para procesar comando
            flagcommand=true;
            break;
         case RETROCESO: //BackSpace --> Borra del buffer el ultimo caracter insertado
            if(xbuff>0) cbuff[--xbuff]=0x00;
            break;
         case ESCAPE: //ESC  --> Borra todo el buffer
            initBuff();
            break;
         default:  //añade caracter al buffer recibido
            cbuff[xbuff++]=c;
      }
   }
   else{
      initBuff();//Si el buffer esta lleno, vacialo
      Print_str("0");  //Envia mensaje de que el buffer esta lleno Error 0
      Printf(INTRO);
   }
}

//Solo imprime los caracteres imprimibles
void echosel(char c)
{
   switch(c){
      case 0x0D: //Si presionamos la tecla intro
             Printf(INTRO);
         break;
      case 0x08: //Si presionamos la tecla BackSpace
         Printf(RETROCESO);
         break;
      case 0x1B: //Si presionamos la tecla ESC
         Printf(ESCAPE);
         break;
      default:
         Printf(c); //Echo de cualquier otro caracter
   }
}

/*
El formato de los comandos es el siguiente:
[a...f] [123] [xx]
servo posicion velocidad
primer byte un caracter alfabético de entre a y e que define al servo
tres bytes para definir la posicion del servo
dos bytes para definir la velocidad de movimiento del servo
a12301 {enter}
mueve el servo 1 a 123 grados de la posicion de origen a la velocidad 01
*/
void command_process()
{
   int i=0;
   char DerIzq= 1; //bandera para saber si va a 180 o a 0 grados
  // DerIzq = 1  Indicará que vamos de 0 a 180 por tanto suma
  // DerIzq = 0  Indicará que vamos de 180 a 0 por tanto resta
   unsigned char cmd[lenbuff]; //comando tecleado
   unsigned char servo[2];
   unsigned char pos[4];  //para almacenar las posiciones
   unsigned char posicion;
   unsigned char velocidad[4];  //para almacenar los incrementos
   unsigned char vel;
   
   unsigned int posF;  //Es posible que estos valores los tengas que dividir
   unsigned int vueltas;
   
   
   flagcommand=false;
   //Recibe el nombre del servo a mover
   strcpy(cmd,cbuff); 
   strncpy(servo,cmd,1);
   //guarda la posicion del servo
   strcpy(cmd,cbuff);
   for(i=1;i<4;i++){
      pos[i-1]= cmd[i];
   }
   posicion = atoi(pos);
   //guarda la velocidad a la que se moverá el servo
   strcpy(cmd,cbuff);
   for(i=4;i<7;i++)
   {
      velocidad[i-4]=cmd[i];
   }
   vel = atoi(velocidad);
   tempo = 0;
   tempoh=0;
   tempol=0;
   switch(servo[0]){
      case 'a':
         posI=SelectServo(0);
         break;
      case 'b':
         posI=SelectServo(1);
         break;
      case 'c':
         posI=SelectServo(2);
         break;
      case 'd':
         posI=SelectServo(3);
         break;
      case 'e':
         posI=SelectServo(4);
         break;
      case 'f':
         posI=SelectServo(5);
         break;
      default:
         Print_str("3"); //Error 3 opcion elegida no válida
         Printf(INTRO);
         break;
   }
   posF= 106.66 * posicion + 8399;

   
   if(posF>posI){
      vueltas = posF - posI;
      vueltas = vueltas / vel;
      DerIzq = 1;
   }
   else
   {
      vueltas = posI - posF;
      vueltas = vueltas/ vel;
      DerIzq = 0;
   }
   
   /********************************************************/
   /*
   Debe de leerse el valor que tiene del servo desde el array
   Žpara determinar el valor inicial y no unicamente dejarlo
   como valor final. esto causa el eeror de que al mover
   multiples motores con una unica variable se moveran en conse-
   cuencia del anterior
   */
  // posI = posF;  Esto no es correcto
 
   if(DerIzq)
   {
      switch(servo[0])
      {
         case 'a':  //mueve al servo uno en incrementos de vel hasta llegar a vueltas
            turnPlus(vueltas, vel, 0);
               break;
         case 'b':  //mueve al servo dos en incrementos de vel hasta llegar a vueltas
            turnPlus(vueltas, vel, 1);
               break;
         case 'c':

            
            turnPlus(vueltas, vel, 2);
               break;
         case 'd':

            turnPlus(vueltas, vel, 3);
               break;
         case 'e':

            turnPlus(vueltas, vel, 4);
               break;
         default:
            Print_str("1"); Printf(INTRO); //Error 1 turnPlusError
      }
   }
   else{
      switch(servo[0])
      {
         case 'a':  //mueve al servo uno en incrementos de vel hasta llegar a vueltas
            turnMinus(vueltas,vel,0);

               break;
         case 'b':  //mueve al servo dos en incrementos de vel hasta llegar a vueltas
            turnMinus(vueltas,vel,1);
               break;
         case 'c':
            turnMinus(vueltas,vel,2);
               break;
         case 'd':
            turnMinus(vueltas,vel,3);
               break;
         case 'e':
            turnMinus(vueltas,vel,4);
               break;
         default:
            Print_str("2");Printf(INTRO); // error 2 turnMinus Error
      } 
   }
   initBuff();
   Print_str("ok");Printf(INTRO);
}
      
void delay_ms(int milis){
delay1ktcy(10*milis);

}

void delay_us(int milis){
delay10tcy(1*milis);
}

unsigned int SelectServo(unsigned char Servo)
{
         tempoh = Servo_PWMH[Servo];
         tempo = tempoh << 8;
         return (tempo | Servo_PWML[Servo]);
}

void turnPlus(int vueltas, unsigned char vel, unsigned char Servo)
{
int i=0;

for(i=0;i<vueltas;i++)
            {
               tempoh = Servo_PWMH[Servo];
               tempoh = tempoh << 8;
               tempo  = tempoh | Servo_PWML[Servo];
               tempo += vel;
               Servo_PWML[Servo] = tempo & 0x00FF;
               tempoh = tempo & 0xFF00;
               tempoh = tempoh >> 8;
               Servo_PWMH[Servo] = tempoh;
               delay_us(100);
            }
}

void turnMinus(int vueltas, unsigned char vel, unsigned char Servo)
{
int i=0;

for(i=0;i<vueltas;i++)
            {
               tempoh = Servo_PWMH[Servo];
               tempoh = tempoh << 8;
               tempo  = tempoh | Servo_PWML[Servo];
               tempo -= vel;
               Servo_PWML[Servo] = tempo & 0x00FF;
               tempoh = tempo & 0xFF00;
               tempoh = tempoh >> 8;
               Servo_PWMH[Servo] = tempoh;
               delay_us(100);
            }
}

Very Happy Very Happy

Espero comentarios, saludos
maigke
maigke
Asiduo del Foro
Asiduo del Foro

Mensajes : 210
Fecha de inscripción : 12/04/2009
Edad : 46
Localización : Mexico

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por Risanti Dom 19 Sep 2010 - 23:52

Excelente Trabajo Maigke y a RedPic por la gran idea..
Se puede observar que has dedicado bastante tiempo a este compilador,yo habia realizado algunas pruebas con servos pero nunca con tantos, de de manera tan eficiente..


Una Consulta, mencionaste que habias encontrado algunos problemas.

no se la causa del por que el SDCC no trabaja bien con las operaciones de 16bits

Por lo que he visto en sdcc snapshot en las ultimas versiones han corregido algunos problemas con pic16. que version Usas???


Saludos
RiSanti
Risanti
Risanti
Asiduo del Foro
Asiduo del Foro

Mensajes : 172
Fecha de inscripción : 07/12/2008
Edad : 39
Localización : La Serena Chile

https://www.facebook.com/risanti.electronica

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por maigke Lun 20 Sep 2010 - 4:35

Saludos y gracias Risanti por tu opinion.

En cuanto a la version de SDCC que uso es la siguiente:
Código:

mike@mike:~$ sdcc -v
SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08 2.9.0 #5416 (Feb  3 2010) (UNIX)

Que es la que viene de facto con Ubuntu 10.04 LTS 32bits en laptop gateway procesador core2 duo t5300 a 1.7GHz cn 2G en ram.

En cuanto a las operaciones de 16bits tuve los siguientes problemas


Esta parte originalmente en el código de CCS PIC C Compiler, la puedes describir de la siguiente forma
Código:

Ticks4NextInterrupt = 65535 - Servo_PWM[Servo_Idx];
set_timer1(Ticks4NextInterrupt);

Y en la versión que propongo, tengo lo siguiente
Código:

      Ticks4NextInterruptH = 0xFF - Servo_PWMH[Servo_Idx];
      Ticks4NextInterruptL = 0xFF - Servo_PWML[Servo_Idx];
      Tmr1Carga(Ticks4NextInterruptH,Ticks4NextInterruptL);

En CCS, la operación es realizada en 16bits, así mismo la carga del timer1, pero en SDCC no se realiza de forma adecuada la operacion de resta, así que partí en 2 bytes para realizar la operacion, ahora tomando en cuenta, que la resta de 0xFFFF - Servo_PWM[Servo_Idx]; no nos dará ningún problema.

En otras partes del código que tuve que realizar unas operaciones similares, fueron en las siguientes:

Código:

void turnMinus(int vueltas, unsigned char vel, unsigned char Servo)
{
int i=0;

for(i=0;i<vueltas;i++)
            {
              tempoh = Servo_PWMH[Servo];
              tempoh = tempoh << 8;
              tempo  = tempoh | Servo_PWML[Servo];
              tempo -= vel;
              Servo_PWML[Servo] = tempo & 0x00FF;
              tempoh = tempo & 0xFF00;
              tempoh = tempoh >> 8;
              Servo_PWMH[Servo] = tempoh;
              delay_us(100);
            }
}


Que en CCS, se puede realizar de la siguiente manera:
Código:

for(i=0;i<4;i++) Servo_PWM[i]+=80;

Sin embargo, en esta solución que plantea RedPic, no modifica en velocidad, el avance del servo; aunque es muchisimo mas sencilla

Puedo decir que SDCC es un compilador no muy sencillo con el cual empezar, pero una vez que le agarras el pelo, te permite muchas cosas.
maigke
maigke
Asiduo del Foro
Asiduo del Foro

Mensajes : 210
Fecha de inscripción : 12/04/2009
Edad : 46
Localización : Mexico

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por maigke Lun 20 Sep 2010 - 13:31

Estos videos que hice ayer, bueno hoy hace unas horas Very Happy

aqui está la simulación:


Y esta es en hardware, no tuve mas que la camara de mi cel, me disculpo de una vez por la resolución.
maigke
maigke
Asiduo del Foro
Asiduo del Foro

Mensajes : 210
Fecha de inscripción : 12/04/2009
Edad : 46
Localización : Mexico

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por Risanti Lun 20 Sep 2010 - 22:46

Esta muy bueno... Maigke..
Sobre los problemas de sdcc es algo q hay que ir probando, en general este es un compilador en desarrollo pero posee cosas muy buenas, la primera que es open source..jajaja


Mira te recomiendo que actualices tu version para ellos descarga el ultima version http://sdcc.sourceforge.net/snap.php#Linux
descarga el archivo y descomprimelo, en /usr/share y /usr/bin ..

En General como te mencione desde febrero hasta hoy se han corregido algunos errores,en Pic16.


Saludos.
RiSanti
Risanti
Risanti
Asiduo del Foro
Asiduo del Foro

Mensajes : 172
Fecha de inscripción : 07/12/2008
Edad : 39
Localización : La Serena Chile

https://www.facebook.com/risanti.electronica

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por maigke Mar 21 Sep 2010 - 10:29

Saludos Risanti!

Muchas gracias por los comentarios!, y en efecto, hay cosas que hay que ir probando, y pues definitivamente, he realizado el cambio, por el hecho de ser open source.

Mas adelante voy a testear, como me comentas con el snapshot, para ver como se comporta SDCC.

Si hay algunos detalles los estaré comentando así como actualizaciones en este post.
maigke
maigke
Asiduo del Foro
Asiduo del Foro

Mensajes : 210
Fecha de inscripción : 12/04/2009
Edad : 46
Localización : Mexico

Volver arriba Ir abajo

Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC Empty Re: Control de 8 servos de RC por puerto serie -- Original de RedPIC traducido a SDCC

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Volver arriba

- Temas similares

 
Permisos de este foro:
No puedes responder a temas en este foro.