Recientemente, los llamados velocímetros digitales para bicicletas (ciclocomputadores) se han generalizado entre los accesorios para bicicletas. Estos dispositivos son capaces de medir muchos parámetros, los principales son la velocidad y la distancia. El principio de medir la velocidad se basa en el cálculo del período de revolución de la rueda, y la distancia se calcula sobre la base de medir el número de tales revoluciones. A menudo, el sensor de revolución de la rueda es un interruptor de láminas junto con un imán en el radio de la rueda. Dependiendo de la funcionalidad, el precio de tales dispositivos varía ampliamente. El velocímetro de bicicleta más barato se puede comprar por aproximadamente 500 p.
Siempre tuve el deseo de tener un dispositivo similar. Al mismo tiempo, formulé una serie de requisitos propios que debería satisfacer. En primer lugar, realmente quería ver un gráfico de los cambios de velocidad dependiendo de la distancia o el tiempo acumulado durante un corto período a medida que se mueve. Y también, para registrar (registrar) mediciones en un dispositivo de almacenamiento para una mayor transferencia de datos estadísticos a una computadora, su visualización más detallada. Los modelos baratos no cumplen completamente con mis requisitos, pero no quiero pagar de más por modelos caros.
Basado en lo anterior, decidí crear mi propio velocímetro para bicicleta basado en el microcontrolador ATmega8. Hubo muchas preguntas, en particular sobre los periféricos utilizados. Accidentalmente me topé con artículos sobre el uso de la pantalla del teléfono móvil Nokia 3310. Una vez que leí la hoja de datos y me aseguré de que fuera fácil de operar, no tuve dudas de que el velocímetro se fabricaría en el cuerpo del teléfono mencionado con su propia pantalla. El caso es bastante bueno, y el dispositivo en sí no es difícil de encontrar.

Como ROM para registrar estadísticas de medición, decidí poner una ROM 24XX512 clásica (512 Kbps), que se controla a través de la interfaz I2C. No me molesté con el uso de una tarjeta de memoria SD / MMC. Otra función importante en el dispositivo es el reloj. Sirven para vincular algunos parámetros específicos medidos (por ejemplo, velocidad máxima) a la fecha y la hora, y también son necesarios para registrar marcas de tiempo en las estadísticas. Como reloj, utilicé un chip de reloj en tiempo real (RTC) separado del microcontrolador, que tiene energía de batería independiente y también se comunica con el controlador a través de I2C.
Implementé requisitos secundarios adicionales en la funcionalidad del dispositivo en la etapa de redacción del programa. Esto incluye todo tipo de problemas organizativos: la cantidad de botones involucrados, la ubicación en la pantalla de varios elementos, la navegación en la interfaz, etc. En términos de navegación, decidí de antemano no complicar el programa, por ejemplo, no implementar el menú de configuración, en particular, la configuración de fecha y hora. El reloj se configura una vez. El reloj funciona independientemente en el chip RTC, gracias a un cuarzo de 32.768 KHz y una batería que dura mucho tiempo. La configuración de fecha y hora se realiza a través de la interfaz UART del velocímetro, conectada al puerto COM de la computadora con un solo clic. A través de la misma interfaz, se suponía que debía leer datos estadísticos desde la ROM a una computadora. Para todo esto, debe escribir el programa apropiado para la computadora. Sin embargo, como lo demostró la práctica adicional, este último tuvo que ser abandonado. En primer lugar, estaba el problema de implementar la recepción de datos desde el controlador a la computadora en la etapa de escribir un programa de computadora. Y, aún más significativamente, el volumen del programa para el controlador aumentó. Fue mucho más interesante colocar la ROM (en el SMIC que aloja SOIC-8) en una plataforma extraíble, acorde con la tarjeta SIM, y usar la ranura libre adecuada en el teléfono móvil. Para hacer esto, es necesario fabricar un lector de ROM basado en un lector de SIM de acuerdo con uno de los esquemas bien conocidos del programador de ROM I2C. Como resultó más tarde, esta decisión no causó inconvenientes innecesarios.
Otra cuestión importante es la salida de información simbólica (incluida la digital) en una pantalla gráfica. Esto requiere información gráfica sobre un símbolo en particular. Esta información está estrechamente relacionada con un parámetro como el tamaño de la fuente mostrada. Para mostrar el parámetro principal, la velocidad de movimiento, para una buena claridad, es conveniente utilizar una fuente grande. Sin embargo, como se mostrará más adelante, dicha información gráfica sobre diez dígitos no cabe en la memoria de MK, y el uso de la misma ROM externa más amplia disminuirá la velocidad de dibujo de la fuente. Decidí usar una fuente con una altura de 8 puntos como la fuente más grande. Extraje la información gráfica de esta fuente del archivo "8X8.FNT" de algún programa de MS DOS, después de haber desentrañado su estructura y realizado un procesamiento adicional.

Como resultó más tarde en la práctica, este tamaño es suficiente para la claridad de la velocidad. Como el tamaño de la fuente adicional, elegí el tamaño 3x5 y dibujé independientemente los gráficos para los números de este tamaño. Estos números pequeños muestran parámetros adicionales: fecha / hora, velocidad media y máxima, ruta.
La información gráfica de ambas fuentes se almacena en ciertas matrices bidimensionales. Cada elemento de la matriz, de 1 byte de tamaño, denota la distribución de píxeles de una columna particular de un dígito específico. Para letra grande, se asignan 8 columnas para cada dígito, y 3 para 3. Para la letra pequeña, tamaño 3X5, la altura formal no es 5, sino 8 puntos (redondeado a un byte). Esto le permite preorganizar la ubicación de la fuente de 5 posiciones dentro del área de 8 posiciones en la dirección vertical utilizando uno de los 4 métodos posibles. Estos hechos se muestran bien en la figura a continuación, que demuestra el modelado de gráficos para los primeros dos dígitos de esta fuente. Excel es conocido por modelar. Los datos iniciales son la disposición de "unidades" en los campos apropiados para los gráficos deseados. De estos, las fórmulas calculan los valores de las matrices, hasta el código del lenguaje C, que luego se puede copiar en el texto del programa para el microcontrolador.

Ahora hablaremos sobre las características de control de la pantalla utilizada. Esta pantalla es monocromática y sus dimensiones son 84 por 48 píxeles. El control de visualización desde el MK se realiza a través de la interfaz SPI. Los bytes transmitidos por SPI se interpretan en la pantalla en dos modos: bytes para visualización y bytes de comandos de configuración. El MK establece estos modos para un pin de pantalla específico (D / C). Se proporciona una lista completa de comandos en la hoja de datos en la pantalla. Algunos de estos comandos se usan en mi dispositivo y se usan para inicializar la pantalla cuando se aplica energía al dispositivo: coeficiente de temperatura, contraste, modo de dibujo secuencial (horizontal o vertical), etc. Noto de inmediato que se aplica el modo de dibujo horizontal. Esto significa que cuando se transfiere un byte en el modo de visualización, la dirección aumenta automáticamente una línea por línea a la derecha. Cuando finaliza la línea, la dirección de la posición va al comienzo de la siguiente línea. Es suficiente enviar primero un comando de posicionamiento especial a la pantalla a una dirección específica de fila y columna (posición inicial), y luego enviar bytes de datos secuencialmente uno tras otro para mostrar gráficos. Vale la pena señalar la característica del espacio de direcciones y la interpretación de los gráficos, dependiendo de los bytes recibidos por la pantalla. Observo que para los gráficos monocromos, un byte contiene información sobre ocho píxeles a la vez.
La pantalla en cuestión se divide verticalmente en 6 zonas horizontales con 8 líneas cada una (6 * 8 = 48). Cada columna de cada zona corresponderá a un byte específico, que se envía con la dirección de la columna correspondiente (0 ... 83) y el número de zona (0 ... 5). La dirección no se cuenta desde uno, desde cero. Por ejemplo, si se posiciona en la dirección (34; 2) y envía un byte de datos de 255 (en forma binaria "11111111"), los 8 píxeles se iluminarán de 16 a 23 verticalmente y en la 35a columna horizontalmente. En mi opinión, uno de los inconvenientes se deriva de esta característica: la incapacidad de controlar el estado de cada píxel individualmente a nivel de hardware. Un byte es la pieza más pequeña de datos para gráficos. Cuando se transmite un byte a la dirección actual, se actualizan los 8 píxeles correspondientes en la zona actual. La pantalla no admite la lectura de la información gráfica que se muestra actualmente en el microcontrolador. Por lo tanto, si es necesario, es necesario almacenar la información de salida en un búfer dedicado de antemano, y para cambiar el estado de los píxeles (bits), aplique máscaras de bits para bytes desde este búfer y transfiéralos nuevamente a la pantalla.
El modelado y la reflexión sobre la ubicación de una información gráfica particular en la pantalla se llevaron a cabo teniendo en cuenta las características anteriores. Esto se hizo para simplificar el código al escribir el programa. Y no es casualidad que el tamaño de fuente se haya considerado de la categoría 8, 16, 24, es decir, un múltiplo de 8. También dividí la información gráfica, por analogía con la pantalla, en 6 zonas horizontales. En la primera zona, los valores de RPM absolutos y actuales (desde el momento en que se enciende el dispositivo) se muestran en letra pequeña. En la segunda zona, los valores absolutos y actuales de la ruta (en kilómetros con redondeo a centésimas). En la tercera zona - velocidad media. En el cuarto - velocidad máxima y en letra grande - la velocidad actual. En la quinta zona, se muestran dos barras de progreso para indicar que la ROM está llena y el número de sobrescrituras. En la sexta, última zona, la fecha y la hora. Es la quinta zona la excepción cuando en la dirección vertical de cualquier columna tomada hay píxeles relacionados con información diferente. Por lo tanto, esta información utilizando máscaras de bits se recopila en un búfer, cuyo contenido se muestra en esta quinta zona. Además, en 3-5 zonas hay información para dibujar un marco alrededor del valor de velocidad visualizado. En la última zona, cada primer bit (menos significativo) en todas las columnas se establece en "1" para dibujar la línea de separación (40a fila). Para esta simulación y visualización de direcciones, representé todo lo anterior en celdas de Excel.

Así es como se ve la primera ventana de visualización. Solo dos ventanas. La segunda ventana es la salida del gráfico (histograma) del movimiento. Para ello, se asignan 5 zonas (40 filas) verticalmente y las 84 columnas horizontalmente. La sexta zona con el reloj es la misma para ambas ventanas.
Al programar, decidí no recurrir al uso de ninguna biblioteca para trabajar con esta pantalla. Personalmente, es más fácil para mí comprender la hoja de datos, implementar parte de las funciones yo mismo, que comprender la biblioteca. Además, se encontraron ciertas ventajas en esto. Recientemente, después de descargar una de las bibliotecas, descubrí sus características funcionales. Es universal, con su ayuda puede controlar píxeles individualmente y posicionarse en la dirección de píxeles real. Pero la biblioteca utiliza un búfer de 84 * 6 bytes de tamaño, y este búfer de temporizador se envía periódicamente a la pantalla, actualizando los gráficos. Por lo tanto, el temporizador y parte de la memoria MK están ocupados. En mi caso particular, no hay necesidad de usar una biblioteca, ya que al modelar, tuve cuidado de antemano para maximizar la separación de información entre las zonas mostradas, que cumplen totalmente con las zonas de visualización. Y no es necesario actualizar periódicamente la información en la pantalla: la información se actualiza solo si y solo cuando cambia (con cada rotación de la rueda, cada vez que se presiona un botón, etc.). Por lo tanto, enfatizo una vez más: dependiendo de la tarea, puede evitar el uso de cualquier biblioteca.
Para trabajar con un microcircuito de reloj y ROM, tampoco recurrí al uso de bibliotecas: todas las funciones son bastante simples e implementadas por mí después de estudiar las hojas de datos para estos componentes.
Ahora considere el circuito eléctrico del dispositivo.

El diseño del velocímetro es relativamente simple. Además de todo lo anterior, el circuito contiene un elemento IC5 MAX756 que sirve como un convertidor de potencia de 3 a 5 voltios para una fuente de alimentación confiable de la batería original del teléfono móvil Nokia 3310. No implementé el circuito para la fuente de alimentación de 3 voltios debido a la falta de MK y periféricos apropiados. En este momento, todavía no he adquirido el MAX756, y todo el circuito todavía está alimentado por una batería externa Krona que usa el regulador LM7805 (no es la mejor opción). Se conecta a la toma de auriculares en la parte inferior del teléfono. El interruptor de láminas SF1, que es un sensor de rotación de la rueda, está conectado al puerto de interrupción INT0 MK (pin 32). Se conecta de forma segura desde la parte inferior del teléfono al puerto de carga. Los botones funcionales S1-S3 conectados a los botones "1", "2", "3" del teléfono móvil están conectados a puertos arbitrarios (pines 23, 27, 28). Un pin S4 está conectado al pin 29 del reinicio MK, que coincide con el botón del extremo superior para encender el teléfono móvil. Lo hice así como así. El dispositivo en sí no tiene un modo de espera y se enciende con energía. Una pantalla IC2 y un conector para parpadear X1 están conectados al puerto SPI del controlador (pines 15-17). Con el conector, que quería hacer sobre la base de los "puntos" existentes en la placa base original para emparejar con una PC (en el mismo lugar), obtuve un pequeño inconveniente, y en el futuro lo transferiré a otro lugar. Una interfaz UART para la conexión del usuario a una computadora está conectada al mismo conector, a través del cual se configuran la fecha y la hora en el dispositivo (pines 30-31, RX / TX). La pantalla está conectada al controlador a través de divisores en resistencias, que sirven para reducir el voltaje, porque la pantalla funciona a un voltaje de 3.3 V. Además, los pines de la pantalla D / C (datos / comando), SCE (luz estroboscópica) y RES (reinicio de la pantalla) están conectados a puertos arbitrarios MK PB0, PB1 y PB2, respectivamente (pines 12-14). La pantalla se alimenta a través de los diodos D1-D3 y la resistencia R6, que sirven para reducir el voltaje de 5 a 3.3 V, evitando el uso de un regulador lineal. El cuarzo Cr1 cronometrado por MK con un valor nominal de 4.5 MHz fue elegido al azar, pero deliberadamente. Él simplemente cayó en mi brazo, y decidí usarlo. Los transistores Q1 y Q2 están conectados a los puertos del PD4 y PD5 MK (pines 2 y 9), en los que se cargan los LED para la luz de fondo de la pantalla y el teclado. El controlador proporciona la capacidad de controlar las luces de fondo individualmente, como lo proporciona el diseño original del teléfono móvil (esto fue a nivel de hardware y no a nivel de usuario), aunque en la práctica esto no es necesario. El bus I2C está conectado a los puertos PC2-PC3 (pines 25-26) y, por simplicidad, se implementa mediante programación utilizando la biblioteca apropiada (aunque está conectado a los puertos TWI de hardware). La ROM IC3 y el reloj de tiempo real (RTC) IC4 están suspendidos en el bus. Haga una reserva de inmediato para que no haya críticas en los comentarios: sé que el DS1307 no es la mejor solución, pero en el momento del desarrollo del circuito no sabía sobre la existencia del DS3231. La ROM se encuentra en un conector extraíble, similar a una tarjeta SIM. Se utiliza un puerto adicional del controlador PC1 (pin 24) para recibir pulsos con una frecuencia de 1 Hz con RTC, por lo que se actualiza el tiempo en la pantalla. Todos los componentes del kit de cuerpo pasivo, de acuerdo con las hojas de datos de cada componente activo.
Considere consideraciones matemáticas para calcular ciertos parámetros. Como ya se mencionó al principio, el principio de medir la velocidad se basa en calcular el período de revolución de la rueda, y la distancia se calcula sobre la base de medir el número de tales revoluciones. El controlador mide el tiempo entre el pulso anterior y el pulso entrante desde el interruptor de láminas. El resultado de la medición se convierte en un valor de velocidad dividiendo el valor del perímetro de la rueda por el período de revolución, y este valor se actualiza en la pantalla con cada pulso (revolución de la rueda). Vale la pena señalar aquí que, desde el punto de vista de la física, se calcula la velocidad promedio de una bicicleta en una sección de la ruta correspondiente al perímetro de la rueda. Por separado, se calcula el número de pulsos, luego se convierte a un valor de distancia. Para medir el período de rotación de la rueda, el controlador utiliza su propio temporizador. ATmega8 tiene un temporizador de 8 bits y otro de 16 bits. El rango dinámico de la medición depende de la profundidad de bits del temporizador. En mi caso, se usa un temporizador de 16 bits, ya que 8 bits (256 cuentas de cuentas) son categóricamente insuficientes. El período de medición máximo (antes de que el temporizador se desborde) corresponderá a la velocidad mínima medida. Puede ingresar el llamado temporizador de software, que medirá períodos largos. Sin embargo, para simplificar el programa, no hice esto. Con el cuarzo usado de 4.5 MHz y un valor máximo de divisor de 1024 en la configuración del temporizador, tenemos: (1 / (4500000/1024)) = 0.000227556 seg. Este valor corresponde al período mínimo de la cuenta. Y el período máximo de la cuenta será 0.000227556 * 65536 = 14.913 segundos. La velocidad máxima medible correspondiente al período mínimo medible será de aproximadamente 30,000 km / h. Ni siquiera valía la pena estipularlo, la "reserva desde arriba" es simplemente enorme.
Pero la velocidad mínima medida correspondiente al período máximo medido será 2.26 / 14.913 / 1000 * 3600 = 0.54 km / h. Aquí 2.26 es el perímetro de la rueda de la bicicleta (en metros) en mi caso. Estoy bastante contento con este valor mínimo medido. Si la bicicleta se mueve a una velocidad inferior a 0,54 km / h, el velocímetro de la bicicleta registrará la falta de movimiento (y el desbordamiento del temporizador). Con este cuarzo, la interfaz UART de 4.5 MHz funciona bien a una velocidad de 2400 baudios con un error aceptable aceptable. Esta velocidad también es suficiente, especialmente porque uso UART para configuraciones de reloj de una sola vez desde una computadora (para copiar la fecha y hora de una computadora a un dispositivo). Si tomas cuarzo en frecuencia más alta, la velocidad mínima medible aumentará, lo que será inaceptable para mí,y deberá usar un temporizador de software. Y si lo toma a continuación, el rendimiento del dispositivo en su conjunto disminuye. Por lo tanto, decidí dejar este cuarzo en particular.Observo que los valores de período y velocidad son inversamente proporcionales, y el temporizador del microcontrolador mide el período discretamente. En nuestro caso, el rango de medición (0.000227556 ... 14.913) está marcado uniformemente con puntos en la cantidad de 65535, dividiéndolo en muchos intervalos iguales. Y estos puntos corresponden a todo tipo de valores medidos. Utilizando la conversión de intervalos de tiempo a velocidad, este sistema de intervalos se convierte de uniforme a inversamente proporcional. Por lo tanto, el rango de velocidades medidas de forma diversa se divide en intervalos desiguales. La longitud de estos intervalos aumenta al aumentar el valor de la velocidad en sí. Dado este hecho, la enorme "reserva desde arriba", sobre la que escribí un poco más arriba, no estará mal. En la práctica, será suficiente tomar el valor de 100 km / h para la velocidad máxima medida de la bicicleta.Esto es solo para no introducir un nuevo dígito (cientos) y no aumentar el ancho del parámetro mostrado en la pantalla. Calculamos cuál es la longitud del intervalo entre valores posibles adyacentes a una velocidad en el vecindario, por ejemplo, a 90 km / h. Usando las fórmulas inversas o la selección, es fácil calcular que para el valor del temporizador 397 (de 65536 posibles) la velocidad medida corresponde a 90.06 km / h. Y con un valor de temporizador vecino de 398 - 89.83 km / h. Y la diferencia entre las velocidades es de 0.23 km / h, que ya es más que aceptable. Y a velocidades más bajas, esta diferencia será aún menor. La pantalla muestra el valor de la velocidad a la centésima más cercana. Sin embargo, en la práctica, redondear al entero más cercano o a las décimas suele ser suficiente. De lo anterior, podemos concluir: la falta de uniformidad de la "cuadrícula" de velocidades puede descuidarse,ya que el error de medición causado por él no excede el error permitido.Para calcular la distancia, es suficiente multiplicar el número de pulsos (revoluciones) por el perímetro de la rueda. En este caso, por supuesto, la distancia se calcula con precisión al perímetro de la rueda, lo cual es bastante aceptable. La velocidad promedio actual se calcula como la relación entre la distancia actual recorrida y el valor de tiempo desde el momento en que se activó. Este es el tiempo que el controlador considera contando el número de pulsos que llegan una vez por segundo con RTC. La velocidad promedio en la pantalla se actualiza junto con la actualización de tiempo (una vez por segundo). Todos los demás parámetros se actualizan con cada revolución de la rueda.Ahora sobre las pequeñas características de la interfaz. El primer botón se usa para cambiar de modo (modo gráfico o modo de visualización de valores). El segundo botón: para mostrar la velocidad máxima absoluta (de todos los tiempos) en lugar de la relativa cuando se mantiene presionada. Además, la fecha y hora de alcanzar esta velocidad se muestran en lugar de la fecha y hora actuales. Y también, el valor de la dirección ROM actual se muestra en lugar del valor de la velocidad relativa (para control). Este valor puede estimarse mediante la barra de progreso horizontal en la línea 38 de la pantalla. En esta ROM, con una capacidad de 65536 bytes (512 kbit), se registran los parámetros medidos. Como se dirá más adelante, es suficiente registrar el parámetro medido inicialmente (el período de rotación de la rueda) con una marca del tiempo inicial.Todos los demás parámetros son calculados fácilmente por un programa de computadora en la etapa de escaneo de ROM. El tercer botón se usa para controlar la luz de fondo. A diferencia del dibujo de pantalla anterior, luego eliminé ceros insignificantes en los parámetros secundarios para mostrarlos con mayor claridad. En modo gráfico, se dibuja un histograma de la velocidad de movimiento de izquierda a derecha, lo que demuestra claramente el proceso de cambio de velocidad en una pequeña porción de la distancia de 84 revoluciones de la rueda. El valor del histograma es la velocidad a una escala de 1 píxel por 1 km / h. Si la velocidad supera los 40 km / h, la imagen se reduce verticalmente 2 veces para evitar que se salga de la escala. No se requiere que las características completas del comportamiento del dispositivo se describan aquí.Más tarde eliminé ceros insignificantes en los parámetros secundarios para mostrarlos más claramente. En modo gráfico, se dibuja un histograma de la velocidad de movimiento de izquierda a derecha, lo que demuestra claramente el proceso de cambio de velocidad en una pequeña porción de la distancia de 84 revoluciones de la rueda. El valor del histograma es la velocidad a una escala de 1 píxel por 1 km / h. Si la velocidad supera los 40 km / h, la imagen se reduce verticalmente 2 veces para evitar que se salga de la escala. No se requiere que las características completas del comportamiento del dispositivo se describan aquí.Más tarde eliminé ceros insignificantes en los parámetros secundarios para mostrarlos más claramente. En modo gráfico, se dibuja un histograma de la velocidad de movimiento de izquierda a derecha, lo que demuestra claramente el proceso de cambio de velocidad en una pequeña porción de la distancia de 84 revoluciones de la rueda. El valor del histograma es la velocidad a una escala de 1 píxel por 1 km / h. Si la velocidad supera los 40 km / h, la imagen se reduce verticalmente 2 veces para evitar que se salga de la escala. No se requiere que las características completas del comportamiento del dispositivo se describan aquí.El valor del histograma es la velocidad a una escala de 1 píxel por 1 km / h. Si la velocidad supera los 40 km / h, la imagen se reduce verticalmente 2 veces para evitar que se salga de la escala. No se requiere que las características completas del comportamiento del dispositivo se describan aquí.El valor del histograma es la velocidad a una escala de 1 píxel por 1 km / h. Si la velocidad supera los 40 km / h, la imagen se reduce verticalmente 2 veces para evitar que se salga de la escala. No se requiere que las características completas del comportamiento del dispositivo se describan aquí.Vale la pena señalar una de las diferencias características entre mi velocímetro y la compra barata. Consiste en la velocidad de actualización de la indicación de velocidad en la pantalla. En mi dispositivo, se actualiza inmediatamente, según lo calculado, con cada rotación de la rueda. En los dispositivos comprados, se actualiza con cierto retraso. Quizás este retraso se deba a un intento de filtrar el ruido de medición (por ejemplo, utilizando el método de promedio móvil) para estabilizar la visualización de la velocidad en la pantalla para una claridad más detallada. O tal vez la pantalla se actualiza completamente a intervalos regulares (por ejemplo, dos veces por segundo). Puede ser conveniente, pero quería implementar una actualización de velocidad con cada revolución de la rueda.La placa de circuito impreso se realiza mediante el método LUT en forma de placa de circuito original del teléfono móvil usado. En la fabricación de la placa de circuito, utilicé el programa SLayout. Al mismo tiempo, tomé una foto de la placa original en ambos lados del escáner de antemano y puse las imágenes en SLayout como plantilla. Esto es necesario para dibujar almohadillas para conectar la pantalla, botones y conectores en lugares exclusivamente necesarios. En la fabricación de la placa, se produjo un error de aproximadamente 0,5 mm. Este error resultó ser aceptable en términos de combinación de pads y elementos. Sin embargo, este error afectó la calidad de la luz de fondo: los LED sellados se desplazaron por una fracción de milímetros y no cayeron en el foco de los mandriles de dispersión de luz. Debido a esto, el brillo de la luz de fondo disminuyó, reduciendo la eficiencia.Las siguientes figuras muestran una vista de la placa de circuito en SLayout junto con tres pequeñas placas de circuito impreso para ROM en forma de tarjeta SIM. Además, se muestran escaneos de la placa de circuito impreso original desde dos lados.
Algunos elementos (botones, conectores) están interconectados por puentes de cable delgados por falta de la capacidad de colocar pistas. Hay un margen para todos los botones disponibles, es decir, es posible usar cualquier botón disponible. Puede ser conveniente hacer que el botón grande en el centro sea un botón para cambiar los modos de visualización. En la esquina superior izquierda de la placa hay una batería RTC de 3 voltios. En general, todos los elementos en el tablero se colocan correctamente con la coordinación de sus dimensiones con las dimensiones de la caja. A diferencia del original dorado, la placa interna está recubierta con soldadura ordinaria. Como se muestra en la práctica inicial, no se pierde el contacto con la pantalla y otros periféricos.El programa para MK resultó ser bastante grande y ocupa una parte significativa de su memoria. Además, el programa proporciona el uso de su propia memoria no volátil del controlador (EEPROM) para grabar y guardar la información necesaria. La siguiente tabla muestra la distribución de esta información por direcciones EEPROM.Dirección | Tamaño | Datos |
0 0 | 4 4 | n (para S) |
4 4 | 2 | t_min (para v_max) |
6 6 | 6 6 | Fecha de t_min |
12 | 2 | Dirección EEPROM |
14 | 1 | Recuento de EEPROM RW |
128 | 80 | Dígitos 8X8 |
208 | 30 | Dígitos 3X5 |
Los primeros cuatro bytes almacenan la distancia recorrida como el número de revoluciones de la rueda. Elegí específicamente el tipo entero de 32 bits para esta variable, ya que en la práctica los valores de la ruta recorrida son relativamente grandes. Por ejemplo, una variable entera de 16 bits podría ahorrar un máximo de 65.536 revoluciones (aproximadamente 148 km), que es naturalmente pequeña. Siguen dos bytes para mantener la velocidad máxima absoluta. De hecho, se ahorra el tiempo mínimo de rotación de la rueda. La variable ocupa dos bytes, porque su valor es el resultado de medir un temporizador de 16 bits. Los siguientes 6 bytes son la fecha y hora en que se alcanzó la velocidad máxima anterior. Los datos se presentan exactamente en el formato en el que se leen del chip RTC (excluyendo el día de la semana). A continuación, dos bytes que almacenan el valor de la dirección actual de la ROM externa. Este es un tipo de puntero, que es necesario para la posibilidad de continuar el registro de estadísticas en la ROM después de la próxima vez que se enciende el dispositivo. MK debe saber en qué posición del espacio de direcciones de la ROM externa se detuvo por última vez. Desde esta posición, MK continuará grabando. A este valor se le asignan 2 bytes, ya que el espacio de direcciones de la ROM externa es de 16 bits. Esto se deduce de un tamaño de ROM de 64 kB. El siguiente es una variable de un solo byte que almacena el valor del número de sobrescrituras de ROM. La sobrescritura es el caso cuando el puntero anterior alcanza el valor máximo y se convierte en cero. En este caso, la información recién recibida en la ROM comenzará a grabarse desde el principio, borrando la información antigua disponible en ella. Una variable entera de un solo byte es capaz de almacenar un máximo de 256 valores. Le recuerdo que los valores del puntero de la dirección ROM y el número de sobrescrituras se indican visualmente mediante dos barras de progreso en la pantalla. Además, después de un gran espacio de copia de seguridad de la EEPROM MK, comenzando en la dirección 128, se almacena información gráfica sobre 8x8 dígitos. Para ello, se asignan 80 bytes (8 bytes por cada dígito, como se mencionó anteriormente). Y finalmente, comenzando en la dirección 208, se almacenan 30 bytes para obtener información gráfica sobre pequeños dígitos de 3x5 (tres bytes por dígito).
Además del programa principal para el microcontrolador, escribí tres programas auxiliares más para la computadora, que se analizarán a continuación. Todos los programas no tienen una interfaz gráfica y funcionan desde la línea de comandos de Windows XP.
El primer programa le permite copiar la fecha y la hora desde una computadora al velocímetro de la bicicleta a través del puerto COM. El velocímetro de la bicicleta está conectado a la computadora a través del chip MAX232. Usando WinAPI, el programa recibe la fecha y hora actuales en una variable estructural especial del tipo SYSTEMTIME. El día actual, mes, año, número de día de la semana, horas, minutos, segundos en formato decimal se extraen de esta variable. Todos estos números, con la excepción del año, no superan los dos decimales (menos de 100) y se encuentran dentro de un byte. El valor del año se convierte en un número de dos dígitos restando de él el número 2000, el valor del milenio actual. Cada uno de estos números decimales de dos dígitos se convierte a la característica de formato decimal binario del chip RTC. En este formato, un número de dos dígitos también ocupa un volumen de un byte. Los 4 bits más significativos están codificados con el dígito de las decenas, y los menos significativos, el número de unidades. Posteriormente, se forma un paquete de 13 bytes a partir de estos números, de acuerdo con un protocolo que determiné previamente. Los primeros cinco bytes representan la palabra "TIEMPO =" según la codificación ASCII estándar. Luego siga los segundos, minutos, horas, día de la semana, día, mes, año. El último byte es el carácter "#", como el carácter del final del mensaje. Este paquete se envía desde la computadora al dispositivo a través del puerto COM. El programa del microcontrolador recibe el paquete y verifica que sea correcto, de acuerdo con el formato anterior. Si los primeros cinco bytes son "TIME =" y el último es "#", el envío se considera correcto, y los bytes en el interior se interpretan en el orden correspondiente. Sin cambiar esta cadena de bytes, el controlador la envía al chip RTC a través del bus I2C, configurándola para la fecha y hora actuales. Observo que este microcircuito admite el cálculo de los días de la semana del 1 al 7, aunque como tal un calendario que determina la correspondencia de la fecha y el día de la semana, no lo es. No proporcioné la visualización de información sobre el día de la semana en mi dispositivo.
El segundo programa está diseñado para procesar datos del contenido de una ROM externa. Inicialmente, se suponía que este contenido debería copiarse desde la ROM al archivo de imagen utilizando algún programa conocido que funciona con programadores conocidos de MK y ROM (por ejemplo, "icprog"). Sin embargo, después de estudiar el principio de operación I2C con más detalle, logré implementar esta funcionalidad y la incluí en mi programa. El esquema del programador ROM de esta serie, que utilicé en el dispositivo, se presenta en la figura a continuación.

La ROM está conectada al puerto COM de la computadora, que se usa no como un medio para intercambiar información a través de RS-232 (donde es suficiente para usar las salidas de TX, RX, GND), sino como un medio de entrada-salida arbitraria de señales lógicas. A través del terminal TX, se alimenta la ROM, que se estabiliza hasta 5V por el regulador 78L05. Al controlar la salida TX de la computadora, podemos encender o apagar el chip ROM. La línea de reloj unidireccional SCL se concentra en el pin RTS del puerto COM, y la línea de datos bidireccional SDA se concentra en dos pines: CTS (recepción de datos) y DTR (transmisión de datos). Las resistencias y los diodos zener D1 y D2 se utilizan para limitar el nivel de señal a TTL, en el que funciona la ROM.
Hice este programador estándar para mi caso especial, donde en lugar de un socket para ROM, se usa un lector SIM de un teléfono móvil roto.

Por medio de WinAPI, el programa accede a los pines del puerto COM de la computadora, establece los valores necesarios para ellos (0 o 1) y también elimina el valor binario entrante de la ROM del pin CTS. Basado en este kit de herramientas, la funcionalidad I2C se implementó de acuerdo con la especificación relevante, sobre la cual no entraré en detalles. El programa puede leer el contenido de la ROM en una imagen de archivo (como un programador normal), y también procesar dicho archivo o procesar información directamente de la ROM. El procesamiento de la información consiste en obtener los archivos de estadísticas de salida en un formato tabular predeterminado basado en la información de entrada de la ROM. Cada uno de estos archivos corresponde a un viaje (desde el momento de la corriente hasta la próxima vez que se enciende el dispositivo). Primero, describiré brevemente el formato de entrada que definí de antemano. Cada vez que se enciende el dispositivo, se escriben dos bytes de ceros en la dirección actual, que se lee desde la EEPROM del microcontrolador. Cuando la rueda comienza a girar (en el primer impulso) después de un tiempo de espera o después de encender el dispositivo, la fecha y hora actuales se escriben en formato decimal binario (como se almacena en los registros del chip RTC). Y luego se registran dos bytes de "unidades" 0xFF. Durante la rotación de la rueda, para cada pulso k-ésimo (k = 2,3, ...), el tiempo de rotación de la rueda entre el pulso (k-1) th y k-th se registra en dos bytes (alto y bajo). Obviamente, esta información es suficiente para vincular la distancia actual (no absoluta) recorrida y la velocidad a la fecha y la hora. El formato de salida es texto y es una tabla tabular en archivos * .csv que se abren en Excel haciendo doble clic con el mouse. Las filas en esta tabla corresponden a las revoluciones de las ruedas, y los valores de las columnas se muestran a continuación.
ADR | Valor de dirección ROM |
FECHA / HORA | Fecha y hora de inicio |
Dic | Valor de temporizador decimal |
tiempo | Hora actual |
t | Tiempo de viaje desde el encendido |
v | Velocidad |
n | Velocidad |
S | El camino |
un | El número absoluto de revoluciones (solo dentro de la ROM actual) |
aS | Ruta absoluta (solo dentro de la ROM actual) |
n_day | El número de revoluciones para el día actual. |
S_day | El camino para el día actual |
v_max | Velocidad máxima para el viaje actual. |
av_max | Velocidad máxima absoluta (solo dentro de la ROM actual) |
v_mid | Velocidad promedio para el viaje actual |
En la figura siguiente se muestra una captura de pantalla del contenido de dicho archivo en Excel. Además, se muestran gráficos de cambios en la velocidad actual, media y máxima en varios colores en un sistema de coordenadas. Argumento (eje X): valores de velocidad como datos de entrada. La figura muestra los cambios de parámetros para las primeras 730 revoluciones. La distancia recorrida está asociada con esta dependencia lineal variable (730 revoluciones corresponden a aproximadamente 1650 m). Por lo tanto, podemos decir que los gráficos reflejan la dependencia de las velocidades en la distancia (precisa a la escala horizontal), en contraste con la dependencia tradicional de la velocidad en el tiempo, a la que se debe prestar atención. Como ya se mencionó, esta característica se debe a la ideología y al principio de medir la velocidad por la velocidad de la rueda. Pero después de todo, a cada revolución de la rueda (el momento de acercamiento del imán y el interruptor de láminas) se le asigna un momento específico en el tiempo. Naturalmente, esta secuencia de marcas de tiempo no es uniforme. Sin embargo, por formalidad y conveniencia, Excel tiene la capacidad de especificar una matriz de valores de tiempo en la ruta o la hora actual como argumento para los gráficos. Pero de todos modos, debe recordarse que la dependencia real de la velocidad en el tiempo (a intervalos de tiempo uniformes para el caso discreto) se habría visto diferente, con una escala horizontal variable.


La siguiente figura muestra la misma dependencia de la velocidad con las revoluciones, pero ya usa el filtro con el método de promedio móvil con un ancho de ventana de 11 revoluciones. Todos los gráficos están construidos en Excel utilizando métodos bien conocidos.

Al comparar los dos gráficos del cambio en la velocidad, es obvio que el componente de alta frecuencia está ausente en el gráfico filtrado, es decir ruido eliminado El ancho de la ventana de media móvil de 11 revoluciones (aproximadamente 25 m), en mi opinión, es demasiado grande. Si realmente plantea la cuestión de filtrar las lecturas del ruido, es suficiente tomar un pequeño ancho de ventana, por ejemplo, igual a tres. Este algoritmo se puede incorporar al programa del velocímetro de la bicicleta, ya que se puede usar no solo para analizar las lecturas, sino también para mostrar estas lecturas en tiempo real. A pesar de la simplicidad de este algoritmo, no entraré en los detalles de su descripción, ya que este tema está cubierto en el curso de las matemáticas y está más allá del alcance de este artículo. Y aquí hay otra aclaración sobre la velocidad promedio. Como ya escribí, la velocidad promedio es el único parámetro que se actualiza no con cada rotación de la rueda, sino con cada segundo. Hice esto para asegurarme de que la pantalla muestra un cambio en la velocidad promedio incluso con movimientos muy lentos. Por lo tanto, los valores de las lecturas en la pantalla en tiempo real diferirán ligeramente de los valores calculados en el futuro por el programa de computadora en la etapa de escaneo de la ROM. Las lecturas de la velocidad absoluta, la ruta absoluta y la velocidad máxima absoluta también serán diferentes. La pantalla muestra valores realmente absolutos (para toda la vida útil del dispositivo) y en las tablas de salida, solo dentro de los límites de la ROM actual que se está leyendo.
El tercer programa, en esencia, es el mismo programa para el microcontrolador de firmware. Trabajo con el programador STK 200 más simple conectado al puerto LPT de la computadora, o mejor dicho, con su análogo, si puede llamarlo así, porque en el caso más simple el programador no contiene ningún elemento activo. De hecho, MK a través de la interfaz SPI se conecta a pines específicos del puerto LPT directamente y funciona como esclavo. El programa implementa un protocolo para intercambiar datos con el controlador ATmega8 de acuerdo con su hoja de datos (p. 237). La capa física SPI se implementa administrando los registros de puertos LPT utilizando la conocida biblioteca dinámica "inpout32.dll". Mi biblioteca está conectada no como un proyecto (ya que evité crear un proyecto como tal en "Dev-cpp" creando un "archivo" simple), sino que utilicé la función LoadLibrary utilizando el tipo estructural HINSTANCE. La biblioteca "inpout32.dll" se asigna a una variable de este tipo y, posteriormente, los punteros a las funciones de esta biblioteca se extraen en variables separadas. Inpout32.dll tiene solo dos funciones que son responsables de la entrada y salida de datos. Se accede a estas funciones utilizando punteros extraídos previamente. Los pines del puerto LPT se controlan individualmente mediante máscaras de bits. En mi caso particular, el programa que escribí funciona con el área EEPROM del controlador y está diseñado para leer, reservar, escribir, corregir y restaurar desde una copia de respaldo de los datos almacenados que pinté anteriormente. Como todos los demás programas, el programa se ejecuta desde la línea de comandos. En tales casos, para implementar la multifuncionalidad del programa, se utilizan las funciones de "cambio de mayúsculas y minúsculas" y un diálogo de usuario de texto, por ejemplo, "ingrese '1' para la operación No. 1, ..., ingrese '0' para salir del programa". Los datos se muestran en varios formatos convenientes para mí. Además de lo anterior, el programa puede mostrar un volcado completo del controlador EEPROM en 512 bytes en la pantalla. Además, el programa puede registrar información gráfica sobre las fuentes utilizadas en la memoria del controlador. En el caso de letra pequeña, tamaño 3X5, el programa toma información del archivo de texto "Fonts 3X5.txt", que se encuentra en el mismo directorio. El archivo contiene una tabla tabular de 30 bytes (3 por 10) escrita en formato hexadecimal. Si lo desea, puede editarse fácilmente en un editor de texto, cambiando así los gráficos de esta fuente. Como ya se mencionó, esta letra pequeña es tan simple que cambiar sus gráficos no tiene sentido. Lo único es que su desplazamiento vertical solo puede ser necesario, ya que hay un stock de espacio en altura de 8 píxeles, y la fuente tiene una altura igual a 5. En el caso de una fuente grande, tamaño 8X8, que muestra la velocidad actual, proporcioné la funcionalidad mucho más interesante. La información gráfica sobre esta fuente no se presenta en un archivo de texto como una tabla de bytes, sino en archivos gráficos visuales BMP. Cada dígito corresponde a uno de esos archivos. Sus parámetros son tamaño 8X8, monocromo con una paleta en blanco y negro. A continuación se muestra una captura de pantalla del conocido editor gráfico "MS Paint" con el archivo "8.bmp" abierto.

Empíricamente, estudié la estructura de los archivos BMP monocromáticos obtenidos de MS Paint ”, y sobre esta base pude aprender a leer cada píxel de una imagen BMP monocromática (excluyendo el uso de estructuras y bibliotecas auxiliares). En la etapa de lectura horizontal línea por línea de abajo hacia arriba (así es como se organiza la estructura del archivo BMP), el programa convierte la información en el formato vertical específico para la pantalla utilizada. Esta operación se lleva a cabo en una pasada, donde se utilizan máscaras de bits y la acumulación de valores variables. A continuación, mostraré esta sección de código para el i-ésimo dígito, prestando atención a la simplicidad del proceso.
for(k=0; k<8; k++){ fnt[i][k] = 0; } for(j=0; j<8; j++){ fseek(f, 62+4*j, SEEK_SET); byte = ~fgetc(f); for(k=0; k<8; k++){ if(byte & pow2(7-k)){ fnt[i][k] += pow2(7-j); } } }
En el primer bucle, los elementos de la matriz fnt se inicializan en ceros. Además, cada k-ésimo elemento de esta matriz (k = 0 ... 7) para el i-ésimo dígito (i = 0 ... 9) llevará información gráfica sobre cada columna correspondiente de cada dígito correspondiente. El siguiente ciclo es la ejecución a lo largo de las líneas de la imagen del archivo BMP. Con el operador fseek, nos posicionamos bytes en el desplazamiento 62 + 4 * j del archivo BMP predefinido f. La estructura del archivo BMP determina la especificidad de la fórmula mediante la cual se calcula el desplazamiento según el número de línea j. En la variable intermedia de byte, obtenemos el valor de byte en el desplazamiento anterior. Este byte almacena información sobre los ocho píxeles de una imagen monocroma en la línea actual j. El operador '~' realiza una inversión bit a bit del byte, lo que conduce a una inversión de color de cada píxel. Esto se debe al hecho de que un píxel negro en la paleta de un archivo BMP monocromo corresponde a un "0" lógico y blanco - "1". En la pantalla aplicada, por el contrario. En un bucle anidado, se produce un análisis de bytes del byte y, al mismo tiempo, la información se acumula en la matriz de salida fnt. Función pow2: elevar un número entero a una potencia entera no negativa, escrita independientemente. En lugar de esta función, puede usar el operador de desplazamiento bit a bit más eficiente "<<", pero al momento de escribir este programa no lo estaba usando.
Además, el programa proporciona la capacidad de escribir en la memoria de MK una de varias opciones gráficas para esta fuente de mi elección. Estas opciones se implementan utilizando directorios (carpetas) con el nombre de la forma "v1", "v2", "v3", etc., que se encuentran en la carpeta "Fonts 8X8" en el mismo directorio que el programa. Y ya en estas carpetas están los archivos BMP necesarios. Gracias a la funcionalidad anterior, es posible corregir o extraer números de una "hoja en blanco" en un editor gráfico, guardarlos y distribuirlos entre directorios. Tengo tres opciones de fuente. La primera opción es la original. El segundo, como el original, pero con un cero tachado y una unidad modificada (sin subrayado). El tercero es una fuente con un borde rectangular.
Las fotos a continuación muestran: la placa de circuito fabricado del dispositivo desde la parte posterior; un dispositivo en la mesa con alimentación conectada (con una versión no final del firmware); Un dispositivo en funcionamiento montado en una bicicleta con un gráfico de cambios de velocidad en él.



En el proceso de operación del dispositivo, sin embargo, se identificaron pequeños defectos asociados con las características de fabricación. En primer lugar, mal contacto de la pantalla con las almohadillas de la placa de circuito impreso. En el teléfono móvil original, los contactos en el tablero están chapados en oro y no hay oxidación. En mi caso, simplemente están enlatados.
En base a lo anterior, se decidió rehacer el dispositivo en otro caso, así como rehacer la placa de circuito impreso, en la cual la pantalla se soldará insolentemente. Comencé este proceso recientemente. El resultado es un diseño más robusto.



Hice el estuche para el dispositivo a partir de una pieza de plexiglás, de 17 mm de espesor, en una fresadora CNC. Para hacer esto, esbocé preliminarmente los bocetos del caso en el programa SPlan, casi completamente sin conocer el tema de los dibujos, CAD, etc.

Estos bocetos son necesarios para la presentación general y la obtención de las coordenadas de los puntos de control. En base a ellos, se escribe un programa para la máquina CNC, teniendo en cuenta los principios generales y las secuencias de fresado. Escribí el programa CNC manualmente en Excel, usando las funciones de autocompletar para operaciones repetidas.


También corregí ligeramente el diseño del dispositivo, se presenta en la figura a continuación.

En lugar de la retroiluminación ya innecesaria del teclado, hay un LED de belleza que parpadea con cada giro del volante. Los conectores también se vuelven a dibujar, y no hay otros elementos que no fueran necesarios en la versión actualizada del diseño. Además, encontré e instalé cuarzo 4.433619 MHz, corrigiendo ligeramente algunas constantes en el código fuente de mi propio programa. También se hicieron algunos cambios menores al programa.
A continuación se presenta una fotografía del producto terminado. El dispositivo funciona con una batería que se encuentra a bordo de la bicicleta. Desde allí, también se proporciona iluminación para viajes en la oscuridad.

Fue en este diseño que el dispositivo funcionó completamente sin ningún problema técnico. El único inconveniente es el uso de un chip RTC de muy baja calidad: en invierno a bajas temperaturas, el tiempo tiene mucha prisa, hay que ajustarlo una vez al mes.