Hola amigosNikolay está con usted nuevamente, en el último artículo "
DevBoy: cómo creé un proyecto de dispositivo de código abierto y lancé un proyecto en Kickstarter ", el énfasis estaba más en la apariencia y el hardware, hoy hablaremos sobre cómo se hace esto "
dentro " y analizaremos la parte del software.

A quién le importa: le pido un gato.
Como se mencionó anteriormente, el proyecto se basa en el microcontrolador
STM32F415RG de STMicroelectronics en el núcleo ARM Cortex-M4. Hay varios IDE diferentes para desarrollar microcontroladores para estos microcontroladores, sin embargo, para un proyecto de código abierto, necesita al menos un IDE gratuito, y preferiblemente de código abierto. Además, el IDE aún debe ser compatible con
STM32CubeMX . Cuando comencé a trabajar en este proyecto, solo había un IDE que cumplía con todos estos requisitos:
System Workbench para STM32 .
Por el momento, existe Atollic TrueStudio, que se convirtió en gratuito después de que STMicroelectronics los compró.
El siguiente programa utilizado es
STM32CubeMX . Este programa es una utilidad para configurar los periféricos del microcontrolador utilizando una interfaz gráfica.

El resultado es un código que incluye
H ardware
A bstraction
L ayer (HAL). A muchos programadores realmente no les gusta esta "
creación ", no está exenta de errores, pero, sin embargo, simplifica enormemente el desarrollo y mejora la portabilidad de los programas entre diferentes microcontroladores de STMicroelectronics.
Además, durante la configuración, puede especificar el uso de algún software de código abierto de terceros, como
FreeRTOS ,
FatFS y algunos otros.
Hemos terminado la descripción del software utilizado, ahora pasemos a la parte más interesante:
DevCore . El nombre proviene del "
Core Development " vamos en orden.
En primer lugar, es
C ++ RTOS Wrapper (
FreeRTOS en este caso ). Vrapper es necesario por dos razones:
- Es mucho mejor crear un objeto y luego llamar a mutex.Take (), por ejemplo, que crear un identificador, llamar a la función create y luego pasar este identificador a todas las funciones mutex
- Si es necesario reemplazar RTOS, es suficiente reemplazar el contenedor y no todas las llamadas a funciones RTOS desde el código
No tiene sentido traer aquí el código del contenedor, a quién le importa:
miramos a GitHub y seguimos adelante.
La siguiente parte es el
Marco de aplicación . Esta es la clase base para todas las tareas. Dado que estos son solo dos archivos relativamente pequeños, tiene sentido enumerarlos por completo:
Las clases heredadas pueden anular 4 funciones virtuales:
- Setup () es una función llamada antes de comenzar una tarea. La finalización del código está garantizada en todas estas funciones de todas las tareas antes de la ejecución de los ciclos principales.
- Loop () : el ciclo principal de la tarea, donde la tarea misma organiza lo que quiere. No se puede usar junto con las siguientes dos funciones.
- TimerExpired () - una función llamada periódicamente con un intervalo dado. Conveniente para implementar el sondeo de un sensor, por ejemplo.
- ProcessMessage () : función para procesar mensajes de otras tareas.
Las dos primeras funciones implementan "
Arduino-Style " para las tareas.
Los dos siguientes implementan el sistema de "
evento " que simplifica la interacción de las tareas. Con este enfoque, la tarea implementa una interfaz externa en forma de funciones que envían datos de envío a la tarea a través de un buzón interno. Con este enfoque, el usuario que usa esta interfaz no necesita preocuparse en qué contexto se realizan las acciones. Es cierto que esto solo es posible para setters o equipos. Para los captadores, es mejor usar mutexes y copia de datos para evitar la captura de mutex durante mucho tiempo.
Este enfoque se detectó cuando estaba desarrollando software para equipos médicos. El microcontrolador tiene un
perro guardián y
, en el caso de muchas tareas, debe realizar un seguimiento de todas ellas. Para esto, hubo una tarea separada que sirvió de perro guardián y recibió mensajes de otras tareas enviadas desde la función TimerExpired (). Si durante el período del temporizador de la tarea * n no hubo mensajes, la tarea murió,
apagamos la luz y tomamos medidas para apagar todas las glándulas que afectan al paciente.
Todas las tareas son singleton, no puede crearlas directamente, pero puede obtener un enlace a la tarea. Para hacer esto, cada tarea implementa el
método estático
GetInstance () :
También se incluyen tareas para
salida de audio , para
módulos de entrada y para
mantenimiento de pantalla.La tarea
de salida de sonido es bastante simple: recibe una variedad de frecuencias y duraciones y simplemente cambia periódicamente la configuración del temporizador para generar pulsos rectangulares de cierta frecuencia.
La tarea de dar servicio a
los módulos de agua también
es bastante simple. De los puntos interesantes, el módulo se detecta automáticamente: primero, usando el ADC, medimos el voltaje, si está en el rango del 25% al 75% del voltaje de suministro, se inserta un joystick analógico, de lo contrario, botones o un codificador. Si no es un joystick, verifique la cuarta línea del módulo de E / S: si está en un nivel alto, estos son botones (
todos los botones se activan y, cuando se presionan los botones, se cierran al suelo ), si está bajo, es un codificador (
se "levanta un
botón pequeño" al suelo y cuando se presiona se cierra al poder ).
— . , 320x240x16bit,
153600 . , — 192 , . ? : ! - …
. . , SPI DMA , .
?
!Pero ella tiene una lista de objetos que saben cómo dibujarse. Cada uno de estos objetos se hereda de la clase VisObject .DrawInBufW() , , (
«» ). .
, — . Action() .
, (
, , ), (
).
DevCore UI(
), I2C, I2C BME280 EEPROM 24256, — .
GitHub :
https://github.com/nickshl/devboyPS , Epic Fail'. , - "
", 180 , (
, ! ) .
— . — …