M.C. Pedro Arturo Cornejo Torres
Temas Selectos de Programación y Electrónica
M.C. Pedro Arturo Cornejo Torres
QUEDAN PROHIBIDOS EL USO Y LA REPRODUCCIÓN TOTAL O PARCIAL POR CUALQUIER MEDIO SIN PERMISO POR ESCRITO O CONCENTIMIENTO DEL AUTOR Copyright © Pedro Arturo Cornejo Torres MMIX Microsoft, Microchip y demás marcas y productos mencionados en este documento, son nombres y marcas registradas por sus respectivas compañías.
1
M.C. Pedro Arturo Cornejo Torres
Introducción.................................................................................................................. 3 Aritmética entera .......................................................................................................... 4 Representación de números enteros sin signo ............................................................ 4 Representación de números enteros positivos y negativos en complemento a dos ...... 5 Desplazamiento Lógico a la Izquierda ................................................................... 6 Desplazamiento Aritmético a la Izquierda ................................................................. 6 Desplazamiento Lógico a la Derecha ......................................................................... 6 Desplazamiento Aritmético a la Derecha ................................................................... 7 División de números con signo entre potencias positivas enteras de dos .................... 7 Multiplicación de números con y sin signo por potencias enteras positivas de dos ..... 9 Aritmética de Punto Fijo ........................................................................................... 9 Multiplicación y División de cantidades en representación de punto fijo ................. 10 Multiplicación usando representación de punto fijo ................................................. 10 División usando representación de punto fijo ...................................................... 11 El algoritmo CORDIC de Volder ............................................................................ 12 CORDIC en modo Rotación de Vectores ............................................................. 12 Detalles de Programación del PIC18F4450 o PIC18F4550 .......................................... 15 Estructura del Bucle de Máquina de Cornejo ........................................................... 15 Valores y Modificaciones al Marco de Trabajo USB de Microchip ......................... 17 Modificaciones en los archivos para utilizar el PIC18F4550.................................... 18 En el archivo “usb_config.h” ............................................................................... 18 En el archivo “usb_function_cdc.c” ..................................................................... 18
2
M.C. Pedro Arturo Cornejo Torres
Introducción En la actualidad existen herramientas muy poderosas de programación y depuración de microcontroladores. Los fabricantes de microcontroladores modernos, han adoptado el lenguaje C para acelerar el desarrollo de firmware y software de sistemas complejos, confiables, eficientes y precisos. En el estudio de la mecatrónica, el entendimiento equilibrado de la tricotomía Electrónica-Informática-Mecánica permitirá que los proyectos sean concluidos, que sean eficientes y eficaces con respecto a los requerimientos en cada una de las etapas de sus diseños. Es por esto que he redactado este documento para que le sirva de apoyo en la incorporación de la tecnología de los sistemas embebidos en sus proyectos de robótica. Estudiaremos y repasaremos conceptos clave de electrónica e informática que considero y estoy seguro que le serán de gran utilidad. También se han incorporado temas que, bajo solicitud e inquietud de los integrantes de algunos equipos, se les considera necesaria una explicación quizás mas detallada. Estos temas son: Aritmética de Punto Fijo, el uso del algoritmo CORDIC de Volder, detalles programación de los microcontroladores PIC18F4450 o PIC18F4550 y el PC, así como sugerencias para intercambiar información entre estos mediante una conexión USB. También se estudian temas de electrónica como control de servomotores con PWM, control de motores de CD y encoder, opto-acopladores de fototransistor para entrada/salida digital y acoplamiento básico para conversión Analógica a Digital con el PIC. Los temas pueden ser estudiados en cualquier orden según su interés. Si usted lo cree necesario, puede contactarme a la siguiente dirección de correo electrónico
[email protected] para aclarar dudas, reportar errores y sugerencias. Este documento no tiene la intención de profundizar en lo que ya ha sido detallado en documentación que ya se le ha puesto a su alcance. Su habilidad en estas áreas de estudio dependerá en definitiva de su dedicación, respeto y responsabilidad a la materia y a la lectura de comprensión.
3
M.C. Pedro Arturo Cornejo Torres
Aritmética entera Se sabe pues, que al utilizar un vector de n bits, es posible generar 2 n códigos discretos diferentes entre si. A cada combinación o código se le puede asociar una cantidad numérica. Esta asociación agrega una semántica aritmética a cada código binario. Por ejemplo, cuando se utiliza un vector de 3 bits se pueden generar 8 códigos binarios diferentes. En la siguiente tabla se muestra una asociación entre cada código binario con una cantidad numérica correspondiente Código Cantidad 000 4 001 1 010 2 011 3 100 5 101 7 110 0 111 6 La aritmética para números enteros, como los que fueron utilizados en el ejemplo anterior, esta bien definida y como también hemos establecido un significado numérico para cada código binario, entonces es válido realizar la suma aritmética entre 000 y 010 (4+2) lo cual da como resultado 111 (6). Resulta fácil pensar en un circuito aritmético digital para realizar los cálculos para sumas que resulten menores o iguales a 7. Se habrá dando cuenta que, aunque funcional esta representación, no resulta práctica ya que no se aprovechan las características posicionales y de ponderación de los sistemas numéricos digitales como el decimal, el binario o el hexadecimal. Nota: La característica de digital no hace referencia exclusivamente a los sistemas numéricos binarios, sino a todo sistema numérico basado en dígitos. Entonces, como los circuitos binarios utilizan dígitos binarios, también resulta correcto llamarlos circuitos digitales. Se dice que un sistema numérico es posicional, ya que se le puede asignar un número ordinal a cada posición digital i y es ponderado porque cada posición digital tiene un factor o peso aritmético que, por lo general, es una potencia de una base como 2 ,i 10i o 16i.
Representación de números enteros sin signo Por ejemplo, para el sistema binario en un vector de 8 bits (byte) a un código binario se le asocia una cantidad numérica así: 2 2 25 24 2 2 21 2 B7 B6 B5 B4 B3 B2 B1 B0
4
M.C. Pedro Arturo Cornejo Torres 7
cantidad =
∑0 B 2
i
i
i=
No es necesario almacenar las constantes de las potencias de 2i, ya que quedan implícitas por la posición del dígito y sólo es necesario almacenar el vector de bits que en este caso es el byte que define a la cantidad. Con la representación anterior, se pueden manejar cantidades enteras desde el 0 hasta el 255. Los algoritmos comunes como la suma, resta, multiplicación y división se aplican como de costumbre sobre dos vectores de bits.
Representación de números enteros positivos y negativos en complemento a dos Para representar números negativos y positivos en binario mediante vectores de bits, se hace uso de un bit de signo y de la codificación en complemento a dos. El complemento a dos es una técnica de codificación de números binarios que simplifica la operación de resta haciendo uso de sumadores binarios, y por ende se simplifica el hardware reduciendo costos sin perder eficiencia. Si se utiliza un vector de 8 bits (byte) entonces una organización de bits conveniente es la siguiente: -/+ 2 25 24 2 2 21 2 B7 B6 B5 B4 B3 B2 B1 B0 En donde el bit de signo es B 7, si se le tiene el valor 0, indica que el valor codificado es positivo, en caso contrario, si se le asigna el valor 1 , la cantidad codificada es un número negativo. 6 cantidad = ∑ Bi 2 i − B7 ( 2 7 ) i 0 =
Ejemplo si el código de 8 bits es 0000 1111, entonces la cantidad asociada es +15, mientras que un código 1111 1111 es 127-128=-1. Por ejemplo supóngase que se desea sumar las siguientes cantidades representadas en complemento a dos 1111 1111 + -1 + 0000 1111 = 15 = (1) 0000 1110 14 Observe que el acarreo final se ignora (el noveno bit) puesto que no es almacenable en un byte. También, como resultado del desbordamiento, el bit B 7 ha cambiado a signo positivo. En complemento a dos, una resta se realiza simplemente con una suma algebraica. Aunque para las operaciones de resta y suma no es necesario hacer ninguna modificación para tratar a números con signo o sin signo, si lo es necesario para las operaciones basadas en desplazamientos a la izquierda o a la derecha, como lo son los algoritmos de digito a digito como lo son la multiplicación, la división y el cálculo de funciones trascendentales como coseno, seno, logaritmo y sus inversas. 5
M.C. Pedro Arturo Cornejo Torres
Desplazamiento Lógico a la Izquierda Para un desplazamiento a la izquierda, de un número codificado en binario ya sea con signo o sin signo simplemente se insertan ceros en la parte derecha, mientras que se desplazan los digitos a la izquierda. Los bits que resulten en desbordamiento por desplazamiento, simplemente se ignoran.
Por ejemplo, volviendo a utilizar el -1 representado en un vector de 8 bits y codificación en complemento a dos. (-1) (-2)
1111 1111 << (Operador de Desplazamiento a la Izquierda) 1= (Un desplazamiento a la izquierda) 1111 1110
El hecho de desplazar a la izquierda un número positivo o negativo es equivalente a multiplicarlo por una potencia n-ésima de dos. En el ejemplo anterior hemos multiplicado por 2 1 es decir 2. Revisando el resultado anterior, podemos verificar que efectivamente el duplo de -1 es -2. 1111 1110 = 126-128=-2. Entonces queda verificado que al insertar ceros en la parte derecha es aritméticamente correcto bajo la representación de complemento a dos. Lo mismo sucede con números positivos. Le encargo como ejercicio con cualquier cantidad positiva en representación de complemento a dos.
Desplazamiento Aritmético a la Izquierda A la operación de desplazamiento a la izquierda se le conoce con dos nombres, que operacionalmente son indistinguibles (que son lo mismo). Desplazamiento Lógico a la Izquierda (LSL Logic Shift to Left) y Desplazamiento Aritmético a la Izquierda (ASL Arithmetic Shift to Left). En lenguajes ensambladores los mnemónicos ASLxx LSLxx se implementan con el mismo código de operación. La operación de Desplazamiento Aritmético es aplicable a las cantidades representadas con signo, mientras que el Desplazamiento Lógico se aplica a las cantidades sin signo. El uso coherente de estos mnemónicos ayuda a mantener conocimiento y recordarle al usuario cuál es la semántica aritmética empleada para representar la cantidad. Desplazamiento Lógico a la Derecha Primero trataremos el desplazamiento a la derecha para números enteros sin signo. Para el desplazamiento a la derecha se debe hacer un tratamiento especial para los números con signo y sin signo. NOTA IMPORTANTE: úmeros sin signo se refiere a que el bit más significativo (MSB) no posee semántica de signo, sino de valor ponderado.
El desplazamiento a la derecha de un vector de bits con representación sin signo, simplemente se desplazan los bits a la derecha mientras se insertan ceros por la parte izquierda. A esto se le conoce como Desplazamiento Lógico a la Derecha (LSR Logic Shift to Right). 6
M.C. Pedro Arturo Cornejo Torres
En el siguiente ejemplo, utilizaremos el número 254 codificado sin signo y aplicaremos el desplazamiento lógico a la derecha. (254) 1111 1110 >> (Operador de Desplazamiento a la Derecha) 1= (126) 0111 1111 Podrá darse cuenta, de que dividir entre potencias n-ésimas de dos equivale simplemente a desplazar n veces a la derecha. Esto es cierto en el caso de representaciones sin signo.
Desplazamiento Aritmético a la Derecha El desplazamiento a la derecha de un vector de bits con representación con signo en complemento a dos, se realiza mediante el empleo del concepto de “extensión de signo”. La extensión de signo consiste en mantener el valor de signo en la parte mas significativa, mientras se copia, se extiende o propaga su valor a la derecha mientras de realiza el desplazamiento de los otros bits a la derecha. A éste desplazamiento se le conoce como Desplazamiento Aritmético a la Derecha. (ASR Arithmetic Shift to Right) Analicemos el siguiente ejemplo. Supongamos que queremos desplazar los bits correspondientes a una representación en complemento a dos del número -2 en un vector de 8 bits. El -2 codificado resulta ser 1111 1110, entonces si lo desplazamos una vez a la derecha, debemos conservar el signo negativo (el valor del bit B 7 debe conservarse y por supuesto propagarse a los siguientes bits menos significativos). (-2) (-1)
1111 1110 >> (Operador de desplazamiento a la derecha) 1 = (Un desplazamiento a la derecha) 1111 1111
El resultado de este desplazamiento a la derecha da como resultado -1. Como puede observarse el desplazamiento a la derecha de todo número diferente a -1 equivale a obtener el cociente que resulta de dividir la cantidad entre una potencia n-ésima de dos. La sentencia anterior dice, para todo numero diferente de -1. ¿Qué pasa cuando el valor a ser desplazado es -1? El resultado es -1, ya que se conservan todos los bits en 1. Así que hay que tener cuidado cuando nuestra intensión es dividir entre 2. Recordar que -1/2 debe ser 0 no seguir siendo -1. Cuando el número tiene signo positivo, entonces, el cero se copia hacia los bits menos significativos, teniéndose así, el efecto simple de un desplazamiento lógico a la derecha.
División de números con signo entre potencias positivas enteras de dos
7
M.C. Pedro Arturo Cornejo Torres Para resolver correctamente el caso cuando la cantidad a dividir es -1 se procede a calcular el desplazamiento lógico a la derecha de la cantidad simétrica (al multiplicarla por -1). Esto se realiza eficientemente al negar todos los bits y luego sumarle 1. Analicemos a continuación el algoritmo de división de x/2n. Para cuando x={-4, -1} (nótese el caso especial cuando x=-1) que son dividendos representados en complemento a dos en un vector de 8 bits. El algoritmo sólo utiliza el LSR (Desplazamiento Lógico a la Derecha) para efectuar esta división. El siguiente algoritmo debe ser aplicado cuando el número x es menor que 0 , es decir, negativo. Cuando el número x es positivo, un desplazamiento lógico a la derecha (LSR) es más que suficiente. Primero x=-4. Como x es negativo: Se complementa Se le suma 1 Se desplaza 1 a la derecha Se complementa Se le suma 1 Listo
(-4) (3) (4) (2) (-3) (-2)
1111 1100 0000 0011 0000 0100 0000 0010 1111 1101 1111 1110
(puede desplazar n veces)
Nótese que realizar -4/2 equivale simplemente a hacer un desplazamiento aritmético a la derecha sin realizar complementos y sumas. Se desplaza 1 a la derecha aritméticamente.
(-4) (-2)
1111 1100 1111 1110
Luego cuando x=-1 y aplicando la secuencia de operaciones anterior se tiene que Se complementa Se le suma 1 Se desplaza 1 a la derecha Se complementa Se le suma 1 Listo
(-1) (0) (1) (0) (-1) (0)
1111 1111 0000 0000 0000 0001 0000 0000 1111 1111 0000 0000
(puede desplazar n veces)
Así se obtiene el resultado correcto de dividir -1 entre 2 cuyo cociente es cero, y por supuesto se obtendrá el resultado para cualquier divisor que sea potencia de dos. Debe tener mucho cuidado con los datos con los que operará. Una mala interpretación de los bits o sus operaciones, pueden conducir a problemas demasiado frustrantes. Evítese molestias y entienda primero estos conceptos de gran relevancia en el desarrollo de sistemas embebidos y en particular para su proyecto.
8
M.C. Pedro Arturo Cornejo Torres
Multiplicación de números con y sin signo por potencias enteras positivas de dos La multiplicar números con y sin signo por potencias enteras positivas de dos, resulta ser demasiado trivial, y que bueno que es así, ya que la multiplicación así como la suma se utiliza con frecuencias muy elevadas durante el procesamiento. Simplemente se utiliza n desplazamientos a la izquierda insertando ceros en la parte inferior (LSL hace esto). Al efectuarse estos desplazamientos el efecto final es equivalente a calcular x2n. Nota: El producto de dos cantidades de n bits requiere como máximo 2 n bits (el doble de bits) para almacenar el producto sin pérdida de información. Es decir, si se multiplican dos cantidades de 8 bits, el resultado requiere de 16 bits para representarse exitosamente.
Aritmética de Punto Fijo La aritmética de punto fijo, es otra representación de cantidades numéricas que están compuestas por una parte entera y una parte fraccional. El computador digital solamente puede manejar cantidades discretas codificadas en vectores finitos (arreglos) de bits. Esto confina a los computadores a utilizar subconjuntos finitos del conjunto infinito de los números reales. Estando convencidos y concientes de que únicamente podemos emplear aproximaciones de los números reales, las operaciones entre estas cantidades, también proyectaran aproximaciones. Estas aproximaciones, dependiendo de la cantidad de bits que se utilicen tanto para la parte entera como la fraccional, pueden ser más que suficientes para una determinada aplicación. Sin darnos cuenta, en las secciones anteriores, hemos estado utilizando una notación de punto fijo, en donde no se tienen bits para representar el código de la parte fraccional de una cantidad. En esas representaciones solo existían ponderaciones que son potencias positivas de dos donde el exponente es un número positivo: 2 n para n es 0 o un valor positivo entero. ¿Qué pasa si introducimos números de exponentes negativos? La respuesta es muy simple, comenzaríamos a trabajar con potencias que son fracciones de potencias con exponente negativo de dos. Una cantidad con representación de punto fijo, puede ser definido de la siguiente manera 2 25 24 2 2 21 2 2-1 2- 2- 2-4 2-5 2- 2- 2- 2D6 D5 D4 D3 D2 D1 D0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9
. punto I
cantidad =
F
∑0 B 2 ∑1 Q i
i
i=
+
f
2
f
−
f =
Donde Q representa a los bits de la parte fraccional y F es el número de éstos bits. En la representación de la figura anterior, F=9 pero puede ser cualquier otra cantidad según se 9
M.C. Pedro Arturo Cornejo Torres necesiten bits para representar la parte fraccional. Se tienen además, y sin menos preciar, 7 bits para representar una la cantidad entera. La cantidad más pequeña que se puede representar utilizando esa misma representación anteriormente expuesta es 0 y la cantidad más grande es 127.998046875 exactamente. En incrementos de 0.001953125 exactamente. (Esto es casi 2 milésimas por incremento o decremento en la parte fraccional) Las cantidades expresadas en punto fijo se suman y se restan como si se tratasen de representaciones enteras ordinarias. para representar cantidades negativas y positivas se emplea la notación en complemento a dos en toda la representación como si se tratase de una cantidad entera ordinaria. Se pierde un bit para almacenar la semántica del signo. -/+ 25 S D5
24 D4
2 D3
2 D2
21 D1
2-1 Q1
2 D0 I
cantidad =
∑0
Bi 2i
2Q2
2Q3
F
+
i=
∑1 Q
f
f
−
−
2-5 Q5
S 2 I 1 +
2Q6
2Q7
2Q8
2Q9
=
f =
F
∑0 B 2 i
∑1 Q
i
+
2( f F ) −
f
I
=
2
2-4 Q4
f =
i=
2
F
−
S 2 I 1 +
En la figura se utiliza S para almacenar el signo de la cantidad. Si el valor es cero, el número es positivo, si es 1 la cantidad es negativa. Observará que las potencias de las posiciones son de nuevo una referencia hacia una semántica aritmética y que esto no afecta a la manera en que el vector de bits es almacenado en la computadora. Al emplear complemento a dos, en toda la representación al tratarla como un entero ordinario, las operaciones de suma y resta se efectúan sin cambio alguno. Una de las ventajas de esta representación de punto fijo es que no es necesario modificar el hardware o el software para incorporar operaciones cantidades con partes fraccionales.
Multiplicación y División de cantidades en representación de punto fijo Multiplicación usando representación de punto fijo Durante los procesos de multiplicación y división es muy importante tener en cuenta que el punto que separa la parte entera de la fraccional cambiará su posición con el objetivo de seguir representando cocientes o productos de manera correcta.
10
M.C. Pedro Arturo Cornejo Torres El siguiente ejemplo de multiplicación muestra el hecho de que el punto cambia su posición (como en cuando multiplicábamos en primaria, ¿Si lo recuerda?). Suponga que se utiliza complemento a dos, I=3 (tres dígitos binarios enteros) y una F=3 (tres dígitos binarios fraccionales) y las cantidades a multiplicar son 010.110 con 110.111 (2.75) (-1.125)
010.110 * 110.111 =
Calculamos el complemento a dos del multiplicador y guardamos el signo para después, por lo que la multiplicación quedaría como: (2.75) 010.110 * (1.125) 001.001 = (complemento a dos del multiplicador) --------------------------010110 + 000000 + 000000 + 010110 + 000000 + 000000 --------------------------(3.09375) 000011.000110 Como es negativo el producto (-3.09375) 111100.111010
(complemento a dos del producto)
Observe que el punto “fijo” se ha desplazado otras tres posiciones hacia la izquierda, y ha requerido el doble de bits para poder ser representado. Antes necesitaba 6 bits, ahora requiere de 12 (con signo incluido) para poder ser representado de forma exacta. Sin embargo es necesario volver a la representación de 6 bits para continuar haciendo otras operaciones como sumas y restas cuya semántica considera sólo tres bits para la parte fraccional. Por lo tanto el resultado debe desplazarse aritméticamente a la derecha F veces (ASR) y tomar los primeros (de derecha a izquierda) bits del resultado desplazado. 111100.111010 >> 3 (Desplazamiento Aritmético a la Derecha) 111111100.111 (Se toman los primeros 6 bits) (-3.125) 100.111 (Cantidad compatible para otras operaciones) Entonces la diferencia entre el valor real y el valor aproximado es de 0.03125 unidades. Podemo resumir en la siguiente fórmula como debe realizarse la multiplicación entre dos cantidades en una representación de punto fijo arbitraria y convencional: producto = ( multiplicando * multiplicador ) >> F
División usando representación de punto fijo
Vamos a partir del hecho de que una multiplicación entera, se produce a partir de la ecuación p = ab , en este caso, a y b son dos números en una representación de punto 11
M.C. Pedro Arturo Cornejo Torres fijo arbitraria, entonces p requiere doble almacenamiento que a o b. Despejemos la formula para encontrar el cociente a. Si a = p / b , entonces el valor del divisor debe estar en una representación tal que la parte fraccional requiera el doble de bits para su representación fraccional. Por lo tanto antes de dividir el divisor por el dividendo, el dividendo p debe ajustarse a doble precisión y el cociente estará listo en la notación convencional que haya elegido. La fórmula para la división en punto fijo es la siguiente, y se realiza un desplazamiento hacia la izquierda (LSL) F veces del divisor antes de dividir.
cociente =
dividendo << F divisor
Puede obtenerse la fórmula anterior, al despejar la fórmula del producto.
El algoritmo CORDIC de Volder El algoritmo CORDIC resuelve una gran clase de problemas, cuando volder diseño éste algoritmo lo hizo principalmente para la evaluación de funciones trigonométricas, posteriormente se aplicó para la evaluación de logaritmos, raíces cuadradas, multiplicaciones, divisiones, funciones hiperbólicas en tiempo constante. La implementación de un CORDIC no se limita a la aritmética de punto fijo (siendo excesivamente eficiente en estas representaciones numéricas) sino que también se extiende fácilmente al procesamiento de valores en punto flotante. El algoritmo CORDIC y sus variantes se encuentran implementados en las unidades de punto flotante de los microprocesadores poderosos de computadoras y servidores, así como en hardware de microprocesadores para el procesamiento de señales. El algoritmo CORDIC se emplea en dos modalidades. Modo de Rotación de Vectores y el Modo de Vectorización. El algoritmo se caracteriza por ser preciso hasta la cantidad de bits que se le especifique e implemente. Es muy eficiente y eficaz, ya que durante la ejecución en cualquiera de las dos modalidades, CORDIC sólo requiere del acceso a una tabla pequeña de constantes así como de sumas, restas y desplazamiento de bits para realizar sus cálculos. CORDIC en modo Rotación de Vectores El modo de Rotación de Vectores, se utiliza para calcular senos y cosenos al efectuar la rotación de un vector bidimensional inicial [1, 0] según un ángulo de rotación dado. No necesariamente se tiene que introducir un vector unitario, puede ser cualquier vector dentro del dominio de la representación y del resultado esperado.
El modo de Vectorización, se utiliza calcular arco seno y arco coseno mediante identidades del arco tangente partiendo de la razón de las medidas del cateto adyacente y el cateto opuesto al ángulo. Un computador digital de rotación de coordenadas (CORDIC) tiene tres registros. El registro X, el registro Y y el registro Z.
12
M.C. Pedro Arturo Cornejo Torres
Estos registros son de entrada y salida para algoritmo de rotación de vectores, en donde la salida se relaciona con la entrada de la siguiente manera: Entrada X= Valor del eje x en punto fijo Y= Valor del eje y en punto fijo Z= Valor en radianes del ángulo en punto fijo
Salida X= K (Xcos(Z) – Ysin(Z)) Y= K (Xsin(Z) + Ycos(Z)) Z=0
Donde K es aproximadamente 1.65. Para obtener el resultado final multiplíquese los registros X e Y por el inverso de 1.65. Véanse los artículos que tratan el tema del algoritmo CORDIC para investigar cómo calcular un valor más preciso de la constante K. La implementación del algoritmo de CORDIC que le otorgado, utiliza una representación de punto fijo con una precisión de 9 bits (F=9) en la parte fraccional, 22 para la parte entera (I=22) y un bit de signo (S). Se utilizan 32 bits para poder manipular multiplicaciones y divisiones. Con tantos bits de holgura podemos, utilizando sólo 32 bits, obtener productos y manejar dividendos de +/- 8192 ó (213) (recuerde los desplazamientos de 9 bits que implican estas operaciones). El siguiente ejemplo, supone que usted ya dispone los archivos de implementación del algoritmo CORDIC. Estos archivos están disponibles en el sitio web de apoyo. Incluya los archivos “Cordic.h”, “Cordic.c” y “CordicROM.h” a su proyecto de MPLAB, Visual C++ o la herramienta que usted prefiera. /****************************************** Ejemplo de Uso del Algoritmo de Cordic Compilado utilizado: Microchip C18 ******************************************/ #include "GenericTypeDefs.h" #include "Compiler.h" #include “Codic.h” long Divide(long x,long y) { return (x<
13
M.C. Pedro Arturo Cornejo Torres //Luego se debe escalar los resultados utilizando __KCircular fpX=Multiply(g_CORDIC_x,__KCircular); fpY=Multiply(g_CORDIC_y,__KCircular); //Ahora fpX y fpY tienen el vector [450,0] rotado PI/6 radianes //[fpX,fpY]=[0x00030b50, 0x0001c2ae] o bien //(1 1000 0101.1 0101 0000, 1110 0001.0 1010 1110) //que es, en base 10: [389 + (336/512), 225+(174/512)].
//Rotación más precisa (Calculadora de Windows): //[389.71143170299739104367542683882, 225.0]
//CORDIC converge y funciona según lo esperado. }
CORDIC en uso
14
M.C. Pedro Arturo Cornejo Torres
Detalles de Programación del PIC18F4450 o PIC18F4550 En esta sección mencionaré algunas recomendaciones de programación y configuración de los algunos periféricos disponibles en el PIC18F4X50 para que éste funcione correctamente con la PC y el resto de su proyecto.
Estructura del Bucle de Máquina de Cornejo El Bucle de Máquina de Cornejo es un algoritmo y técnica de implementación que permite a un microprocesador funcionar cuando éste no se encuentre atendiendo a solicitudes de interrupción por hardware. Además establece priorización entre tareas de interrupción, tareas no interrumpibles y tareas interrumpibles. Se sabe que el microprocesador puede programarse para: a) Procesamiento de Solicitudes de Interrupciones mediante Rutinas de Servicio de Interrupción (ISR’s). Cuando se utiliza exclusivamente este paradigma, el microprocesador atiende a los periféricos al responder a sus solicitudes de interrupción. Un periférico genera una solicitud de interrupción, cuando su estado ha cambiado. Cuando toda solicitud ha sido servida, el microprocesador entra en espera hasta que otra solicitud de servicio se genere. El procesamiento de la información se realiza solamente cuando se sirve a una interrupción. b) Procesamiento mediante encuesta. Cuando se utiliza exclusivamente este paradigma, el microprocesador encuesta a cada periférico de manera periódica en busca de cambios en sus estados. Cuando el programa que corre ese microprocesador ha detectado que el estado de un dispositivo ha cambiado, el microprocesador, instruido por el programa, hará el procesamiento indicado. En este paradigma, el procesador siempre está activo. c) Utilizando ambos paradigmas. Algunos problemas se resuelven más fácilmente mediante el uso de interrupciones, otros son más sencillos mediante encuesta. Otros problemas requieren de ambos paradigmas para funcionar eficaz y eficientemente. El Bucle de Máquina de Cornejo es un ciclo repetitivo que se compone un conjunto de pasos que es interrumpible y otro conjunto de pasos que no lo es. El conjunto de pasos interrumpibles está conformado por algoritmos cuya ejecución puede ser interrumpida por una solicitud de interrupción, y los momentos en el que los pasos inician o terminan no se considera crítico. El conjunto de pasos no interrumpibles está conformado por tareas que cuando inician, éstas deben terminar en los tiempos adecuados y son tareas que se consideran críticas. Estas tareas no interrumpibles se les conoce con el nombre de “Operaciones Atómicas”.
15
M.C. Pedro Arturo Cornejo Torres A continuación se muestra un ejemplo de Bucle de Máquina de Cornejo: /************************************************** Estructura básica de un bucle de máquina. Estructura de Bucle de Máquina de Cornejo mailto:
[email protected] ***************************************************/
//Implementación de los vectores de interrupción… . . . //Tareas no interrumpibles char TareasNoInterrumpibles() { //Lista de sentencias de tareas no interrumpibles return 0; //Si no se permite la ejecución de otras tareas, excepto éstas. return 1; //Si se permite la ejecución de interrupciones y otras tareas. } //Tareas interrumpibles void TareasInterrumpibles() { //Lista de sentencias de tareas interrumpibles } //Variable Global de permiso para activar interrupciones char g_bRespaldoGIE=1; /************************************* Punto de entrada: void main(void) **************************************/ void main(void) { //Inicializar periféricos y configurar interrupciones (GIE permanece en cero) Inicializar(); while(1) { //Hacer tareas no interrumpibles (Conjunto No Interrumpible) if(TareasNoInterrumpibles()==0) continue; //Se sigue procesando el conjunto no interrumpible //Habilitar el procesamiento por interrupción GIE=g_bRespaldoGIE; //Hacer las tareas no críticas (Conjunto Interrumpible) TareasInterrumpibles(); //Guardar el estado de GIE g_bRespaldoGIE=GIE; //Deshabilitar interrupciones GIE=0; //Otras tareas no interrumpibles } }
La estructura se caracteriza principalmente por deshabilitar y habilitar las interrupciones de manera periódica antes y después de ejecutar las tareas no interrumpibles. De esta manera, se pueden implementar transacciones u operaciones atómicas de manera organizada. El estado del habilitador de interrupciones global GIE se almacena en la variable bRespaldoGIE ya que las tareas no interrumpibles así como las interrumpibles pueden controlar al habilitador de interrupciones de manera arbitraria. Las tareas no interrumpibles no deben tardar mucho en su ejecución, ya que esto aumentaría la latencia al atender interrupciones de hardware.
16
M.C. Pedro Arturo Cornejo Torres Las tareas que tomen mucho tiempo y que no sean críticos deben implementarse como tareas interrumpibles y como máquinas de estado o autómatas. El siguiente ejemplo es un caso de uso del Bucle de Máquina de Cornejo . . . unsigned char g_bGIEBackup=1; char IsUSBConfigured(void) { if( (USBDeviceState < CONFIGURED_STATE )||(USBSuspendControl==1)) return 0; return 1; } void main() { //Inicializar estado de máquina InitSystem(); //Inicializar variables e interfase de usuario (LEDS, LCD, Teclado) InitUser(); //Habilitar interrupciones de periféricos INTCONbits.PEIE=1; //Entrar al ciclo de máquina while(1) { /***************** TAREAS NO INTERRUMPIBLES *******************/ USBDeviceTasks(); //Si el USB no ha alcanzado el estado de configurado, //o se encuentra en suspención, continuar realizando USBDeviceTasks if(!IsUSBConfigured()) continue; //Habilitar interrupciones globales INTCONbits.GIE=g_bGIEBackup; /****************TAREAS INTERRUMPIBLES**************/ //Ya se ha alcanzado el estado de configurado //y no se encuentra en suspención //por lo que se puede obtener información proveniente del host ProcessIncommingPacketsStateMachine(&g_USBTSM); //Realizar tareas de recepción y envió en el USART por paquete do { USARTRxTasks(); USARTTxTasks(); } while(g_bUSARTState==USART_STATE_TRANSMITTING || g_bUSARTState==USART_STATE_RECEIVING); ProcessIncommingPacketsStateMachine(&g_USARTTSM); //Procesar envíos pendientes por USB CDC CDCTxService(); //Respaldar GIE g_bGIEBackup=INTCONbits.GIE; //Deshabilitar interrupciones INTCONbits.GIE=0; /********************* TAREAS NO INTERRUMPIBLES ****************/ StatusLedTasks(); } }
Valores y Modificaciones al Marco de Trabajo USB de Microchip A continuación, mostraré las modificaciones y los valores requeridos para poder realizar exitosamente una conexión USB entre el PC y los PIC18F4450 y PIC18F4550.
17
M.C. Pedro Arturo Cornejo Torres Para poder realizar diferentes tipos de tareas, le recomiendo utilice la estructura de Bucle de Máquina de Cornejo para que pueda hacerse cargo de las tareas no interrumpibles de USB y las tareas que usted necesite implementar como lo son servicios de interrupción o tareas interrumpibles. El proyecto MPLAB, debe contener los siguientes archivos que corresponden al marco de trabajo USB de Microchip. (Microchip USB Device Framework) usb_config.c usb_device.c usb_descriptors.c usb_function_cdc.c usb_config.h Así como los demás archivos, aunque no asociados al proyecto explícitamente, que están almacenados y al alcance en la subcarpeta “.\usb” del proyecto. Descargue el proyecto inicial para el PIC18F4450 que ya posee la estructura de proyecto inicial. Si está utilizando el PIC18F4450 necesitará el archivo con las instrucciones de enlace 18F4450.lkr. Este archivo se encuentra el directorio de instalación de Microchip C18, “C:\MCC18\lkr”. En caso de utilizar el PIC18F4550 deberá especificar el nuevo archivo con instrucciones de enlace para ese MCU. El archivo también se encuentra en esa carpeta “C:\MCC18\lkr” con el nombre 18F4550.lkr.
Modificaciones en los archivos para utilizar el PIC18F4550 En el archivo “usb_config.h”
Debido a que el PIC18F4550 tiene más memoria, se pueden utilizar características más eficientes. /* CDC */ #define CDC_COMM_INTF_ID #define CDC_COMM_EP #define CDC_COMM_IN_EP_SIZE
0x0 2 8
#define #define #define #define
0x01 3 64 Modifique a este valor (antes 32) 64 Modifique a este valor (antes 32)
CDC_DATA_INTF_ID CDC_DATA_EP CDC_DATA_OUT_EP_SIZE CDC_DATA_IN_EP_SIZE
En el archivo “usb_function_cdc.c”
Realice las modificaciones necesarias para que el ajustarse al siguiente fragmento. /** V A R I A B L E S ********************************************************/ #if defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50) #pragma udata usbram2 #elif defined(__18F2455) || defined(__18F2550) || defined(__18F4455) || defined(__18F4550)\ || defined(__18F2458) || defined(__18F2453) || defined(__18F4558) || defined(__18F4553) #pragma udata USB_VARIABLES=0x500 Debe ser 0x500 el banco de Intercambio de Datos #elif defined(__18F4450) || defined(__18F2450) #pragma udata USB_VARIABLES=0x430
18
M.C. Pedro Arturo Cornejo Torres #else #pragma udata #endif
Si tras haber realizado los cambios sigue teniendo problemas con la conexión USB en el PIC18F4550, puede utilizar otro mecanismo de transferencia USB. Para más información acerca de estos cambios véase la documentación del PIC18F4550 y la organización de memoria de USB. En el archivo “usb_config.h” realice la siguiente modificación //Make sure only one of the below "#define USB_PING_PONG_MODE" //is uncommented. #define USB_PING_PONG_MODE USB_PING_PONG__NO_PING_PONG Descomente esta línea //#define USB_PING_PONG_MODE USB_PING_PONG__FULL_PING_PONG Comente esta línea //#define USB_PING_PONG_MODE USB_PING_PONG__EP0_OUT_ONLY //#define USB_PING_PONG_MODE USB_PING_PONG__ALL_BUT_EP0 //NOTE: This mode is not supported in PIC18F4550 family rev A3 devices
Esta última modificación no debe ser necesaria. Verifique su diseño, sus algoritmos, sus tiempos de procesamiento y priorización de tareas, puede que esto sea el causante de los problemas de sincronización y conexión.
19