jueves, 25 de febrero de 2016

Componentes de un sistema embebido.

Un sistema embebido en principio estaría formando por un microprocesador y un software que se ejecute sobre este. Sin embargo este software necesitara sin duda un lugar donde poder guardarse para luego ser ejecutado por el procesador. Esto podría tomar la forma de memoria RAM o ROM, Todo sistema embebido necesitara en alguna medida una cierta cantidad de memoria, la cual puede incluso encontrarse dentro del mismo chip del procesador. Además de esto normalmente un sistema embebido contara con una serie de salidas y entradas necesarias para comunicarse con el mundo exterior. Debido a que las tareas realizadas por sistemas embebidos son de relativa sencillez, los procesadores comunmente usados cuentan con registros de 8 o 16 bits. En su memoria solo reside el programa destinado a gobernar una aplicación determinada. Sus líneas de entrada/salida soportan el conexionado de los sensores y actuadores del dispositivo a controlar y todos los recursos complementarios disponibles tiene como única finalidad atender a sus requerimientos. Estas son las únicas características que tienen en común los sistemas embebidos, todo lo demás será totalmente diferente para cada sistema embebido en particular debido a la inmensa diversidad de aplicaciones disponibles. 


Arquitectura básica mas empleada 
Un PC embebido posee una arquitectura semejante a la de un PC. Brevemente éstos son los elementos básicos: 
Microprocesador 
Es el encargado de realizar las operaciones de cálculo principales del sistema. Ejecuta código para realizar una determinada tarea y dirige el funcionamiento de los demás elementos que le rodean, a modo de director de una orquesta. 

Memoria 
En ella se encuentra almacenado el código de los programas que el sistema puede ejecutar así como los datos. Su característica principal es que debe tener un acceso de lectura y escritura lo más rápido posible para que el microprocesador no pierda tiempo en tareas que no son meramente de cálculo. Al ser volátil el sistema requiere de un soporte donde se almacenen los datos incluso sin disponer de alimentación o energía. 

Caché Memoria 
más rápida que la principal en la que se almacenan los datos y el código accedido últimamente. Dado que el sistema realiza microtareas, muchas veces repetitivas, la caché hace ahorrar tiempo ya que no hará falta ir a memoria principal si el dato o la instrucción ya se encuentra en la caché. Dado su alto precio tiene un tamaño muy inferior (8 – 512 KB) con respecto a la principal (8 – 256 MB). 

Disco duro 
En él la información no es volátil y además puede conseguir capacidades muy elevadas. A diferencia de la memoria que es de estado sólido éste suele ser magnético. Pero su excesivo tamaño a veces lo hace inviable para PCs embebidos, con lo que se requieren soluciones como discos de estado sólido. Existen en el mercado varias soluciones de esta clase (DiskOnChip, CompactFlash, IDE Flash Drive, etc.) con capacidades suficientes para la mayoría de sistemas embebidos (desde 2 hasta mas de 1 GB). El controlador del disco duro de PCs estándar cumple con el estándar IDE y es un chip más de la placa madre. 

Disco flexible 
Su función es la de un disco duro pero con discos con capacidades mucho más pequeñas y la ventaja de su portabilidad. Siempre se encuentra en un PC estándar pero no así en un PC embebido. 

BIOS-ROM BIOS (Basic Input & Output System, sistema básico de entrada y salida) 
es código que es necesario para inicializar el ordenador y para poner en comunicación los distintos elementos de la placa madre. La ROM (Read Only Memory, memoria de sólo lectura no volátil) es un chip donde se encuentra el código BIOS. 

CMOS-RAM 
Es un chip de memoria de lectura y escritura alimentado con una pila donde se almacena el tipo y ubicación de los dispositivos conectados a la placa madre (disco duro, puertos de entrada y salida, etc.). Además contiene un reloj en permanente funcionamiento que ofrece al sistema la fecha y la hora. 

Chip Set Chip 
que se encarga de controlar las interrupciones dirigidas al microprocesador, el acceso directo a memoria (DMA) y al bus ISA, además de ofrecer temporizadores, etc. Es frecuente encontrar la CMOS-RAM y el reloj de tiempo real en el interior del Chip Set. 

Entradas y salidas al sistema

Definición formal de sistema embebido.

Se entiende por sistemas embebidos a una combinación de hardware y software de computadora, sumado tal vez a algunas piezas mecánicas o de otro tipo, diseñado para tener una función específica. Es común el uso de estos dispositivos pero pocos se dan cuenta que hay un procesador y un programa ejecutándose que les permite funcionar. 

Esto ofrece un contraste con la computadora personal, que si bien también esta formada por una combinación de hardware y software mas algunas piezas mecánicas (discos rígidos, por ejemplo). Sin embargo la computadora personal no es diseñada para un uso especifico. Si no que es posible darle muchos usos diferentes. Muchas veces un sistema embebido es un componente de un sistema mucho mas grande, como por ejemplo los sistemas de frenos o el sistema de inyección de combustible, en automóviles actuales son sistemas embebidos. 

Esta combinación de software y hardware puede ser reemplazada en muchos casos por un circuito integrado que realice la misma tarea. Pero una de las ventajas de los sistemas embebidos es su flexibilidad. Ya que a la hora de realizar alguna modificación resulta mucho mas sencillo modificar una líneas de código al software del sistema embebido que reemplazar todo el circuito integrado. Un uso muy común de los sistemas embebidos es en los sistemas de tiempo real, entendiéndose por sistemas en tiempo real a aquellos sistemas en los que el control del tiempo es vital para el correcto funcionamiento. Los sistemas en tiempo real necesitan realizar ciertas operaciones o cálculos en un limite de tiempo. Donde ese limite de tiempo resulta crucial. Un ejemplo claro de un sistema de tiempo real es el control de trafico aéreo. 

Algo de historia


El primer sistema embebido reconocido fue el sistema de guía de Apolo desarrollado por el laboratorio de desarrollo del MIT para las misiones Apolo hacia la luna. Cada vuelo hacia la luna tenía dos de estos sistemas. La función era manejar el sistema de guía inercial de los módulos de excursión lunar. En un comienzo fue considerado como el elemento que más riesgo presentaba en el proyecto Apolo. Este sistema de cómputo fue el primero en utilizar circuitos integrados y utilizaba una memoria RAM magnética, con un tamaño de palabra de 16 bits. El software fue escrito en el lenguaje ensamblador propio y constituía en el sistema operativo básico, pero capaz de soportar hasta ocho tareas simultáneas. El primer sistema embebido producido en masa, fue el computador guía del misil norteamericano Minuteman II en 1962. El principal aspecto de diseño del computador del Minuteman, es que además de estar construido con circuitos integrados, permitía reprogramar los algoritmos de guía del misil para la reducción de errores, y permitía realizar pruebas sobre el misil ahorrando así el peso de los cables y conectores. 


Técnicas Digitales II Cortex™ M3

Excelente LINK sobre sistema enmbebidos sobre ARM CORTEX M3.

RESUMEN
El procesador ARM Cortex™-M3 „
ARM® y arquitectura ARM „ Set de instrucciones „
Thumb®-2 Instruction Set Architecture (ISA) „
Alg g una imágenes de Cortex™-M3 „
Aplicaciones del procesador Cortex™-M3 „
Temas a profundizar „
Lecturas adicionales

http://laboratorios.fi.uba.ar/lse/seminario/material-1erC2010/Tecnicas_Digitales_II-R4052-2010-Cortex_M3-Introduccion.pdf

FREERTOS (Con ejercicios)

(EXCELENTE ENLACE http://mcgilbertobarron.com/freeRTOS.php)
Descripción:
Un sistema operativo en tiempo real es un segmento de codigo con un juego de APs que un usuario puede utilizar para desarrollar aplicaciones.
Caracteristicas: 
•FreeRTOS nunca realiza una operación no determinista (el paso de una lista unida, una sección crítica o una interrupción).
•El temporizador de software es muy eficiente, no usa ningún tiempo del CPU a no ser que un temporizador en realidad necesite tratamiento. Los temporizadores de software no contienen variables que tienen que ser contadas debajo de 0.
•Las listas de tareas Bloqueadas no consumen un tiempo periódico.
•El modelo de uso de coleta de FreeRTOS logra combinar la simplicidad con la flexibilidad a los atributos que son normalmente son exclusivos.
•La reutilización de código obtenida radicalmente reduce en general el tamaño de código, que al mismo tiempo ayuda a realizar pruebas.
Principales objetivos:
•Proveer un rtos sencillo de utilizar
•Tamaño de codigo reducido
•Robusto

La mayoría de los sistemas operativos se caracterizan por dar soporte a las siguiente areas:

•Determinismo
•Sensibilidad
•Control del usuario
•Fiabilidad
•Tolerancia a los fallos

Determinismo:
Un sistema operativo es determinista si realiza las operaciones en instantes fijos y determinados o en intervalos de tiempo predeterminados. Cuando hay varios procesos compitiendo por el mismo recurso, no será por completo determinista. Para que el sistema sea determinista se tiene que tener en cuenta dos puntos: la velocidad con la que pueda responder a las interrupciones; y si el sistema posee suficiente capacidad para gestionar las peticiones en tiempos definidos.

Sensibilidad:
Esta característica la determina el tiempo que tarda un RTOS en reconocer una interrupción, después de reconocerla depende de “La cantidad de tiempo necesaria para iniciar la gestión de la interrupción y empezar la ejecución de la rutina de servicio a la interrupción (Interrupt Service Routine ISR)”. Si la ejecución de ISR requiere un cambio de proceso el tiempo será mayor afectando drásticamente la sensibilidad. En conjunto, el determinismo y la sensibilidad conforman el tiempo de respuesta a sucesos externos.

Control de usuario:
Esta característica es mayor en un RTOS que en un sistema de tiempo compartido, en el segundo caso, el usuario no puede asignar prioridades, decidir sobre algoritmos de planificación o que procesos pueden estar residentes en la memoria.

Fiabilidad:
Un RTOS controla sucesos que tienen lugar en el entorno y su propia escala de tiempo, las pérdidas o degradaciones en el sistema , pueden tener consecuencias en el proceso controlado.

Tolerancia a fallos:
Un RTOS se diseña para responder ante varias formas de fallo. Éste intentará corregir el problema o minimizar sus efectos antes de proseguir con la ejecución. Se asocia la Estabilidad a la Tolerancia de Fallos, se considera un sistema estable, cuando en los casos en los que es imposible cumplir todos los plazos de ejecución de tareas se cumplan al menos los de las más críticas y de mayor prioridad. 

FreeRTOS:
El Rtos FreeRTOS es un sistema operativo en tiempo real desarrollado profesionalmente con estrictas normas de calidad. Es robusto y brinda soporte a los usuarios mediante un foro de ayuda.Su licencia es gratuita y puede ser utilizado para desarrollar aplicaciones comerciales.

Ejercicios del FreeRTOS

Descarga los ejercicios del FreeRTOS del siguiente enlace Ejercicios
Descarga los ejercicios del FreeRTOS del siguiente enlace para la version 7 del LPCXpresso Ide Ejercicios
Descarga el archivo FreeRTOSPlus del siguiente enlace FreeRTOSPlus
Otros RTOS:
µC/OS-II
Es portable, ROMable, escalable preventivo, kernel determinístico multitareas en tiempo real para microprocesadores, microcontroladores y DSPs.

RTOS mas básico no se puede!

Un Sistema Operativo de tiempo Real (RTOS) es una colección de recursos de software que provee al desarrollador de sistemas embebidos el esqueleto o estructura básica del software sobre las cuales se va a implementar una solución específica. El RTOS permite mejorar la eficiencia de los sistemas embebidos ya que simplifica enormemente el manejo de las tareas o procesos. Un RTOS siempre incluye un Kernel el cual es un programa relativamente pequeño pero bastante confiable que corre casi independientemente del resto de las tareas; el cual es el encargado de administrar las secuencias de las actividades a ser ejecutadas por la CPU.
Un sistema embebido esta generalmente compuesto por secuencias de código comúnmente llamadas “tareas”. El Kernel cambia la ejecución de las actividades (para los sistemas embebidos generalmente emplean “single cores” de CPU por lo cual solo puede se ejecutar una sola tarea específica en un momento de tiempo determinado) dependiendo de las demandas dadas por Kernel secuenciador. El Kernel también incluye una colección de recursos con el fin de intercambiar mensajes entre las diversas tareas así como también para sincronizar actividades dentro del sistema embebido. Gracias a estos recursos, se evita el uso de variables globales en el sistema (las cuales son peligrosas debido a que literalmente “explotan” con el uso de multitareas).
El RTOS, al igual que los programas, debe usar los recursos de memoria RAM de la CPU. La cantidad de memoria utilizada por el sistema operativo se conoce a menudo como “footprint” (huella) y por lo general esta dada en Kbytes. Con el fin de ahorrar recursos de memoria, los RTOS generalmente incluyen únicamente los servicios indispensables que el usuario necesita. La mayoría de ellos permiten ser configurados extensivamente para satisfacer las necesidades específicas del diseñador. Los RTOS también tienen otros recursos adicionales como: administrador de archivos del sistema, interfaz gráfica del usuario (GUI), protocolos de comunicaciones (conjunto de librerías para TCP/IP, USB, etc.), ayudas de depuración y otros módulos adicionales que son empleados según la aplicación que se desee desarrollar.
Un aspecto importante a considerar de los sistemas operativos de tiempo real es su capacidad de ser determinísticos; esto es, responder a tareas específicas dentro de periodos de tiempo determinados. El RTOS generalmente garantiza respuestas en tiempo real a eventos reales lo cual es posible mediante control de la ejecución de las tareas a niveles de microsegundo (dependiendo de la CPU), de allí su nombre “tiempo real”.
Una diferencia fundamental de los RTOS con los sistemas operativos de escritorio para computadores es que una vez iniciado este, el sistema operativo toma control de la máquina tan pronto como es encendida y luego de esto permite la inicialización de las aplicaciones. Esto es, las aplicaciones y el sistema operativos en los computadores de escritorio son compilados y enlazados de manera separada. Por otro lado, en los sistemas embebidos, el RTOS y la aplicación son generalmente compilados al mismo tiempo y están mucho mas atados el uno de la otra. En un RTOS todo es diferente, cada actividad desarrollada por la CPU puede ser segregada a su propia Tarea, la cual esta bajo la supervisión del Kernel, por ejemplo, una tarea puede manejar la visualización en el display mientras que otra puede estar controlando las comunicaciones (TCP por ejemplo) y una tercera puede estar realizando algún tipo de procesamiento con los datos. En general, el manejador de interrupciones maneja cierto número de interrupciones. Las tareas pueden ser creadas, programadas para ser ejecutadas en un momento específico; de igual manera pueden ser borradas o re-creadas en el futuro (del flujo del programa) según la necesidad. Todos estos mecanismos simplifican ampliamente la labor del ingeniero programador, ya que en vez de usar retardos codificados en software, los ciclos de la CPU nunca son desperdiciados, y la designación de tareas puede ser mas sencilla en vez de emplear código “espagueti” intentando coordinar múltiples tareas las cuales la mayoría de veces no se relacionan las unas con las otras.
Cuando utilizar un RTOS?
En general, cuando un sistema embebido requiere la ejecución de múltiples actividades independientes, un RTOS es la solución preferida debido a su robustez, alta confiabilidad y código simplificado. Por ejemplo, si nuestro sistema requiere manejar datos de múltiples fuentes, manejar varias salidas mientras que al mismo tiempo realiza cómputos y procesamiento; el RTOS es la solución ideal. Debido a la creciente complejidad de los protocolos de comunicación (CAN, TCP y USB por ejemplo) se requiere a menudo el manejo de múltiples tareas y complejos arbitramientos los cuales pueden beneficiarse ampliamente con el uso de un RTOS.
Abajo se mencionan algunos Sistemas Operativos de Tiempo Real – RTOS que son de código-abierto y no-comerciales, los cuales se pueden emplear y modificar con el fin de hacer su sistema embebido más robusto y poderoso
– FreeRTOS
– µC/OS-II Kernel de Micrium
– FreeOSEK
– Tnkernel
– eCos
– CooCox CoOS
– TinyOS
– PICos18
– AvrX
– RTEMS

miércoles, 24 de febrero de 2016

RTOS tutorial basico.

En esta sección se ofrece un tutorial sobre cómo escribir aplicaciones que utilizan un RTOS en microcontroladores de memoria limitada. Si usted está buscando un turorial FreeRTOS específica o un tutorial más completo sobre el uso de un RTOS en un sistema embebido, entonces los libros FreeRTOS será un recurso más valioso.Esta parte del sitio web presenta cuatro contrastantes soluciones de diseño a una aplicación en tiempo real incrustado hipotético. La idoneidad de cada solución se juzga para ordenadores integrados con diferentes capacidades de memoria RAM, ROM y procesamiento. Además se evalúa la simplicidad y facilidad de mantenimiento correspondiente de cada diseño. Esta no es la intención de presentar una lista exhaustiva de los posibles diseños, sino una guía para las formas en que el kernel en tiempo real FreeRTOS puede ser utilizado.
Cabe señalar que esta sección fue escrito hace varios años - cuando FreeRTOS se utilizó principalmente en muy pequeñas microcontroladores. Desde ese momento se ha vuelto más común el uso de FreeRTOS en microcontroladores mucho más grandes que no están tan restringidos en la ROM y RAM que proporcionan.
La aplicación se ejecutará en una placa computadora incorporada que debe controlar una planta manteniendo al mismo tiempo las dos interfaces de usuario locales y remotos.
Se representa anteriormente, el sistema consta de:
  1. Un ordenador incorporado dentro de un terminal de control.
  2. Dos sensores en red de bus de campo.
  3. La planta siendo controlado (podría ser cualquier cosa, motor, calentador, etc.). Esto está conectado en la misma red de bus de campo.
  4. Un teclado de matriz que se analizará con la finalidad general de IO.
  5. Dos indicadores LED.
  6. Una pantalla LCD.
  7. Un servidor web incorporado al que un equipo de monitorización remota puede adjuntar.
  8. Una interfaz RS232 a una utilidad de configuración que se ejecuta en un PDA.

Requisitos de software de primer nivel

Aquí estamos interesados ​​en los requerimientos de secuencia y temporización, en lugar de los requerimientos funcionales exactos.

Control de la planta

Cada ciclo de control se realice la siguiente secuencia:
  1. Transmitir una trama en el bus de campo para solicitar los datos de los sensores conectados en red.
  2. Espere a recibir los datos de ambos sensores.
  3. Ejecutar el algoritmo de control.
  4. Transmitir una orden a la planta.
La función de control del ordenador incorporado transmitirá una solicitud cada 10 ms exactamente, y el comando resultante se transmitirá dentro de 5 ms de esta solicitud. El algoritmo de control depende de la sincronización exacta, por lo que es de suma importancia que se cumplan estos requisitos de tiempo. El tiempo de t de control pudiera dar o no convergencia al sistema de control base.

CONTROL tx 10ms Rx 5ms

Interfaz del operador local

El teclado y la pantalla LCD pueden ser utilizados por el operador para seleccionar, ver y modificar los datos del sistema. La interfaz de operador funcionará mientras la planta está siendo controlado.
Para asegurar que no se pierdan las pulsaciones de teclas del teclado deberá ser escaneado por lo menos cada 15 ms. La pantalla LCD se actualizará en un plazo de 50 ms de un ser tecla pulsada.
Nótese que durante el diseño del sistema solo se estan indicando tipo receta de cocina requerimientos de tiempo e importancia de dichos esquemas dentro del sistema.

PANTALLA t actualización: 50ms
TECLADO t escaneo: 15ms

LED

El LED se utiliza para indicar el estado del sistema. Un LED verde intermitente indicará que el sistema está funcionando como se esperaba. Un LED rojo intermitente indicará una condición de falla.
El LED correcta se encenderá y se apagará una vez cada segundo. Esta tasa de encendido se mantiene entre 50 ms.

LED On-Off: 50ms

Interfaz RS232 PDA

La interfaz RS232 PDA será capaz de ver y acceder a los mismos datos que la interfaz de operador local, y aplicar las mismas restricciones de tiempo - ignorando cualquier tiempos de transmisión de datos.

TXRX RS232 (BAUDIOS): 9600bps

Interfaz de TCP / IP

El servidor web incorporado deberá atender las peticiones HTTP dentro de un segundo. 

Solución # 1 SIN RTOS ¿Por qué utilizar un kernel RTOS?


<<< | >>>
Véase también el artículo FAQ " ¿Por qué utilizar un RTOS? ".

Sinopsis

Muchas aplicaciones pueden ser producidos sin el uso de un núcleo RTOS y esta página describe un enfoque que podría ser tomada.
A pesar de que la aplicación en este caso es probable que sea demasiado complejo para este tipo de enfoque de la página se incluye para destacar tanto los posibles problemas y proporcionar un contraste con los siguientes diseños de software basada RTOS.

Implementación

Esta solución utiliza un enfoque de bucle infinito tradicional, por lo que cada componente de la aplicación es representada por una función que se ejecuta hasta su finalización.
Lo ideal sería que un temporizador de hardware se utiliza para programar la función de control de la planta momento crítico. Sin embargo, tener que esperar a la llegada de datos y el complejo cálculo realizado hacen la función de control inadecuado para la ejecución dentro de una rutina de servicio de interrupción.

Concepto de la Operación

La frecuencia y el orden en el que los componentes se denominan en el bucle infinito se pueden modificar para introducir algo de priorización. Un par de tales alternativas de secuenciación se proporcionan en el ejemplo siguiente.

Configuración del planificador

El planificador RTOS no se utiliza.

Evaluación

tamaño pequeño código.
No depende de código fuente terceros.
Sin memoria RAM RTOS, ROM o procesamiento de arriba.
Difícil atender a los requisitos de tiempo complejas.
No escala bien sin un gran aumento de la complejidad.
Timing difícil de evaluar o mantener debido a las interdependencias entre las diferentes funciones.

Conclusión

El enfoque de bucle simple es muy bueno para pequeñas aplicaciones y aplicaciones con requisitos de tiempo flexibles - pero puede llegar a ser complejos, difíciles de analizar y difícil de mantener si se amplía a los sistemas más grandes.

Ejemplo

Este ejemplo es una aplicación parcial de la aplicación hipotética introducido previamente.

La función de control de la planta

La función de control puede ser representado por el siguiente pseudo código:
PlantControlCycle (void)
{
    TransmitRequest ();
    WaitForFirstSensorResponse ();

    (datos si ya ha recibido el primer sensor)
    { 
        WaitForSecondSensorResponse ();
        
        (datos si ya ha recibido segundo sensor)
        {
            PerformControlAlgorithm ();
            TransmitResults ();
        }
    }
}

Las funciones de interfaz humana

Esto incluye el teclado, pantalla LCD, comunicaciones RS232 y el servidor web incorporado.
El siguiente pseudo código representa una estructura de bucle infinito simple para el control de estas interfaces.
int main (void)
{
    Inicializar ();
    
    para( ;; )
    {
        ScanKeypad ();
        UpdateLCD ();
        ProcessRS232Characters ();
        ProcessHTTPRequests ();   
    }

    // Nunca debe llegar hasta aquí.
    return 0;
}
Esto supone dos cosas: En primer lugar, las comunicaciones IO es amortiguada por las rutinas de servicio de interrupción de modo periféricos no requieren votación. En segundo lugar, la función de llamadas individuales dentro del bucle ejecutar lo suficientemente rápido como para que se cumplan todos los requisitos máximos de tiempo.

La programación de la función de control de la planta

La longitud de la función de control significa que no puede simplemente ser llamado desde una interrupción de 10 ms temporizador.
Añadiéndolo al bucle infinito requeriría la introducción de algún tipo de control temporal. Por ejemplo ... :
// Bandera utiliza para marcar el momento en que una
// Ciclo de control debe comenzar (exclusión mutua
// Cuestiones que se ignoran para este ejemplo).
int TimerExpired;

// Rutina de servicio de interrupción del temporizador. Esta
// Está configurado para ejecutar cada 10 ms.
TimerInterrupt vacío (vacío)
{    
    TimerExpired = true;
}


// Principal () todavía contiene el bucle infinito - 
// Dentro de la cual una llamada al control de la planta
// Función se ha añadido.
int main (void)
{
    Inicializar ();
    
    para( ;; )
    {
        // Girar hasta que es hora para la siguiente
        // Ciclo.
        si (TimerExpired)
        {
            PlantControlCycle ();
            TimerExpired = false;

            ScanKeypad ();
            UpdateLCD ();

            // Los LEDs podrían utilizar una cuenta de
            // El número de interrupciones, o una
            // Diferente temporizador.
            ProcessLEDs ();

            // Comms tampones deben ser grandes
            // Suficiente para mantener el valor de 10 ms
            // Datos.
            ProcessRS232Characters ();
            ProcessHTTPRequests ();   
        }

        // El procesador se puede poner a dormir
        // Aquí siempre es despertado por cualquier
        // interrumpir.
    }

    // Nunca debe llegar hasta aquí.
    return 0;
}
... Pero esto no es una solución aceptable:
  • Un retraso o fallo en los resultados de bus de campo en un aumento del tiempo de ejecución de la función de control de la planta. Los requisitos de tiempo de las funciones de la interfaz lo más probable es ser violada.
  • La ejecución de todas las funciones de cada ciclo también podría resultar en una violación de la sincronización del ciclo de control.
  • Fluctuación en el tiempo de ejecución puede causar ciclos se puede perder. Por ejemplo, el tiempo de ejecución de ProcessHTTPRequests () podría ser insignificante cuando no se han recibido solicitudes HTTP, pero bastante largo cuando se servía una página.
  • No es muy fácil de mantener - que depende de cada función que se ejecuta dentro del tiempo máximo.
  • Los tampones de comunicación solamente se limpian una vez por ciclo que requiere su longitud a ser más grandes de lo que sería necesario.


estructuras alternativas

Dos factores pueden ser identificados que limitan la idoneidad de la estructura de bucle sencillo descrito hasta ahora.
  1. La duración de cada llamada a la funciónPermitiendo que cada función para ejecutar en su totalidad lleva demasiado tiempo. Esto se puede prevenir mediante el fraccionamiento de cada función en un número de estados.Sólo un estado se ejecuta cada llamada. El uso de la función de control como un ejemplo:
    // Define los estados para la función del ciclo de control.
    typdef enumeración eCONTROL_STATES
    {
        ESTART, // Iniciar nuevo ciclo. 
        eWait1, // Espera a que la primera respuesta del sensor. 
        eWait2   // esperar a la segunda respuesta del sensor.
    eControlStates};
    
    PlantControlCycle (void)
    {
    eControlState raíces estática = ESTART;
    
        interruptor (raíces)
        {
            ESTART caso:
                TransmitRequest ();
                Estate = eWait1;
                romper;
                
            eWait1 caso;
                (datos si ya ha recibido el primer sensor)
                {
                    Estate = eWait2;
                }
                // ¿Cómo están los tiempos de espera para ser manipulados?
                romper;
                
            eWait2 caso;
                (datos si ya ha recibido el primer sensor)
                {
                    PerformControlAlgorithm ();
                    TransmitResults ();
                    
                    Estate = ESTART;
                }
                // ¿Cómo están los tiempos de espera para ser manipulados?
                romper;           
        }
    }
    
    Esta función ahora es estructuralmente más compleja, e introduce nuevos problemas de agenda. El código en sí será más difícil de entender cuando se agregan los estados adicionales - por ejemplo, para manejar las condiciones de tiempo de espera y de error.
  2. La granularidad del temporizadorUn temporizador de intervalo más corto dará más flexibilidad.
    La implementación de la función de control como una máquina de estados (una al hacerlo haciendo cada llamada más corta) puede permitir que se llama a partir de una interrupción del temporizador. El intervalo del temporizador tendrá que ser lo suficientemente corto como para asegurar la función se vuelve a llamar a una frecuencia que cumpla con los requisitos de tiempo. Esta opción está plagado de problemas de tiempo y mantenimiento.
    Alternativamente, la solución bucle infinito podría modificarse para llamar a diferentes funciones en cada bucle - con la función de control de alta prioridad se llama con más frecuencia:
    int main (void)
    {
    int contador = -1;
    
        Inicializar ();
        
        // Cada función se implementa como un estado 
        // Máquina de modo está garantizado para ejecutar 
        // Rápidamente - pero debe ser llamado con frecuencia.
        
        // Nota la frecuencia del temporizador se ha planteado.
        
        para( ;; )
        {
            si (TimerExpired)
            {
                Contador ++;
                
                interruptor (Contador)
                {
                    caso 0: ControlCycle ();
                              ScanKeypad ();
                              romper;
                              
                    Caso 1: UpdateLCD ();
                              romper;
    
                    Caso 2: ControlCycle ();
                              ProcessRS232Characters ();
                              romper;
    
                    Caso 3: ProcessHTTPRequests ();
                              
                              // Volver a empezar
                              Contador = -1;                          
                              romper;
                              
                }
                
                TimerExpired = false;
            }
        }
    
        // Nunca debe llegar hasta aquí.
        return 0;
    }
    
    Más información se puede introducir por medio de contadores de eventos, por lo que la funcionalidad de prioridad más bajo sólo se llama si se ha producido un evento que requiere servicio:
        para( ;; )
        {
            si (TimerExpired)
            {
                Contador ++;
                
                // Procesar el ciclo de control cada otro bucle.
                interruptor (Contador)
                {
                    caso 0: ControlCycle ();
                              romper;
                              
                    Caso 1: contador = -1;
                              romper;
                }
    
                // Proceso de sólo una de las otras funciones. único proceso
                // Una función si hay algo que hacer. EventStatus ()
                // Comprueba si hay eventos desde la última iteración.
                interruptor (EventStatus ())
                {
                    EVENT_KEY caso: ScanKeypad ();
                                        UpdateLCD ();
                                        romper;
                               
                    EVENT_232 caso: ProcessRS232Characters ();
                                        romper;
                                
                    EVENT_TCP caso: ProcessHTTPRequests ();
                                        romper;
                }
                
                TimerExpired = false;
            }
        }
    
    Proceso de sucesos en esta forma reducirá los ciclos de CPU desperdiciados pero el diseño sigue exhibirán fluctuación en la frecuencia con la que se ejecuta el ciclo de control.

Solución # 2 CON RTOS Un sistema completamente Preferente


Sinopsis

Esta es una solución multitarea preferente tradicional. Se hace un uso completo de los servicios RTOS sin tener en cuenta a la memoria y el procesador resultante por encima. Hay una partición simplista de la funcionalidad requerida para una serie de tareas autónomas.

Implementación

Una tarea separada se crea para cada parte del sistema que puede ser identificado como siendo capaz de existir de forma aislada, o que tienen un requisito de tiempo particular.

Solución # 2 funciones tareas y prioridades
Las tareas se bloqueará hasta que un evento indica que se requiere un procesamiento. Eventos o bien puede ser externo (como pulsación de una tecla), o interno (por ejemplo, un temporizador expira). Este enfoque orientado a eventos significa que no hay tiempo de CPU se desperdicia votación para eventos que no han ocurrido.
Las prioridades se asignan a tareas de acuerdo a sus requerimientos de tiempo. El más estricto el requisito de tiempo mayor será la prioridad (no todas las evaluaciones de asignación de prioridad son que simplista).

Concepto de la Operación

La tarea de mayor prioridad que es capaz de ejecutar (no está bloqueado) es la tarea garantizada por el RTOS para obtener el tiempo de procesador. El núcleo se suspenda inmediatamente la ejecución de una tarea debería estar disponible una tarea de mayor prioridad.
Esta programación se realiza automáticamente, sin el conocimiento explícito, el diseño o los comandos dentro del código fuente de la aplicación. Sin embargo, es responsabilidad de los diseñadores de aplicaciones para garantizar que las tareas se asignan una prioridad adecuada.
Cuando ninguna tarea es capaz de ejecutar la tarea ociosa ejecutará. La tarea de inicio cuenta con la opción de colocar el procesador en modo ahorro de energía.

Configuración del planificador

El programador está configurado para una operación preventiva. La frecuencia del núcleo garrapata debe fijarse en el valor más lento que proporciona la granularidad de tiempo requerido.

Evaluación

, Segmentados, de diseño simple de mantener flexibles, con pocas interdependencias.
La utilización del procesador se conecta automáticamente a partir de una tarea a otra en función de las necesidades más urgentes sin ninguna acción explícita requerida dentro del código fuente de la aplicación.
La estructura orientada a eventos asegura que ningún tiempo de CPU se desperdicia votación para eventos que no han ocurrido. Procesamiento sólo se realiza cuando hay trabajo que necesitaba ser hecho.
El consumo de energía puede reducirse si la tarea ociosa coloca el procesador en modo ahorro de energía (sueño), pero también puede ser desperdiciado como la interrupción de la garrapata a veces se despierta el procesador innecesariamente.
La funcionalidad del núcleo utilizará los recursos de procesamiento. El alcance de esta dependerá de la frecuencia kernel garrapata elegido.
Esta solución requiere una gran cantidad de tareas, cada una de las cuales requieren su propia pila, y muchos de los cuales requiere una cola en la que se pueden recibir eventos. Por lo tanto, esta solución utiliza una gran cantidad de memoria RAM.
contexto frecuente el cambio entre las tareas de la misma prioridad será un desperdicio de ciclos de procesador.

Conclusión

Esto puede ser una buena solución proporciona la RAM y capacidad de procesamiento disponible.La partición de la aplicación en tareas y la prioridad asignada a cada tarea requiere una cuidadosa consideración.

Ejemplo

Este ejemplo es una aplicación parcial de la aplicación hipotética introducido previamente. se utiliza la API FreeRTOS.

Control de tareas planta

Esta tarea implementa toda la funcionalidad de control. Tiene requerimientos críticos de tiempo y por lo tanto se le da la más alta prioridad en el sistema:
#define CYCLE_RATE_MS 10
#define MAX_COMMS_DELAY 2

PlantControlTask ​​anular (pvParameters void *)
{
TickType_t xLastWakeTime;
Tipo de datos datos1, datos2;

    InitialiseTheQueue ();

    // UN
    xLastWakeTime = xTaskGetTickCount ();

    // B
    para( ;; )
    {
        // C
        vTaskDelayUntil (y xLastWakeTime, CYCLE_RATE_MS);
        
        // Solicitar datos de los sensores.
        TransmitRequest ();
        
        // D
        si (xQueueReceive (xFieldBusQueue, y Datos1, MAX_COMMS_DELAY))
        {
            // E
            si (xQueueReceive (xFieldBusQueue, y Datos2, MAX_COMMS_DELAY))
            {
                PerformControlAlgorithm ();
                TransmitResults ();                
            }
        } 
    }
    
    // Nunca se tiene aquí!
}
Haciendo referencia a las etiquetas dentro del fragmento de código anterior:
  1. xLastWakeTime es inicializado. Esta variable se utiliza con el vTaskDelayUntil () la función de API para controlar la frecuencia a la que realiza la función de control.
  2. Esta función se ejecuta como una tarea autónoma por lo que nunca debe salir.
  3. vTaskDelayUntil () le dice al núcleo que esta tarea debe comenzar a ejecutar exactamente 10 ms después de la hora almacenada en xLastWakeTime . Hasta que se alcanza esta vez la tarea de control bloqueará. Como esta es la tarea de mayor prioridad dentro del sistema se garantiza que comience a ejecutar de nuevo exactamente en el momento correcto. Será adelantarse a cualquier tarea de menor prioridad que le pasa a estar en ejecución.
  4. Hay un tiempo finito entre los datos que se solicitan de los sensores conectados en red y que están recibiendo datos. Los datos que llegan en el bus de campo se coloca en elxFieldBusQueue por una rutina de servicio de interrupción, la tarea de control, por tanto, puede hacer una llamada de bloqueo en la cola para esperar a que los datos estén disponibles. Al igual que antes, ya que es la tarea de mayor prioridad en el sistema está garantizado para continuar con la ejecución inmediata de datos está disponible.
  5. Como 'D', a la espera de los datos del segundo sensor.
Un valor de retorno de 0 desde xQueueReceive () indica que no hay datos llegaron dentro del plazo de bloque especificado. Esta es una condición de error la tarea debe manejar. Esta y otras funciones de gestión de errores se ha omitido por simplicidad.

Embedded Web Server Tarea

La tarea del servidor web incorporado puede ser representado por el siguiente pseudo código.Esto sólo se utiliza el tiempo de procesador cuando hay datos disponibles, pero tomará un tiempo variable y relativamente largo para completar. Por lo tanto, se le da una prioridad baja para evitar que afectar de forma adversa la sincronización de las tareas de control de planta, RS232 o escaneo teclado.
WebServerTask vacío (pvParameters void *)
{
Datos DataTypeA;

    para( ;; )
    {
        // Bloque de datos hasta que llega. xEthernetQueue es llenado por el
        // Ethernet rutina de servicio de interrupción.
        si (xQueueReceive (xEthernetQueue, y bases de datos, max_delay))
        {
            ProcessHTTPData (datos);
        }        
    }
}

Interfaz RS232

Esto es muy similar en estructura a la tarea del servidor Web incorporado. Se da una prioridad media para asegurarse de que no afecta negativamente en la planificación de la tarea de control de la planta.
RS232Task anular (pvParameters void *)
{
Datos DataTypeB;

    para( ;; )
    {
        // Bloque de datos hasta que llega. xRS232Queue es llenado por el
        // Rutina de servicio de interrupción RS232.
        si (xQueueReceive (xRS232Queue, y bases de datos, max_delay))
        {
            ProcessSerialCharacters (datos);
        }        
    }
}

Teclado exploración de la tarea

Esta es una tarea cíclica simple. Se da una prioridad media como sus requisitos de tiempo son similares a la tarea RS232.
El tiempo de ciclo se ajusta mucho más rápido que el límite especificado. Esto es para tener en cuenta el hecho de que no puede obtener el tiempo de procesador de inmediato a petición - y una vez que la ejecución puede conseguir se anticipó por la tarea de control de la planta.
DELAY_PERIOD #define 4

KeyScanTask anular (pvParmeters void *)
{
charla clave;
TickType_t xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount ();

    para( ;; )
    {
        // Espera a que el próximo ciclo.
        vTaskDelayUntil (y xLastWakeTime, DELAY_PERIOD);
        
        // La ejecución del teclado.
        si (KeyPressed (& Key))
        {
            UpdateDisplay (Key);
        }
    }
}
Si la temporización global del sistema eran tales que este se podría hacer la tarea de prioridad más bajo entonces la llamada a vTaskDelayUntil () podría ser eliminado por completo. La función de exploración clave sería luego ejecutar continuamente siempre que todas las tareas de mayor prioridad se bloquearon - tomar efectivamente el lugar de la tarea vacía.

Tarea LED

Esta es la más simple de todas las tareas.
DELAY_PERIOD #define 1000

LEDTask vacío (pvParmeters void *)
{
TickType_t xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount ();

    para( ;; )
    {
        // Espera a que el próximo ciclo.
        vTaskDelayUntil (y xLastWakeTime, DELAY_PERIOD);

        // Flash del LED apropiado.
        si (SystemIsHealthy ())
        {
            FlashLED (VERDE);
        }
        más
        {
            FlashLED (RED);
        }        
    }
}

ChibiOS para el IDE Arduino

Un sistema operativo en tiempo real es una pieza bastante complicado de software, incluso con una pequeña RTOS - debido a la forma en que se mete con varios detalles de bajo nivel de ejecución del código, tales como pilas y las interrupciones. Es por lo tanto no es poca cosa cuando todo se puede hacer como una biblioteca de complemento estándar para el IDE de Arduino.
Pero eso es exactamente lo que ha sido hecho por Bill Greiman con ChibiOS , en forma de una biblioteca llamada "ChibiOS_AVR" (también hay una versión ARM para la debida y Teensy).
Así que vamos a continuar donde lo dejé ayer e instalar esta cosa para su uso con JeeNodes, eh?
  • descargar una copia de ChibiOS20130208.zip de esta página en Google Code
  • descomprimirá y el interior encontrará una carpeta llamada ChibiOS_AVR
  • moverlo dentro de la bibliotecas carpeta en su carpeta de bocetos IDE (al lado de JeeLib, etc)
  • También puede ser que desee mover ChibiOS_ARM y SdFat junto a él, para su uso posterior
  • otras cosas en ese archivo ZIP son un archivo README y la documentación HTML
  • eso es todo, ahora relanzar el IDE de Arduino para que sea reconocer las nuevas bibliotecas
Eso es realmente todo lo que hay que hacer. La carpeta ChibiOS_AVR también contiene una docena de ejemplos, cada uno de los cuales es digno de mirar en y probar. Tenga en cuenta que no hay ningún LED en un JeeNode estándar, y que el LED azul del USB JeeNode SMD y JeeNode está en el pin 9 y tiene una polaridad inversa ( "0" a su vez en "1" apagarlo ).
Nota: Estoy usando esto con Arduino IDE 1.5.2, pero también debería funcionar con 1.0.x IDE
Las cosas simples son todavía relativamente simple con un RTOS, pero estar preparados para hacer frente a toda una serie de nuevos conceptos y técnicas cuando realmente comienza a sumergirse en un montón de maneras de hacer las tareas e interrumpe el trabajo en conjunto -. Exclusiones mutuas, semáforos, eventos, colas, buzones ...
Por suerte, ChibiOS viene con una gran cantidad de documentación, incluyendo algunos generales guías y de cómo-a . La documentación AVR-específica se puede encontrar aquí(al igual que en ese archivo ZIP que acaba de descargar).
No estoy seguro de que este es el mejor lugar para ello, pero he puesto el ejemplo de ayer en JeeLib por ahora.
Me gustaría ir a la RTOS y ChibiOS un poco más en las próximas semanas, aunque sólo sea para ver cómo la comunicación inalámbrica y los modos de suspensión de baja potencia se pueden montar en ese país.
Solo un dato por ahora: la latencia de cambio de contexto de ChibiOS en una ATmega328 @ 16 MHz parece ser alrededor de 15 mu s. O, para decirlo de otra manera: se puede cambiar entre múltiples tareas durante sesenta mil veces por segundo. Trago.
TUTORIAL

1 El muestreo usando el ADC

Fig.1 - Potenciómetro diagrama.
Un análogo al convertidor digital de es un dispositivo que convierte una cantidad física continua (por lo general de tensión) a un número digital que representa la amplitud de la cantidad.
En esta demostración, estamos muestreando voltaje a través de unpotenciómetro para establecer su posición. Un potenciómetro es un mando de tres pines que proporciona una resistencia variable entre WA y WB pasadores (Fig.1). Cantidad de resistencia entre A y B es constante, pero girando el eje del potenciómetro, cambiamos la cantidad de resistencia a cada lado de W.
Conexión de A a 3 V, B a GND (o viceversa) y la tensión de muestreo entre W y GND que podría medir la posición del limpiaparabrisas: según divisor de voltaje , el voltaje muestreado sería proporcional a la cantidad de resistencia entre W y el pasador conectado a GND.

2 ADC en ChibiOS

STM32 tiene más de un ADC. Como siempre, tuvimos que permitirá subsistema ADC en halconf.h y controlador adecuado en mcuconf.h .
Cada ADC tiene más de un canal. Podríamos tomar muestras de estos canales que eligen una secuencia personalizada. Con el fin de hacer que teníamos que configurar algún registro ADC aunqueADCConversionGroup . Por otra parte, podríamos configurar la frecuencia de muestreo y el modo. Nuestro grupo de conversión es:
/ *
 * Grupo de conversión ADC.
 * Modo: tampón circular, 10 muestras de 1 canal, SW activa.
 * Canales: IN0.
 * / 
Static  const ADCConversionGroup my_conversion_group = {
  FALSO,                             / * NO CIRCULAR * / 
  MY_NUM_CH,                         / * NUMB DE CH * / 
  NULL ,                              / * NO ADC RETROLLAMADA * / 
  NULL ,                              / * NO ADC ERROR RETROLLAMADA * / 
  0 ,                                 / * CR1 * / 
  ADC_CR2_SWSTART,                   / * CR2 * / 
  0 ,                                 / * * SMPR1 / 
  ADC_SMPR2_SMP_AN0 (ADC_SAMPLE_3),   / * * SMPR2 / 
  ADC_SQR1_NUM_CH (MY_NUM_CH),        / * SQR1 * / 
  0 ,                                 / * * SQR2 / 
  ADC_SQR3_SQ1_N (ADC_CHANNEL_IN0)    / * SQR3 * / 
};
Estamos muestreando de forma no circular, de un solo canal ( ADC_CHANNEL_IN0 ). La frecuencia de muestreo es igual a tres ciclos de reloj principal ( ADC_SAMPLE_3 ), (Para más información ver para los registros de ADC en Manual de referencia).
Hemos desactivado el dos de devolución de llamada de ADC. La primera de ellas se produce durante el muestreo dos veces (en el medio y en el final del grupo de conversión); el segundo se produce en caso de error ADC.
En principal tuvimos para configurar nuestra pasador. En hilo de ADC que empezamos, el muestreo de un tampón de n elementos y hacer que significa en los datos con el fin de eliminar el ruido.
estática msg_t Thd2 ( void * arg)  {
   unsigned II;
  ( Vacío ) arg;
  chRegSetThreadName ( "controlador Led" );
   / *
   * Activa el conductor ADC1.
   * / 
  AdcStart (y ADCD1, NULL );
   mientras que (TRUE) {
    adcConvert (y ADCD1, y my_conversion_group, sample_buff, MY_SAMPLING_NUMBER); . / * Hacer media de los valores muestreados * / 
    media = 0 ;
     para (ii = 0 ; ii <MY_NUM_CH * MY_SAMPLING_NUMBER; ii ++) {
    
      media + = sample_buff [ii];
    }
    decir / = MY_NUM_CH * MY_SAMPLING_NUMBER;
    lastvalue = ( float ) significa * 3 / 4096 ;
    flag = true;
  }
  volver  0 ;
}
Tenga en cuenta que podemos utilizar el ADC en modo continuo utilizando otro API: adcStartConversion () .Recuerde siempre que teníamos a la dimensión muestras de tampón correctamente para evitar un desbordamiento:
estática  adcsample_t sample_buff [MY_NUM_CH * MY_SAMPLING_NUMBER];

3 de atenuación mediante PWM

La figura 2 -Relation entre el ciclo de trabajo y el valor medio.
La modulación por ancho de pulso es una técnica utilizada para codificar un mensaje en una señal pulsante. Es un tipo de modulación. Aunque esta técnica de modulación puede utilizarse para codificar la información para su transmisión, su uso principal es permitir el control de la potencia suministrada a los aparatos eléctricos, especialmente a las cargas inerciales tales como motores.
Por otra parte, podemos usar PWM a desvanecerse la intensidad del LED.Esto es posible gracias principio de que el valor medio de PWM es proporcional a su ciclo de trabajo .

4 PWM en ChibiOS

Simplificando, PWM es una onda cuadrada que se caracteriza por un período fijo y un ciclo de trabajo variable.La mejor manera de darse cuenta de que está utilizando un contador de tiempo. La fijación de la frecuencia del temporizador, (de ahí período), podríamos definir periodo PWM y ciclo de trabajo como múltiplo del temporizador cuántica. Tenga en cuenta que la frecuencia del temporizador debe ser varios órdenes de magnitud mayor que la frecuencia de PWM con el fin de tener una buena resolución ciclo de trabajo.
En este punto, debe quedar claro que la frecuencia del campo de PWMConfig se denomina temporizador relacionado y que hay un temporizador para cada PWM. . Dado que cada temporizador como algo más que un canal que podría generar más de PWM con el mismo periodo pero diferente ciclo de trabajo
del controlador PWM tiene devoluciones de llamada: una es común a cada canal y se produce cada periodo, otros son de canal en función y se producen cuando los interruptores de salida PWM, por lo tanto, depende de ciclo de trabajo. Esta es la PWMConfig verde usado desvaneciendo LED de intensidad:
estática PWMConfig pwmcfg = {
   1000000 ,                                     / * 1 MHz de frecuencia de reloj PWM. * / 
  1000 ,                                        / * Período Inicial de PWM de 1 ms. * /
  pwmpcb,
  {
   {PWM_OUTPUT_ACTIVE_HIGH, pwmc1cb},
   {PWM_OUTPUT_DISABLED, NULL },
   {PWM_OUTPUT_DISABLED, NULL },
   {PWM_OUTPUT_DISABLED, NULL }
  },
  0 ,
   0 
};

Tenga en cuenta que la frecuencia del temporizador es de 1 MHz y que PWM periodo inicial es de 1000 es decir temporizador cuántica 1ms. Pwmpcb es el período de devolución de llamada y pwmc1cb es la devolución de llamada del canal 1; Por otra parte, el primer canal está activo y la salida es alta durante un período de tiempo proporcional al ciclo de trabajo, en lugar de otros canales están desactivados.
Como todos los pilotos, PWM debe iniciarse antes de usarlo. PWM API permite iniciar la elección de los canales de ciclo de trabajo, así como el período de PWM cambio, canal desactivado y dejar de conducir. Con el fin de LED se desvanecen apenas comenzamos el conductor antes de lazo de hilo y permitir que continuamente cambiando de canal ciclo de trabajo (en nuestro caso elegimos el ciclo de trabajo proporcional a durar valor muestreado).
estática msg_t Thd1  ( void * arg)  { 
  ( vacío ) arg;
  chRegSetThreadName ( "controlador Led" );
  pwmStart (y PWMD1, y pwmcfg); mientras que (TRUE) {
  
    porcentaje = lastvalue * 10.000 / 3 ;
     si (porcentaje < 100 ) {
      porcentaje = 0 ;
      pwmDisableChannel (y PWMD1, 0 );
      palClearPad (GPIOA, GPIOA_LED_GREEN);
    }
    otra cosa  si (porcentaje> 9900 ) {
      porcentaje = 10000 ;
      pwmDisableChannel (y PWMD1, 0 );
      palSetPad (GPIOA, GPIOA_LED_GREEN);
    }
    otra cosa {
      pwmEnableChannel (y PWMD1, 0 , PWM_PERCENTAGE_TO_WIDTH (y PWMD1, porcentaje));
    }
    chThdSleepMilliseconds ( 1 );
  }
  volver RDY_OK;
}

LED verde no está conectado directamente a nuestra salida del temporizador y utilizamos las devoluciones de llamada para hacer una PWM de software. Cuando el ciclo de trabajo es del 0% o 100% entre uno pwmpcb ypwmc1cb devoluciones de llamada no podría ocurrir: que explica los controles sobre los bordes del ciclo de trabajo.
estática  vacío  pwmpcb (PWMDriver * pwmp)  { 
  ( vacío ) pwmp;
   si (porcentaje)
    palSetPad (GPIOA, GPIOA_LED_GREEN);
} Static void pwmc1cb (PWMDriver * pwmp) {   ( vacío ) pwmp;
   

  palClearPad (GPIOA, GPIOA_LED_GREEN);
}
Recuerde que antes de usar PWM para permitir subsistema en halconf.h y asignar temporizador en mcuconf.h.

5 La rueda de color

La conducción de un LED RGB utilizamos tres canales de la misma PWM. Rueda de colores evitar que más de dos uniones se afinan juntos: esto porque encender el tercer cambio de color de unión hacia la saturación perdedora blanco.
mientras que (TRUE) {
  tmp = lastvalue * 90 ;
  ii = tmp / 90 ;
  jj = tmp% 90 ;
   si (== ii 0 ) {
    porcentaje [ 0 ] = 10.000 * sin (jj * 3,14 / 180 );
    porcentaje [ 1 ] = 0 ;
    porcentaje [ 2 ] = 10.000 * cos (jj * 3,14 / 180 );
  }
  otra cosa  si (ii == 1 ) {
    porcentaje [ 0 ] = 10.000 * cos (jj * 3,14 / 180 );
    porcentaje [ 1 ] = 10.000 * sin (jj * 3,14 / 180 );
    porcentaje [ 2 ] = 0 ;
  }
  otra cosa  si (ii == 2 ) {
    porcentaje [ 0 ] = 0 ;
    porcentaje [ 1 ] = 10.000 * cos (jj * 3,14 / 180 );
    porcentaje [ 2 ] = 10.000 * sin (jj * 3,14 / 180 ); 
  ...
  
}

6 Nuestro circuito

El circuito que hicimos para conducir el LED RGB es la siguiente:
Fig.3 - El muestreo y el circuito de regulación de luz.

7 Proyecto utilizado en este tutorial

Este código ha sido probado utilizando ChibiOS / RT 3.0.x.