encoder por software

Upload: angel-daza-garcia

Post on 19-Jul-2015

405 views

Category:

Documents


5 download

TRANSCRIPT

Encoder por SoftwareExpongo varias formas de construir un PIC Encoder de forma sencilla con diferentes tipos de PIC de la empresa Microchip.

PIC Encoder con 16F628A

El funcionamiento de este encoder es extremadamente sencillo. Un bucle se encarga de comprobar el estado de las entrada RA0 y RA1 (A y B respectivamente en el grfico de abajo) en el menor tiempo

posible. En condiciones normales la velocidad de lectura suele rondar unas 25.000 veces por segundo para un cristal de 4MHz dependiendo de la longitud del programa. Esto es ms que suficiente para poner el encoder directo al eje de la mayora de los motores, para un mximo de

5 pulsos por vuelta del motor. Aunque normalmente con 4MHz es ms que suficiente, aumentando los MHz del cristal consegirs velocidades de lectura mayores. Con 8MHz doblars la velocidad de lectura, con 12MHz la triplicars (...), con 20MHz la quintuplicars. Mira el DataSheet del PIC para saber los MHz mximo que soporta. Cada aumento de 4MHz incrementas una vez el factor de multiplicacin y esto es debido a que una instruccin en ensamblador necesita 4 ciclos de reloj para ejecutarse.

Como puedes ver en la imagen, hemos de detectar cundo hay un flanco de subida o de bajada en la entrada 'A' (un cambio de estado) siempre que 'B' est a '1'. Si A es el bit bajo (LSB) y B es el bit alto (MSB), al considerar los dos bits como un nmero tenemos que si hubo un cambio de 2 (10 en binario) a 3 (11 en binario), se ha producido un flanco de subida, por tanto hemos de incrementar el contador. Y al revs, cuando el PIC detectar que en las entradas hubo un 3 (11 en binario) y pasa a 2 (10 en binario), es decir, un flaco de bajada, ha de decrementar el contador. En el programa para el PIC el valor 'anterior' se almacena en la variable AUX, y el valor 'actual' se almacena en la variable ENC; la variable que hace de contador se llama X. A continuacin tienes los programas en CCS C y en Pronton IDE. Haciendo clic aqu vers el cdigo para un 16F84A en Proton IDE; el esquema sigue siendo el mismo porque ambos PICs son idnticos, aunque el 16F628A tiene muchas ms funciones internas.

Programa PIC Encoder con 16F628A en CCS:The translation could modify the code. Use the code without translating. #include #FUSES NOWDT, XT, PUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD #use delay(clock=4000000) #byte porta = 0x05 #byte portb = 0x06 // Asignamos PortA. // Asignamos PortB.

// ---------- Programa Principial ---------void main() { port_b_pullups(FALSE); las salidas del puerto B. setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); configuramos lo ms bsico. setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); necesitamos Vref.

// Sin resistencias pullups a // Al no usar el TIMER // Sin comparadores. // Al no usar comparadores no

//---- Fin de la configuracin del 16F628A ---int8 con los 8 int8 siguiente int8 siguiente x; // Declaramos el valor de X como byte, se corresponder LEDs de salida. enc; // Se almacenar el valor actual de RA0 y RA1, hasta la comparacin. aux; // Se almacenar el valor anterior de RA0 y RA1, hasta la comparacin. // Puerto A como entradas. Slo usamos RA0 y // Puerto B como salidas, para los 8 LEDs.

set_tris_a(0b11111); RA1. set_tris_b(0b00000000); portb=0; // x=0; // contar. enc=0; // valores de RA0 y

Inicialmente ponemos a cero el puerto B. Inicialmente ponemos a cero la variable que se usa para Inicialmente ponemos a cero la variable que tomar los RA1.

While (true) { aux=enc; // Igualamos 'AUX' y 'ENC' para luego comparar cuando cambie 'ENC'. enc=porta & 3; // Aislamos RA0 y RA1 como un nmero de 2 bits y se carga en la variable 'ENC'. If ((aux==2)&&(enc==3))// Si en la comparacin hay flanco de subida, { x++; valor de X. } // entonces incrementar una unidad el

If ((aux==3)&&(enc==2))// Si en la comparacin hay flanco de bajada, { x--; valor de X. } portb = x; los 8 LED de salida. } } // El valor de X sale por el puerto B, // entonces decrementar una unidad el

Programa PIC Encoder con 16F628A en Proton IDE:The translation could modify the code. Use the code without translating. Device=16F628A REMINDERS = False Config XT_OSC, PWRTE_ON, CP_OFF, WDT_OFF, BODEN_OFF, LVP_OFF REMINDERS = True ALL_DIGITAL = True ' Entradas/Salidas todas digitales. TRISA TRISB PORTB=0 = %11111 ' Puerto A como entradas. Slo usamos RA0 y RA1. = %00000000 ' Puerto B como salidas, para los 8 LEDs. ' Inicialmente ponemos a cero el puerto B.

Dim x As Byte ' Declaramos el valor de X como byte, se corresponder con los 8 LEDs de salida. Dim Aux As Byte ' Se almacenar el valor anterior de RA0 y RA1, hasta la siguiente comparacin. Dim Enc As Byte ' Se almacenar el valor actual de RA0 y RA1, hasta la siguiente comparacin. x=0 Aux=0 Enc=0 While 1=1 ' Ponemos todas las variables a cero.

' Bucle infinito.

Aux = Enc ' Igualamos 'AUX' y 'ENC' para luego comparar cuando cambie 'ENC'. Enc = (PORTA & 3) ' Aislamos RA0 y RA1 como un nmero de 2 bits y se carga en la variable 'ENC'. If Aux = 2 And Enc = 3 Then Inc x ' Si en la comparacin hay flanco de subida, incrementamos X. If Aux = 3 And Enc = 2 Then Dec x ' Si en la comparacin hay flanco de bajada, decrementamos X. PORTB = x B, los 8 LED de salida. ' El valor de X sale por el puerto

Wend End

Buscando la sencillez para comprender mejor el funcionamiento del programa, el encoder est limitado a una resolucin de 8 bits. Si aades unas pocas lneas de programacin podrs aumentar la resolucin de salida hasta 11 bits (para el 16F628A y el 16F84A, en otros PICs podran ser ms) si aprovechas las patillas que no se usan. El encoder slo funcionar con un acondicionador de seal de tecnologa TTL tipo 74LS14 7414. No has de utilizar tecnologa CMOS, como por ejemplo el 74HC14 el 74HCT14. Desconozco la razn, pero CMOS no funciona como acondicionador de seales para los encoders que en esta web presento. El acondicionador slo lo necesitamos cuando se utilizan foto barreras tipo TCST

1103, aunque en principio puede ser cualquier otro modelo. Si usas sensores Hall digitales entonces no te har falta el acondicionador y podrs inyectar las seales del encoder directamente al PIC (altamente recomendado). Por favor, no uses encoders tipo potencimetro porque son mecnicos y no funcionara. Ese tipo de encoders (mecnico) se mueve con escobillas metlicas a modo de interruptor, y stos emiten mucho ruido elctrico entre las escobillas y la superficie de contacto y adems sufren desgaste. Para ms informacin y cmo se ha de construir el encoder haz clic aqu.

Encoder con un 16F876

La forma ms eficaz de hacer un encoder a travs de un microcontrolador (PIC) es usar la interrupcin externa RB0/INT. Sucede que cuando salta una interrupcin externa, el micro deja lo que estaba haciendo y se va a atender la interrupcin inmediatamente. Esto sera una interrupcin por hardware, en nuestro caso es la interrupcin RB0/INT. Funciona de la siguiente manera: Podemos hacer que la interrupcin se active con un flanco de subida o de bajada, esto es programable modificando el registro INTEDG. Cuando ocurre una interrupcin por

flanco de subida hemos de programar la siguiente interrupcin para que se active por flanco de bajada e incrementamos el contador si RB1 est a 1. Y viceversa, si ocurre una interrupcin por flanco de bajada hemos de programar la siguiente interrupcin por flanco de subida y decrementamos el contador si RB1 est a 1. La nica condicin que ha de cumplir es que cuando ocurra la interrupcin RB0/INT previamente programada (sea de subida o de bajada), RB1 ha de estar a 1. No tiene ms secretos y cuenta los pulsos de forma muy eficiente. Una cosa muy buena que tiene esta forma de funcionar es que mientras el PIC no recibe interrupciones (RB0/INT en este caso) puede dedicarse a hacer otra cosa, como controlar motores, calcular velocidades, etc. Y como contrapartida, las interrupciones tienen un problema, y es que cuando intentes hacer comunicaciones tipo seriales, podra perturbar los tiempos de temporizacin que rigen esas comunicaciones y hacer que fallen. Uso el PIC 16F876A, pero puede ser cualquier PIC que tenga RB0/INT y conozcas bien. He escogido este PIC porque es muy conocido, econmico y tiene suficientes entradas/salidas para poner los LED como puerto independiente y as la programacin se hace ms sencilla de comprender. Si aades unas pocas lneas de programacin podrs aumentar la resolucin de salida aprovechando las patillas no usadas. Recuerda que, si tu encoder es ptico, es esencial usar como acondicionador de seal un disparador de Schmitt TTL, tipo 7414 o bien 74LS14. Nunca uses como acondicionador de seal la NOT convencional 7404 (porque no es Trigger Schmitt), ni tampoco usar tecnologa CMOS, como por ejemplo el 74HC14 (HC y HCT es CMOS), porque fallara (comprobado). Y ni qu decir que los encoder tipo potencimetro (mecnicos) slo dan problemas porque emiten mucho ruido elctrico porque funcionan por contacto mecnico. Para ms informacin haz clic aqu. Si usas el encoder con sensores Hall digitales no hace falta poner las dos puertas NOT con disparador Schmitt a las entradas de este circuito, porque el encoder con sensores Hall digitales ya las lleva incluida dentro de su electrnica y puedes conectarlo directamente al PIC. Para ms

informacin haz clic en cualquiera de los enlaces indicados en azul de este prrafo. Expongo dos versiones del programa en

PIC Encoder: en CCS y

Proton IDE.

Cdigo PIC Encoder en CCS:The translation could modify the code. Use the code without translating. #include #FUSES NOWDT, XT, PUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT #use delay(clock=4000000) #ZERO_RAM #byte porta = 0x05 // Asignamos PortA (No lo usamos). #byte portb = 0x06 // Asignamos PortB (Usamos RB0 y RB1). #byte portc = 0x07 // Asignamos PortC (8 salidas a LED). // ------ Variable Global -----int8 x=0; //Declaramos el valor de X como byte, es decir, 8 bits. // ---------- Interrupcin ---------#INT_EXT void IntRB0() { if (bit_test(portb,0)) // Si RB0 se ha puesto a 1 (flanco de subida), { ext_int_edge(H_TO_L); // entonces activar la siguiente interrupcin por flanco de bajada. if (bit_test(portb,1)) // Si RB1 est 1, { x++; // entonces incrementar el contador X. } } else // Si RB0 se ha puesto a 0 (flanco de bajada), { ext_int_edge(L_TO_H); // entonces activar la siguiente interrupcin por flanco de subida. if (bit_test(portb,1)) // Si RB1 est 1, { x--; // entonces decrementar el contador X. } } } // ---------- Programa Principial ---------void main() { port_b_pullups(FALSE); setup_adc_ports(NO_ANALOGS); setup_adc(ADC_CLOCK_DIV_2); setup_spi(SPI_SS_DISABLED);

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); //---- Fin de la configuracin del 16F876A ---enable_interrupts(int_ext); ext_int_edge(L_TO_H); de Subida. enable_interrupts(GLOBAL); set_tris_a(0b111111); set_tris_b(0b11111111); RB0 y RB1). set_tris_c(0b00000000); LED, 8 bits). While (true) { portc = x; LED de salida. } } //Activar Interrupcion Externa. //Inicialmente Interrupcin por Flaco //Interrupciones Generales Activadas. //Puerto A como entrada (No usado). //Puerto B como entrada (slo usamos //Puerto C todo como salida (Salida a

//El valor de X sale por el puerto C, 8

Cdigo PIC Encoder en Proton IDE:The translation could modify the code. Use the code without translating. Device=16F876A REMINDERS = FALSE Config XT_OSC, PWRTE_ON, CPD_OFF, WDT_OFF, BODEN_OFF, LVP_OFF REMINDERS = TRUE Symbol INTF Symbol INTE Symbol GIE Symbol INTEDG subida. = = = = INTCON.1 INTCON.4 INTCON.7 OPTION_REG.6 ' ' ' ' RB0 External Interrupt Flag. RB0 External Interrupt Enable. Global Interrupt Enable. Flag = 0 Flanco bajada. Flag = 1 Flanco

On_INTERRUPT GoTo Interrupcion rpida). GIE = 1 INTE = 1 INTEDG = 1 se dispare

' Interrupcin por hardware (es la ms

' Activa interrupciones generales. ' Activa la interrupcin externa RB0/INT. ' Hace que inicialmente la interrupcin ' por flanco de subida.

ALL_DIGITAL = TRUE digitales.

' Todas las entradas y salidas son

TRISA TRISB TRISC travs

= %111111 = %11111111 = %00000000 de los LED. Byte

' Puerto A y B todo entradas. ' Puerto C como salida para visualizar a

Dim x As actual. x=0 While 1=1

' Variable X ---> contador de posicin

' |------ Programa Principal ------| ' El contenido de X se visualiza en el

PORTC = x Puerto C a travs de los LED. Wend End Interrupcion: -----

' |--------------------------------|

'-------- Decodificador de Encoder ---------

Context SAVE ' Salva en contexto de los registros antes de operar con la interrupcin. If PORTB.0 = 1 Then ' Si RB0 se ha puesto a 1 (flanco de subida), INTEDG = 0 ' entonces activar la siguiente interrupcin por flanco de bajada. If PORTB.1 = 1 Then ' Si RB1 est a 1, Inc x ' entonces incrementar el contador X. EndIf EndIf If PORTB.0 = 0 Then ' Si RB0 se ha puesto a 0 (flanco de bajada), INTEDG = 1 ' entonces activar la siguiente interrupcin por flanco de subida. If PORTB.1 = 1 Then ' Si RB1 est 1, Dec x ' entonces decrementar el contador X. EndIf EndIf INTF = 0 RB0/INT. ' Borra el "flag" de la interrupcin

' para poder permitir la siguiente interrupcin. Context Restore ' Restablece el contexto de los registros tal como estaban antes de la ' interrupcin.

PIC Encoder 18F4550En el apartado anterior hemos usado un PIC 16F876A para nuestro PIC Encoder. Ahora vamos a hacer exactamente lo mismo pero con el PIC 18F4550 y es vlido para todos los PIC 18Fxx5x. Primero lo vamos a realizar sin USB, para familiarizarnos con este PIC, viendo el resultado en los LED, y despus con USB. Las entradas A y B slo valen para la contruccin de un encoder tipo foto barrera, usando por ejemplo dos TCST 1103. Para ms informacin haz clic aqu. Tambin puedes hacerlo con sensores Hall digitales (entonces puedes quitar los dos 74LS14 que hacen de acondicionador de la seales del encoder); haz clic aqu para ms informacin.

Funciona de la siguiente manera: Podemos hacer que la interrupcin se active con un flanco de subida o de bajada, esto es programable modificando el registro INTEDG. Cuando ocurre una interrupcin por flanco de subida hemos de programar la siguiente interrupcin para que se active por flanco de bajada e incrementamos el contador si RB1 est a 1. Y viceversa, si ocurre una interrupcin por flanco de bajada hemos de programar la siguiente interrupcin por flanco de subida y decrementamos el contador si RB1 est a 1. La nica condicin que ha de cumplir es que cuando ocurra la interrupcin previamente programada (sea de subida o de bajada) en RB0, RB1 ha de estar a 1. No tiene ms secretos y cuenta los pulsos de forma muy eficiente.

En realidad casi no cambia los programas (con respecto al ejemplo del 16F876), excepto por unos detalles, pero antes echa un ojo al esquema. La primera diferencia es que hacemos la salida a los LED a travs de Port D. Los PICs 18F2455 y 18F2550 no tienen puerto D, tendras que hacer la salida a los LED a travs del puerto A (sin olvidar poner una resistencia de RA4 a positivo porque es salida con colector abierto). En este caso slo tendramos 6 bits en vez de 8, pero como se trata de ver el funcionamiento de conteo nos puede servir. En principio el programa est configurado para un cristal de 4MHz pero como en este ejercicio no usamos el USB puedes usar el cristal que desees mientras est en el rango de 4 a 48MHz. Existen algunos cambios segn sea CCS o Proton IDE:

En Proton IDE, la direccin del registro OPTION_REG.6 (16Fxxxx) pasa a llamarse INTCON2.6 (18Fxx5x), es el registro en el que configuramos si queremos la interrupcin cuando se produzca un flanco de subida o de bajada. Haz clic aqu para ms informacin. Es lo nico que cambia en Proton IDE.

En CCS la direccin de los puertos A B C D E cambia de lugar.

Expongo dos versiones del programa

PIC Encoder para la familia 18Fxx5x: en CCS y en Proton IDE.

(Teniendo en cuenta que los PIC 18F2455/2550 no tienen puerto D y habra que cambiar este detalle por el puerto A.)

Cdigo PIC Encoder en CCS:The translation could modify the code. Use the code without translating. #Include // Usamos el PIC 18F4550, puedes declarar cualquiera de los // 18Fxx5x. #Fuses XT, NOWDT, NOPROTECT, NOLVP, BROWNOUT #use Delay( Clock = 4000000 )

#Byte PortA = 18Fxx5x. #Byte PortB = 18Fxx5x. #Byte PortC = 18Fxx5x. #Byte PortD = 18Fxx5x (Slo

0xF80 0xF81 0xF82 0xF83 40/44

// Direccin del puerto A para la familia // Direccin del puerto B para la familia // Direccin del puerto C para la familia // Direccin del puerto D para la familia // pines). // Direccin del puerto E para la familia

#Byte PortE = 0xF84 18Fxx5x.

// ------ Variable Global -----Int8 x = 0; // decir, 8 bits. // su valor lo // programa principal. // antes la interrupcin //

Declaramos el valor de X como Byte, es Esta variable ha de ser global porque usaremos en la interrupcin y en el Por tanto declaramos esta variable y de "void main".

// --------- Interrupcin --------#INT_EXT // Interrupcin Externa por RB0: Decodificacin de Encoder. Void IntRB0() { // CCS se encarga de desactiva automticamente cualquier interrupcin. // No hace falta guardar contextos de registros. If (Bit_Test(PortB, 0)) subida), { Ext_Int_Edge(H_TO_L); interrupcin por flanco de If (Bit_Test(PortB, 1)) { x++; valor de X. } } Else bajada), { Ext_Int_Edge(L_TO_H); interrupcin por flanco de // Si RB0 se ha puesto a 1 (flanco de // entonces activar la siguiente // bajada. // Si RB1 est a 1, // entonces incrementar una unidad el

// Si RB0 se ha puesto a 0 (flanco de // entonces activar la siguiente subida. Si RB1 est 1, entonces decrementar una unidad el

// If (Bit_Test(PortB, 1)) // { x--; // valor de X. } } // Al finalizar la interrupcin automticamente

CCS se encarga de volver a poner

// la badera INTF = 0 ---> borra la interrupcin para poder permitir la siguiente; // no hemos de hacer nada por nuestra parte. } Void Main() // Inicio y configuracin. { Port_B_Pullups(FALSE); // Configuracin para el PIC 18F4550. Setup_ADC_Ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital, etc... Setup_adc(ADC_CLOCK_DIV_2); Setup_spi(SPI_SS_DISABLED); Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); Setup_timer_1(T1_DISABLED); Setup_timer_2(T2_DISABLED,0,1); Setup_comparator(NC_NC_NC_NC); Setup_vref(FALSE); Enable_Interrupts(Int_Ext); de RB0. Ext_Int_Edge(L_TO_H); flanco de subida. Enable_Interrupts(GLOBAL); Set_Tris_A(0b11111111); no usamos el Puerto A. Set_Tris_B(0b11111111); las entradas RB0 y RB1. Set_Tris_C(0b11111111); no usamos el Puerto C. Set_Tris_D(0b00000000); irn a los LEDs). Set_Tris_E(0b11111111); no usamos el Puerto E. // Activar Interrupcin Externa a travs // Inicialmente detectar interrupcin por // Interrupciones Generales Activadas. // Puerto A todo entradas, en este caso // Puerto B todo entradas, slo usamos // Puerto C todo entradas, en este caso // Puerto D todo salidas (8 bits que

// Puerto E todo entradas, en este caso

// ---------- Programa Principial ---------While (True) { PortD = x; los 8 LED de salida. } }

// El valor de X sale por el Puerto D a

Cdigo PIC Encoder en Proton IDE:The translation could modify the code. Use the code without translating. Device = 18F4550 ' Usamos el PIC 18F4550, pero puedes declarar cualquiera de los 18Fxx5x. REMINDERS = 1 XTAL = 4 cristal de 4MHz. ' Comunicar todos los avisos de compilacin. ' Pon el cristal que quieras; en principio usamos un

Symbol INTF = INTCON.1 Symbol INTE = INTCON.4 Symbol GIE = INTCON.7 Symbol INTEDG = INTCON2.6 = 1 int. por flanco subida. On_INTERRUPT GoTo Interrupcion rpida). GIE = 1 INTE = 1 RB0/INT. INTEDG = 1 se habilite ALL_DIGITAL = TRUE digitales. TRISA = %11111111 no usamos el Puerto A. TRISB = %11111111 las entradas RB0 y RB1. TRISC = %11111111 no usamos el Puerto C. TRISD = %00000000 irn a los LEDs). TRISE = %11111111 no usamos el Puerto E. Dim x As Byte actual con resolucin x=0 While 1=1 PORTD = x Puerto D a travs de Wend End Interrupcion: -----Context SAVE de operar con la If PORTB.0 = 1 Then subida), INTEDG = 0 interrupcin por flanco de

' ' ' '

RB0 External Interrupt Flag RB0 External Interrupt Enable Global Interrupt Enable Flag = 0 int. por flanco bajada. Flag

' Interrupcin por Hardware (es la ms ' Activa interrupciones generales. ' Activa la interrupcin externa ' Hace que inicialmente la interrupcin ' por flanco de subida. ' Todas las entradas y salidas son

' Puerto A todo entradas, en este caso ' Puerto B todo entradas, slo usamos ' Puerto C todo entradas, en este caso ' Puerto D todo salidas (8 bits que

' Puerto E todo entradas, en este caso ' Variable X ---> contador de posicin ' 0..255 ' |------ Programa Principal ------| ' El contenido de X se visualiza en el ' los LED. ' |--------------------------------|

'-------- Decodificador de Encoder -------' Salva en contexto de los registros antes ' interrupcin. ' Si RB0 se ha puesto a 1 (flanco de ' entonces activar la siguiente ' bajada.

If PORTB.1 = 1 Then Inc x EndIf Else bajada), INTEDG = 1 interrupcin por flanco de If PORTB.1 = 1 Then Dec x EndIf EndIf INTF = 0 RB0/INT para poder permitir Context Restore tal como estaban antes

' Si RB1 est a 1, ' entonces incrementar el contador X. ' Si RB0 se ha puesto a 0 (flanco de ' entonces activar la siguiente ' subida. ' Si RB1 est 1, ' entonces decrementar el contador X.

' Borra el "flag" de la interrupcin ' la siguiente interrupcin cuando ocurra. ' Restablece el contexto de los registros ' de la interrupcin.