TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: Miquel_S en 26 de Agosto de 2012, 15:45:13
-
Hola, necesito de vuestra ayuda, porque despues de quince dias ya no se como conseguir el proposito que quiero, necesito poner ContTICKS a 1 y ContRtcc a 0 dentro de la interrupcion al cabo de 20ms aproximadamente, luego ya ajustare el tiempo hasta los 20ms exactos.
Esto es lo que tengo:
;******************************************************************************************************
; FileName: MainPWM.asm
;******************************************************************************************************
;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------
list p = PIC16873A ; Seleccionar procesador.-
#include "P16F873A.inc" ; Incluir archivo P16F873A.inc
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the
; .asm file. The lables following the directive are located in the respective
; .inc file. See the data sheet for additional information on configuration
; word settings.
;
;------------------------------------------------------------------------------
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; VARIABLES
;------------------------------------------------------------------------------
CBLOCK H'20'
W_Temp
STATUS_Temp
ContRtcc
ContTICKS
ENDC;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; CONSTANTES
;------------------------------------------------------------------------------
;Pulsador equ 0 ; Definimos Pulsador como el bit 0 de un registro, en este caso PORTA.-
;Led equ 1 ; Definimos Led como el bit 1 de un registro, en este caso PORTA.-
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG H'00' ; Aqui comienza el micro.-
GOTO Inicio ; Salto a Inicio de mi programa.-
ORG H'04' ; Salta al vector de Interrupcion.-
GOTO Inicio_ISR
ORG H'05' ; Origen del codigo de programa.-
;------------------------------------------------------------------------------
; VECTOR DE INTERRUPCION
;------------------------------------------------------------------------------
Inicio_ISR ;**** Guardado de registro W y STATUS.-
movwf W_Temp ; Copiamos W a un registro Temporario.-
swapf STATUS,W ; Invertimos los nibles del registro STATUS.-
movwf STATUS_Temp ; Guardamos STATUS en un registro temporal.-
ISR ;**** Atendemos la Interrupcion.-
btfss INTCON,T0IF
goto Fin_ISR
incf ContRtcc,F
movlw 0x04
subwf ContRtcc,0
btfss STATUS,Z
goto Actualizar_TMR0
goto AjusteFino
Actualizar_TMR0
movlw 0x00
movwf TMR0
bcf INTCON,T0IF
goto Fin_ISR
AjusteFino
movlw .33
movwf TMR0
bcf STATUS,Z
bcf INTCON,T0IF
movlw 0x05
subwf ContRtcc,0
btfss STATUS,Z
goto Fin_ISR
bsf ContTICKS,0
bcf ContRtcc,0
Fin_ISR ;**** Restauramos los valores de W y STATUS.-
swapf STATUS_Temp,W ; Invertimos los nibles de STATUS_Temp.-
movwf STATUS
swapf W_Temp,F ; Invertimos los nibles y lo guardamos en el mismo registro.-
swapf W_Temp,W ; Invertimos los nibles nuevamente y lo guardamos en W.-
retfie ; Salimos de la Interrupcion.-
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
Inicio ;**** Configuracion de Puertos ****
bcf STATUS,RP0
bcf STATUS,RP1 ; Bank 0.-
clrf PORTA ; Limpiamos PORTA.-
clrf TMR0 ; Limpiamos TMR0.-
clrf INTCON ; Desactivamos interrupciones y limpiamos T0IF.-
bsf STATUS,RP0 ; Bank 1.-
movlw 0x06
movwf ADCON1 ; I/O digitales.-
movlw b'00000000'
movwf TRISA ; RA<0> input RA<1:7> output.-
movlw b'10000011'
movwf OPTION_REG
bcf STATUS,RP0 ; Bank 0.-
movlw 0x00
movwf TMR0
bsf INTCON,T0IE ; Habilitamos interrupcion TMR0.-
bsf INTCON,GIE ; Habilitamos todas las interrupciones.-
loop nop
goto loop
END ; Fin del codigo.-Agradeceria de vuestra ayuda.
Saludos!
-
Hola,
No estas poniendo ConTICKS en 1 y ContRtcc en 0.
bsf ContTICKS,0 <-Estas poniendo en 1 el bit 0 de ConTICKS
bcf ContRtcc,0 <-Estas poniendo en 0 el bit 0 de ContRtcc
Deberias hacer:
movlw 0x01
movwf ConTICKS
clrf ContRtcc
Saludos
-
Hola Nubbeo gracias por responder, dos cosas, la primera es que no consigo modificar nunca estas dos variables, el programa no pasa por ellas y no soy capaz de ver el porque, si pruebas de simularlo lo veras.
Y como segunda cosa que igual me equivoco, en la parte de clrf ContRtcc ahi tienes razon me equivoque ya que como se incrementa hasta llegar a 5 no estamos trabajando con un solo bit, pero en bsf ContTICKS,0 como solo puede ser 1 o 0 creo que es correcto hacerlo de esta manera.
Seguire probando haber si doy con el fallo.
Saludos!
-
Yo el problema que veo que ademas es muy comun, por lo menoa a mi me ha pasado muchas veces, es que cuando la cuenta de ContRtcc llega a 4 no lo pones a 0, y entonces te cuenta 255, desde 5 hasta que sea 4 otra vez. Cuando llega a 4 va a AjusteFino ahi debes hacer un clrf ContRtcc, para que despues vuelva a contar hasta 4.
El registro ContTICKS no lo varias nunca ¿cuando quieres que varie este registro?
-
Gracias tapi8 por responder, voy a probar lo que tu me dices, aunque creo que ya lo prove, no lo se seguro porque tantas cosas he probado que creo que no me queda nada por probar :5].
Referente al registro ContTICKS, si se debe modificar, la idea es contar 4 desbordes del TMR0 completos y otro incompleto para conseguir los 20ms que necesito,una vez tenga los 20ms pongo ContTICKS a 1 y borro ContRtcc para luego fuera de la interrupcion comprobar si ContTICKS esta a 1.
La idea es esta:
#int_RTCC
RTCC_isr()
{
++contRTCC;
if(contRTCC==4)
{
set_TIMER0(AJUSTE_FINO_DE_RTCC);
}
if(contRTCC==5)
{
flagRTCC=1;
contRTCC=0x00;
}
}
Escrita originalmente por RedPic
Gracias de nuevo y Saludos!
Miquel_S
-
Bien, ya se lo que quieres. El mejor TIMER cuando se quiere una gran precision es TIMER1, que es de 16 bits, hasta 65535 puedes ajustar hasta 1uS A 4Mz y media millonesima a 8Mhz Y 200ns A 20Mhz, si necesitas buena precision pero NO a la millonesima TIMER0 te vale, en escala de 128 consigues 19968us cargando el offset con 100, como cuando entra en interrupcion te va a consumis 20us mas o menos le pone unos "nop" y ya tienes 20ms casi a la millonesima y muy sencillo de hacer ya que cuando salte la interrupcion haces lo que quieras hacer, sin contadores ni nada.
Tal y como lo tienes tu en preescaler de 16 si en vez de ponerlo a 0 le cargas 6 te da 4ms justos, pero como al realizar la rutina de interrupcion consumes ciclos (24 ciclos en tu programa) mejor cargarlo con 8 y te da en cada desborde 3968us y cuentas 5 desbordes y cuando desborde 5 veces haces:
CLRF ContRtcc ;para que quede a 0 para siguiente cuenta
BSF ContTICKS,0 ; para señalizar que van 5 desbordes=20ms
Como te van a faltar unas millonesimas pones unos NOP, esto simulando en MPLAB ves cuantas millonesimas te faltan. Si es para manejar servos, que te conozco :lol: :lol: tiene que dar buena precision, pero NO a la millonesima. Yo en tu caso usaria TIMER0 en preescaler 128 y directo sin ninguna complicacion.
-
Gracias tapi8 por tu ayuda, voy a ver como lo hago si con TIMER1 para conseguir una buena precision, o por el contrario lo dejo por TIMER0
y añado nop, depende de lo que le pida al bot.
Os ire contando los avances y posteando las dudas que seguro surgiran.
Saludos!
-
Yo creo que TIMER0 para los servos te vale de sobra, y de esta manera te quedan TIMER1 y TIMER2 para otrs cosas donde necesites mas precision.
Pones el TIMER a contar los pines donde esten conectados los servos a 1, cuentas con bucles los tiempos proporcionales a los grados que les quieras dar a cada uno, entre 0.3ms y 2.3ms (segun el servo) y vas haciendo:
CALL DELAY ; el tiempo proporcional a los grados
BCF SERVO_0 ; acaba dutty servo con menos grados
CALL DELAY
BCF SERVO_1
etc
Creo que vale la pena hacerlo sin interrupcion (esto depende del resto del programa) porque cada 20ms empleas como maximo 2.3ms o 2.5ms segun sea el servo, en cada PWM de 20ms tienes 17.5 como minimo donde puedes hacer todo lo que quieras.
-
Gracias por los consejos tapi8 ya te contare.
Saludos!
-
Hola de nuevo, sigo liado con los 20ms, he conseguido temporizar 20ms exactos en la primera pasada del programa, 40ms exactos en la segunda pasada, pero luego ya voy perdiendo microsegundos cada vez.
La que seria la tercera pasada pierdo 6us la cuarta 8us y asi sucesivamente, y no entiendo el porque, y al cabo de un tiempo se convertira en milisegundos.
Alguien podria explicarme como evitar esto, recuerdo haber visto un programa en ASM el cual conseguia la temporizacion exacta cada vez con la interrupcion del TMR0 pero no recuerdo donde.
;******************************************************************************************************
; FileName: MainPWM.asm
;******************************************************************************************************
;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------
list p = PIC16873A ; Seleccionar procesador.-
#include "P16F873A.inc" ; Incluir archivo P16F873A.inc
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the
; .asm file. The lables following the directive are located in the respective
; .inc file. See the data sheet for additional information on configuration
; word settings.
;
;------------------------------------------------------------------------------
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; VARIABLES
;------------------------------------------------------------------------------
CBLOCK H'20'
;W_Temp
;STATUS_Temp
FlagRTCC
FlagSERVO
ENDC;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; CONSTANTES
;------------------------------------------------------------------------------
Servo equ 0 ; Definimos Pulsador como el bit 0 de un registro, en este caso PORTA.-
;Led equ 1 ; Definimos Led como el bit 1 de un registro, en este caso PORTA.-
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG H'00' ; Aqui comienza el micro.-
GOTO Inicio ; Salto a Inicio de mi programa.-
ORG H'04' ; Salta al vector de Interrupcion.-
GOTO ISR
ORG H'05' ; Origen del codigo de programa.-
;------------------------------------------------------------------------------
; VECTOR DE INTERRUPCION
;------------------------------------------------------------------------------
ISR ;**** Atendemos la Interrupcion.-
btfss INTCON,T0IF
goto loop
bcf INTCON,T0IF
nop
nop
nop
nop
nop
nop
bsf FlagRTCC,0
retfie
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
Inicio ;**** Configuracion de Puertos ****
bcf STATUS,RP0
bcf STATUS,RP1 ; Bank 0.-
clrf PORTA ; Limpiamos PORTA.-
clrf TMR0 ; Limpiamos TMR0.-
clrf INTCON ; Desactivamos interrupciones y limpiamos T0IF.-
bsf STATUS,RP0 ; Bank 1.-
movlw 0x06
movwf ADCON1 ; I/O digitales.-
movlw b'00000000'
movwf TRISA ; RA<0> input RA<1:7> output.-
movlw b'10000110'
movwf OPTION_REG
bcf STATUS,RP0 ; Bank 0.-
movlw .100
movwf TMR0
bsf INTCON,T0IE ; Habilitamos interrupcion TMR0.-
bsf INTCON,GIE ; Habilitamos todas las interrupciones.-
loop btfss FlagRTCC,0
goto loop
bcf FlagRTCC,0
nop
movlw .100
movwf TMR0
goto loop
nop
END ; Fin del codigo.-
Saludos y Gracias!
-
En la primera te sale 20.009 porque hace la configuracion, despues te da siempre 19.992, si sumas las dos primeras te salen 40.001, pero esa primera no la debes tener en cuenta ya que solo pasa una vez, el tiempo que te vale es 19.992 que creo que para manejar servos te vale de sobra, si le ones 8 NOP mas te dara exacto, no se si te vale la pena, eso tu veras. La desviacion es de 0.04% que creo que es aceptable
-
De nuevo gracias, acatare tu opinion tapi8.
Miquel_S
-
Si no quieres gastar mas memoria de programa sustituye los NOP por GOTO $+1 y ya te da exacto, creo que tuve que poner uno mas, pruebalo asi, a mi me salen 20ms exactos, excepto la primera vez por lo que ya te dije.. Al hacer GOTO en vez de Nop, consume dos ciclos de instruccion en vez de un ciclo:
;******************************************************************************************************
; FileName: MainPWM.asm
;******************************************************************************************************
;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------
list p = PIC16873A ; Seleccionar procesador.-
#include "P16F873A.inc" ; Incluir archivo P16F873A.inc
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the
; .asm file. The lables following the directive are located in the respective
; .inc file. See the data sheet for additional information on configuration
; word settings.
;
;------------------------------------------------------------------------------
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; VARIABLES
;------------------------------------------------------------------------------
CBLOCK H'20'
;W_Temp
;STATUS_Temp
FlagRTCC
FlagSERVO
ENDC;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; CONSTANTES
;------------------------------------------------------------------------------
Servo equ 0 ; Definimos Pulsador como el bit 0 de un registro, en este caso PORTA.-
;Led equ 1 ; Definimos Led como el bit 1 de un registro, en este caso PORTA.-
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG H'00' ; Aqui comienza el micro.-
GOTO Inicio ; Salto a Inicio de mi programa.-
ORG H'04' ; Salta al vector de Interrupcion.-
GOTO ISR
ORG H'05' ; Origen del codigo de programa.-
;------------------------------------------------------------------------------
; VECTOR DE INTERRUPCION
;------------------------------------------------------------------------------
ISR ;**** Atendemos la Interrupcion.-
btfss INTCON,T0IF
goto loop
bcf INTCON,T0IF
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
; nop
; nop
; nop
; nop
; nop
; nop
bsf FlagRTCC,0
retfie
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
Inicio ;**** Configuracion de Puertos ****
bcf STATUS,RP0
bcf STATUS,RP1 ; Bank 0.-
clrf PORTA ; Limpiamos PORTA.-
clrf TMR0 ; Limpiamos TMR0.-
clrf INTCON ; Desactivamos interrupciones y limpiamos T0IF.-
bsf STATUS,RP0 ; Bank 1.-
movlw 0x06
movwf ADCON1 ; I/O digitales.-
movlw b'00000000'
movwf TRISA ; RA<0> input RA<1:7> output.-
movlw b'10000110'
movwf OPTION_REG
bcf STATUS,RP0 ; Bank 0.-
movlw .100
movwf TMR0
bsf INTCON,T0IE ; Habilitamos interrupcion TMR0.-
bsf INTCON,GIE ; Habilitamos todas las interrupciones.-
loop btfss FlagRTCC,0
goto loop
bcf FlagRTCC,0
nop
movlw .100
movwf TMR0
goto loop
nop
END
-
Gracias por el dato tapi8 seguire tu consejo :-/
Miquel_S
-
Aunque lleve dias sin decir nada sigo vivo :mrgreen: pero estoy intentando comparar dos variables.
Saludos!
-
Para comparar dos variables las restas y despues si son iguales se pone a 1 STATUS,Z, si quieres saber si una es mayor que otra tienes que chequear STATUS,C o STATUS,DC, aqui no estoy seguro :lol: prueba en el MPLAB que FLAG se te pone a 1 al ser el resultado negativo es uno de esos dos que son los BITS 0 y 1 de STATUS.
MOVF VARIABLE_1
SUBWF VARIABLE_2
BTFSS STATUS,Z
GOTO NO_IGUALES
GOTO IGUALES
Si VARIABLE_1 es menor el resultado sera negativo y se pondran a 1 (creo, esto compruebalo con el simulador) C o DC.
-
Gracias tapi8 tan atento como siempre, precisamente el lo que estaba intentando pero se ve que hago la cuenta de ticks erronea, ahora debo acompañar a mi hijo a por los libros de FP y luego me pongo con ello.
Saludos!
-
Si es para hacer una cuenta hasta un numero determinado, por ejemplo si quieres saber si un contador llego a 50:
INCF CONTADOR,1
MOVLW .50 ;con cambiar este numero contara hasta el que quieras
SUBWF CONTADOR,0 ; restamos y guardamos resultado en W
BTFSS STATUS,Z ; miramos si el resultado es 0
GOTO NO_CERO ; el flag esta a 0 por lo tanto el resultado NO fue 0
CLRF CONTADOR ;fue 0, llego a 50, borramos contador para siguiente cuenta
GOTO ES_CERO ;o sigue aqui el programa con lo que tenga que hacer
Esta sin depurar, aunque no creo que tenga muchos errores, compruebalo, no es la primera vez que en 7 lineas cometo 10 fallos :lol: :lol:
-
De nuevo gracias por tomarte la molestia de darme una solucion, voy a mirar como lo monto, la idea es dentro de los 20ms poner en alto el pin un numero determinado de milisegundos para luego ponerlo de nuevo a 0 hasta los 20ms.
PD: No me digas la solucion si no me funciona te pregunto.
Un saludo y gracias de nuevo.
-
:8} :8} No doy pie con bola, tengo esto:
loop btfss FlagRTCC,0 ; Revisamos si el bit 0 de la variable FlagRTCC vale 1.-
goto loop ; No, repetimos.-
bcf FlagRTCC,0 ; Si, ponemos la variable a 0.-
bsf PORTA,Servo ; Ponemos a 1 el bit 0 de la Puerta A.- (HASTA AQUI 20ms)
movlw .100
movwf TMR0
call LeerTMR0 ; Llamamos a la funcion para leer TMR0.-
; incf ValorTMR0
; movlw .112
; subwf ValorTMR0,0
; btfss STATUS,Z
; goto $-4
; bcf PORTA,Servo
goto loop
;------------------------------------------------------------------------------
; FUNCIONES
;------------------------------------------------------------------------------
LeerTMR0
movf TMR0,W
movwf ValorTMR0
return
END ; Fin del codigo.-Pero necesito leer constantemente el TMR0 para saber cuando a llegado a .112 y asi poner a cero PORTA,Servo, para luego dejar de leer el TMR0 y que el TMR0 siga contando hasta desbordarse, y asi sucesivamente.
Gracias.
-
No Miquel, asi es muy complicado, quieres contar 1.5ms ¿verdad?, que es el tiempo que quieres que este en alto
ACTIVAR_SERVO
bsf PORTA,Servo ; Ponemos a 1 el bit 0 de la Puerta A.- (HASTA AQUI 20ms)
movlw .100
movwf TMR0
call DEMORA ;llamamos DEMORA de 1.5ms
bcf PORTA,Servo ; Ponemos a 0 el bit 0 de la Puerta A
;aqui puedes hacer todo lo que quieras, ya que tienes mucho tiempo
;hasta que se desborde el TIMER
btfss INTCON,T0IF
goto $-1 ;no desbordo, esperamos
goto ACTIVAR_SERVO ;ya desbordo, repetimos, ya que al servo hay que enviarle
;pulsos constantemente
DEMORA movlw .249 ; 1 set numero de repeticion
movwf PDel0 ; 1 |
PLoop0 clrwdt ; 1 clear watchdog
PDelL1 goto PDelL2 ; 2 ciclos delay
PDelL2
decfsz PDel0, 1 ; 1 + (1) es el tiempo 0 ?
goto PLoop0 ; 2 no, loop
clrwdt ; 1 ciclo delay
return ; 2+2 Fin.
-
Gracias tapi8, esta solucion la habia pensado pero no me sirve porque tendria que crear demoras para cada posicion del servo, de todas formas me ha venido a la cabeza otra posible solucion, en cuanto pueda la probare y os cuento.
Saludos!
-
No, no es necesario, si los vas a mover de 10 en 10º, por ejemplo, haces una para esos grados y la llamas las veces que necesites, mas una de 0.5ms que la llamaras al principio, ya que 0.5ms es 0º o -90º segun como le llames.
-
Gracias tapi8, voy a estudiar tu propuesta a parte de la idea que tengo en mente.
Saludos!
-
pues bien estoy inicializando en la programacion pic en asm.... el problema radica es que mi rpofesor de esta materia es muy malo... y necesito arreglar un codigo; ya e entendido gran parte de este pero hay unos q no tengo ni la menor idea miren es esto!!!!!
MOVLF24 MACRO MESS TBLPTRU TBLPTRH TBLPTRL
MOVLW MESS >>.16
MOVWF TBLPTRU
MOVLW MESS >>.8
MOVWF TBLPTRH
MOVLW MESS &0XFF
MOVWF TBLPTRL
ENDM
MESS: data 0xb0a4,0xf9c0,0X8888
org MESS+VIDEOBSIZE
LOADMESSAGE: ;CARGA VIDEO BUF CON MENSAJE LITERAL GUARDADO EN FLASH
MOVLF24 MESS TBLPTRU TBLPTRH TBLPTRL ;MACRO
MOVLF16 VIDE0 FSRH FSRL ;MACRO
mi pregunta q es esa libreria macro y tambien la parte de " MESS: data 0xb0a4,0xf9c0,0X8888 // org MESS+VIDEOBSIZE
aclaro que este es un trozo del codigo
-
En segundo lugar no repetir los mensajes en distintas partes del foro.
Asi que vuelve a leer las reglas del foro.
Ademas ésta respuesta debe ser borrada por algun moderador ya que no tiene nada que ver la consulta con el tema del titulo, al menos desde mi punto de vista.
-
Ademas ésta respuesta debe ser borrada por algun moderador ya que no tiene nada que ver la consulta con el tema del titulo, al menos desde mi punto de vista.
Totalmente de acuerdo Fer, aunque quien inicio el hilo fue Miquel...creo que ese mensaje no pinta nada aqui.
-
Hola de nuevo, estoy jugando con esta parte de codigo:
LeerTMR0
movf TMR0,W
movwf ValorTMR0
clrw
movlw .112
subwf ValorTMR0
btfss STATUS,Z
goto $-6
returnpero me encuentro con que en la variable ValorTMR0 se carga el valor que le da la gana, y no acierto a ver el porque, ya que estoy borrando el valor del registro W precisamente para evitar este error, o eso creia.
Saludos!
-
Este es el codigo completo:
;******************************************************************************************************
; FileName:PWMServo_v1.0.asm
;******************************************************************************************************
;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------
list p = PIC16F873A ; Seleccionar procesador.-
#include "P16F873A.inc" ; Incluir archivo P16F873A.inc
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the
; .asm file. The lables following the directive are located in the respective
; .inc file. See the data sheet for additional information on configuration
; word settings.
;
;------------------------------------------------------------------------------
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
ERRORLEVEL -302
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; VARIABLES
;------------------------------------------------------------------------------
CBLOCK H'20'
FlagRTCC ; Variable usada para avisarnos que han pasado 20ms.-
ValorTMR0 ; Variable usada para guardar el valor leido del TMR0.-
ENDC;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; CONSTANTES
;------------------------------------------------------------------------------
Servo equ 0 ; Definimos Servo como el bit 0 de un registro, en este caso PORTA.-
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG H'00' ; Aqui comienza el micro.-
GOTO Inicio ; Salto a Inicio de mi programa.-
ORG H'04' ; Salta al vector de Interrupcion.-
GOTO ISR
ORG H'05' ; Origen del codigo de programa.-
;------------------------------------------------------------------------------
; VECTOR DE INTERRUPCION
;------------------------------------------------------------------------------
ISR ;**** Atendemos la Interrupcion.-
btfss INTCON,T0IF
goto loop
bcf INTCON,T0IF
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
bsf FlagRTCC,0
retfie
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
Inicio ;**** Configuracion de Puertos ****
bcf STATUS,RP0
bcf STATUS,RP1 ; Bank 0.-
clrf PORTA ; Limpiamos PORTA.-
clrf TMR0 ; Limpiamos TMR0.-
clrf INTCON ; Desactivamos interrupciones y limpiamos T0IF.-
bsf STATUS,RP0 ; Bank 1.-
movlw 0x06
movwf ADCON1 ; I/O digitales.-
movlw b'00000000'
movwf TRISA ; RA<0:7> output.-
movlw b'10000110'
movwf OPTION_REG
bcf STATUS,RP0 ; Bank 0.-
movlw .100 ; Cargamos TMR0 el valor 100 en decimal.-
movwf TMR0
bsf INTCON,T0IE ; Habilitamos interrupcion TMR0.-
bsf INTCON,GIE ; Habilitamos todas las interrupciones.-
loop btfss FlagRTCC,0 ; Revisamos si el bit 0 de la variable FlagRTCC vale 1.-
goto loop ; No, repetimos.-
bcf FlagRTCC,0 ; Si, ponemos la variable a 0.-
bsf PORTA,Servo ; Ponemos a 1 el bit 0 de la Puerta A.- (HASTA AQUI 20ms)
movlw .100
movwf TMR0
call LeerTMR0 ; Llamamos a la funcion para leer TMR0.-
bcf PORTA,Servo ; Ponemos a 0 el bit 0 de la Puerta A.-
goto loop
;------------------------------------------------------------------------------
; FUNCIONES
;------------------------------------------------------------------------------
LeerTMR0
movf TMR0,W
movwf ValorTMR0
clrw
movlw .112
subwf ValorTMR0
btfss STATUS,Z
goto $-6
return
END ; Fin del codigo.-Lo bueno es que funciona en la vida real, pero con el error comentado en el post anterior el cual me gustaria darle solucion, ahora voy a intentar variar el valor de la variable con un potenciometro a traves del ADC.
Pero esto sera en un apartado diferente para no mezclar una cosa con otra.
Gracias a tapi8 por la ayuda aportada.
Miquel_S
-
movf TMR0,W
movwf ValorTMR0
Aqui lo que estas es leyendo el TIMER0 y este esta variando constantemente, segun en el preescaler que lo tengas, lo cargas en el reg ValorTMR0 y despues compruebas si llego a 112, bien, tendria que funcionar, despues para cada posicion del servo solo tendrias que variar ese valor de 112,
Lo bueno es que funciona en la vida real, pero con el error comentado en el post anterior el cual me gustaria darle solucion, ahora voy a intentar variar el valor de la variable con un potenciometro a traves del ADC.
Si te funciona en la realidad perfecto, como ya te comento antes no tienes ningun error, es que tiene que ir variando, desde 100 que es el numero con que lo cargas hasta 112 primero y hasta desbordar despues, para completar los 20ms.
¿Es para un servo solo? ¿O son varios en distintas posiciones?
En el ISR mejor guardar los reg. W y STATUS, y restaurarlos al terminar la interrupcion.
-
Hola tapi8, de nuevo gracias por la ayuda ofrecida desinteresadamente, tomare en cuenta lo de guardar los registros antes de entrar en la interrupcion para restaurarlos a la salida de la misma.
Referente a si sera un solo servo o varios, la idea es hasta 18 para poder controlar un hexapodo, pero todo se andara, ya que primero me interesa poder guardar las diferentes posiciones del servo para luego reproducirlas.
PD: Por curiosidad cual es tu nombre :oops: no porque no me guste tapi8, pero me suena raro llamarte tapi8 ;-)
Miquel_S
-
PD: Por curiosidad cual es tu nombre no porque no me guste tapi8, pero me suena raro llamarte tapi8
Pues Tapi, me quedo desde pequeño :lol: el 8 lo tuve que poner porque no me dejaba Tapi solamente.
Referente a si sera un solo servo o varios, la idea es hasta 18 para poder controlar un hexapodo, pero todo se andara, ya que primero me interesa poder guardar las diferentes posiciones del servo para luego reproducirlas.
Pues para hacer eso lo tienes bastante facil, ya que si partes de 90º en todas las patitas y un paso adelante supongamos 30º, haces 3 movimientos de 10 en 10º (asi es un movimiento mas natural, si das 30º de golpe es un movimiento mas robotico) aumentas de 112 a 113 y tendras 100º (un poquito mas) ya que 10º son 111us y con TIMER en preescaler 128, solo puedes aumentar y reducir en 128us, a continuacion 114 y estara a algo mas de 110º, 115 y 120º, despues haces al reves empiezas a ir para atras otra vez 114,113,112 volvera a estar en 90º y supongo que ira hacia atras la pata, entonces restas uno 111=80º, 110=70º y 109=60º, bueno esto despues cuando ande ya se vera si asi esta bien o hay que hacer modificaciones.
Yo suprimiria la interrupcion, creo que no te aporta nada, solo te complica un poco mas. Una vez que pones a 0 el servo solo tienes que esperar a que se desborde el TIMER, chequeas el flag "INTCON,T0IF" y te evitas la interrupcion, si lo haces con interrupcion, creo que vas atener que hacer los chequeos de los grados (112,111, etc) dentro de la interrupcion.
-
Hola otra vez, intentare enfocarlo de la manera expuesta por ti haber si consigo reproducir los movimientos mas suaves, aparte de intentar controlar los servos en paralelo.
http://linuxdroids.wordpress.com/2010/05/07/control-de-servos-en-paralelo-con-pic/
Miquel_S
-
Como te lo explica en ese enlace, la segunda menera, va bien encaminado, aunque no te da el resultado final, pero es sencillo.
Supongamos que quieres 3 servos a 60º otros 3 a 90º y otros 3 a 120º, por poner los extremos y el punto medio, al principio pones el TIMER a contar, pones todos los servos a 1 y chequeas cuando llega a 109 (empezo a contar en 100) y pones a 0 los que van a estar en 60º, sigues chequeando hasta que llega a 112 y pones a 0 los de 90º y cuequeas cuando llega a 115 y bajas los que estan a 120º, esperas a que el TIMER se desborde y ya esta, con un contador haces que esto se repita las veces que quieras, ya que cada 20ms seria muy rapido, creo yo, por ejemplo 6 veces que serian 120ms, a continuacion supongamos que quieres que los de 60º se pongan a 70º y los de 90 a 100º, en vez de 109 miras cuando llega a 110 y pones a 0 los que antes estaban a 60º y estaran a 70º, despues miras cuando llegan a 113 y pones los tres que antes estaban a 90 a 0 y ya estan en 100º y en 115º bajas los de 120º que siguen igual.
Todos estos grados no son exactos porque TIMER0 en vez de 111us que son 10º te cuenta 128us minimo, tendras un poco de desviacion pero bueno aqui creo que da igual. Puedes usar preescaler mas bajo y tendras mas precision pero tendras que hacer varios desbordes y te complicara un poco mas. Otra opcion es usar TIMER1, pero creo que tendras otro problema y es que como cambia cada millonesima si se te escapa, cosa que pasara, se te predera el programa. Esta la solucion de los bucles de tiempo, como ya te dije en un post anterior, asi le das los pasos y grados que quieras, de una manera muy sencilla, y con precision a la millonesima. Esta ultima es la mejor, la mas sencilla y yo diria que hasta la mas elegante :lol: ademas si con movimiento de 10 en 10º no te gusta cambias la temporizacion de 111us a la mitad 55us y los mueves de 5 en 5º el doble de rapido, en vez de 6 repeticiones haces 3 y quedara mas bonito, beno esto lo creo yo.
No se si has visto este hilo, es por un problema de interferencias en servos y Suki y Nocturno (foreros muy fiables) ponen un par de soluciones, a ti seguramente tambie te meteran interferencias al ser muchos servos:
http://www.todopic.com.ar/foros/index.php?topic=39282.0
-
Me gusta, a medida que aumentan los posts la cosa se complica :) o sea que voy a ver como enfoco todo esto y veremos al final que es lo que sale, al tener algo en claro creare un tema nuevo con un enlace en este post para no mezclar las cosas.
Excelente explicacion compañero, GRACIAS tapi.
Saludos!
-
No pude resistir la tentacion de hacer un programa (en realidad solo es la idea) para los 16 servos, hice lo que serian 3 secuencias una
todos a 90º (la que podria ser la posicion de partida) otra moviendolos de 4 en 4 en distintos angulos y otra moviendolos de 2 en 2.
Un par de aclaraciones sobre el programa, en POSICION_1, para moverlos de 4 en 4 lo hago con mascara, haciendo una "and" con un literal sobre el puerto en el que quiero escribir, de este modo los que estan a 0 en el literal quedaran en 0 y los que esten en 1 quedaran con
el valor que tengan, no variaran:
movlw 0XF0 ;para aplicar mascara, pone servos 0,1,2,3 a 0
andwf PORTB ;resto de PORTB queda como estaba
Hago una temporizacion de 1166us que corresponde a 60º, 666 de 60º mas 500us de 0º, esto lo hago porque doy por hecho que nunca va a haber ningun servo que tenga menos de 60º (en cada programa habra que ver cual es este minimo) asi me ahorro de hacer 6 llamadas a demora al principio de cada ciclo.
Cada secuencia se repite 10 veces por 20ms=200ms, despues si en la realidad va lento se disminuye esta numero y si va rapido se aumenta, tambien se podria tener en unas secuencias mas tiempo y en otras menos, si por ejemplo quieres hacerla bailar. :lol: :lol: Tambien se puede hacer una temporizacion mas pequeña de 10º y asi se conseguirian movimientos mas reales, esto habra que ver en la practica como se comporta.
Esta hecho para un 16f887 pero se puede cambiar facil para otro 16f, lo depure en el MPLAB para que lo puedas simular y ver como funciona:
;Cuando son muchas salidas o muchas entradas, es mejor definirlos, asi cuando cambiemos algun pin
;no tendremos que modificar el programa, solo cambiar en el #DEFINE cual es su nueva ubicacion, ademas
;hace el programa mas comprensible tanto para el programador, como para algun colaborador que lo revise.
#DEFINE SERVO_0 PORTB,0
#DEFINE SERVO_1 PORTB,1
#DEFINE SERVO_2 PORTB,2
#DEFINE SERVO_3 PORTB,3
#DEFINE SERVO_4 PORTB,4
#DEFINE SERVO_5 PORTB,5
#DEFINE SERVO_6 PORTB,6
#DEFINE SERVO_7 PORTB,7
#DEFINE SERVO_8 PORTC,0
#DEFINE SERVO_9 PORTC,1
#DEFINE SERVO_10 PORTC,2
#DEFINE SERVO_11 PORTC,3
#DEFINE SERVO_12 PORTC,4
#DEFINE SERVO_13 PORTC,5
#DEFINE SERVO_14 PORTC,6
#DEFINE SERVO_15 PORTC,7
list p=16F887
#include P16F887.inc
;__CONFIG _33C4 _3FFF ; creo que asi esta bien para inter_osc 4Mz
ERRORLEVEL -305
ERRORLEVEL -302
CBLOCK 0X20
CONTADOR
PDel0
PDel1
ENDC
CONFIGURACION
banksel ANSEL ;seleccionamos banco 4
clrf ANSEL ;ponemos PORTA digital
clrf ANSELH ;ponemos PORTB digital
bcf STATUS,RP1
bsf STATUS,RP0 ;banco 1 para configurar puertos
clrf TRISB ;todas salidas
clrf TRISC ;todas salidas
movlw 0X06 ;0000 0110
movwf OPTION_REG ;TIMER0, PREESCALER 128
movlw 0X20 ;0010 0000
movwf INTCON ;activar TIMER0 sin interrupcion
bcf STATUS,RP0
clrf CONTADOR
;*************En POSICION_0 TODOS A 90º, para no hacer mas bucles de retardo*************
;*************llamaremos 1 vez bucle de 60º y 3 veces el de 10º**************************
POSICION_0
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTB ;ya estan a 1 los del PORTB
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTC ;ya estan a 1 los del PORTC
movlw .100 ;cargamos TIMER0 para 20ms
movwf TMR0
call DEMORA_60º ;llamamos DEMORA inicial, para servos con DUTTY 60º (minimo posible)
call DEMORA_10º ;llamamos bucle de 10º 3 veces para completar 90º
call DEMORA_10º
call DEMORA_10º
clrf PORTB
clrf PORTC ;ponemos todos lo duttys a 0, todos 90º
;aqui tienes mucho tiempo, minimo 17.5ms, ya que los tiempos en alto de los duttys son
;como maximo 2.5ms y el TIMER desborda a los 20ms, podrias ejecutar 17500 instrucciones
btfss INTCON,T0IF ;aqui esperamos desborde del TIMER0
goto $-1 ;no desbordo, espera
bcf INTCON,T0IF
incf CONTADOR,1 ;desbordo, contaremos los desbordes
movlw .10 ;contando 10 cada movimiento tardara 200ms
subwf CONTADOR,0 ;cuanto menor sea el numero mas rapido ira la araña
btfss STATUS,Z
goto POSICION_0 ;todavia no van 20 veces sigue en esta posicion
clrf CONTADOR ;cuando vayan 20 pasara a siguiente posicion
;*********Aqui vamos a poner servos 0,1,2,3 a 60º, servos 4,5,6,7 a 80º, servos 8,9,10,11 a 100º****
;**********servos 12,13,14,15 a 120º, son posiciones a modo de ejemplo****************************
POSICION_1
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTB ;ya estan a 1 los del PORTB
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTC ;ya estan a 1 los del PORTC
movlw .100 ;cargamos TIMER0 para 20ms
movwf TMR0
call DEMORA_60º ;llamamos DEMORA inicial, para servos con menor DUTTY
movlw 0XF0 ;para aplicar mascara, pone servos 0,1,2,3 a 0, 60º
andwf PORTB ;resto de PORTB queda como estaba
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
call DEMORA_10º ;2 veces para completar 80º, 60+10+10
movlw 0X0F ;mascara igual que antes pero para servos 4,5,6,7
andwf PORTB ;es lo mismo que hacer "bcf SERVO_4-bcf SERVO_5-bcf SERVO_6-bcf SERVO_7"
call DEMORA_10º
call DEMORA_10º ;2 demoras mas para 100º
movlw 0XF0 ;mascara igual que antes pero para servos 8,9,10,11
andwf PORTC ;es lo mismo que hacer "bcf SERVO_8-bcf SERVO_9-bcf SERVO_10-bcf SERVO_11"
call DEMORA_10º
call DEMORA_10º ;2 demoras mas para 120º
movlw 0X0F ;mascara igual que antes pero para servos 12,13,14,15
andwf PORTC ;es lo mismo que hacer "bcf SERVO_12-bcf SERVO_13-bcf SERVO_14-bcf SERVO_15"
;aqui tienes mucho tiempo, minimo 17.5ms, ya que los tiempos en alto de los duttys son
;como maximo 2.5ms y el TIMER desborda a los 20ms, podrias ejecutar 17500 instrucciones
btfss INTCON,T0IF ;aqui esperamos desborde del TIMER0
goto $-1 ;no desbordo, espera
bcf INTCON,T0IF
incf CONTADOR,1 ;desbordo, contaremos los desbordes
movlw .10 ;contando 10 cada movimiento tardara 200ms
subwf CONTADOR,0 ;cuanto menor sea el numero mas rapido ira la araña
btfss STATUS,Z
goto POSICION_1 ;todavia no van 20 veces sigue en esta posicion
clrf CONTADOR ;cuando vayan 20 pasara a siguiente posicion
;***********En esta posicion los pondremos de 2 en 2 en distisntos angulos, servo 0 y 1 en 60º**************
;***********2 y 3 en 70º y asi sucesivamente, al ir de 2 en 2 no lo haremos con mascara sino directamente****
POSICION_2
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTB ;ya estan a 1 los del PORTB
movlw 0XFF ;para poner a 1 todos los servos
movwf PORTC ;ya estan a 1 los del PORTC
movlw .100 ;cargamos TIMER0 para 20ms
movwf TMR0
call DEMORA_60º ;llamamos DEMORA inicial, para servos con menor DUTTY
bcf SERVO_0 ;ponemos a 0 duttys de 60º
bcf SERVO_1 ;ponemos a 0 duttys de 60º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_2 ;ponemos a 0 duttys de 70º
bcf SERVO_3 ;ponemos a 0 duttys de 70º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_4 ;ponemos a 0 duttys de 80º
bcf SERVO_5 ;ponemos a 0 duttys de 80º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_6 ;ponemos a 0 duttys de 90º
bcf SERVO_7 ;ponemos a 0 duttys de 90º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_8 ;ponemos a 0 duttys de 100º
bcf SERVO_9 ;ponemos a 0 duttys de 100º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_10 ;ponemos a 0 duttys de 110º
bcf SERVO_11 ;ponemos a 0 duttys de 110º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_12 ;ponemos a 0 duttys de 120º
bcf SERVO_13 ;ponemos a 0 duttys de 120º
call DEMORA_10º ;llamamos DEMORA_10º equivalente a 10º
bcf SERVO_14 ;ponemos a 0 duttys de 130º
bcf SERVO_15 ;ponemos a 0 duttys de 130º
;aqui tienes mucho tiempo, minimo 17.5ms, ya que los tiempos en alto de los duttys son
;como maximo 2.5ms y el TIMER desborda a los 20ms, podrias ejecutar 17500 instrucciones
btfss INTCON,T0IF ;aqui esperamos desborde del TIMER0
goto $-1 ;no desbordo, espera
bcf INTCON,T0IF
incf CONTADOR,1 ;desbordo, contaremos los desbordes
movlw .10 ;contando 10 cada movimiento tardara 200ms
subwf CONTADOR,0 ;cuanto menor sea el numero mas rapido ira la araña
btfss STATUS,Z
goto POSICION_2 ;todavia no van 20 veces sigue en esta posicion
clrf CONTADOR
DEMORA_60º ; retardo inicial de 1166us, 666us proporcional ya que 2000us son 180º
; mas 500us que son 0º, 666+500=1166us
movlw .232 ; 1 set numero de repeticion
movwf PDel0 ; 1 |
PLoop0 clrwdt ; 1 clear watchdog
clrwdt ; 1 ciclo delay
decfsz PDel0, 1 ; 1 + (1) es el tiempo 0 ?
goto PLoop0 ; 2 no, loop
clrwdt ; 1 ciclo delay
return ; 2+2 Fin.
DEMORA_10º ; retardo de 111us, equivalente a 10º
movlw .26 ; 1 set numero de repeticion
movwf PDel0 ; 1 |
PLoop1 clrwdt ; 1 clear watchdog
decfsz PDel0, 1 ; 1 + (1) es el tiempo 0 ?
goto PLoop1 ; 2 no, loop
PDelL1 goto PDelL2 ; 2 ciclos delay
PDelL2
return ; 2+2 Fin.
END
-
((:-)) ((:-))
Que malo que eres :5] :D
Gracias por el programa, me lo estudiare bien a fondo, ya que estoy seguro que es mejor que lo que tengo empezado, aunque hay cosas parecidas.
Saludos!
-
Bueno, despues de varios dias con el programa de tapi voy a intentar darle otro enfoque, usando parte del codigo de tapi y parte mia voy a ver si consigo lo que quiero, y es que los servos se posicionen sin error y sin temblores en su sitio.
Cogiendo la idea de RedPic: http://www.todopic.com.ar/foros/index.php?topic=24801.0 voy a intentar hacer todas las temporizaciones con el timer, ya que usando demoras como comenta tapi en su programa, al no correr por igual las demoras y el timer0 es cuando tengo los problemas de temblores.
Os tendre informados :shock:
Saludos!