Autor Tema: Test Servo SG90  (Leído 1318 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
Test Servo SG90
« en: 28 de Noviembre de 2014, 19:30:12 »
Buenas tardes, estoy intentando hacer trabajar un servo SG90con un pic 16f887, el programa se basa en el post de redpic de hace algunos años, lo pase a xc8, con la unica diferencia de que el oscilador interno de mi programa es de 8 MHz, lo simule en proteus y todo parece estar bien, pero a la hora de pasarlo a la protoboard no funciona, ya intente usando alimentaciones separadas para el pic y el servo. Adjunto el programa para ver si alguien lo puede checar con un servo o guiarme en como hacer funcionar el mio.
gracias de antemano

config.h
Código: [Seleccionar]
#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = ON // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled)

// CONFIG2
#pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off)

main.c
Código: [Seleccionar]
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"

#define _XTAL_FREQ 8000000

#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

unsigned char contint = 0;
unsigned char Ajustetimer0 = 60;
unsigned char flagint = 0;
unsigned char tservo = 0;
unsigned char tmin = 120;
unsigned char tmed = 190;
unsigned char tmax = 254;
unsigned char flagservo = 0;
unsigned char valtimer = 0;

void ajuste ();

void interrupt inttim0(void){
    if (INTCONbits.T0IF && INTCONbits.T0IE){
    contint++;
        if (contint==9)
        {
            TMR0= Ajustetimer0;
        }
        if (contint==10)
        {
            flagint = 1;
            contint = 0;
        }
    }
    INTCONbits.T0IF = 0;
}

void main(void) {
    OSCCON = 0b01110101; // Reloj de 8 MHz
    TRISD = 0x0F;


    OPTION_REGbits.T0CS = 0; //Timer0 como temporizador
    OPTION_REGbits.PSA = 0; //Prescaler asignado al Timer0
    OPTION_REGbits.PS = 0b011; //Prescaler de 1:16

    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.T0IE = 1;

    

    while (1){

        if (flagint==1){
            PORTDbits.RD5 = 1;
            flagservo = 1;
            flagint = 0;
           }
        if (flagservo==1){
            valtimer = TMR0;
            if (valtimer > tservo){
                PORTDbits.RD5 = 0;
                flagservo = 0;
            }
        }
        ajuste ();
        }


    return;
}

void ajuste (){
    if (PORTDbits.RD0 ==1){
        __delay_ms(100);
        if (PORTDbits.RD0 ==1){
        tservo = tmin;
        }
    }
    if (PORTDbits.RD1 ==1){
        __delay_ms(100);
        if (PORTDbits.RD1 ==1){
        tservo = tmed;
        }
    }
    if (PORTDbits.RD2 ==1){
        __delay_ms(100);
        if (PORTDbits.RD2 ==1){
        tservo = tmax;
        }
    }

}

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7306
Re: Test Servo SG90
« Respuesta #1 en: 28 de Noviembre de 2014, 21:29:03 »
El ejemplo parece estar bien, no ser por que no andaria... utilizas el LVP ???
#pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled)

Es lo unico en las palabras de configuracion que me hace "ruido" (pero deberia andar si es que lo programas de esa forma, al menos yo siempre programe con LVP=OFF), y deberia andar """bien""" y no causarte que no veas nada en la salida.

Una de las cosas es que estas intentando hacer es un PWM por software a pesar que tenes un PWM en hardware.

Y Digo """bien""" por que hay cosas que estan mal en el concepto.

1-
En tu rutina de interrupcion:
Citar
if (INTCONbits.T0IF && INTCONbits.T0IE){
Eso esta de mas, ya que solo entraria ahi si fuera si o si ese caso (es decir habilitadas y ese flag en alto). Deberias desactivar la interrupcion el T0IE   apenas entra a la interrupcion y limpiar el flag cuando entra o cuando sale ANTES DE HABILITAR LA INTERRUPCION. Al final de la rutina habilitas la interrupcion nuevamente.
Código: [Seleccionar]
interrupcion() {
INTCONbits.T0IE = 0
INTCONbits.T0IF = 0
// aca la rutina de tu interrupcion
INTCONbits.T0IE = 1
}

2-
La idea general del sistema es mantener un periodo de 20ms, pero tu programa cuando presionas un boton se encuentra con: __delay_ms(100);, es decir 100ms mas (si entra una sola ves, sino suponete la señal de 20mS y luego una de 220mS), haciendo que el periodo sea muchisimo mayor y luego volves a 20ms. Por la forma que funciona es decir asignando un valor y no un incremento no vale la pena hacer un antirebote, de forma que si entra 100 veces no va a importar que lo asigne muchas veces, distinto seria un incremeneto donde incrementaria una cantidad aleatoria segun la cantidad de rebotes que detecte. Tendrias una salida mas estable justamente quitando ese delay.

3-
Si quisieras mantener tus 8Mhz en el oscilador podrias usar un divisor por 32 y no por 16 ( como en el ejemplo de 4Mhz) del TMR0 asi mantenes tus 20ms de periodo (Si es que mantuviste la misma cantidad de interrupciones, si lo cambiaste entonces olvidate de esto). Aunque si lo cambiaste el pulso en alto deberia ser el doble.

4-
Deberias poner a 0 el TMR0 cuando lo terminas de configurar.

5-
Por que crear un __delay_ms(), cuando XC8 ya lo tiene en el xc.h ? y tambien lei:
Citar
The _delay (x) inline function is limited slightly over 3 * 256 * 256
Lo que es igual a 196.6k y vos lo utilizas con 200k con tu macro. De todas formas no lo necesitarias para este caso como dije en el punto 2.

Es lo unico que veo mal, realmente otra cosa no se me ocurre. Y lo mas seguro es que es por la forma de programacion, el LVP. Y no estes programando nada.
« Última modificación: 28 de Noviembre de 2014, 21:59:00 por KILLERJC »

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
Re: Test Servo SG90
« Respuesta #2 en: 28 de Noviembre de 2014, 23:35:21 »
Buenas noches KILLERJC, tienes razon, tenia mal esa palabra de configuracion, como no hacia nada en la proto tenia la sensacion de que no estaba programandose mi pic, pense que era algo mas, hice las correcciones que me dices y todo esta funcionando!!  :-/, este servo en particular necesita pulsos de .500-2.400 mS asi que varie un poco los datos para centrar y mover a ambos lados el servo (con respecto al post de redpic), haciendo pruebas por que con los .5 mS el servo alcanzaba el tope y queria seguir girando.

tengo algunas dudas:

Citar
if (INTCONbits.T0IF && INTCONbits.T0IE){
esto se usaria en el caso de tener mas de 1 interrupciones habilitadas?

no se si sirva de algo pero aca dejo el codigo corregido, por si alguien lo quiere usar

config.h
Código: [Seleccionar]
#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = OFF         // Low Voltage Programming Disnable bit (RB3/PGM pin has PGM function, low voltage programming disabled)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)


main.c
Código: [Seleccionar]
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"

#define _XTAL_FREQ 8000000

unsigned char contint = 0;
unsigned char Ajustetimer0 = 30;
unsigned char flagint = 0;
unsigned char tservo = 0;
unsigned char tmin = 37;
unsigned char tmed = 90;
unsigned char tmax = 150;
unsigned char flagservo = 0;
unsigned char valtimer = 0;

void ajuste ();

void interrupt inttim0(void){
    INTCONbits.T0IE = 0;
    INTCONbits.T0IF = 0;
    contint++;
        if (contint==4)
        {
            TMR0= Ajustetimer0;
        }
        if (contint==5)
        {
            flagint = 1;
            contint = 0;
        }
    INTCONbits.T0IE = 1;
}

void main(void) {
    OSCCON = 0b01110101;    // Reloj de 8 MHz
    TRISD = 0x0F;


    OPTION_REGbits.T0CS = 0;       //Timer0 como temporizador
    OPTION_REGbits.PSA = 0;        //Prescaler asignado al Timer0
    OPTION_REGbits.PS = 0b100;     //Prescaler de 1:32

    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.T0IE = 1;

    TMR0 = 0;

    while (1){

        if (flagint==1){
            PORTDbits.RD5 = 1;
            flagservo = 1;
            flagint = 0;
           }
        if (flagservo==1){
            valtimer = TMR0;
            if (valtimer > tservo){
                PORTDbits.RD5 = 0;
                flagservo = 0;
            }
        }
        ajuste ();
        }


    return;
}

void ajuste (){
    if (PORTDbits.RD0 ==1){
        tservo = tmin;
        }
   
    if (PORTDbits.RD1 ==1){
        tservo = tmed;
        }
   
    if (PORTDbits.RD2 ==1){
        tservo = tmax;
        }
    }

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7306
Re: Test Servo SG90
« Respuesta #3 en: 02 de Diciembre de 2014, 16:27:11 »
tengo algunas dudas:

Citar
if (INTCONbits.T0IF && INTCONbits.T0IE){
esto se usaria en el caso de tener mas de 1 interrupciones habilitadas?


Si asi es, deberias tener esa condicion para varias interrupciones. Como vi que era una sola puse que no hacia falta :P

Desconectado josecuello

  • PIC10
  • *
  • Mensajes: 2
Re:Test Servo SG90
« Respuesta #4 en: 10 de Junio de 2019, 16:20:31 »
Estoy realizando este mismo proyecto pero con un PIC16F877A, ¿qué debo cambiarle al código?