Download Curso introductorio a la arquitectura ARM con Cortex M4

Document related concepts
no text concepts found
Transcript
Curso introductorio a la
arquitectura ARM con
Cortex M4
Microcontrolador STM32F407VG
Realizado y editado por:
`
Calle Urquiza 1695 – Gchú. (Entre Ríos)
(2820) ARGENTINA
e-mail: [email protected]
[email protected]
Revisión: Marzo 2017
2
Índice de contenido
Prologo.......................................................................................................................................................5
Capitulo I....................................................................................................................................................6
Historia de la Arquitectura ARM...........................................................................................................6
Que es Cortex M4..................................................................................................................................8
Algunos detalles del STM32F407VG...................................................................................................9
Características heredadas de RISC......................................................................................................11
Algunas ventajas de RISC...................................................................................................................11
Desventajas de RISC...........................................................................................................................11
Bus AMBA..........................................................................................................................................11
Pipeline................................................................................................................................................12
FPU......................................................................................................................................................14
ARM y Thumb....................................................................................................................................14
Modos de Funcionamiento..................................................................................................................14
Modo usuario (Thread ).......................................................................................................................15
Modos de Privilegios (Handler)..........................................................................................................15
El sistema de memoria ARM...............................................................................................................16
Que es CMSIS.....................................................................................................................................18
Características de la placa entrenadora................................................................................................21
Configurando el entorno de trabajo.....................................................................................................26
Puedo programar el microcontrolador sin un programador específico?.............................................30
Mi Primer Programa en KEIL.............................................................................................................31
Capitulo II................................................................................................................................................41
Interrupciones......................................................................................................................................41
Temporizador del sistema (SysTick)...................................................................................................48
Funcionamiento de la USART.............................................................................................................57
Conversor Analógico con STM32F407VG.........................................................................................64
Capitulo III...............................................................................................................................................67
Pantalla LCD 16x2 con STM32..........................................................................................................67
Voltímetro con pantalla LCD 16x2.................................................................................................69
Midiendo la temperatura del Núcleo Cortex..................................................................................71
Canales DMA......................................................................................................................................77
Modo DMA de doble buffer................................................................................................................90
Emular memoria EEPROM en FLASH..............................................................................................90
Protocolo I2C......................................................................................................................................93
Sensor para medir Temperatura y Humedad HDC1000....................................................................103
Driver para el sensor HDC1000...................................................................................................104
Sensor Barométrico LPS25HB..........................................................................................................110
Driver para el sensor LPS25HB....................................................................................................114
Sensor BME280 (Todo en uno).........................................................................................................119
Impresoras Térmicas.........................................................................................................................121
Puerto SDIO con STM32..................................................................................................................123
Memoria SD con FAT........................................................................................................................128
Ejemplo de manejo de FAT con STM32.......................................................................................135
Creando un disco extraíble a partir de una memoria SD..............................................................139
Control PID.......................................................................................................................................141
3
Funcionamiento general de un PID..............................................................................................142
Control PID con STM32F407......................................................................................................142
Datalogger de temperatura................................................................................................................147
Capitulo IV.............................................................................................................................................154
FSMC (Flexible Static Memory Controller)....................................................................................154
Pantallas TFT................................................................................................................................154
Que es RFID.................................................................................................................................161
Origen de los RFID.......................................................................................................................161
Frecuencias en distintos países.....................................................................................................161
Cantidad de información almacenada en una etiqueta de RFID...................................................162
Etiquetas de lectura y lectura/escritura.........................................................................................162
Etiquetas pasiva y etiquetas activas.............................................................................................162
Colisión entre tarjetas...................................................................................................................162
Modo lector denso........................................................................................................................163
Tags pasivos usados en el ejemplo...............................................................................................163
Receptor RFID CR95HF...............................................................................................................164
Comandos del CR95HF................................................................................................................166
Hardware usado en el proyecto.....................................................................................................176
Driver para RFID CR95HF...........................................................................................................178
Sensor de imagen OV7670 con STM32F407...............................................................................186
Formato de la imagen...................................................................................................................187
RGB..............................................................................................................................................187
Señales de la cámara.....................................................................................................................189
SCCB (Serial Camera Control Bus).............................................................................................191
Estructura del proyecto DCMI_OV7670......................................................................................193
Manejo del Touch-Screen.............................................................................................................196
Protocolo 1-wire................................................................................................................................202
Niveles eléctricos del bus.............................................................................................................202
Envío y recepción de datos...........................................................................................................203
Ejemplo con 1-Wire y el sensor DS18B20 & UART...................................................................203
Ejemplo con 1-Wire y el sensor DS18B20 & LCD TFT..............................................................207
Ethernet y MII (Media Independent Interface).................................................................................210
Señales del transmisor Ethernet....................................................................................................210
Señales del receptor Ethernet........................................................................................................210
Reducción Media Independent Interface (RMII)..........................................................................211
El stackt LwIP controlando LED´s mediante CGI.......................................................................213
SSI (Server Side Include).............................................................................................................217
Que es un socket?.........................................................................................................................220
Capturando paquetes con LwIP....................................................................................................221
Wi-Fi con ESP8266......................................................................................................................227
Enviando datos con ESP8266.......................................................................................................230
Sensor OPT3001................................................................................................................................236
CAN BUS ( Controller Area Network).............................................................................................239
CAN BUS Loop Back (Sin la capa física)....................................................................................241
CAN NORMAL (Con la capa física)...........................................................................................248
Bibliografía............................................................................................................................................256
4
Capitulo I.
Historia de la Arquitectura ARM.
ARM es una empresa presente en el mercado desde 1990 y que ha logrado en estos pocos años colocar
productos de consumo global diseñando una arquitectura que lidera a escala mundial en 32 bits.
Concebida originalmente por Acorn Computers para uso en computadoras, los primeros productos
basados en ARM fueron los Acorn Archimedes lanzados en 1987.
La relativa simplicidad de los procesadores ARM los ha convertido en la tecnología dominante en el
mercado de la electrónica móvil integrada, microprocesadores y microcontroladores pequeños, de bajo
consumo y relativamente bajo costo. En la actualidad alrededor del 98% de los teléfonos móviles
vendidos cada año utilizan al menos un procesador ARM.
Desde 2009, los procesadores ARM son aproximadamente el 90% de todos los procesadores RISC de
32 bits que se utilizan en la electrónica de consumo, incluyendo PDA, Tablets, Teléfonos
inteligente,videoconsolas, calculadoras, reproductores digitales de música y medios (fotos, vídeos,
etc.), y periféricos de computadoras como discos duros y routers.
La arquitectura ARM es licenciable. Las empresas que son titulares de licencias ARM actuales o
anteriores incluyen a empresas como Alcatel-Lucent, Apple Inc., AppliedMicro, Atmel, Broadcom,
Cirrus Logic, Digital Equipment Corporation, Ember, Energy Micro, Freescale, Intel, LG,Marvell
Technology Group, Microsemi, Microsoft, NEC, Nintendo, Nokia , Nuvoton, Nvidia, Sony, NXP (antes
Philips), Oki, ON Semiconductor, Psion, Qualcomm, Samsung, Sharp, STMicroelectronics, Symbios
Logic, Texas Instruments, VLSI Technology, Yamaha, y ZiiLABS.
ARM solo desarrolla la arquitectura pero no fabrica chips, estos son fabricados por otras empresas que
licencian esta arquitectura.
El origen de ARM se remonta a 1983 como un proyecto de desarrollo en la empresa Acorn Computers
cuya meta era, originalmente, el desarrollo de un procesador avanzado, pero con una arquitectura
similar a la del MOS 6502.
La razón era que Acorn tenía una larga línea de computadoras basados en ese micro.
El equipo terminó el diseño preliminar y los primeros prototipos del procesador en el año 1985, al que
llamaron ARM1. La primera versión utilizada comercialmente se bautizó como ARM2 y se lanzó al
mercado en el año 1986.
La arquitectura del ARM2 posee un bus de datos de 32 bits y ofrece un espacio de direcciones de 26
bits, junto con 16 registros de 32 bits. Uno de estos registros se utiliza como contador de programa,
aprovechándose sus 4 bits superiores y los 2 inferiores para contener las banderas del propio
procesador.
El ARM2 es probablemente el procesador de 32 bits útil más simple del mundo, ya que posee sólo
30.000 transistores. Su simplicidad se debe a que no está basado en microcódigo (sistema que suele
ocupar la cuarta parte de la cantidad total de transistores usados en un procesador) y a que, como era
común en aquella época, no incluye caché. Gracias a esto, su consumo en energía es bastante bajo, a la
vez que ofrece un mejor rendimiento que un 286.
Su sucesor, el ARM3, incluye una pequeña memoria caché de 4 KB, lo que mejora los accesos a
memoria repetitivos.
A finales de los años 80 Apple Computer comenzó a trabajar con Acorn en nuevas versiones del núcleo
ARM.
6
Características heredadas de RISC.
La arquitectura ARM incorporó algunas características del diseño RISC de Berkeley, aunque no todas.
Las que se mantuvieron son:
• Arquitectura de carga y almacenamiento(load-store). Las instrucciones que acceden a memoria
están separadas de las instrucciones que procesan los datos, ya que en este último caso los datos
necesariamente están en registros.
• Instrucciones de longitud fija de 32 bits. Campos de instrucciones uniforme y de longitud fija
para simplificar la decodificación de las instrucciones.
• Formatos de instrucción de 3 direcciones. Consta de “f” bits para el código de operación, “n”
bits para especificar la dirección del 1er. operando, “n” bits para especificar la dirección del
2do. operando y “n” bits para especificar la dirección del resultado (el destino).
Algunas ventajas de RISC.
•
•
•
Menor desperdicio de área de silicio. Un procesador simple economiza transistores y área de
silicio. En consecuencia una CPU RISC deja mayor área libre para realizar mejoras de
rendimiento, tales como, memoria caché, funciones de manejo de memoria, punto flotante por
hardware,etc.
Menor tiempo de desarrollo. Un procesador simple tiene menor costo y lleva menos esfuerzo de
diseño, se adapta mejor a sistemas de tecnología de procesos.
Mayor rendimiento. Si se diseña un procesador simple y luego se le agregan instrucciones
complejas hará en forma más eficiente varias funciones de alto nivel pero también decaerá un
poco el reloj para el conjunto de las instrucciones. Midiendo los beneficios de esta técnica en
programas típicos se comprueba que todos los sets de instrucciones complejos hacen que el
programa corra a menor velocidad.
Desventajas de RISC.
•
•
No ejecuta códigos x86.Pero hay programas de emulación para varias plataformas RISCs.
Pobre densidad de código. Comparada con CISC. Ésto es consecuencia del set de instrucciones
de longitud fija. En ausencia de memoria caché, esta pobre densidad de código significa que la
búsqueda de la instrucción necesita un aumento del ancho de banda de la memoria principal,
dando por resultado un mayor consumo.
Bus AMBA.
El significado de esta sigla es Advanced Microcontroller Bus Architecture. La misma se refiere a un
standard de facto, abierto, que facilita la interconexión de bloques de propiedad intelectual para formar
“Sistemas On Chip”, es decir, circuitos integrados formados por varios procesadores y periféricos,
interconectados en un bus común. Los procesadores ARM utilizan esta arquitectura para interconexión
de los diferentes bloques internos que forman el chip.
Podemos ver en el gráfico anterior que en el procesador hay tres buses con tres velocidades distintas.
•
•
•
AHB1 corriendo a 168Mhz.
APB2 corriendo a 84Mhz.
APB1 corriendo a 42Mhz.
11
Esto último es muy importante porque marca una de las grandes diferencias con un microcontrolador
de 8 bits o de arquitectura “tradicional” en donde podemos tener la certeza de que cada operación dura
un determinado tiempo o ciclo de CPU lo que lleva a que los tiempos en juego se pueden determinar
con facilidad. En un micro de 32 bits hay varios buses y los tiempos ya no son tan fáciles de predecir ya
que otros periféricos pueden estar usando estos buses o si el micro tiene memoria cache esto altera los
tiempos en juego por lo que debe usted desterrar la idea que solo basta con contar las instrucciones y
multiplicar por la velocidad del bus.
Lo siguiente que puede resultar un poco confuso es que todo dentro del Cortex tiene su reloj individual
que por defecto esta desconectado.
Es decir entonces que para hacer uso de un módulo una de las configuraciones que debemos incluir es
activar y el reloj y determinar una frecuencia de operación dentro del rango que el bus admite.
Pipeline.
Se llama “pipeline” a la técnica que aprovecha un método para optimizar los recursos de hardware y
también el rendimiento del procesador.
Consiste en comenzar a procesar una instrucción antes de que se haya finalizado de procesar la actual.
En la siguiente figura se ilustra la ejecución de instrucciones con la técnica pipeline.
Tomando la secuencia de operaciones a partir de la instrucción “1”, el procesador se organiza de tal
manera que tan pronto como haya completado la primera etapa de esa instrucción, “fetch” y haya
avanzado hacia la segunda etapa, comenzará la primera etapa, “fetch”, de la próxima instrucción. En
principio, de esta manera el tiempo de ejecución debería ser hasta seis veces más veloz que el que
corresponde a instrucciones no superpuestas pero, como veremos luego, en la práctica no ocurre así.
Una de las características clave del alto desempeño de los microcontroladores ARM es el pipeline.
ARM7 tiene un pipeline de tres etapas que aumentan el flujo de instrucciones a través del procesador.
Así que cada instrucción se ejecuta en tres etapas:
1) Recoger: Se lee la instrucción de la memoria y se coloca en el pipeline
2) Decodificar: Se decodifica la instrucción.
3) Ejecutar: Se ejecuta la instrucción.
12
El pipeline se implementa en el nivel de hardware. Pipeline es lineal, lo que significa que el procesador
ejecuta una instrucción mientras está cargando otra para ser decodificada. Si bien esto suena interesante
presenta problemas con los saltos, por ejemplo cuando una instrucción necesita de un dato que todavía
no ha sido decodificado por lo que se ve obligado a esperar la ejecución de la instrucción que contiene
la información, esto se mejora con técnicas predictivas a nivel de hardware.
Registros del Procesador.
Existen trece registros de propósito general todos de 32 bits, otra gran diferencia con
microcontroladores menores donde solo existen un registro de trabajo y la interacción de nuestras
aplicaciones con este registro es fácilmente predecible, con trece registros la historia se complica y ya
no es tan claro como el procesador usará estos registros cuando programamos en lenguajes como C
donde la independencia con el hardware es importante.
Dos registros para el manejo del Stack, Main Stack Pointer (MSP) que es cargado con el valor
0x00000000 luego de un Reset, y el Procesador Pointer (PSP.
El Link Register (LR), registro R14 almacena la información de declaraciónes de subrutinas, llamadas a
funciones y excepciones, valores de retorno. Luego de un reset el valor LR es 0xFFFFFFFF.
El Program Status Register (PSR) se usa para para monitorear el estado del programa en ejecución, por
ejemplo si un número es negativo o cero entre otras cosas.
Luego de un RESET el PC se carga con el valor 0x00004 y el M4 puede dirección hasta un límite
teórico de 4GB.
13
Procesadores Escalares:
Los procesadores escalares son el tipo más simple de procesadores. Cada instrucción de un
procesador escalar opera sobre un dato cada vez. En contraposición, en un procesador
vectorial una sola instrucción opera simultáneamente sobre un conjunto de datos. La
diferencia entre ambos es la misma que entre la aritmética escalar y la vectorial. Los
procesadores escalares pueden ser CPUs completas o ALUs. En algunos casos, un
procesador puede estar compuesto de una CPU y varias ALUs, formando el conjunto un
procesador superescalar.
Instrucciones Ortogonales:
La ortogonalidad es una propiedad de las unidades centrales de procesamiento. Se dice
que un conjunto de instrucciones es ortogonal cuando se puede utilizar cualquier modo de
direccionamiento en cualquier instrucción. La búsqueda de la ortogonalidad hace que el
diseño de la unidad central de procesamiento sea más complejo pero aporta una mayor
facilidad de programación.
La programación para este dispositivo es C casi podemos decir de manera obligada, la complejidad de
sus funciones, estructura y posibles configuraciones de trabajo hacen que estos dispositivos no sean
aptos para una total programación en lenguajes de bajo nivel.
Existen en la actualidad herramientas/soft de programación para todos los sistemas operativos y
muchas de estas herramientas basadas en Linux y Windows son de uso libre corriendo por ejemplo en
Eclipse.
Nosotros en el curso usaremos el entorno de KEIL en Windows pero los programas pueden ser
compilados en cualquier herramienta como veremos mas adelante.
17
Para trabajar con solo necesitamos una computadora con puerto USB puesto que la propia placa que
estamos usando se alimenta desde el USB.
Al conectar la placa entrenadora puede suceder que el firmware del programador STLink embebido en
la placa este desactualizado, esto depende de las distintas versiones que hay en el mercado de esta
entrenadora.
Para actualizar el firmware solo debe ejecutar el siguiente programa que encontrará dentro de las
herramientas del curso.
Esto actualizará el firmware de su programador a la versión mas resiente.
23
También encontrará un soft programador para esta arquitectura, si ha programado usted PIC´s podemos
decir que sería algo como el PicKit, ICD3, etc. Todo lo necesario para instalarlo junto a los drivers
USB están en el paquete de herramientas del curso. Antes de intentar trabajar con la entrenadora se
deben instalar los drivers para que el sistema la reconozca. Sin embargo normalmente no necesitaremos
lidiar con el programador ya que el entorno KEIL integra la placa entrenadora/programadora en sus
herramientas y todo el trabajo lo haremos desde el mismo entorno sin necesidad de trabajar con
ninguna herramienta exterior.
Con KEIL podremos hacer una gran variedad de aplicaciones para distintos ambientes y necesidades.
Una de las características mas interesantes que tiene la arquitectura ARM es que nos permite
formar parte de una comunidad donde existen muchos desarrolladores de aplicaciones para
hardware diverso donde hay mucho código y paquetes de programas ya resueltos, rutinas que
son de uso libre que inclusive pueden haber sido escritas para Cortex M3 y son perfectamente
portables a M4 con simples ajustes en el proyecto a compilar.
24
Configurando el entorno de trabajo.
Desde la lengüeta Device seleccionamos el micro-controlador, desde la lengüeta Target definimos
algunas configuraciones básicas para nuestro controlador. MicroLib es una biblioteca altamente
optimizado para aplicaciones embebidas escritas en C basados en ARM. Cuando se compara con la
biblioteca de C estándar que se incluye con el compilador de ARM, MicroLib proporciona
significativas ventajas en cuanto al tamaño de código requerido para muchos sistemas embebidos.
26
Aquí configuramos el entorno, las rutas de archivos y librerías, si en el paso anterior indicamos que
usaremos librerías provistas por STM en este paso indicamos donde están estas librerías.
IMPORTANTE: MicroLib es una biblioteca altamente optimizado para
aplicaciones embebidas escritas en C basados en ARM. Cuando se compara con la
biblioteca de C estándar que se incluye con el compilador de ARM, MicroLib
proporciona significativas ventajas en cuanto al tamaño de código requerido para
muchos sistemas embebidos.
Recordar: Todos los trabajos ejemplos están para
ser compilados con MICROLIB.
KEIL lo puede descargar directamente desde su pagina oficial.
28
Desde la lengüeta Debug siempre dentro de Utilities indicamos que el programador es del tipo SW y
no del tipo JTAG. (Si olvido este paso el programador NO FUNCIONARÁ.)
Puedo programar el microcontrolador sin un programador específico?
El controlador STM32F407VG y todos los
dispositivos de STMicroelectronics tienen
incorporado un cargador que funciona con el
protocolo UART y que permite bajar nuestro
código directamente a la memoria FLASH de
controlador.
Solo se necesita un conversor USB-RS232 para
nuestra notebook, elegir el COM en uso,
conectar el TX al pin PB10 y RX al pin PB11 en
el caso del STM32F407VG.
Si durante el arranque del controlador detecta un
nivel alto en el pin Boot 0 ejecuta el cargador
que espera recibir el programa que se guardará
en FLASH a través del puerto COM.
Luego se cambia el nivel de Boot 0, un RESET y
se ejecuta el programa grabado.
Es importante comentar que este cargador no
consume recursos del microcontrolador ni memoria de programa, es un módulo aparte agregado por
STM para simplificar el proceso de grabación de la FLASH con la aplicación programada.
30
Mi Primer Programa en KEIL
Teniendo todo ya configurado vamos a intentar escribir nuestro primer programa, una plantilla genérica
de un programa con CMSIS.
Podemos ver aquí los dos archivos para el inicio del sistema generados por CMSIS.
El archivo startup_stm32f4xx.s es el archivo de arranque del sistema dentro de este archivo se puede
leer lo siguiente:
El archivo startup_stm32f4xx.s llama a funciones que se encuentran en system_stm32f4xx.c, este
archivo es el que contiene la configuración de hardware del microcontrolador como velocidad de los
buses, tipo de cristal, reloj para USB, etc.
*===============================================================================
*
Supported STM32F4xx device revision
| Rev A
*----------------------------------------------------------------------------*
System Clock source
| PLL (HSE)
*----------------------------------------------------------------------------*
SYSCLK(Hz)
| 168000000
*----------------------------------------------------------------------------*
HCLK(Hz)
| 168000000
*----------------------------------------------------------------------------*
AHB Prescaler
| 1
*----------------------------------------------------------------------------*
APB1 Prescaler
| 4
*----------------------------------------------------------------------------*
APB2 Prescaler
| 2
*----------------------------------------------------------------------------*
HSE Frequency(Hz)
| 8000000
*----------------------------------------------------------------------------*
PLL_M
| 8
31
Se declara el uso de la estructura para la configuración de los puertos GPIO.
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
Aquí se activa el reloj que proviene del bus AHB1 y específicamente lo estamos activando para el
puerto D.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
Específicamente vamos a configurar el pin 15 del puerto D e indicamos que será salida. También se
podrían configurar mas pines de una sola vez por ejemplo de la siguiente forma:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13| GPIO_Pin_14;
En la siguiente línea indicamos que la salida será del tipo Push-Pull. (Opuesto a Open Drain).
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
Los pines del puerto en modo salida pueden ser configurados en tres modos distintos.
• open drain Salida de colector abierto.
• open drain, with pull-up Transistor para el nivel bajo y una resistencia a nivel alto.
• push-pull Un transistor para el nivel alto y otro para el nivel bajo.
En el modo entrada son tres también los modos de funcionamiento:
•
•
•
pull-up Un resistor conectado a nivel alto.
Pull-down Un resistor conectado a nivel bajo.
pull-up and pull-down Un resistor conectado a nivel alto y otro a nivel bajo (Se utiliza en
raras ocasiones, no es una configuración usual).
Se configura el puerto a 100Mhz.
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
No hay resistencias Pull-Up ya que el puerto funciona como salida.
GPIO_InitStructure.GPIO_PuPd
= GPIO_PuPd_NOPULL;
Finalmente la estructura se hace activa.
GPIO_Init(GPIOD,&GPIO_LED);
Es en este momento que la configuración pasa a ser efectiva y el puerto es configurado.
Importante:
Todo trabaja a 3V, por lo tanto los niveles lógicos son de 3V tenga especial cuidado de no
mezclar niveles digitales de 5V puesto que podría dañar la placa entrenadora.
36
Para el tratamiento de estos datos con la información provista por el fabricante podemos crear una
función que lo resuelva.
float temperatura_leer_grados(void) {
float grados;
ADC_SoftwareStartConv(ADC1); // Inicia la conversión
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)){}
grados = ADC_GetConversionValue(ADC1);
grados = (grados *3.3)/4095;
grados = ((grados - 0.76)/2.5)+25;
return(grados);
// Retorna el valor ya escalado
}
Importante:
Tenga en cuenta que incluso si usted no está usando un disparador externo mediante la instrucción:
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None
En la declaración ADC_InitStructure.ADC_ExternalTrigConv sigue siendo necesaria para la estructura
que se escriba “algo” válido de lo contrario se producen resultados extraños en las conversiones.
La inicialización T1_CC1 es equivalente a la inicialización del miembro de estructura a 0.
Para visualizar los datos usaremos una pantalla 16x2 Hitachi 44780, el controlador para esta pantalla lo
encontramos en los archivos stm32f4_hd44780.c y stm32f4_hd44780.h donde se encuentran tanto las
funciones para el manejo de la pantalla como la conexión de los pines.
La pantalla se puede conectar a cualquier puerto del controlador solo basta editar el archivo
stm32f4_hd44780.h que es donde se encuentran estas definiciones.
El archivo temperatura_intern.c tiene todas las funciones para la medición de temperatura y el archivo
temperatura_intern.h las correspondientes declaraciones de variables y funciones.
72
Canales DMA.
Hay dos controladores DMA “casi” idénticos siendo la principal diferencia que solo el DMA2 puede
realizar transferencias de memoria a memoria y claro que los DMA están conectados a distintos buses
de reloj.
Cada DMA puede manejar ocho stream (ocho canales FIFO), cada flujo de datos deberá estar asociado
a uno de estos canales.
Los periféricos tienes asociado tanto el canal como el stream.
En el manual del dispositivo se puede consultar el mapeo de los periféricos y su relación con los DMA.
77
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4; // Cuatro conversiones en ADC3
ADC_Init(ADC3, &ADC_InitStructure);
Configura el órden de lectura de los canales y la velocidad
ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_144Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 2, ADC_SampleTime_144Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_144Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 4, ADC_SampleTime_144Cycles);
/* Habilita la transferencia DMA con el ADC3 (Modo Single-ADC) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
/* Habilita ADC3 DMA */
ADC_DMACmd(ADC3, ENABLE);
/* Habilita ADC3 */
ADC_Cmd(ADC3, ENABLE);
}
/******************* FIRTEC Capacitación *****FIN DE ARCHIVO**********************/
Vemos otro ejemplo de uso del DMA tratando los datos desde la UART4.
El objetivo es recibir 16 Bytes almacenarlos en el DMA y transmitirlos por el mismo puerto.
De acuerdo al mapa de periféricos vemos que la recepción del UART4 se conecta al Canal4 con el
Stream2 del DMA1. Observe que 16 Bytes son 128 bits que es lo máximo que puede manejar el FIFO
del módulo DMA.
Se activan los relojes de los módulos que se usarán:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
Configuramos los pines que usaremos en el puerto UART.
En este programa usaremos el PA0 para transmitir y el PA1 para recibir los datos.
83
Modo DMA de doble buffer.
Funciona como el modo normal (single-buffer), con la diferencia de que se tiene dos punteros a
memoria. Cuando el modo doble buffer está activo el modo circular es activado automáticamente y en
cada extremo de la transacción (DMA_SxNDTR register reach 0), el punteros memoria se mantiene.
Esto permite que el software pueda procesar un área de memoria mientras que la segunda área de
memoria está siendo utilizado o completado por la transferencia DMA.
El modo de doble buffer es adecuado cuando necesitamos hacer el seguimiento de una señal o para el
muestreo de una señal que evoluciona rápido en el tiempo y necesitamos que los datos en proceso de
ser tratados no se interfieran con los datos que están siendo capturados.
Emular memoria EEPROM en FLASH.
Muchos microcontroladores cuentan con memoria EEPROM para guardar datos que el usurario desea
conservar cuando el controlador ha sido desconectado, un ejemplo podría ser la clave de una alarma.
Es poco práctico que para cambiar la clave de una alarma o sistema de acceso debiéramos re-programar
nuestro controlador, es mas lógico pensar que el usuario puede hacerlo por si mismo.
El STM32F407 no dispone de memoria EEPROM sin embargo podemos emular esta memoria en la
propia FLASH asignando sectores de FLASH a las que llamaremos páginas.
La memoria de programa de este microcontrolador es de 1MB y está definida desde la dirección
0X200FFFFF a 0x20000000 (1,048,575 Bytes) si bien el procesador puede direccionar 4GB este Mega
Byte está mapeado dentro de estos 4 GB teóricos.
El ejemplo que tratamos esta basado en la nota de aplicación AN3969 de STM donde se crean dos
páginas de 16K.
•
•
Página 0 con dirección de 0x0000 a 0x3FFF
Página 1 con dirección de 0x4000 a 0x7FFF
La dirección FLASH donde inicia la emulación está en 0x08008000 y se usan dos sectores de 16K para
crear estas páginas con direcciones virtuales.
90
Sensor para medir Temperatura y Humedad HDC1000.
Con este sensor podemos medir temperatura con un rango que va desde -40 grados a +125 grados y
humedad de 0 a 100%. Utiliza un conversor analógico de 14 bits lo que da una precisión mas que
aceptable para aplicaciones donde el control de estas variables sea necesario. Un ejemplo podría ser un
invernáculo, una bodega, una cámara frigorífica, etc.
Desarrollado por Texas Instruments y ha sido calibrado en fábrica por lo que no requiere ajuste alguno.
Este sensor tiene una serie de registros de 16 bits para su configuración y uso.
En la dirección 0x00 se guardan dos Bytes que corresponden a la temperatura y en la dirección 0x01
dos Bytes para la humedad.
La dirección 0x02 es el registro de configuración, en este registro nos interesa solamente el bit 12 que
configura la forma en que los datos estarán disponibles.
Si el bit es puesto a uno la temperatura y humedad serán accedidos en secuencia, primero la
temperatura y luego la humedad.
En nuestro ejemplo y para simplificar las cosas, estamos usando un sensor ya montado en una placa
impresa construido por MikroElektronika y por su bajo costo no justifica construirla. (Sin embargo el
fabricante de la placa brinda todos los diagramas de conexionado).
Para el manejo de este sensor hemos desarrollado un pequeño driver que resuelve todo su
103
while(1);
}
HD44780_Puts(0, 0,"STM32F4<>HDC1000");
Config_Sensor();
while(1){
Leer_Sensor();
sprintf(floatStr,"T:%2.1f",temperature);
HD44780_Puts(0, 1,floatStr);
sprintf(floatStr,"Hum:%2.1f%%",humidity);
HD44780_Puts(7, 1,floatStr);
Delayms(500);
}
}
/*** fin del archivo ***********************************************************/
El resultado final obtenido es el que se aprecia en la imagen.
La dirección I2C de este sensor es 0x40 y su ID es 0x1000, este ID se encuentra escrito en el registro
0xFF y puede ser usado para verificar si el sensor accedido es el correcto.
Analizando la función que lee el sensor.
void Leer_Sensor() {
I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter);
I2C_write(I2C1, 0x00);
108
En la imagen siguiente se puede ver como están dispuestos estos registros de datos. Las direcciones
0x28, 0x29 y 0x2A contienen la información de presión, las direcciones 0x2B y 0x2C contienen el
valor de temperatura con su signo.
Un detalle curioso es que si pretendemos leer consecutivamente los registros en un acceso I2C de
lectura de múltiples registros consecutivos, en ocasiones el valor leído se corrompe. No ocurre si se lee
los registros de uno en uno como se verá en el ejemplo mostrado.
El fabricante indica que para interpretar correctamente la temperatura se aplica el siguiente criterio.
En la practica veremos que el valor de temperatura en realidad es un tanto inexacto a la hora de
implementarlo como valor útil, en realidad el sensor lo utiliza en sus procesos internos con la presión
siendo para el usuario un valor agregado.
112
Para el cálculo de la temperatura aplicamos la siguiente formula:
Para el cálculo de la presión absoluta los pasos indicados por el fabricante serían como sigue:
En el ejemplo siguiente vemos como leer y mostrar el valor de presión atmosférica, el resultado final es
el que se aprecia en la siguiente foto.
El sensor por cuestiones prácticas, hemos usado uno ya montado en una pequeña placa.
Un detalle a tener en cuenta es que, al menos en la placa que probamos, no están soldadas las
resistencias de 4,7K necesarias para el correcto funcionamiento del bus I2C siendo necesarias
colocarlas de manera externa.
Para dialogar con el sensor necesitaremos de un driver, en la página siguiente podemos ver el listado
completo des driver que permite el acceso y control del sensor LPS25HB.
113
SD_Response(&response, RESP_R1);
//Configura SDIO->CLKC
tempreg=0;
tempreg|=(0x01)<<11; //4 bit para el bus
tempreg|=SDIO_CLKCR_CLKEN; // Clock habilitado
// Nuevo clock =48/(Div+2)=48/2=24
SDIO->CLKCR=tempreg; // Ahora se pueden usar los comandos de lectura/escritura
}
El resto de las funciones las encontrará en el archivo SDIO.C y SDIO.H dentro de la
carpeta de proyecto SDIO.
Memoria SD con FAT.
Secure Digital (SD) es un formato de tarjeta de memoria
inventado por Panasonic. Se utiliza en dispositivos portátiles
tales como cámaras fotográficas digitales, PDA, teléfonos
móviles, computadoras portátiles e incluso videoconsolas,
entre muchos otros.
Estas tarjetas tienen unas dimensiones de 32 mm x 24 mm x
2,1 mm. Existen dos tipos: unos que funcionan a velocidades
normales, y otros de alta velocidad que tienen tasas de
transferencia de datos más altas. Algunas cámaras
fotográficas digitales requieren tarjetas de alta velocidad para poder grabar vídeo con fluidez o para
capturar múltiples fotografías en una sucesión rápida.
Los dispositivos con ranuras SD pueden utilizar tarjetas MMC, que son más finas, pero las tarjetas SD
no caben en las ranuras MMC.
Asimismo, se pueden utilizar en las ranuras de CompactFlash o de PC Card con un adaptador.
Sus variantes MiniSD y MicroSD se pueden utilizar, también directamente, en ranuras SD mediante un
adaptadores.
Todas las tarjetas de memoria SD y SDIO necesitan soportar el antiguo modo SPI/MMC que soporta la
interfaz de serie de cuatro cables ligeramente más lenta (reloj, entrada serial, salida serial y selección de
chip) que es compatible con los puertos SPI en muchos microcontroladores.
Muchas cámaras digitales, reproductores de audio digital y otros dispositivos portátiles, probablemente
utilicen exclusivamente el modo MMC. La documentación para implementar este modo es arancelada
sin embargo, la documentación parcial para SDIO es libre y existe documentación libre disponible para
tarjetas de memoria como parte de las hojas de especificación de algunos fabricantes.
El modo MMC no proporciona acceso a las características propietarias de cifrado de las tarjetas SD y la
documentación libre de SD no describe dichas características.
La información del cifrado es utilizada primordialmente por los productores de medios y no es muy
utilizada por los consumidores quienes típicamente utilizan tarjetas SD para almacenar datos no
protegidos.
Existen 3 modos de transferencia soportados por SD:
• Modo SPI: entrada separada serial y salida serial.
128
herramientas del curso.
La idea es lograr escribir con el microcontrolador un archivo de texto (Hola.txt) con el contenido
“Manejando archivos con FAT”.
Luego podemos ver el contenido de este archivo en nuestra computadora como se muestra en la
siguiente imagen.
También vamos a crear un archivo de texto (Mensaje.txt) con un texto cualquiera que será leído por
nuestro controlador y toda la información del contenido de la memoria será enviada a través del puerto
serial .
La comunicación se establece a 11520 baudios.
El pin PC_7 recibe y el pin PC_6 a transmite.
La trama se establece en 8 bits S/Paridad.
133
Captura de pantalla en el momento en que se conecta la memoria SD. Como se observa el sistema
detecta nuestra memoria como una unidad de disco donde podemos leer, borrar o guardar doscumentos
creados en nuestra computadora. El proyecto completo listo para ser compilado y/o reformado a
voluntad lo encontrará en la carpeta USB_MemSD.
Utiliza el puerto USB de usuario.
Proyecto completo
140
Funcionamiento general de un PID.
Para el correcto funcionamiento de un controlador PID que controle un proceso o sistema se necesita,
al menos:
1. Un sensor, que determine el estado del sistema.
2. Un controlador, que genere la señal que gobierna al actuador.
3. Un actuador, que modifique al sistema de manera controlada.
El sensor proporciona la información al controlador, la cual representa el punto actual en el que se
encuentra el proceso o sistema.
El controlador lee una señal externa que representa el valor que se desea alcanzar. Esta señal recibe el
nombre de punto de consigna (o punto de referencia), la cual es de la misma naturaleza y tiene el
mismo rango de valores que la señal que proporciona el sensor.
El controlador resta la señal de punto actual a la señal de punto de consigna, obteniendo así la señal de
error, que determina en cada instante la diferencia que hay entre el valor deseado (consigna) y el valor
medido. La señal de error es utilizada por cada uno de los 3 componentes del controlador PID. Las 3
señales sumadas, componen la señal de salida que el controlador va a utilizar para gobernar al actuador.
La señal resultante de la suma de estas tres se llama variable manipulada que será transformada para
ser compatible con el actuador utilizado en el sistema.
Las tres componentes de un controlador PID son: parte Proporcional, acción Integral y acción
Derivativa. El peso de la influencia que cada una de estas partes tiene en la suma final, viene dado por
la constante proporcional, el tiempo integral y el tiempo derivativo, respectivamente. Se pretenderá
lograr que el bucle de control corrija eficazmente y en el mínimo tiempo posible los efectos de las
perturbaciones.
Control PID con STM32F407.
CMSIS de ARM proporciona funciones matemáticas avanzadas para el diseño de un control PID.
También hay funciones PID en diferentes formatos para f32, q31 y Q7. Este proyecto implementa un
142
controlador PID con STM32F4xx usando funciones PID de ARM que ofrece tres funciones diferentes
para el PID. f32: float, q31: número entero, Q7: char.
Para cada uno de los tres tipos, tiene tres funciones:
f32
arm_pid_init_f32
arm_pid_reset_f32
arm_pid_f32
q31
arm_pid_init_q31
arm_pid_reset_q31
arm_pid_q31
q7
arm_pid_init_q7
arm_pid_reset_q7
arm_pid_q7
También hay una estructura donde se pasa parámetros al PID.
En el proyecto tratado se utilizan dos sensores de temperatura DS18B20. Se configuran en la
resolución de 12 bits por lo que demora unos ~ 750ms entre cada medición.
El proyecto completo se puede ver funcionado en este link.
143
#define TEMP_CURRENT
#define TEMP_WANT
temps[1]
temps[0]
// Temperatura Actual
// Temperatura Referencia
#define PID_PARAM_KP
#define PID_PARAM_KI
#define PID_PARAM_KD
100
0.025
20
// Proporcional
// Integral
// Derivativo
char str[100];
int main(void) {
PWM_TIM_t TIM_Data; // Timer para el PWM
uint8_t devices, i, count;
uint8_t device[EXPECTING_SENSORS][8]; // ID de los sensores
float temps[EXPECTING_SENSORS]; // Temperatura de los sensores
float pid_error; // PID Error
float duty = 0; // Duty del PWM
arm_pid_instance_f32 PID;
// Función PID de ARM
// Seteo de los parámetros del PID
PID.Kp = PID_PARAM_KP; // Proporcional
PID.Ki = PID_PARAM_KI; // Integral
PID.Kd = PID_PARAM_KD; // Derivativo
arm_pid_init_f32(&PID, 1); // Configura la función ARM PID float 32
DELAY_Init();
// Configura los retardos
PWM_InitTimer(TIM2, &TIM_Data, 1000);
// TIM2 a 1kHz (Carrier del PWM)
// Configura TIM2 en Canal1, PinsPack 2 (PA5)
PWM_InitChannel(TIM2, PWM_Channel_1, PWM_PinsPack_2);
// Seteo del duty cycle por defecto
PWM_SetChannelPercent(TIM2, &TIM_Data, PWM_Channel_1, duty);
// Inicializa 1-Wire en pin PA6 (Archivo defines.h)
OneWire_Init();
HD44780_Init(20, 2);
// LCD en 20 columnas x 2 filas
// Verificar la presencia de sensores 1-Wire
count = 0;
devices = OneWire_First();
while (devices) {
// Busca los códigos ROM de los sensores
OneWire_GetFullROM(device[count]);
count++;
devices = OneWire_Next();
145
unsigned char bandera =0;
static char ArchNombre[13];
char temp[11];
char espacio[20];
uint8_t devices,count;
uint8_t device[EXPECTING_SENSORS][8];
float temps[EXPECTING_SENSORS];
unsigned char minuto_anterior = 0;
TM_DS1307_Time_t time;
static void fault_err (FRESULT rc);
#define EXPECTING_SENSORS
1
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) //!< IAR Compiler
#pragma data_alignment=4
#endif
#endif // USB_OTG_HS_INTERNAL_DMA_ENABLED
__ALIGN_BEGIN USB_OTG_CORE_HANDLE
USB_OTG_dev __ALIGN_END ;
FUNCION PRINCIPAL DEL PROGRAMA
int main(void){
TM_DS1307_Init();
/*
// Valores por defecto para el calendario
time.hours = 8;
time.minutes = 8;
time.seconds = 10;
time.date = 16;
time.day = 6;
time.month = 1;
time.year = 15;
TM_DS1307_SetDateTime(&time);
*/
HD44780_Init(16, 2);
// 16 col x 2 filas
DELAY_Init();
// Configura las rutinas de tiempo
OneWire_Init();
// OneWire en pin PC0
149
Modo lector denso.
Este es una modalidad de operación que previene que los lectores interfieran entre sí cuando muchos de
estos lectores se utilizan ubicándolos de manera cercana el uno del otro. Los lectores saltan entre los
canales dentro de cierto rango del espectro de la frecuencia y puede ser necesario que tengan que captar
una señal antes de poder usar un canal. Si "escuchan" que otro lector está usando ese canal, saltan a
otro canal para evitar interferir con el lector que está usando ese canal.
Tags pasivos usados en el ejemplo.
En el ejemplo propuesto usamos los típicos tags de uso común para reglamentar el ingreso a edificios,
controla de alarmas, etc. Su funcionamiento se basa en la señal que le llega de los lectores. Ésta induce
una pequeña corriente eléctrica, suficiente para el funcionamiento del circuito integrado CMOS del tag
y la transmisión de información al lector.
La distancia de aplicación de estos tags es para uso cercano, unos pocos centímetros entre el tag y el
lector.
Debido a la importancia en el consumo de energía, la respuesta del tag pasivo ha de ser breve,
normalmente poco más que un número de identificación.
La posición u orientación de los tags presentados frente al lector puede afectar al funcionamiento
óptimo, se pretende siempre intentar la máxima interacción entre las antenas.
163
}
Escribe_Comando(0x02,2);
Leer_Comando();
}
En este caso el código enviado es 0x02, no confundirlo con con el comando que también es 0x02.
Una vez que todas las configuraciones están terminadas solo resta recibir los distintos tag que se
presenten frente al receptor RFID.
La detección de los tags se resume en un bucle while() que llama a la función Buscar_TagID(), esta
función es la encargada de leer el tag, intenta primero con el protocolo 18092 y si no tiene éxito cambia
al protocolo 14443.
Si miramos dentro de la función que detecta los tags podemos ver donde se determina el protocolo de
recepción (marcado en rojo).
void Buscar_TagID(){
sdata[0] = 0x00;
sdata[1] = 0xFF;
sdata[2] = 0xFF;
sdata[3] = 0x00;
sdata[4] = 0x00;
Escribe_Comando(0x04,5);
Leer_Comando();
.
.
.
(Resto de la función)
En la hoja de datos se indica la secuencia de bytes que se deben enviar para configurar el chip en uno u
otro protocolo.
En el bucle principal del programa se interroga por nuevos tags y se los muestra en una pantalla LCD,
174
La placa RFID tiene varios pines, varios de ellos no llevan conexión. Los pines SS1 y SS0 son los
encargados de la selección del tipo de conexión al microcontrolador, UART o SPI.
El pin Int1 es el pin encargado de validad el estado de los bits presentados en SS0 y SS1, la acción
sobre este pin está a cargo del software siguiendo el procedimiento indicado en la hoja de datos.
Los pines que se vinculan al puerto SPI se conectan este órden.
•
•
SDI se conecta al pin MOSI de nuestro controlador, GPIOB_15 en este ejemplo.
SDO se conecta al pin MISO de nuestro controlador, GPIO_14 en este ejemplo.
177
}
unsigned char SPI_RX_Byte(void)
{
while(SPI_I2S_GetFlagStatus(Open_SPIx, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(Open_SPIx,0x00);
while(SPI_I2S_GetFlagStatus(Open_SPIx, SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(Open_SPIx);
}
Una vez que tenemos todos los archivos podemos ensamblar el proyecto, su aspecto final debería ser
como se aprecia en la siguiente imagen. Los archivos para el manejo de la pantalla LCD como las
rutinas de tiempo no se incluyen por razones de espacio y por considera que son de uso común
existiendo muchos ejemplos que se descargan libremente de internet.
Sensor de imagen OV7670 con STM32F407
El OV7670 es un sensor de imagen de bajo costo con un DSP integrado que puede operar a un máximo
de 30 fps y 640 x 480 de resolución (VGA), equivalente a 0.3 Megapixels.
La imagen capturada puede ser pre-procesada por el DSP antes de enviarla al puerto DCMI. Este preprocesamiento se puede configurar a través de un registro de control (SCCE).
El módulo de la cámara tiene una doble fila de 8 pines por lado:
La interfaz se conecta a la placa entrenadora mediante 16 conexiones.
186
Manejo del Touch-Screen.
El hardware que maneja el Touch es el controlador XPT2046 y su driver está en el archivo
TouchPanel.c
El panel táctil es del mismo tamaño que la pantalla LCD de modo que si pulsamos un lugar en el panel
táctil, conoceremos las coordenadas (x, y) que corresponde a la pantalla. El XPT2046 es un controlador
de pantalla táctil resistiva de 4 hilos que incorpora un conversor de 12 bits 125 kHz de muestreo.
El método que utilizamos para obtener las coordenadas (x, y) se llama referencia diferencial. La teoría
no se explica aquí. Si usted tiene interés, puede echar un vistazo a la hoja de datos XPT2046.
Estructura interna del controlador.
Conexiones mínimas del controlador.
196
El siguiente programa utiliza el Touch Screen de la pantalla TFT y nos servirá de ejemplo.
/**********************************************************************************
* Nombre
: Touch_TFT.c
* Descripción : Manejo del TouchScreen
* Target
: STM32F407VG
* ToolChain
: MDK-ARM
* IDE
: uVision 4
*
*
www.firtec.com.ar
*********************************************************/
#include "stm32f4xx.h"
#include "LCD/LCD.h"
#include "TouchPanel/TouchPanel.h"
#include <stdio.h>
int main(void){
int8_t
temp[20]={0};
uint16_t tempx=0,tempy=0;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
TP_Init();
Configurar_LCD();
LCD_Clear(Black);
TouchPanel_Calibrate();
LCD_DrawLine( 0, 0, 320, 0, White);
// Línea superior
LCD_DrawLine( 0, 222, 320, 222, White); // Línea título, abajo
LCD_DrawLine( 0, 239, 320, 239, White); // Línea abajo final
LCD_DrawLine( 319, 0, 319, 240, White); // Línea vertical derecha
LCD_DrawLine( 0, 0, 0, 240, White);
GUI_Text(1,223,"
http://www.firtec.com.ar
",White,Blue);
LCD_DrawLine( 319, 0, 319, 240, White);
// Línea vertical derecha
while (1)
{
getDisplayPoint(&display, Read_Ads7846(), &matrix );
TP_DrawPoint(display.x,display.y);
if(tempx != display.x || tempy != display.y)
{
sprintf(temp,"X:%3d,Y:%3d",tempx,tempy);
GUI_Text(10,10,(uint8_t*)temp,Red,Black);
tempx = display.x;
tempy = display.y;
}
}
}
197
// LEE por la dir ROM de cada sensor y guarda en temps
TM_DS18B20_Read(&device[i][0], &temps[i]);
sprintf(buf, "T%d: %3.2f ", i, temps[i]);
GUI_Text(Y,X,buf,White,Red);
Y=Y+100;
}
alarm_count = 0;
// Verifica si algún sensor tiene seteada alarmas
while (TM_DS18B20_AlarmSearch()) {
// Almacena la dir ROM del sensor con alarma
TM_OneWire_GetFullROM(&alarm_device[alarm_count][0]);
alarm_count++;
}
sprintf(buf, "Alarmas Activas: %d", alarm_count);
GUI_Text(92,100,buf,Black,Cyan);
X =120;
Y =86;
// Muestra cuantas sensores con alarma existen
if (alarm_count > 0) {
// Muestra el ROM code del sensor con alarma
for (j = 0; j < alarm_count; j++) {
for (i = 0; i < 8; i++) {
sprintf(buf, "%02X ", alarm_device[j][i]);
GUI_Text(Y,X,buf,Black,Green);
Y = Y + 20;
}
}
}
X = X + 20;
Y =82;
else{
GUI_Text(7,120,"
GUI_Text(7,140,"
GUI_Text(7,160,"
",Cyan,Green);
",Black,Green);
",Cyan,Green);
}
Delayms(250);
}
}
Resultado esperado de nuestra aplicación en ejecución.
209
Configura los LED's de la placa
void LED_Init(void){
STM_EVAL_LEDInit(LED1);
STM_EVAL_LEDInit(LED2);
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1)
{}
}
#endif
Aspecto del proyecto a compilar.
Que es un socket?
Seguramente encontrará variadas definiciones de lo que es un
Socket en redes informáticas, sin embargo desde el punto de vista
de la electrónica con microcontroladores, podríamos simplemente
decir que es el RS-232 de TCP-IP.
Una de las formas mas simples de conectar un microcontrolador,
PLC o electrónica en general a una computadora es a través de una
UART con el conocido protocolo RS-232. Un socket hace eso
mismo, establece una conexión entre dos puntos, sin importar donde se encuentren estos puntos y esto
si es una gran diferencia con el viejo RS-232.
Podemos hacer una medición de voltaje, temperatura, humedad o lo que fuera necesario verificar y
transmitir estos datos a cualquier parte del mundo por TCP-IP para esto solo necesitamos tres cosas:
220
1. Una dirección IP donde enviar los datos.
2. Un puerto virtual donde los datos será recogidos.
3. El conocimiento para darle forma a la idea
Hay varios tipos de socket pero dos son de uso mas común.
• Los socket de flujo (SOCK_STREAM) que son transportados por TCP (Protocolo de Control
de Transmisión) y asegura que los mensajes lleguen en el mismo orden que fueron enviados y
sin errores. Telnet, los navegadores y muchas aplicaciones usan este tipo de conexión fiable y
segura.
• Los socket de datagrama (SOCK_DGRAM) son transportados por UDP (Protocolo de
Datagramas de Usuario), Es la forma mas simple de enviar datos por la red. Simplemente
montamos un paquete le damos una dirección destino y un puerto y listo!! El SOCK_DGRAM es
mas rápido que el anterior pero claro aquí no importa el orden en que los paquetes llegan y
varias cosas mas no son tomadas en cuenta motivo por el cual es mas rápido. Pero cuando lo
que enviamos son simples datos de una medición o el estado de una máquina y solo estaremos
usando la conexión para enviar datos sueltos y esporádicos (mismo que hacemos con RS-232 y
microcontroladores) este tipo de socket es ideal para mover datos con nuestra electrónica.
Capturando paquetes con LwIP.
Con una exigencia de memoria RAM muy baja y ocupando menos de 40KB de memoria de programa,
la pila LwIP es muy adecuada para embeberla en microcontroladores.
Esta formado por varios archivos todos escritos en C que se pueden adaptar a casi cualquier necesidad
ya que su uso es libre.
LwIP ofrece tres API's para el manejo de red, RAW, NETCON y SOCKET.
La gestión de los paquetes se realiza en un buffer llamado pbuf que asigna y organiza toda la memoria
para el correcto funcionamiento del satck, básicamente hay tres tpos de pbuf, el PBUF_POOL que es
el mas adecuado para recibir paquetes y almacenarlos rápidamente y es el que usaremos. PBF_RAM es
mas lento puesto que lleva mas gestión de memoria y los paquetes no se guardan en espacios contiguos
resultando en una fragmentación de memoria, aplicaciones puntuales hacen uso de este modo.
PBUF_ROM se utiliza para enviar datos constantes obtenidos de la memoria de programa.
El pbuf que usaremos tiene el siguiente formato.
Básicamente es una estructura con varios campos, el campo next es un apuntador al siguiente pbuf dado
221
#********************************************************************************
def info():
showinfo(title='Acerca de..', message='Script en Python 2.7 \n
www.firtec.com.ar')
def makemenu(parent):
menubar = Frame(parent)
menubar.pack(side=TOP, fill=X)
fbutton = Menubutton(menubar, text='Menu', underline=0)
fbutton.pack(side=LEFT)
file = Menu(fbutton)
file.add_command(label='Acerca de...', command=info,
underline=0)
file.add_command(label='Salir',
command=parent.quit, underline=0)
fbutton.config(menu=file)
makemenu(ventana)
label_Nombre_IP = Label(ventana, text="IP:", bg="beige", fg="blue",
font=("Helvetica", 14))
label_Nombre_IP.place(x=18, y=35)
label_IP = Label(ventana, bg="beige", fg="blue", font=("Helvetica", 14))
label_IP.config(text = Dir_IP)
label_IP.place(x=42, y=35)
label = Label(ventana, text="Voltios:???", bg="beige", fg="red", font=("Helvetica",
28))
label.place(x=100, y=80)
ventana.after(1, update_label)
ventana.mainloop( )
Resultado obtenido al ejecutar el programa Python
224
Wi-Fi con ESP8266.
El chip ESP8266 brinda la posibilidad de conexión a una red Wi-Fi con
mucha facilidad sin importar la arquitectura del micro utilizado. (ARM,
PIC, ATMEL etc).
Soporta el protocolo 802.11 y tiene capacidad para Wi-Fi Direct (P2P),
integra el stack TCP/IP con un núcleo Cortex M3 con arquitectura RISC
de 32bits a 80Mhz. Cuenta con 64KBytes de RAM para instrucciones y
96KBytes de RAM para datos. Los módulos que usan este chip son de
varios fabricantes y vienen en diferentes formatos con distintos pines
para puertos GPIO, puertos de comunicaciones, un canal analógico.
Incluso algunos módulos integran una memoria Flash SPI que se suma a
la memoria propia para guardar programas que controlan el propio
ESP8266 sin necesidad de un microcontrolador.
El firmware que trae por defecto solo permite controlarlo mediante
comandos AT por lo que no puede ejecutar ningún programa, para esto
hay que cambiar el firmware por otro, hay varios por ejemplo
NodeMCU, una plataforma abierta para la “Internet de las Cosas”que fue
desarrollada en China.
Cuando apareció el módulo Wi-Fi ESP8266, el mundo de los hobbistas se entusiasmó bastante ante el
surgimiento de un dispositivo capaz de entregar conectividad inalámbrica a plataformas de hardware a
un bajo costo, entre los entusiastas se encontraba un grupo de desarrolladores chinos de plataformas
abiertas de hardware, quienes se basaron en el ESP8266 para lanzar un kit llamado NodeMCU para el
desarrollo de prototipos compatible con Arduino, que se programa en Lua. NodeMCU ha sido bastante
bien recibido por la gente dedicada a desarrollar proyectos Hazlo-Tu-Mismo, pues permite el desarrollo
de sistemas como por ejemplo para el monitoreo de temperaturas y humedad ambiental en habitaciones
a un costo muy bajo.
Sin embargo el uso de este firmware no solo sirve para Arduino, también podemos usarlo en otras
arquitecturas como por ejemplo ARM.
Para los comandos AT la comunicación se realza mediante una conexión UART, y cualquier programa
terminal sirve sin embargo el programa que usemos debe enviar un final de línea en cada transmisión.
Para actualizar el firmware se debe usar un programa especial que permite el acceso a la Flash o
memoria de programa.
Este procedimiento puede inutilizar de manera permanente el modulo Wi-Fi si no se realiza
correctamente.
Es importante conocer el origen del firmware que se está cargando en el módulo, hay muchas versiones
modificadas en Internet y no todas funcionan correctamente, además será necesario cargar los
parámetros de acceso a nuestra red Wi-Fi lo que en definitiva es abrir una puerta al mundo en nuestra
propia red con los consabidos riesgos de seguridad.
Siempre conviene descargar las versiones oficiales desde el sitio de Espressif, fabricante del chip.
Descargaremos los firmware denominados como “based on ESP8266_NONOS_SDK_Vx.x.x”. La
denominación NONOS significa sin sistema operativo y responden a comandos AT.
La conveniencia de cambiar de firmware esta en relación con lo que necesitamos hacer y con el tipo de
módulo que tenemos, para cambiar de firmware es importante contar con memoria de programa, Lua es
un lenguaje interpretado y es necesario cargar el interprete Lua en el ESP8266 para que este pueda
correr los programas, si tenemos un módulo que tiene pocos pines GPIO, sin memoria exterior
227
Para esto enviamos AT+CWJAP=”nombre_de_la_red”,”clave”, esperamos un momento y si todo está
correcto responderá OK. Para saber que dirección IP nos ha asignado enviamos el comando AT+CIFSR
que nos informa el IP por ejemplo podemos tener una respuesta como la que se aprecia en la siguiente
imágen.
En el caso que nuestro módulo este en modo 3, tendremos como respuesta dos direcciones IP, una será
192.168.4.1 que es la que corresponde al modo 2 asignada por el propio DHCP interno, (esta dirección
no se puede cambiar) y la otra será la que nos asigna el servidor DHCP de nuestra red.
El paso siguiente será crear un socket UDP con el ESP8266 que reporte el voltaje presente en un canal
analógico a un servidor. En la siguiente imagen se aprecia como los datos son representados tanto en
una pantalla LCD y en la computadora.
Se ha definido una pequeña función que se encarga de configurar el ESP8266 para la creación del
socket, esta función asume que los parámetros de red (SSID y Password) ya fueron cargados
anteriormente.
El programa principal del proyecto es el siguiente. (El servidor Python se encuentra dentro de a
carpeta con el ejemplo).
/***********************************************************************
* Descripción : Envío de datos con un modulo WiFi ESP8266. Se conecta
*
a la red enviando los datos de un canal analógico
*
Los datos también se muestran en un LCD 16x2.
* Target
: STM32F407VG
* ToolChain
: MDK-ARM
* IDE
: uVision 5
*
www.firtec.com.ar
*
************************************************************************/
// Conexiones del LCD al controlador
//-----------------------------------// Pin RW GPIOE_4
// Pin RS GPIOB_2
// Pin E GPIOB_7
231
tiempo_UDP++;
if(tiempo_UDP == 100){
Enviar_String(floatStr);
tiempo_UDP =0;
}
// Espera
// Envía el dato al socket
}
}
También podríamos enviar los datos de temperatura y humedad con el sensor HDC1000.
Datos recibidos en el Socket Servidor
En este ejemplo se ha usado la misma biblioteca que se usara en el ejemplo del HDC1000 con su
configuración I2C.
La función principal de este ejemplo es la siguiente.
int main(void) {
TM_DELAY_Init();
Config_USARTx();
Config_I2C1();
lcd_init();
device_id = Leer_SensorID();
lcd_locate(0,0);
if(device_id != 0x1000){
lcd_str(" HDC1000 ERROR!");
while(1);
}
Config_Sensor();
Delayms(1000);
lcd_locate(0,0);
lcd_str("Espere........");
Configurar_ESP8266();
lcd_locate(0,0);
lcd_str(" ECP8266 WiFi");
while (1){
Delayms(500);
Leer_Sensor();
sprintf(floatStr,"%2.1f - %2.1f%% ", temperature,humidity);
Enviar_String(floatStr);
sprintf(floatStr,"T:%2.1f",temperature);
235
El sensor se vincula con el procesador mediante un bus I2C con identificador I2C 0x44.
OPT3001 en funcionamiento
En el siguiente ejemplo podemos ver como implementar el uso de este sensor.
/***********************************************************************
* Descripción : Medición de luz ambiente en el rango de visión del
*
ojo humano con el sensor OPT3001
* Target
: STM32F407VG
* ToolChain
: MDK-ARM
* IDE
: uVision 5
*
www.firtec.com.ar
*
************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "lcd_hd44780_lib.h"
#include "tm_stm32f4_delay.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include ".\OPT3001_Driver\OPT3001_Driver.h"
char floatStr[10];
char txt_viejo[10];
unsigned char temp;
237
interrumpa la línea L, ocurrirá lo contrario. Esta situación permite que el sistema siga trabajando con
uno de los cables cortados o comunicados a masa.
Es importante tener en cuenta que el trenzado entre ambas líneas sirve para anular los campos
magnéticos, por lo que no se debe modificar en ningún caso ni el paso ni la longitud de dichos cables.
Dado que la línea es un par trenzado se necesitan resistencias de terminación 120 ohm en ambos
extremos del bus, solo colocar la resistencias en los extremos no en los nodos individuales.
El controlador STM32F407VG tiene dos puertos CAN, estos puertos tienen todo lo necesario a nivel
lógico para el tratamiento de las tramas CAN sin embargo para implementar las comunicaciones se
necesita la capa física (al igual que Ethernet, RS-232, etc).
La capa física la implementamos con un integrado muy popular en el mundo CAN que ademas de ser
muy económico funciona muy bien y se puede conseguir ya montado en una placa como se ve en la
imagen. Para verificar el funcionamiento del CAN inicialmente no necesitamos la capa física puesto
240
}
CanRxMsg RxMessage;
CAN_Receive(CAN2,CAN_FIFO0, &RxMessage);
CAN2_ID=RxMessage.StdId;
CAN2_Dato0=RxMessage.Data[0];
CAN2_Dato1=RxMessage.Data[1];
CAN2_Dato2=RxMessage.Data[2];
CAN2_Dato3=RxMessage.Data[3];
CAN2_Dato4=RxMessage.Data[4];
CAN2_Dato5=RxMessage.Data[5];
CAN2_Dato6=RxMessage.Data[6];
CAN2_Dato7=RxMessage.Data[7];
CAN_ClearITPendingBit(CAN2,CAN_IT_FMP0);
Bandera_Can2 = ENABLE;
Resultado obtenido al ejecutar el programa.
255