Vous êtes sur la page 1sur 58

Sistemas Digitales FreeRTOS en ATMEGA32 Portaci on, Drivers y Simulaci on de Tareas

Nicol as Ilich Samus Profesor: Jos e Ju arez

Universidad Nacional de Quilmes 10 de Febrero de 2012

Indice general

Licenciamiento

Portaci on de FreeRTOS a ATMEGA32


a ATMEGA32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . serial.c de FreeRTOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . a ATMEGA32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4
5 5 5 5 6 6 6 6

1. Portaci on de FreeRTOS 1.1. port.h . . . . . . . . . . 1.2. portmacro.h . . . . . . 1.3. Creaci on del Port . . .

2. Portaci on de la librer a lib 2.1. Registros . . . . . . . . . . 2.2. Bits . . . . . . . . . . . . . 2.3. Interrupciones . . . . . . .

II

Creaci on de un Proyecto en AVR Studio 5 con FreeRTOS


con . . . . . . . . . . . . FreeRTOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7
8 8 8 9 10

3. Creaci on de un Proyecto en AVR Studio 5 3.1. Software necesario . . . . . . . . . . . . . . . 3.2. Nuevo proyecto . . . . . . . . . . . . . . . . . 3.3. Incluir FreeRTOS . . . . . . . . . . . . . . . 3.4. Conguraci on del proyecto . . . . . . . . . .

III

Drivers y Simulaci on de Tareas

12
13 14 14 14 15 18 18 18 21 21 22 24 26 26 28

4. Introducci on 5. Sistemas con FreeRTOS 5.1. LCD . . . . . . . . . . . . . . . . 5.1.1. Tareas de demostraci on . 5.1.2. C odigo Fuente . . . . . . 5.2. Teclado Matricial Hexadecimal 5.2.1. Tareas de demostraci on . 5.2.2. C odigo Fuente . . . . . . 5.3. Conversor Anal ogico Digital . . 5.3.1. Tareas de demostraci on . 5.3.2. C odigo Fuente . . . . . . 5.4. Puerto Serie . . . . . . . . . . . . 5.4.1. Tareas de demostraci on . 5.4.2. C odigo Fuente . . . . . . 5.5. Leds y Botones . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

Ap endice

30

A. Librer a para Display LCD 30 A.1. lcd lib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 A.2. lcd lib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

B. Librer a para Teclado Matricial Hexadecimal 39 B.1. keypad lib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 B.2. keypad lib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 C. Librer a para Conversor Anal ogico Digital 41 C.1. adc lib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 C.2. adc lib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 D. Librer a para Puerto Serie 43 D.1. lib serial.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 D.2. lib serial.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 E. Librer a para LEDs 55 E.1. led lib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 E.2. led lib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 F. Librer a para Botones 56 F.1. boton lib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 F.2. boton lib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

Bibliograf a

57

Licencias

FreeRTOS en ATMEGA32 por Nicol as Ilich Samus se encuentra bajo una Licencia Creative Commons Atribuci on-NoComercial-CompartirDerivadasIgual 3.0 Unported a excepci on de los Ap endices A y D los cuales est an licenciados de forma independiente al presente trabajo.

Parte I

Portaci on de FreeRTOS a ATMEGA32

Cap tulo 1 Portaci on de FreeRTOS a ATMEGA32

La portaci on a ATMEGA32 se realiz o a partir del port que FreeRTOS dispone para el ATMEGA323.

1.1.

port.h

Se analiz o el archivo port.h y se obtuvieron las siguientes conclusiones: No fue necesario cambiar ninguno de los par ametros a continuaci on ya que ambos microcontroladores comparten las mismas deniciones. /* Start tasks with interrupts enables . */ # define p or t F L A G S _ I N T _ E N A B L E D ( ( portSTACK_TYPE ) 0 x80 ) /* Hardware constants for timer 1. */ # define p o r t C L E A R _ C O U N T E R _ O N _ M A T C H ( ( unsigned char ) 0 x08 ) # define portPRESCALE_64 ( ( unsigned char ) 0 x03 ) # define p or tC L O CK _ P RE S C AL E R ( ( unsigned long ) 64 ) # define p o r t C O M P A R E _ M A T C H _ A _ I N T E R R U P T _ E N A B L E ( ( unsigned char ) 0 x10 ) Como los dos microcontroladores poseen los mismos registros (R0-R31) y se encuentran en las mismas posiciones de memoria, tampoco fue necesario redenir las funciones portSAVE CONTEXT(), portRESTORE CONTEXT() ni *pxPortInitialiseStack().

1.2.

portmacro.h

Se analiz o el archivo port.h y se obtuvieron las siguientes conclusiones: En este archivo estan las deniciones de los tipos de datos del port, en el se realiza un mapeo entre los tipos de datos estandar de C y aquellos m as apropiados en el microcontrolador portado. Tambi en se encuentran las deniciones de las funciones portENTER CRITICAL(), portEXIT CRITICAL(), portDISABLE INTERRUPTS() y portENABLE INTERRUPTS() entre otras. Todas estas funciones estan escritas totalmente en assembler debido a su interacci on directa con el microcontrolador. As como con el archivo port.h, no fue necesario cambiar nada ya que todos los microcontroladores AVR de la l nea ATMEGA poseen el mismo set de instrucciones y sus arquitecturas son de 8bits por lo que los tipos de datos tambi en son coincidentes.

1.3.

Creaci on del Port

Para dejar expl cito que estamos trabajando con un ATMEGA32 en vez de un ATMEGA323 se gener o una nueva carpeta dentro de freeRTOS/Source/portable/GCC llamada ATMEGA32 y se copiaron all los archivos port.h y portmacro.h correspondientes al ATMEGA323.

Cap tulo 2 Portaci on de la librer a lib serial.c de FreeRTOS a ATMEGA32

Cuando se intent o utilizar la librer a para comunicaci on serie provista por FreeRTOS surgi o la necesidad de portar la misma para ATMEGA32 debido a que los nombres de los registros, los bits y las interrupciones para manejar la USART son distintos en el ATMEGA323. A continuaci on se detallan los cambios realizados a lo largo del c odigo.

2.1.

Registros

Se reemplazaron los siguientes registros. UCSR0B por UCSRB. UCSR0A por UCSRA.

2.2.

Bits

Se reemplazaron los siguientes bits. UBRR0L por UBRRL. UBRR0H por UBRRH. UCSR0C por UCSRC. UDR0 por UDR. UDRE0 por UDRE. RXC0 por RXC.

2.3.

Interrupciones

Se agregaron dos condicionales para usar las interrupciones propias del ATMEGA32. USART Receive Complete: # if defined ( __AVR_ATmega32__ ) ISR ( USART_RXC_vect ) # endif USART Data Ready: # if defined ( __AVR_ATmega32__ ) ISR ( USART_UDRE_vect ) # endif

Parte II

Creaci on de un Proyecto en AVR Studio 5 con FreeRTOS

Cap tulo 3 Creaci on de un Proyecto en AVR Studio 5 con FreeRTOS

En esta secci on se describen los pasos a seguir para generar un proyecto desde cero en AVR Studio 5 que incluya las librer as de FreeRTOS manteniendo la organizaci on de archivos con la que FreeRTOS es distribuido.

3.1.

Software necesario
Atmel AVR Studio 5 FreeRTOS Versi on 7.1.0 (Ultima versi on disponible a la fecha)

3.2.

Nuevo proyecto

Una vez instalado AVR Studio, lo ejecutamos y nos encontramos con la pantalla de bienvenida.

Figura 3.1: Pantalla de bienvenida. 1. Hacemos click en New Project para crear un nuevo proyecto. Seleccionamos C Executable Project, completamos el campo Name con el valor deseado y nalmente hacemos click en OK.

Figura 3.2: Nuevo proyecto. 2. Seleccionamos el dispositivo que sera nuestro target en el proyecto. En este caso seleccionamos el ATMEGA32 y terminamos haciendo click en OK.

Figura 3.3: Selecci on del dispositivo target.

3.3.

Incluir FreeRTOS

Para incluir los archivos de FreeRTOS en nuestro proyecto debemos hacer lo siguiente: 1. Copiar el archivo FreeRTOSCong.h ubicado en el directorio donde descomprimimos FreeRTOS y dentro de este en Demo\AVR ATMega323 WinAVR a la raiz de nuestro proyecto, en este caso: C:\Documents and Settings\Administrador\Escritorio\drivers sidi\AVRGCC1\AVRGCC1 2. Crear una carpeta llamada FreeRTOS en la raiz de nuestro proyecto y copiar en ella la carpeta Source, excluyendo la carpeta portable. 3. Crear la carpeta portable en Source. 4. Crear las carpetas GCC y MemMang dentro de portable. 5. Crear la carpeta ATMEGA32 y copiar los archivos port.c y portmacro.h correspondientes al ATMEGA32 [?, Ver el apunte Portaci on de FreeRTOS de ATMEGA323 a ATMEGA32]. 6. En la carpeta MemMang copiar el archivo heap 1.c incluido en FreeRTOS.

7. Crear una carpeta llamada Drivers en la ra z de nuestro proyecto. Ser a donde guardemos las librer as que utilicemos y/o creemos para manejar los distintos perif ericos del microcontrolador o dispositivos externos. 8. Modicar el archivo portable.h ubicado en nuestro proyecto en la carpeta FreeRTOS\Source\include en la linea 74. Donde dice ATMega323 poner ATMEGA32. 9. Ahora, devuelta en AVR Studio hacemos click en Show all Files en el Solution Explorer

10. Inclu mos las carpetas FreeRTOS y Drivers y el archivo FreeRTOSCong.h en el proyecto. Cabe aclarar que cada vez que se agreguen archivos por fuera de AVR Studio ser a necesario seguir este procedimiento.

3.4.

Conguraci on del proyecto

Ahora vamos a congurar el proyecto para que luego pueda compilarse correctamente. 1. Hacemos click derecho sobre el proyecto y luego en propiedades.

2. Ingresamos a la solapa Toolchain.

10

3. En la Secci on Symbols agregamos dos entradas: F CPU=8000000 : Establece la velocidad del cristal que utilizaremos. En este caso se us o 8Mhz y no 16Mhz ya que como se simul o con Proteus Isis mayor velocidad implicaba mayor consumo de CPU y la p erdida de rendimiento era considerable. ametro para saber que est a trabajando con un GCC MEGA AVR : FreeRTOS necesita este par AVR y as aplicar conguraci on dependiente de la arquitectura.

4. En la Secci on Directories agregamos 4 entradas como paths relativos: El directorio ra z. include donde se encuentran los headers de FreeRTOS. ATMEGA32 donde se encuentran los archivos propios de puerto. Drivers donde se encuentran las librer as de los perif ericos y dispositivos.

5. En la Seccion Optimization seleccionamos Optimize for size -Os 6. Por u ltimo, en el archivo FreeRTOSCong.h que copiamos desde el directorio de la Demo inclu da con FreeRTOS debemos modicar el par ametro congUSE IDLE HOOK para que sea cero en nuestro primer proyecto a menos, claro, que lo vayamos a usar. Asimismo algunas caracter sticas del sistema vienen deshabilitadas por default y en caso de ser necesarias en el proyecto deben habilitarse primero. En lo descrito anteriormente se intent o conservar la estructura de las carpetas de FreeRTOS dentro del proyecto para no perder la idea general propuesta por los desarrolladores y, en caso de tener que trabajar con una arquitectura distinta o en proyectos ya establecidos, no haya que interpretar la misma nuevamente.

11

Parte III

Drivers y Simulaci on de Tareas

12

Cap tulo 4 Introducci on

Se desarrollaron cuatro implementaciones distintas de FreeRTOS con tareas de demostraci on de las caracter sticas del sistema (ejecuci on de tareas en tiempo real, el uso de sem aforos, colas y colas binarias), del uso de los perif ericos del microcontrolador (USART, los puertos de entrada/salida y los conversores anal ogico/digitales) y del manejo de dispositivos como el display LCD y el teclado matricial de 4x4. Los sistemas fueron implementados para funcionar con un reloj de 8Mhz, se opt o por esta velocidad ya que a 16Mhz la PC en la que se realiz o la simulaci on perd a la caracter stica de tiempo real. Esto fue reportado por el simulador y vericado con una tarea simple de generaci on de forma de onda. Por otro lado, se pens o en realizar todas las simulaciones a 1Mhz para obtener un buen rendimiento, pero por ser un numero muy bajo iban a existir importantes limitaciones en cuanto a la frecuencia del tick de FreeRTOS. Con la elecci on de trabajar a 8Mhz se pudo congurar una frecuencia de tick de 1Khz, la cual fue apropiada para mantener los requerimientos de todos los sistemas propuestos.

13

Cap tulo 5 Sistemas con FreeRTOS

5.1.

LCD

En esta demostraci on se plantea un sistema compuesto de un generador de onda cuadrada, el cual se inicia y se detiene por medio de un pulsador. Se utiliz o un display LCD para reportar la cantidad de tareas del sistema y el estado de la tarea encargada de generar la onda cuadrada. Se opt o por usar el driver LCD lcd lib.c desarrollado por el sitio Scienceprog.com el cual es distribuido bajo la GNU Public License. Al mismo se le agreg o el m etodo LCDInt162String() para visualizar variables de punto jo de 16bits con un sujo, esto fue necesario para visualizar los valores adquiridos por el conversor anal ogico digital y no desperdiciar memoria RAM con el uso de variables del tipo oat.

5.1.1.

Tareas de demostraci on

Se implementaron tres tareas de demostraci on. vLEDFlaskTask(): Se encarga de generar una forma de onda cuadrada de 10Hz. vLCDUpdateTask(): Es la encargada de inicializar y actualizar el m odulo LCD con la cantidad de tareas en ejecuci on y el estado de la tarea vLEDFlashTask. vToggleTask(): Es la encargada de revisar el estado del pulsador y suspender o reanudar seg un corresponda a la tarea vLEDFlashTask() luego de la inicializaci on. A continuaci on se puede ver la simulaci on en Proteus Isis del c odigo compilado del ejemplo.

Figura 5.1: Simulaci on en Proteus Isis. 14

Figura 5.2: Analizador l ogico de Proteus Isis reportando los 10Hz requeridos. En la demostraci on puede verse que el LCD reporta cuatro tareas independientemente de que vLEDFlashTask() se encuentre suspendida o no, esto es debido a que la tarea suspendida no fue eliminada ya que no se llam o a vTaskDelete(). Tambi en se debe tener en cuenta la existencia de la tarea idleTask. Adem as el Analizador L ogico reporta con una resoluci on de 25s el cumplimiento del requerimiento de frecuencia sobre el pin PD0.

5.1.2.

C odigo Fuente

El c odigo fuente del driver LCD utilizado en esta demostraci on se encuentra en el Ap endice A, E y F. tasks.c En este archivo se denen las tareas del RTOS. /* * tasks . c * * Creado : 26/01/2012 20:42:25 * Autor : nikosamus */ # include < avr / pgmspace .h > // FreeRTOS # include " FreeRTOS . h " # include " task . h " // Drivers # include " lcd_lib . h " # include " led_lib . h " # include " boton_lib . h " // Header # include " tasks . h " // Tarea encargada de generar la onda cuadrada de 10 Hz // TICK TAREA TOGGLE 15

// 1000 / 50 / 2 = 10 Hz void vLEDFlashTask ( void * pvParameters ) { portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; LEDInit () ; for ( ;; ) { LEDToggle (0) ; vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } } // Tarea encargada de actualizar el LCD void vLCDUpdateTask ( void * pvParameters ) { // Cadenas almacenadas en ROM static const uint8_t titulo [] PROGMEM = " FreeRTOS & DriverLCD " ; static const uint8_t sidi [] PROGMEM = " Sistemas Digitales " ; static const uint8_t tareas [] PROGMEM = " TAREAS : " ; static const uint8_t strVLED [] PROGMEM = " vLEDFlashTask : " ; // Armado de la base de tiempo portTickType xLastWakeTime ; const portTickType xFrequency = 500; xLastWakeTime = xTask GetTic kCount () ; unsigned portBASE_TYPE uxTasks ; // Inicializacion del LCD LCDinit () ; LCDclr () ; LCDcursorOFF () ; CopyStringtoLCD ( titulo , 0 , 0) ; CopyStringtoLCD ( sidi , 0 , 1) ; CopyStringtoLCD ( tareas , 0 , 2) ; CopyStringtoLCD ( strVLED , 0 , 3) ; // Ejecutar siempre que la tarea este en tiempo de ejecucion for (;;) { // Obtener cantidad de tareas y visualizarlas uxTasks = u x T a s k G e t N u m b e r O f T a s k s () ; LCDGotoXY (13 ,2) ; LCDsendChar ( uxTasks +48) ; LCDGotoXY (15 ,3) ; // Si la tarea esta suspendida mostrar " SUSP " y si esta corriendo " RUN " if ( x T as k I s T a s k S u s p e n d e d ( x L E D F l a s h T a s k H a n d l e r ) ) { LCDstring ( " SUSP " ,4) ; } else { LCDstring ( " RUN " ,4) ; } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } } // Tarea que monitorea el pulsador y cambia el estado de la tarea vLEDFlashTask void vToggleTask ( void * pvParameters ) { // Base de tiempo portTickType xLastWakeTime ; const portTickType xFrequency = 200; xLastWakeTime = xTask GetTic kCount () ; unsigned portBASE_TYPE ; // Inicializar boton

16

BOTONInit () ; // Ejecutar siempre que la tarea este en tiempo de ejecucion for (;;) { if ( BOTONCheckPin (0) ) { // Cambiar el estado de la tarea segun su estado actual if ( xT a s k I s T a s k S u s p e n d e d ( x L E D F l a s h T a s k H a n d l e r ) ) { vTaskResume ( x L E D F l a s h T a s k H a n d l e r ) ; } else { vTaskSuspend ( x L E D F l a s h T a s k H a n d l e r ) ; } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; // Debounce : No seguir hasta que se detecte el flanco bajo while ( BOTONCheckPin (0) ) { } } } }

main.c En este archivo se inicializa el RTOS y se instancian las tareas. /* * main . c * Demostracion de Driver LCD * Creado : 02/02/2012 17:22:09 * Autor : nikosamus */ # include # include # include # include < avr / io .h > " FreeRTOS . h " " task . h " " tasks . h "

/* Prioridades de las Tareas */ # define m a i n L C D _ T O G G L E _ T A S K _ P R I O R I T Y # define m a i n L C D _ U P D A T E _ T A S K _ P R I O R I T Y # define m a i n L C D _ F L A S H _ T A S K _ P R I O R I T Y

( tskIDLE_PRIORITY ) ( tskIDLE_PRIORITY ) +1 ( tskIDLE_PRIORITY ) +2

portSHORT main ( void ) { // Creacion de la tarea de actualizacion del LCD xTaskCreate ( vLCDUpdateTask ,( signed char *) " LCD " , configMINIMAL_STACK_SIZE , NULL , mainLCD_UPDATE_TASK_PRIORITY , NULL ) ; // Creacion de la tarea que genera la onda cuadrada xTaskCreate ( vLEDFlashTask ,( signed char *) " LEDFlash " , configMINIMAL_STACK_SIZE , NULL , mainLCD_FLASH_TASK_PRIORITY , & x L E D F l a s h T a s k H a n d l e r ) ; // Creacion de la tarea que cambia el estado de vLEDFlashTask xTaskCreate ( vToggleTask ,( signed char *) " ToggleTask " , configMINIMAL_STACK_SIZE , NULL , mainLCD_TOGGLE_TASK_PRIORITY , NULL ) ; // Iniciar el Scheduler v Ta s k St ar tS c h ed u l e r () ; // Nunca se debe llegar aqui while (1) { }

17

return 0; }

5.2.

Teclado Matricial Hexadecimal

Se implement o un sistema muy simple en el que se actualiza el LCD con la tecla presionada en el teclado hexadecimal. Este driver fue desarrollado desde cero e incluye una u nica funci on KEYPADGetTeclaPresionada(), que es la encargada de recorrer y vericar el estado de las teclas del teclado matricial y devolver aquella que haya sido presionada. Se simul o el c odigo compilado del ejemplo sobre Proteus Isis utilizando el LCD y una variaci on del teclado KEYPAD-SMALLCALC modicado para que en vez de s mbolos de calculadora muestre los 16 caracteres de la base hexadecimal.

Figura 5.3: Teclado Hexadecimal en Proteus Isis.

5.2.1.

Tareas de demostraci on

Se implementaron dos tareas de demostraci on. vLCDUpdateTask(): Es la encargada de inicializar y actualizar el modulo LCD con la tecla presionada, enviada desde la tarea vKEYPADReadTask. a trav es de una cola. vKEYPADReadTask(): Se encarga de monitorear el teclado y de poner en la cola de comunicaci on entre tareas el caracter asociado a la tecla presionada para su posterior visualizaci on.

5.2.2.

C odigo Fuente

El c odigo fuente de los drivers utilizados en esta demostraci on se encuentran en los Ap endices A y B.

18

tasks.c En este archivo se denen las tareas del RTOS. /* * tasks . c * * Creado : 03/02/2012 20:10:50 * Autor : nikosamus */ # include < avr / pgmspace .h > // RTOS # include " FreeRTOS . h " # include " task . h " # include " queue . h " // Drivers # include " lcd_lib . h " # include " keypad_lib . h " // Tareas # include " tasks . h " static xQueueHandle xQueueKeyPress ; /* Tarea de lectura del teclado , para comunicarse con la tarea de actualizacion del LCD se utiliza una cola */ void vKEYPADReadTask ( void * pvParameters ) { // Ejecutar tarea 20 veces por segundo portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; uint8_t intTecla ; // Creacion de la cola de comunicacion entre tareas xQueueKeyPress = xQueueCreate (1 , sizeof ( uint8_t ) ) ; // Ejecutar siempre que la tarea este en tiempo de ejecucion for (;;) { // Obtener tecla presionada intTecla = K E Y P A D G e t T e c l a P r e s i o n a d a () ; // Si no se recibe un espacio ( ninguna tecla ) , enviar al final de la cola if ( intTecla !=0 x20 ) { xQueueSendToBack ( xQueueKeyPress , & intTecla , 0 ) ; vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } } } // Tarea de incializacion y actualizacion del LCD , muestra la ultima tecla presionada void vLCDUpdateTask ( void * pvParameters ) { // Ejecutar tarea 20 veces por segundo portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; static const uint8_t STR_SIDI [] PROGMEM = " Sistemas Digitales " ; static const uint8_t STR_TITULO [] PROGMEM = " FreeRTOS & Keypad " ; static const uint8_t STR_TECLA [] PROGMEM = " TECLA PRESIONADA : " ; uint8_t in tT ecl aP re si on ad a ;

19

// Inicializar LCD LCDinit () ; LCDclr () ; LCDcursorOFF () ; // Cadenas estaticas CopyStringtoLCD ( STR_SIDI , 0 , 0) ; CopyStringtoLCD ( STR_TITULO , 0 , 1) ; CopyStringtoLCD ( STR_TECLA , 0 , 3) ; // Ejecutar siempre que la tarea este en tiempo de ejecucion for (;;) { // Si hay algun elemento en la cola , visualizarlo en la posicion (19 ,3) if ( xQueueReceive ( xQueueKeyPress , ( void * ) & intTeclaPresionada , 0 ) != pdFAIL ) { LCDGotoXY (19 ,3) ; LCDsendChar ( i nt Te cl aPr es io na da ) ; } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } }

main.c En este archivo se inicializa el RTOS y se instancian las tareas. /* * main . c * * Creado : 03/02/2012 20:02:33 * Autor : nikosamus */ # include < avr / io .h > // FreeRTOS # include " FreeRTOS . h " # include " task . h " # include " queue . h " // Header # include " tasks . h " /* Prioridades de las Tareas */ # define m a i n L C D _ U P D A T E _ T A S K _ P R I O R I T Y # define m a i n K E Y P A D _ R E A D _ T A S K _ P R I O R I T Y

( tskIDLE_PRIORITY ) ( tskIDLE_PRIORITY )

portSHORT main ( void ) { // Crear tarea : vKEYPADReadTask mayor prioridad xTaskCreate ( vKEYPADReadTask , ( signed char * ) " KEYPAD " , configMINIMAL_STACK_SIZE , NULL , mainKEYPAD_READ_TASK_PRIORITY , NULL ); // Crear tarea : vLCDUpdateTask xTaskCreate ( vLCDUpdateTask , ( signed char * ) " LCD " , configMINIMAL_STACK_SIZE , NULL , mainLCD_UPDATE_TASK_PRIORITY , NULL ); // Iniciar el Scheduler v Ta s k St ar tS c h ed u l e r () ; // Nunca se debe llegar aqui

20

while (1) { } return 0; }

5.3.

Conversor Anal ogico Digital

Se implement o un sistema encargado de tomar muestras de las tres primeras entradas del conversor anal ogico digital (PORTA) y visualizar sus valores en el LCD. Se congur o el conversor para utilizar una resoluci on de 10 bits. Para la visualizaci on adecuada de los valores de la conversi on, es decir, su conversi on de valores entre 0 y 1024 a valores entre 0 y 5V se us o la funci on LCDInt162String() que utiliza c alculos de punto jo. Este driver fue desarrollado desde cero, dispone de las funciones ADCInit() que es la encargada de inion. cializar el perif erico y ADCGetSample(pin adc) que es la que realiza y devuelve la conversi Se simul o el c odigo compilado del ejemplo utilizando Proteus Isis. Se conectaron tres potenci ometros a las tres primeras entradas del PORTA y a los valores de referencia de alimentaci on (VCC y GND). Tambi en se incorpor o un LCD para visualizar el resultado de las conversiones.

Figura 5.4: Conversor Anal ogico/Digital en Proteus Isis.

5.3.1.

Tareas de demostraci on

Se implementaron dos tareas de demostraci on. vLCDUpdateTask():Se encarga de inicializar y actualizar el modulo LCD con los valores de las conversiones realizadas por vADCSampleTask. vADSampleTask(): Esta tarea realiza las conversiones anal ogico/digitales. Hace uso de una cola para comunicarlas a la tarea de visualizaci on vLCDUpdateTask() y tambi en de un sem aforo para 21

indicar que se encuentra realizando una conversi on. Si se implementara otra tarea que hiciera uso del conversor ADC esta podr a chequear, antes de intentar una conversi on, que el sem aforo se encuentre libre y tomarlo para no pisarse con la primer tarea.

5.3.2.

C odigo Fuente

El c odigo fuente de los drivers utilizados en esta demostraci on se encuentra en los Ap endices A y C. tasks.c En este archivo se denen las tareas que del RTOS. /* * tasks . c * * Creado : 03/02/2012 20:10:50 * Autor : nikosamus */ # include < avr / pgmspace .h > // RTOS # include " FreeRTOS . h " # include " task . h " # include " queue . h " # include " semphr . h " // Drivers # include " lcd_lib . h " # include " adc_lib . h " // Tareas # include " tasks . h " // Cola de comunicacion entre tareas static xQueueHandle xQueueADCSample ; // Semaforo para tomar control del ADC static xSemaphoreHandle x Se m a ph o r eA D C Sa m p le ; /* Tarea de muestreo del ADC , se comunica con la tarea de actualizacion del LCD por medio de una cola y usa un semaforo para indicar que esta usando el ADC */ void vADCSampleTask ( void * pvParameters ) { // Ejecutar 1/3 de tarea 20 veces por segundo algo como tarea : 6 ,3 veces por segundo . portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; ADCSample ADCMuestra ; // Enum para no usar numeros magicos enum intEntradas { iADC0 , iADC1 , iADC2 , iADC3 , iADC4 , iADC5 , iADC6 , iADC7 }; // Inicializacion de variables y Drivers v S e m a p h o r e C r e a t e B i n a r y ( x S e ma p h or e A DC S a mp l e ) ; xQueueADCSample = xQueueCreate (3 , sizeof ( ADCSample ) ) ; ADCInit () ; for (;;) { // Lectura de los primeros 3 ADC del microcontrolador for ( uint8_t intInput = iADC0 ; intInput < iADC3 ; intInput ++) { // Intento tomar el semaforo para ganar acceso al ADC if ( xSe m a ph o r eA D C Sa m p le != NULL ) { if ( xSemaphoreTake ( xSemaphoreADCSample ,( portTickType ) 10) == pdTRUE ){ // Toma de la muestra ADCMuestra = ADCGetSample ( intInput ) ;

22

// Envio a la cola de comunicacion entre tareas xQueueSend ( xQueueADCSample , & ADCMuestra , 0 ) ; // Devuelvo el semaforo xSemaphoreGive ( x Se m a ph o r eA D C Sa m p le ) ; } } // Incluyendo el delay entre conversiones aumenta muchisimo el rendimiento ya que se puede borrar algun elemento de la cola al llamar a vLCDUpdateTask () entre conversiones vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } } } // Tarea de incializacion y actualizacion del LCD con los valoread adquiridos por vADCSampleTask () void vLCDUpdateTask ( void * pvParameters ) { // Ejecutar tarea 100 veces por segundo portTickType xLastWakeTime ; const portTickType xFrequency = 10; static const uint8_t STR_TITULO [] PROGMEM = " FreeRTOS & ADC "; static const uint8_t STR_ADC [] PROGMEM = " Ch : Valor : " ; ADCSample adcSample ; xLastWakeTime = xTask GetTic kCount () ; // Inicializar LCD LCDinit () ; LCDclr () ; LCDcursorOFF () ; // Cadenas estaticas CopyStringtoLCD ( STR_TITULO , CopyStringtoLCD ( STR_ADC , 0 , CopyStringtoLCD ( STR_ADC , 0 , CopyStringtoLCD ( STR_ADC , 0 ,

0 , 0) ; 1) ; 2) ; 3) ;

// Ejecutar siempre que la tarea se encuentre en tiempo de ejecucion for (;;) { // Si hay una conversion ADC en la cola , visualizarla if ( xQueueReceive ( xQueueADCSample , ( void * ) & adcSample , 0 ) != pdFAIL ) { // Visualizar el pin en el que se realizo la conversion . LCDGotoXY (3 , adcSample . Pin +1) ; LCDsendChar ( adcSample . Pin +48) ; // Visualizar el valor de la conversion ajustado para que la representacion coincida con el rango del conversor . LCDGotoXY (11 , adcSample . Pin +1) ; adcSample . Value = adcSample . Value *50000/1024; LCDInt162String ( adcSample . Value ,1 , ' V ' ) ; } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } }

main.c En este archivo se inicializa el RTOS y se instancian las tareas. /* * main . c * * Creado : 03/02/2012 20:02:33

23

* Autor : nikosamus */ # include < avr / io .h > // FreeRTOS # include " FreeRTOS . h " # include " queue . h " # include " task . h " // Header # include " tasks . h "

/* Prioridades de las Tareas */ # define m a i n A D C _ R E A D _ T A S K _ P R I O R I T Y # define m a i n L C D _ U P D A T E _ T A S K _ P R I O R I T Y portSHORT main ( void ) { xTaskCreate ( vADCSampleTask , configMINIMAL_STACK_SIZE , xTaskCreate ( vLCDUpdateTask , configMINIMAL_STACK_SIZE , ); // Iniciar el Scheduler v Ta s k St ar tS c h ed u l e r () ; // Nunca debe llegar aqui while (1) { } return 0; }

( tskIDLE_PRIORITY ) +1 ( tskIDLE_PRIORITY )

( signed char * ) " KEYPAD " , NULL , mainADC_READ_TASK_PRIORITY , NULL ) ; ( signed char * ) " LCD " , NULL , mainLCD_UPDATE_TASK_PRIORITY , NULL

5.4.

Puerto Serie

En esta demostraci on se estableci o una comunicaci on entre la PC y el microcontrolador de modo tal que al iniciarse, el microcontrolador salude a la PC con el mensaje: Demostracion del puerto serie con FreeRTOS, luego cada vez que la PC env e una cadena, el microcontrolador le responder a con tres mensajes: Recibiendo cadena. Un echo de la cadena enviada. Cadena recibida. Y escribir a una l nea con el mensaje en el display LCD. Se opt o por usar el driver para puerto serie lib serial.c distribu do como parte de FreeRTOS. Esta librer a se distribuye bajo la licencia GNU Public License con la excepci on FreeRTOS descrita en el Ap endice D. Para la demostraci on del puerto serie en Porteus Isis se us o el conector COMPIM (Comm Port Physical Interface Model) conectado al puerto virtual COM4 creado con el software Virtual Serial Port Emulator en modalidad connector. Este puerto serie puede ser abierto dos veces, es decir, dos aplicaciones distintas pueden abrirlo simult aneamente para generar una comunicaci on entre ellas. En este caso, las aplicaciones fueron Terminal.exe y Proteus Isis.

24

Figura 5.5: Simulaci on en Proteus Isis en comunicaci on con la terminal.

Figura 5.6: Terminal conectada al puerto serie virtual compartido.

25

5.4.1.

Tareas de demostraci on

Se implementaron dos tareas de demostraci on. vLCDUpdateTask(): Es la tarea encargada de inicializar, y actualizar el modulo LCD con la cadena recibida por vSERIALCommTask(). vSERIALCommTask(): Esta tarea se encarga de recibir la cadena enviada por la PC a trav es del puerto serie y transmitirla a la tarea vLCDUpdateTask() por medio de una cola.

5.4.2.

C odigo Fuente

El c odigo fuente de los drivers utilizados en esta demostraci on se encuentra en los Ap endices A y D. tasks.c En este archivo se denen las tareas del RTOS. /* * tasks . c * * Creado : 03/02/2012 20:10:50 * Autor : nikosamus */ # include < avr / pgmspace .h > // RTOS # include " FreeRTOS . h " # include " task . h " # include " queue . h " // Drivers # include " lcd_lib . h " # include " lib_serial . h " // Tareas # include " tasks . h " /* Cola de comunicacion entre tareas */ static xQueueHandle xQueueSerialComm ; /* Manejador del puerto serie . Requerido por el driver */ xComPortHandle xSerialPort ; // Tarea de recepcion de caracteres por el puerto serie ; // Los guarda en una cola para comunicarlos a la tarea de actualizacion del LCD . void vSerialCommTask ( void * pvParameters ) { // Ejecutar la tarea 20 veces por segundo . portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; uint8_t cRxedChar ; // Driver USART : Baudios (57600 por restriccion de Isis ) , Tamano de la cola de envio , Tamano de la cola de recepcion // Iniciar Driver Serie xSerialPort = x S e r i a l P o r t I n i t M i n i m a l ( 57600 , 80 , 16) ; // Crear una cola para 16 caracteres xQueueSerialComm = xQueueCreate (16 , sizeof ( uint8_t ) ) ; // Bienvenida avrSerialPrint_P ( PSTR ( " \ rDemostracion del puerto serie con FreeRTOS \ r " )); // Ejecutar siempre que la tarea este en tiempo de ejecucion 26

for (;;) { // Recibir caracter inicial while ( xSerialGetChar ( xSerialPort , & cRxedChar , xNoBlock ) ) { // Si se recibe un caracter mandar mensaje avrSerialPrint_P ( PSTR ( " \ rRecibiendo cadena \ r " ) ) ; // Devolver el caracter avrSerialWrite ( cRxedChar ) ; // Poner el caracter en la cola para mostrarlo en el LCD xQueueSend ( xQueueSerialComm , & cRxedChar , 0 ) ; // Recibir el resto de los caracteres while ( xSerialGetChar ( xSerialPort , & cRxedChar , xNoBlock ) ) { // Devolver el caracter avrSerialWrite ( cRxedChar ) ; // Poner el caracter en la cola para mostrarlo en el LCD xQueueSend ( xQueueSerialComm , & cRxedChar , 0 ) ; } // Mensaje de fin de transmision avrSerialPrint_P ( PSTR ( " \ rCadena recibida \ r " ) ) ; } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } } /* Tarea de actulizacion del LCD , lee la cola de comunicacion entre tareas y escribe una linea en el LCD . No se soluciono intencionalmente el problema de la delimitacion de las lineas recibidas en la cola para mostrar el efecto de la interrupcion de la tarea vLCDUpdateTask cuando aun quedan caracteres por recibir y se agregan nuevos al final de la cola */ void vLCDUpdateTask ( void * pvParameters ) { // Ejecutar la tarea 20 veces por segundo . portTickType xLastWakeTime ; const portTickType xFrequency = 50; xLastWakeTime = xTask GetTic kCount () ; static const uint8_t STR_TITULO [] PROGMEM = " freeRTOS & Serial " ; static uint8_t charSerialRX ; static uint8_t intColumnaLcd =0 , intFilaLcd =1; // Inicializar LCD LCDinit () ; LCDclr () ; LCDcursorOFF () ; // Cadenas estaticas CopyStringtoLCD ( STR_TITULO , 0 , 0) ; // Ejecuar siempre que la tarea este en tiempo de ejecucion for (;;) { LCDGotoXY (0 , intFilaLcd ) ; intColumnaLcd =3; // Mientras halla caracteres en la cola y no se supere el largo de la linea , visualizarlos . while ( xQueueReceive ( xQueueSerialComm , ( void * ) & charSerialRX , xNoBlock ) != pdFAIL && intColumnaLcd <20) { LCDsendChar ( intFilaLcd +48) ; LCDstring ( " : " ,2) ; LCDsendChar ( charSerialRX ) ; intColumnaLcd ++; // Mientras halla caracteres en la cola y no se supere el largo de

27

la linea , visualizarlos . while ( xQueueReceive ( xQueueSerialComm , ( void * ) & charSerialRX , xNoBlock ) != pdFAIL && intColumnaLcd <20) { LCDsendChar ( charSerialRX ) ; intColumnaLcd ++; } // Si se encuentra en la ultima fila volver a la segunda if ( intFilaLcd >2) { intFilaLcd =1; } else { intFilaLcd ++; } } vTaskDelayUntil (& xLastWakeTime , xFrequency ) ; } }

main.c En este archivo se inicializa el RTOS y se instancian las tareas. /* * main . c * * Creado : 03/02/2012 20:02:33 * Autor : nikosamus */ # include # include # include # include # include < avr / io .h > " FreeRTOS . h " " task . h " " tasks . h " " queue . h "

/* Prioridades de las Tareas */ # define m a i n S E R I A L _ C O M M _ T A S K _ P R I O R I T Y ( tskIDLE_PRIORITY ) +1 # define m a i n L C D _ U P D A T E _ T A S K _ P R I O R I T Y ( tskIDLE_PRIORITY ) portSHORT main ( void ) { xTaskCreate ( vSerialCommTask , ( signed char * ) " SERIAL " , configMINIMAL_STACK_SIZE , NULL , mainSERIAL_COMM_TASK_PRIORITY , NULL ); xTaskCreate ( vLCDUpdateTask , ( signed char * ) " LCD " , configMINIMAL_STACK_SIZE , NULL , mainLCD_UPDATE_TASK_PRIORITY , NULL ); // Iniciar el Scheduler v Ta s k St ar tS c h ed u l e r () ; // Nunca se debe llegar aqui while (1) { } return 0; }

5.5.

Leds y Botones

Se escribieron dos peque nas y muy b asicas librer as para la depuraci on y la interacci on con el microcontrolador. Se decidi o darles esta entidad y no simplemente intercalar el c odigo que ejecutan dentro de las tareas y/o los drivers para mantener un c odigo prolijo y segmentado seg un su funci on. Ser a bueno en un futuro combinar ambas librer as y generar una que sea capaz de congurar libremente todos los pines de un

28

puerto como entradas o salidas. La librer a led lib.c s olo dispone de dos m etodos; LEDInit() para inicializar el puerto al que se encuentran conectados los leds y LEDTogle(nro pin) que invierte el valor actual del pin seleccionado. La librer a boton lib.c tambi en dispone de dos m etodos BOTONInit() que inicializa el puerto y BOTONCheckPin(nro pin) que devuelve el valor actual del pin seleccionado. Estas librer as se encuentran disponibles en los Ap endices E y F.

29

Ap endice A Librer a para Display LCD

A.1.

lcd lib.h

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // File Name : ' lcd_lib . h ' // Title : 8 and 4 bit LCd interface // Author : Scienceprog . com - Copyright ( C ) 2007 // Created : 2007 -03 -29 // Revised : 2007 -08 -08 // Version : 1.0 // Target MCU : Atmel AVR series // // This code is distributed under the GNU Public License // which can be found at http :// www . gnu . org / licenses / gpl . txt // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # ifndef LIB_LCD_H_ # define LIB_LCD_H_ # include < inttypes .h > # include " hardwareConfig . h " // Uncomment this if LCD 4 bit interface is used // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # define LCD_4bit // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # define # define # define # define # define # define # define # define # define # define # define LCD_RS LCD_RW LCD_E 2 LCD_D0 LCD_D1 LCD_D2 LCD_D3 LCD_D4 LCD_D5 LCD_D6 LCD_D7 0 // define MCU pin connected to LCD RS 1 // define MCU pin connected to LCD R / W // define MCU pin connected to LCD E 0 // define MCU pin connected to LCD D0 1 // define MCU pin connected to LCD D1 2 // define MCU pin connected to LCD D1 3 // define MCU pin connected to LCD D2 4 // define MCU pin connected to LCD D3 5 // define MCU pin connected to LCD D4 6 // define MCU pin connected to LCD D5 7 // define MCU pin connected to LCD D6 // define MCU port connected to LCD // define MCU port connected to LCD // define MCU direction register for

# define LDP c o n fi g L CD _ D AT A _ PO R T data pins # define LCP c o n f i g L C D _ C O N T R O L _ P O R T control pins # define LDDR co nf ig LC D_ DA TA _R EG port connected to LCD data pins

30

# define LCDR c o n f i g L C D _ C O N T R O L _ R E G // define MCU direction register for port connected to LCD control pins # define LCD_CLR 0 // DB0 : clear display # define LCD_HOME 1 // DB1 : return to home position # define LCD_ENTRY_MODE 2 // DB2 : set entry mode # define LCD_ENTRY_INC 1 // DB1 : increment # define LCD_ENTRY_SHIFT 0 // DB2 : shift # define LCD_ON_CTRL 3 // DB3 : turn lcd / cursor on # define LCD_ON_DISPLAY 2 // DB2 : turn display on # define LCD_ON_CURSOR 1 // DB1 : turn cursor on # define LCD_ON_BLINK 0 // DB0 : blinking cursor # define LCD_MOVE 4 // DB4 : move cursor / display # define LCD_MOVE_DISP 3 // DB3 : move display (0 - > move cursor ) # define LCD_MOVE_RIGHT 2 // DB2 : move right (0 - > left ) # define LCD_FUNCTION 5 // DB5 : function set # define LCD_F UNCTIO N_8BIT 4 // DB4 : set 8 BIT mode (0 - >4 BIT mode ) # define L CD _F U N CT I O N_ 2 L IN E S 3 // DB3 : two lines (0 - > one line ) # define L CD _F U N CT I O N_ 1 0 DO T S 2 // DB2 : 5 x10 font (0 - >5 x7 font ) # define LCD_CGRAM 6 // DB6 : set CG RAM address # define LCD_DDRAM 7 // DB7 : set DD RAM address // reading : # define LCD_BUSY 7 // DB7 : LCD is busy # define LCD_LINES 4 // visible lines # define LCD_LINE_LENGTH 20 // line length ( in characters ) // cursor position to DDRAM mapping # define L CD _L I N E0 _ D DR A M AD D R 0 x00 # define L CD _L I N E1 _ D DR A M AD D R 0 x40 # define L CD _L I N E2 _ D DR A M AD D R 0 x14 # define L CD _L I N E3 _ D DR A M AD D R 0 x54 // progress bar defines # define P RO G R E S S P I X E L S _ P E R _ C H A R 6 void LCDInt162String ( uint16_t , uint8_t , uint8_t ) ; void LCDsendChar ( uint8_t ) ; // forms data ready to send to LCD void LCDsendCommand ( uint8_t ) ; // forms data ready to send to LCD void LCDinit ( void ) ; // Initializes LCD void LCDclr ( void ) ; // Clears LCD void LCDhome ( void ) ; // LCD cursor home void LCDstring ( uint8_t * , uint8_t ) ; // Outputs string to LCD void LCDGotoXY ( uint8_t , uint8_t ) ; // Cursor to X Y position void CopyStringtoLCD ( const uint8_t * , uint8_t , uint8_t ) ; // copies flash string to LCD at x , y void LCDdefinechar ( const uint8_t * , uint8_t ) ; // write char to LCD CGRAM void LCDshiftRight ( uint8_t ) ; // shift by n characters Right void LCDshiftLeft ( uint8_t ) ; // shift by n characters Left void LCDcursorOn ( void ) ; // Underline cursor ON void LCDcursorOnBlink ( void ) ; // Underline blinking cursor ON void LCDcursorOFF ( void ) ; // Cursor OFF void LCDblank ( void ) ; // LCD blank but not cleared void LCDvisible ( void ) ; // LCD visible void LCDcursorLeft ( uint8_t ) ; // Shift cursor left by n void LCDcursorRight ( uint8_t ) ; // shif cursor right by n // displays a horizontal progress bar at the current cursor location // < progress > is the value the bargraph should indicate // < maxprogress > is the value at the end of the bargraph // < length > is the number of LCD characters that the bargraph should cover // adapted from AVRLIB - displays progress only for 8 bit variables void LCDprogressBar ( uint8_t progress , uint8_t maxprogress , uint8_t length ) ;

31

# endif /* LIB_LCD_H_ */

A.2.

lcd lib.c

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // File Name : ' lcd_lib . c ' // Title : 8 and 4 bit LCd interface // Author : Scienceprog . com - Copyright ( C ) 2007 // Created : 2007 -03 -29 // Revised : 2007 -08 -08 // Version : 1.0 // Target MCU : Atmel AVR series // // This code is distributed under the GNU Public License // which can be found at http :// www . gnu . org / licenses / gpl . txt // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # include < inttypes .h > # include < avr / io .h > # include < avr / pgmspace .h > # include < util / delay .h > # include " lcd_lib . h " /* Metodo para escribir un nummero de 16 bits como cadena * Autor : nikosamus */ void LCDInt162String ( uint16_t intValor , uint8_t intFixedPoint , uint8_t charSuffix ) { uint8_t dmilesimas =0 , milesimas =0 , centesimas =0 , decimas =0 , unidades =0; while ( intValor >10000) { intValor -= 10000; dmilesimas ++; } while ( intValor >1000) { intValor -= 1000; milesimas ++; } while ( intValor >100) { intValor -= 100; centesimas ++; } while ( intValor >10) { intValor -= 10; decimas ++; } while ( intValor >1) { intValor -= 1; unidades ++; } if ( intFixedPoint ==0) { LCDsendChar ( ' 0 ' ) ; LCDsendChar ( ' , ' ) ;} if ( milesimas != ' x ' ) { LCDsendChar ( dmilesimas +48) ; } if ( intFixedPoint ==1) { LCDsendChar ( ' , ' ) ;} if ( milesimas != ' x ' ) { LCDsendChar ( milesimas +48) ; } 32

if ( intFixedPoint ==2) { LCDsendChar ( ' , ' ) ;} if ( centesimas != ' x ' ) { LCDsendChar ( centesimas +48) ; } if ( intFixedPoint ==3) { LCDsendChar ( ' , ' ) ;} if ( decimas != ' x ' ) { LCDsendChar ( decimas +48) ; } if ( intFixedPoint ==4) { LCDsendChar ( ' , ' ) ;} if ( unidades != ' x ' ) { LCDsendChar ( unidades +48) ; } if ( charSuffix !=0 xFF ) { LCDsendChar ( charSuffix ) ; } } const uint8_t { 0 x00 , 0 x1F , progress 0 x00 , 0 x1F , progress 0 x00 , 0 x1F , progress 0 x00 , 0 x1F , progress 0 x00 , 0 x1F , progress 0 x00 , 0 x1F , progress 0 x03 , 0 x07 , 0 x18 , 0 x1C , arrow }; LcdCustomChar [] PROGMEM = // define 8 custom LCD chars 0 x00 , block 0 x10 , block 0 x18 , block 0 x1C , block 0 x1E , block 0 x1F , block 0 x0F , 0 x1E , 0 x00 , 0 x00 , 0 x00 , 0 x1F , 0 x00 , // 0. 0/5 full 0 x10 , 0 x10 , 0 x10 , 0 x1F , 0 x00 , // 1. 1/5 full 0 x18 , 0 x18 , 0 x18 , 0 x1F , 0 x00 , // 2. 2/5 full 0 x1C , 0 x1C , 0 x1C , 0 x1F , 0 x00 , // 3. 3/5 full 0 x1E , 0 x1E , 0 x1E , 0 x1F , 0 x00 , // 4. 4/5 full 0 x1F , 0 x1F , 0 x1F , 0 x1F , 0 x00 , // 5. 5/5 full 0 x1F , 0 x0F , 0 x07 , 0 x03 , 0 x00 , // 6. rewind arrow 0 x1F , 0 x1E , 0 x1C , 0 x18 , 0 x00 // 7. fast - forward

void LCDsendChar ( uint8_t ch ) { # ifdef LCD_4bit // 4 bit part LDP =( ch &0 b11110000 ) ; LCP |=1 < < LCD_RS ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; LCP &=~(1 < < LCD_RS ) ; _delay_ms (1) ; LDP =(( ch &0 b00001111 ) < <4) ; LCP |=1 < < LCD_RS ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; LCP &=~(1 < < LCD_RS ) ; _delay_ms (1) ; # else // 8 bit part LDP = ch ; LCP |=1 < < LCD_RS ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ;

// Sends Char to LCD

33

LCP &=~(1 < < LCD_RS ) ; _delay_ms (1) ; # endif } void LCDsendCommand ( uint8_t cmd ) // Sends Command to LCD { # ifdef LCD_4bit // 4 bit part LDP =( cmd &0 b11110000 ) ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; LDP =(( cmd &0 b00001111 ) < <4) ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; # else // 8 bit part LDP = cmd ; LCP |=1 < < LCD_E ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; # endif } void LCDinit ( void ) // Initializes LCD { # ifdef LCD_4bit // 4 bit part _delay_ms (15) ; LDP =0 x00 ; LCP =0 x00 ; LDDR |=1 < < LCD_D7 |1 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 ; LCDR |=1 < < LCD_E |1 < < LCD_RW |1 < < LCD_RS ; // - -- -- -- -- one - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 ; // 4 bit mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // - - - - - - - - - - - two - - - - - - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 ; // 4 bit mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // ------- three - - - - - - - - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |0 < < LCD_D4 ; // 4 bit mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // - - - - - - - -4 bit - - dual line - - - - - - - - - - - - - - LCDsendCommand (0 b00101000 ) ; // ----- increment address , invisible cursor shift - - - - - LCDsendCommand (0 b00001100 ) ; // init 8 custom chars uint8_t ch =0 , chn =0; while ( ch <64) {

34

LCDdefinechar (( LcdCustomChar + ch ) , chn ++) ; ch = ch +8; }

# else // 8 bit part _delay_ms (15) ; LDP =0 x00 ; LCP =0 x00 ; LDDR |=1 < < LCD_D7 |1 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 |1 < < LCD_D3 |1 < < LCD_D2 |1 < < LCD_D1 |1 < < LCD_D0 ; LCDR |=1 < < LCD_E |1 < < LCD_RW |1 < < LCD_RS ; // - -- -- -- -- one - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 |0 < < LCD_D3 |0 < < LCD_D2 |0 < < LCD_D1 |0 < < LCD_D0 ; // 8 it mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // - - - - - - - - - - - two - - - - - - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 |0 < < LCD_D3 |0 < < LCD_D2 |0 < < LCD_D1 |0 < < LCD_D0 ; // 8 it mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // ------- three - - - - - - - - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 |0 < < LCD_D3 |0 < < LCD_D2 |0 < < LCD_D1 |0 < < LCD_D0 ; // 8 it mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // - - - - - - - -8 bit dual line - - - - - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |1 < < LCD_D5 |1 < < LCD_D4 |1 < < LCD_D3 |0 < < LCD_D2 |0 < < LCD_D1 |0 < < LCD_D0 ; // 8 it mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (1) ; // ----- increment address , invisible cursor shift - - - - - LDP =0 < < LCD_D7 |0 < < LCD_D6 |0 < < LCD_D5 |0 < < LCD_D4 |1 < < LCD_D3 |1 < < LCD_D2 |0 < < LCD_D1 |0 < < LCD_D0 ; // 8 it mode LCP |=1 < < LCD_E |0 < < LCD_RW |0 < < LCD_RS ; _delay_ms (1) ; LCP &=~(1 < < LCD_E ) ; _delay_ms (5) ; // init custom chars uint8_t ch =0 , chn =0; while ( ch <64) { LCDdefinechar (( LcdCustomChar + ch ) , chn ++) ; ch = ch +8; } # endif } void LCDclr ( void ) // Clears LCD { LCDsendCommand (1 < < LCD_CLR ) ; }

35

void LCDhome ( void ) // LCD cursor home { LCDsendCommand (1 < < LCD_HOME ) ; } void LCDstring ( uint8_t * data , uint8_t nBytes ) // Outputs string to LCD { register uint8_t i ; // check to make sure we have a good pointer if (! data ) return ; // print data for ( i =0; i < nBytes ; i ++) { LCDsendChar ( data [ i ]) ; } } void LCDGotoXY ( uint8_t x , uint8_t y ) // Cursor to X Y position { register uint8_t DDRAMAddr ; // remap lines into proper order switch ( y ) { case 0: DDRAMAddr = L CD _ L IN E 0 _D D R AM A D DR + x ; break ; case 1: DDRAMAddr = L CD _ L IN E 1 _D D R AM A D DR + x ; break ; case 2: DDRAMAddr = L CD _ L IN E 2 _D D R AM A D DR + x ; break ; case 3: DDRAMAddr = L CD _ L IN E 3 _D D R AM A D DR + x ; break ; default : DDRAMAddr = L CD _ L IN E 0 _D D R AM A D DR + x ; } // set data address LCDsendCommand (1 < < LCD_DDRAM | DDRAMAddr ) ; } // Copies string from flash memory to LCD at x y position // const uint8_t welcomeln1 [] PROGMEM =" AVR LCD DEMO \0"; // CopyStringtoLCD ( welcomeln1 , 3 , 1) ; void CopyStringtoLCD ( const uint8_t * FlashLoc , uint8_t x , uint8_t y ) { uint8_t i ; LCDGotoXY (x , y ) ; for ( i =0;( uint8_t ) pgm_read_byte (& FlashLoc [ i ]) ; i ++) { LCDsendChar (( uint8_t ) pgm_read_byte (& FlashLoc [ i ]) ) ; } } // defines char symbol in CGRAM /* const uint8_t backslash [] PROGMEM = { 0 b00000000 ,// back slash 0 b00010000 , 0 b00001000 , 0 b00000100 , 0 b00000010 , 0 b00000001 , 0 b00000000 , 0 b00000000 }; LCDdefinechar ( backslash ,0) ; */ void LCDdefinechar ( const uint8_t * pc , uint8_t char_code ) { uint8_t a , pcc ;

36

uint16_t i ; a =( char_code < <3) |0 x40 ; for ( i =0; i <8; i ++) { pcc = pgm_read_byte (& pc [ i ]) ; LCDsendCommand ( a ++) ; LCDsendChar ( pcc ) ; } } void LCDshiftLeft ( uint8_t n ) // Scrol n of characters Right { for ( uint8_t i =0; i < n ; i ++) { LCDsendCommand (0 x1E ) ; } } void LCDshiftRight ( uint8_t n ) // Scrol n of characters Left { for ( uint8_t i =0; i < n ; i ++) { LCDsendCommand (0 x18 ) ; } } void LCDcursorOn ( void ) // displays LCD cursor { LCDsendCommand (0 x0E ) ; } void LCDcursorOnBlink ( void ) // displays LCD blinking cursor { LCDsendCommand (0 x0F ) ; } void LCDcursorOFF ( void ) // turns OFF cursor { LCDsendCommand (0 x0C ) ; } void LCDblank ( void ) // blanks LCD { LCDsendCommand (0 x08 ) ; } void LCDvisible ( void ) // Shows LCD { LCDsendCommand (0 x0C ) ; } void LCDcursorLeft ( uint8_t n ) // Moves cursor by n poisitions left { for ( uint8_t i =0; i < n ; i ++) { LCDsendCommand (0 x10 ) ; } } void LCDcursorRight ( uint8_t n ) // Moves cursor by n poisitions left { for ( uint8_t i =0; i < n ; i ++) { LCDsendCommand (0 x14 ) ; } } // adapted fro mAVRLIB void LCDprogressBar ( uint8_t progress , uint8_t maxprogress , uint8_t length ) { uint8_t i ;

37

uint16_t pixelprogress ; uint8_t c ; // // // // // draw a progress bar displaying ( progress / maxprogress ) starting from the current cursor position with a total length of " length " characters *** note , LCD chars 0 -5 must be programmed as the bar characters char 0 = empty ... char 5 = full

// total pixel length of bargraph equals length * PROGRESSPIXELS_PER_CHAR ; // pixel length of bar itself is pixelprogress = (( progress *( length * P R O G R E S S P I X E L S _ P E R _ C H A R ) ) / maxprogress ) ; // print exactly " length " characters for ( i =0; i < length ; i ++) { // check if this is a full block , or partial or empty // ( u16 ) cast is needed to avoid sign comparison warning if ( (( i *( uint16_t ) P R O G R E S S P I X E L S _ P E R _ C H A R ) +5) > pixelprogress ) { // this is a partial or empty block if ( (( i *( uint16_t ) P R O G R E S S P I X E L S _ P E R _ C H A R ) ) > pixelprogress ) { // this is an empty block // use space character ? c = 0; } else { // this is a partial block c = pixelprogress % P R O G R E S S P I X E L S _ P E R _ C H A R ; } } else { // this is a full block c = 5; } // write character to display LCDsendChar ( c ) ; } }

38

Ap endice B Librer a para Teclado Matricial Hexadecimal

B.1.

keypad lib.h

/* * keypad_lib . h * * Created : 03/02/2012 20:12:18 * Author : nikosamus */ # ifndef KEYPAD_LIB_H_ # define KEYPAD_LIB_H_ unsigned int K E Y P A D G e t T e c l a P r e s i o n a d a ( void ) ; # endif /* KEYPAD_LIB_H_ */

B.2.

keypad lib.c

/* * keypad_lib . c * * Creado : 03/02/2012 20:12:05 * Autor : nikosamus * */ # include # include # include # include " keypad_lib . h " " hardwareConfig . h " < avr / io .h > < inttypes .h >

unsigned int K E Y P A D G e t T e c l a P r e s i o n a d a () { uint8_t intNumero =0 x20 ; // Enum para evitar numeros magicos enum intElementos { ELE_0 , ELE_1 , ELE_2 , ELE_3 , E_FIN }; // Px0 , Px1 , Px2 y Px3 Filas : entradas en alto ( pullup activado ) // Px4 , Px5 , Px6 y Px7 Columnas : salidas en bajo conf igKEYP AD_PO RT |= 0 x0F ; for ( uint8_t intColumna = ELE_0 ; intColumna != E_FIN ; intColumna ++ ) { // Pongo en bajo todos los pines configKEYPAD_REG &=(0 x00 ) ; // Pongo en alto la columna seleccionada /* Columna 0: 0001 0000 Columna 1: 0010 0000 39

Columna 2: 0100 0000 Columna 3: 1000 0000 */ configKEYPAD_REG |= ( 0 X10 << intColumna ) ; for ( uint8_t intFila = ELE_0 ; intFila != E_FIN ; intFila ++ ) { // Leo la fila seleccionada /* Fila 0: xxxx 0001 Fila 1: xxxx 0010 Fila 2: xxxx 0100 Fila 3: xxxx 1000 */ if (!( configKEYPAD_PIN & (0 x01 << intFila ) ) ) { // Calculo el entero ( de 0 a 15) intNumero = intColumna + intFila *4; // Si esta entre 10 y 15 asigno el caracter ascii entre A y F if ( intNumero <0 x9 ) { intNumero +=48; } else if ( intNumero >0 x9 && intNumero <0 x10 ) { // Si esta entre 0 y 9 asigno el caracter ascii entre 0 y 9 intNumero +=55; } return ( intNumero ) ; } } } return 0 x20 ; // Espacio . No se presiono ninguna tecla }

40

Ap endice C Librer a para Conversor Anal ogico Digital

C.1.

adc lib.h

/* * adc_lib . h * * Created : 04/02/2012 20:59:00 * Author : nikosamus */ # ifndef ADC_LIB_H_ # define ADC_LIB_H_ // Estructura de datos de la conversion typedef struct { uint8_t Pin ; uint16_t Value ; } ADCSample ; void ADCInit ( void ) ; ADCSample ADCGetSample ( uint8_t ) ; uint16_t ADCGetConversion ( void ) ; # endif /* ADC_LIB_H_ */

C.2.

adc lib.c

/* * adc_lib . c * * Created : 04/02/2012 20:58:34 * Author : nikosamus */ # include < inttypes .h > # include < avr / io .h > # include < util / delay .h > // Drivers # include " adc_lib . h " // Configuracion # include " hardwareConfig . h " /* Inicializacion del ADC */ void ADCInit ( void ) { configADC_PORT &= (0 x00 ) ; 41

configADC_REG &= (0 x00 ) ; // Fuente de voltaje externa ADMUX &= (0 < < REFS1 ) | (0 < < REFS0 ) ; // No inciar conversion , no auto trigger , FLAG interrupcion , interrupcion deshabilitada ADCSRA &= ~(1 < < ADSC ) | ~(1 < < ADATE ) | ~(1 < < ADIF ) | ~(1 < < ADIE ) ; // Habilitar ADC , Preescaler = 128 ADCSRA |= (1 < < ADEN ) | (1 < < ADPS2 ) | (1 < < ADPS1 ) | (1 < < ADPS0 ) ; } /* Toma la muestra del ADC y genera un pulso en un LED para control */ ADCSample ADCGetSample ( uint8_t intInput ) { ADCSample adcsSample ; uint8_t tmp = ADMUX ; // Setear la entrada que queremos en el multiplexor tmp &= ~0 x1F ; tmp |= intInput ; ADMUX = tmp ; // Iniciar conversion ADCSRA |= 1 << ADSC ; // Poner el numero de entrada en la estructura de datos adcsSample . Pin = intInput ; // Esperar al fin de conversion while ( ADCSRA & (1 < < ADSC ) ) { _delay_us (30) ; } // Poner el valor de la conversion en la estructura de datos adcsSample . Value = ADC ; // Devolver estructura de datos return adcsSample ; }

42

Ap endice D Librer a para Puerto Serie

D.1.

lib serial.h

/* FreeRTOS V7 .0.1 - Copyright ( C ) 2011 Real Time Engineers Ltd .

********************************************************************* * * * FreeRTOS tutorial books are available in pdf and paperback . * * Complete , revised , and edited pdf reference manuals are also * * available . * * * * Purchasing FreeRTOS documentation will not only help you , by * * ensuring you get running as quickly as possible and with an * * in - depth knowledge of how to use FreeRTOS , it will also help * * the FreeRTOS project to continue with its mission of providing * * professional grade , cross platform , de facto standard solutions * * for microcontrollers - completely free of charge ! * * * * > > > See http :// www . FreeRTOS . org / Documentation for details . <<< * * * * Thank you for using FreeRTOS , and thank you for your support ! * * * *********************************************************************

This file is part of the FreeRTOS distribution . FreeRTOS is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License ( version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception . >>> NOTE < < < The modification to the GPL is included to allow you to distribute a combined work that includes FreeRTOS without being obliged to provide the source code for proprietary components outside of the FreeRTOS kernel . FreeRTOS is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for more details . You should have received a copy of the GNU General Public License and the FreeRTOS license exception along with FreeRTOS ; if not it can be viewed here : http :// www . freertos . org / a00114 . html and also obtained by writing to Richard Barry , contact details for whom are available on the FreeRTOS WEB site . 1 tab == 4 spaces ! http :// www . FreeRTOS . org - Documentation , latest information , license

43

and contact details . http :// www . SafeRTOS . com - A version that is certified for use in safety critical systems . http :// www . OpenRTOS . com - Commercial support , development , porting , licensing and training services . */ # ifndef LIB_SERIAL_H # define LIB_SERIAL_H # ifdef __cplusplus extern " C " { # endif # include < avr / pgmspace .h > /* Constants for writing to UCSR0B . */ # define serRX_INT_ENABLE ( ( uint8_t # define serRX_ENABLE ( ( uint8_t ) # define serTX_ENABLE ( ( uint8_t ) # define serTX_INT_ENABLE ( ( uint8_t

) 0 x80 ) 0 x10 ) 0 x08 ) ) 0 x20 )

/* Constants for writing to UCSR0C . */ # define serUCSRC_SELECT ( ( uint8_t ) 0 x80 ) # define se rE IG HT _D AT A_ BI TS ( ( uint8_t ) 0 x06 ) /* Constant for zero block time on xQueue */ # define xNoBlock ( ( uint8_t ) 0 x00 ) typedef enum { serCOM1 , serCOM2 , serCOM3 , serCOM4 , serCOM5 , serCOM6 , serCOM7 , serCOM8 } eCOMPort ; typedef enum { serNO_PARITY , serODD_PARITY , serEVEN_PARITY , serMARK_PARITY , serSPACE_PARITY } eParity ; typedef enum { serSTOP_1 , serSTOP_2 } eStopBits ; typedef enum { serBITS_5 , serBITS_6 ,

44

serBITS_7 , serBITS_8 } eDataBits ; typedef enum { ser50 , ser75 , ser110 , ser134 , ser150 , ser200 , ser300 , ser600 , ser1200 , ser1800 , ser2400 , ser4800 , ser9600 , ser19200 , ser38400 , ser57600 , ser115200 } eBaud ;

typedef void * xComPortHandle ; /* * Create a handle reference for the ( only ) serial port . * */ extern xComPortHandle xSerialPort ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // xSerialPrintf_P ( PSTR ("\ r \ nMessage %u %u %u ") , var1 , var2 , var2 ) ; /* * * Serial printf . * @param format printf format string . */ void xSerialPrintf ( char * format , ...) ; /* * * Serial printf from PROGMEM to the serial port . * @param format printf format string . */ void xSerialPrintf_P ( PGM_P format , ...) ; /* * * Print a character string to the serial port . * @param str string to print . */ void xSerialPrint ( char * str ) ; /* * * Print a character string from PROGMEM to the serial port . * @param str string to print . */ void xSerialPrint_P ( PGM_P str ) ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

45

xComPortHandle x S e r i a l P o r t I n i t M i n i m a l ( unsigned long ulWantedBaud , portBASE_TYPE uxTxQueueLength , portBASE_TYPE uxRxQueueLength ) ; void vSerialClose ( xComPortHandle xPort ) ; // xComPortHandle xSerialPortInit ( eCOMPort ePort , eBaud eWantedBaud , eParity eWantedParity , eDataBits eWantedDataBits , eStopBits eWantedStopBits , unsigned portBASE_TYPE uxBufferLength ) ; // void vSerialPutString ( xComPortHandle pxPort , const signed char * const pcString , unsigned short usStringLength ) ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* * * Interrupt driven routines to interface to ISR serial port IO . * */ portBASE_TYPE xSerialGetChar ( xComPortHandle pxPort , uint8_t * pcRxedChar , portTickType xBlockTime ) ; portBASE_TYPE xSerialPutChar ( xComPortHandle pxPort , uint8_t cOutChar , portTickType xBlockTime ) ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // polling write and read routines , for use before freeRTOS v T as k S ta r t Sc h e du l e r // same as arguments and function as above , but don ' t use the interrupts . void avrSerialPrintf ( char * format , ...) ; void avr Seria lPrint f_P ( PGM_P format , ...) ; void avrSerialPrint ( char * str ) ; void avrSerialPrint_P ( PGM_P str ) ; void avrSerialWrite ( uint8_t DataOut ) ; uint8_t avrSerialRead ( void ) ; uint8_t a v r S e r i a l C h e c k R x C o m p l e t e ( void ) ; uint8_t a vr S e r i a l C h e c k T x R e a d y ( void ) ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

# ifdef __cplusplus } # endif # endif

D.2.

lib serial.c

/* FreeRTOS V7 .0.1 - Copyright ( C ) 2011 Real Time Engineers Ltd .

***************************************************************** * * * FreeRTOS tutorial books are available in pdf and paperback . * * Complete , revised , and edited pdf reference manuals are also * 46

* available . * * * * Purchasing FreeRTOS documentation will not only help you , by * * ensuring you get running as quickly as possible and with an * * in - depth knowledge of how to use FreeRTOS , it will also help * * the FreeRTOS project to continue with its mission of providing * * professional grade , cross platform , de facto standard solutions * * for microcontrollers - completely free of charge ! * * * * > > > See http :// www . FreeRTOS . org / Documentation for details . <<< * * * * Thank you for using FreeRTOS , and thank you for your support ! * * * *****************************************************************

This file is part of the FreeRTOS distribution . FreeRTOS is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License ( version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception . >>> NOTE < < < The modification to the GPL is included to allow you to distribute a combined work that includes FreeRTOS without being obliged to provide the source code for proprietary components outside of the FreeRTOS kernel . FreeRTOS is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for more details . You should have received a copy of the GNU General Public License and the FreeRTOS license exception along with FreeRTOS ; if not it can be viewed here : http :// www . freertos . org / a00114 . html and also obtained by writing to Richard Barry , contact details for whom are available on the FreeRTOS WEB site . 1 tab == 4 spaces ! http :// www . FreeRTOS . org - Documentation , latest information , license and contact details . http :// www . SafeRTOS . com - A version that is certified for use in safety critical systems . http :// www . OpenRTOS . com - Commercial support , development , porting , licensing and training services . */ /* Changes from V1 .2.3 + The function xPortInitMinimal () has been renamed to x S e r i a l P o r t I n i t M i n i m a l () and the function xPortInit () has been renamed to xSerialPortInit () . Changes from V2 .0.0 + Delay periods are now specified using variables and constants of portTickType rather than unsigned long . + x Q u e u eR e c e i v e F r o m I S R () used in place of xQueueReceive () within the ISR . Changes from V2 .6.0

47

+ Replaced the inb () and outb () functions with direct memory access . This allows the port to be built with the 20050414 build of WinAVR . */ /* BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER . */ /* Also with polling serial functions , for use before scheduler is enabled */ # include < stdio .h > # include < stdarg .h > # include < string .h > # include < util / delay .h > # include < avr / io .h > # include < avr / interrupt .h > # include < avr / pgmspace .h > # include < FreeRTOS .h > # include < task .h > # include < queue .h > # include < lib_serial .h >

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* nikosamus : Port ATMEGA32 * Reemplazo de UCSR0B por UCSRB */ # define vInterruptOn () \ { \ uint8_t ucByte ; \ ucByte = UCSRB ; \ ucByte |= serTX_INT_ENABLE ; \ UCSRB = ucByte ; \ } /* nikosamus : Port ATMEGA32 * Reemplazo de UCSR0B por UCSRB */ # define vInterruptOff () \ { \ uint8_t ucByte ; \ \ ucByte = UCSRB ; \ ucByte &= ~ serTX_INT_ENABLE ; UCSRB = ucByte ; \ }

static xQueueHandle xRxedChars ; static xQueueHandle xCharsForTx ; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // xSerialPrintf_P ( PSTR ("\ r \ nMessage %u %u %u ") , var1 , var2 , var2 ) ; void xSerialPrintf ( char * format , ...) {

48

va_list arg ; char temp [80]; va_start ( arg , format ) ; vsnprintf ( temp , 80 , format , arg ) ; xSerialPrint ( temp ) ; va_end ( arg ) ; } void xSerialPrintf_P ( PGM_P format , ...) { va_list arg ; char temp [80]; va_start ( arg , format ) ; vsnprintf_P ( temp , 80 , format , arg ) ; xSerialPrint ( temp ) ; va_end ( arg ) ; } void xSerialPrint ( char * str ) { int16_t i = 0; size_t stringlength ; stringlength = strlen ( str ) ; while ( i < stringlength ) xSerialPutChar ( xSerialPort , str [ i ++] , xNoBlock ) ; } void xSerialPrint_P ( PGM_P str ) { uint16_t i = 0; size_t stringlength ; stringlength = strlen_P ( str ) ; while ( i < stringlength ) xSerialPutChar ( xSerialPort , pgm_read_byte (& str [ i ++]) , xNoBlock ) ; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ portBASE_TYPE xSerialGetChar ( xComPortHandle pxPort , uint8_t * pcRxedChar , portTickType xBlockTime ) { /* Only one port is supported . */ ( void ) pxPort ; /* Get the next character from the buffer . Return false if no characters are available , or arrive before xBlockTime expires . */ if ( xQueueReceive ( xRxedChars , pcRxedChar , xBlockTime ) ) { return pdTRUE ; } else { return pdFALSE ; } }

49

portBASE_TYPE xSerialPutChar ( xComPortHandle pxPort , uint8_t cOutChar , portTickType xBlockTime ) { /* Only one port is supported . */ ( void ) pxPort ; /* Return false if after the block time there is no room on the Tx queue . */ if ( xQueueSendToBack ( xCharsForTx , & cOutChar , xBlockTime ) != pdPASS ) { return pdFAIL ; } vInterruptOn () ; return pdPASS ; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* nikosamus : Port ATMEGA32 * Reemplazo de UBRR0L por UBRRL , UBRR0H por UBRRH y UCSR0C por UCSRC */ xComPortHandle x S e r i a l P o r t I n i t M i n i m a l ( unsigned long ulWantedBaud , portBASE_TYPE uxTxQueueLength , portBASE_TYPE uxRxQueueLength ) { unsigned long ulBa udRate Counte r ; uint8_t ucByte ; po rt EN TE R_ CR IT IC AL () ; { /* Create the queues used by the serial communications task . */ xRxedChars = xQueueCreate ( uxRxQueueLength , ( portBASE_TYPE ) sizeof ( portBASE_TYPE ) ) ; xCharsForTx = xQueueCreate ( uxTxQueueLength , ( portBASE_TYPE ) sizeof ( portBASE_TYPE ) ) ; /* Calculate the baud rate register value from the equation in the data sheet . */ ul BaudRa teCoun ter = ( co nfi gC PU _C LO CK _H Z / ( ulWantedBaud * 16 UL ) - 1; // At Arduino 16 MHz ; above data sheet calculation is wrong . Need below from < util / setbaud .h > ulBa udRate Count er = (( c on fi gC PU _C LO CK_ HZ + ulWantedBaud * 8 UL ) / ( ulWantedBaud * 16 UL ) - 1) ; /* Set the baud rate . */ ucByte = ( uint8_t ) ( ul BaudRa teCoun ter & ( unsigned long ) 0 xff ) ; UBRRL = ucByte ; ulBa udRate Count er > >= ( unsigned long ) 8; ucByte = ( uint8_t ) ( ul BaudRa teCoun ter & ( unsigned long ) 0 xff ) ; UBRRH = ucByte ; /* Enable the Rx interrupt . The Tx interrupt will get enabled later . Also enable the Rx and Tx . */ UCSRB = ( serRX_INT_ENABLE | serRX_ENABLE | serTX_ENABLE ) ; /* Set the data bits to 8. */ UCSRC = ( serUCSRC_SELECT | s erE IG HT _D AT A_ BI TS ) ;

//

50

} port EXIT_C RITIC AL () ; /* Unlike other ports , this serial code does not allow for more than one com port . We therefore don ' t return a pointer to a port structure and can instead just return NULL . */ return NULL ; } /* nikosamus : Port ATMEGA32 * Reemplazo de UCSR0B por UCSRB */ void vSerialClose ( xComPortHandle xPort ) { uint8_t ucByte ; /* The parameter is not used . */ ( void ) xPort ; /* Turn off the interrupts . We may also want to delete the queues and / or re - install the original ISR . */ po rt EN TE R_ CR IT IC AL () ; { vInterruptOff () ; ucByte = UCSRB ; ucByte &= ~ serRX_INT_ENABLE ; UCSRB = ucByte ; } port EXIT_C RITIC AL () ; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // polling read and write routines , for use before freeRTOS v T as k S ta r t Sc h e du l e r // same as above , but doesn ' t use interrupts . void avrSerialPrintf ( char * format , ...) { va_list arg ; char temp [80]; va_start ( arg , format ) ; vsnprintf ( temp , 80 , format , arg ) ; avrSerialPrint ( temp ) ; va_end ( arg ) ; } void avr Seria lPrint f_P ( PGM_P format , ...) { va_list arg ; char temp [80]; va_start ( arg , format ) ; vsnprintf_P ( temp , 80 , format , arg ) ; avrSerialPrint ( temp ) ; va_end ( arg ) ; }

51

void avrSerialPrint ( char * str ) { uint16_t i = 0; size_t stringlength ; stringlength = strlen ( str ) ; while ( i < stringlength ) avrSerialWrite ( str [ i ++]) ; } void avrSerialPrint_P ( PGM_P str ) { int i = 0; size_t stringlength ; stringlength = strlen_P ( str ) ; while ( i < stringlength ) avrSerialWrite ( pgm_read_byte (& str [ i ++]) ) ; } /* nikosamus : Port ATMEGA32 * Reemplazo de UDR0 por UDR */ void avrSerialWrite ( uint8_t DataOut ) { while (! a v r S e r i a l C h e c k T x R e a d y () ) // while NOT ready to transmit _delay_ms (1) ; // delay UDR = DataOut ; } /* nikosamus : Port ATMEGA32 * Reemplazo de UDR0 por UDR */ uint8_t avrSerialRead ( void ) { while (! a v r S e r i a l C h e c k R x C o m p l e t e () ) // While data is NOT available to read _delay_ms (1) ; // delay return UDR ; } /* nikosamus : Port ATMEGA32 * Reemplazo de UCSR0A por UCSRA y RXC0 por RXC */ uint8_t a v r S e r i a l C h e c k R x C o m p l e t e ( void ) { return ( UCSRA & (1 << RXC ) ) ; // nonzero if serial data is available to read . } /* nikosamus : Port ATMEGA32 * Reemplazo de UCSR0A por UCSRA y UDRE0 por UDRE */ uint8_t a vr S e r i a l C h e c k T x R e a d y ( void ) { return ( UCSRA & (1 << UDRE ) ) ; // nonzero if transmit register is ready to receive new data . }

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ # if defined ( __AVR _ATmeg a640__ ) || defined ( _ _AV R_ AT me ga 12 80 __ ) || defined ( __ AV R_ AT me ga 12 81 __ ) || defined ( _ _AV R_ AT me ga 25 60 __ ) || defined (

52

_ _AV R_ AT me ga 25 61 __ ) ISR ( USART0_RX_vect ) # elif defined ( __ AV R_ AT me ga 32 4P __ ) || defined ( _ _AV R_ AT me ga 64 4P __ ) || defined ( _ _A V R _A T m eg a 1 28 4 P __ ) || defined ( _ _A V R _A T m eg a 3 24 P A __ ) || defined ( _ _A V R _A T m eg a 6 44 P A __ ) ISR ( USART0_RX_vect ) # elif defined ( __AVR _ATmeg a168__ ) || defined ( _ _AV R_ AT me ga 32 8P __ ) ISR ( USART_RX_vect ) /* nikosamus : Port ATMEGA32 * Especificacion de la RSI para ATMEGA32 * Reemplazo de UDR0 por UDR */ # elif defined ( __AVR_ATmega32__ ) ISR ( USART_RXC_vect ) # endif { uint8_t cChar ; signed portBASE_TYPE x H i g h e r P r i o r i t y T a s k W o k e n = pdFALSE ; /* Get the character and post it on the queue of Rxed characters . If the post causes a task to wake force a context switch as the awoken task may have a higher priority than the task we have interrupted . */ cChar = UDR ; x Q u e u e S e n d T o B a c k F r o m I S R ( xRxedChars , & cChar , & x H i g h e r P r i o r i t y T a s k W o k e n ); if ( x H i g h e r P r i o r i t y T a s k W o k e n != pdFALSE ) { taskYIELD () ; } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ # if defined ( __AVR _ATmeg a640__ ) || defined ( _ _AV R_ AT me ga 12 80 __ ) || defined ( __ AV R_ AT me ga 12 81 __ ) || defined ( _ _AV R_ AT me ga 25 60 __ ) || defined ( _ _AV R_ AT me ga 25 61 __ ) ISR ( USART0_UDRE_vect ) # elif defined ( __ AV R_ AT me ga 32 4P __ ) || defined ( _ _AV R_ AT me ga 64 4P __ ) || defined ( _ _A V R _A T m eg a 1 28 4 P __ ) || defined ( _ _A V R _A T m eg a 3 24 P A __ ) || defined ( _ _A V R _A T m eg a 6 44 P A __ ) ISR ( USART0_UDRE_vect ) # elif defined ( __AVR _ATmeg a168__ ) || defined ( _ _AV R_ AT me ga 32 8P __ ) ISR ( USART_UDRE_vect ) /* nikosamus : Port ATMEGA32 * Especificacion de la RSI para ATMEGA32 * Reemplazo de UDR0 por UDR */ # elif defined ( __AVR_ATmega32__ ) ISR ( USART_UDRE_vect ) # endif { uint8_t cChar ; int8_t cTaskWoken ; if ( x Q u eu e R e c e i v e F r o m I S R ( xCharsForTx , & cChar , & cTaskWoken ) == pdTRUE ) { /* Send the next character queued for Tx . */ UDR = cChar ; }

53

else { /* Queue empty , nothing to send . */ vInterruptOff () ; } }

54

Ap endice E Librer a para LEDs

E.1.

led lib.h

/* * led_lib . h * * Created : 06/02/2012 18:30:13 * Author : nikosamus */

# ifndef LED_LIB_H_ # define LED_LIB_H_ # include " hardwareConfig . h " void LEDInit ( void ) ; void LEDToggle ( uint8_t ) ; # endif /* LED_LIB_H_ */

E.2.

led lib.c

/* * led_lib . c * * Created : 06/02/2012 18:30:00 * Author : nikosamus */ # include < inttypes .h > # include < avr / io .h > # include " hardwareConfig . h " // Incializacion del puerto de LEDs void LEDInit ( void ) { configLED_REG =0 xFF ; configLED_PORT =0 x00 ; } // Invertir el valor del pin seleccionado con una XOR void LEDToggle ( uint8_t intLed ) { configLED_PORT ^=(1 < < intLed ) ; }

55

Ap endice F Librer a para Botones

F.1.

boton lib.h

/* * boton_lib . h * * Created : 09/02/2012 18:14:38 * Author : nikosamus */ # ifndef BOTON_LIB_H_ # define BOTON_LIB_H_ void BOTONInit ( void ) ; uint8_t BOTONCheckPin ( uint8_t ) ; # endif /* BOTON_LIB_H_ */

F.2.

boton lib.c

/* * boton_lib . c * * Created : 07/02/2012 18:14:15 * Author : nikosamus */ # include < avr / io .h > # include < util / delay .h > # include " boton_lib . h " # include " hardwareConfig . h " // Inicializacion del puerto void BOTONInit ( void ) { // Puerto de botones como salida configBOTON_REG = 0 x00 ; // Activo Pullups internos configBOTON_PORT = 0 xFF ; } // Devolver el estado del pin consultado uint8_t BOTONCheckPin ( uint8_t intPin ) { return !( configBOTON_PIN &(1 < < intPin ) ) ; }

56

Bibliograf a

[1] Richard Barry, FreeRTOS Fundamentals, Real Time Engineers Ltd, Inglaterra, 2012. http://www.freertos.org/implementation/index.html?http://www.freertos.org/ implementation/a00003.html [2] Richard Barry, FreeRTOS Implementation, Real Time Engineers Ltd, Inglaterra, 2012. http://www.freertos.org/implementation/index.html [3] Richard Barry, Atmel AVR (MegaAVR) / WinAVR Port, Real Time Engineers Ltd, Inglaterra, 2012. http://www.freertos.org/index.html?http://www.freertos.org/a00098.html [4] ATMEL, AVR084: Replacing ATmega323 by ATmega32. http://www.atmel.com/Images/doc2518.pdf [5] Antonio Jimenez Bellido, Herramientas libres para la implementaci on de sistemas de control en tiempo real con microcontroladores ARM7, Escuela T ecnica Superior de Ingenier a de Telecomunicaci on, Universidad de M alaga, Espa na, M alaga, 2010. http://es.scribd.com/doc/68622187/67/INTRODUCCION-A-FREERTOS [6] N ucleo Monol tico Wikipedia, 2012. http://es.wikipedia.org/wiki/Ncleo_monoltico [7] Micron ucleo Wikipedia, 2012. http://es.wikipedia.org/wiki/Microncleo [8] Ing. Marcelo Lorenzati, Desarrollo de drivers y aplicaciones para FreeRtos, SASE 2010, Argentina, Buenos Aires, Marzo 2010. [9] Jos e Daniel Mu noz Fr as, Sistemas Empotrados en Tiempo Real. Una introducci on basada en FreeRTOS y en el microcontrolador ColdFire MCF5282, Espa na, Febrero 2009. http://books.google.com.ar/books?id=og3fCjuh27kC

57

Vous aimerez peut-être aussi