Un margen tan amplio de revoluciones condiciona cajas de cambios con desarrollos muy similares, por lo cual, en un viaje largo es fácil olvidarse y no saber que marcha tenemos engranada.
Debido a ésto, en su momento proliferaron unos displays que indicaban la marcha engranda midiendo los desarrollos mediante las revoluciones del motor y del piñón de ataque.
En la entrada del blog de hoy, os presento el diseño que realicé hace ya tres años y que tuve instalado durante en varios años en mi moto.
Dviersas pruebas de software en casa.
Verificando el conjunto sobre la motocicleta.
Hardware
El diseño del hardware es simple, meditante dos etapas inversoras realizadas con transistores mosfet las señales del motor son adaptadas a los niveles de tensión del microcontrolador, evitando la llegada de glitch de alta frecuencia, provinientes del circuito de encendido del motor y que afectan fuertemente al micro.
La protección de las puertas de los mosfet se realiza mediante una red RC y diodos.
La etapa de alimentación está formada por un simple regulador 7805 smd y condensadores.
Un display de 7-segmentos es conectado al micro mediante su puerta b y resistencias de polarización.
El desarrolló del pcb lo realicé mediante la plataforma Orcad.
Software
La programación la realicé en C utilizando el compilador CCS.
El programa está basado en una interrupcion por flanco anscendente y un contador de pulsos configurado mediante el Timer0.
Por cada flanco ascendente el programa cuenta las vueltas del motor, calculando el desarrollo.
Comparando el desarrollo con los valores programados en la memoria flash interna calcula la marcha engranada representandola en el display de 7 segmentos.
Código fuente.
/*
Indicador de marchas digital con luces de cambio.
Fco. Javier Ruiz Vidorreta V1.0.
*/
#include "Indicador.h"
// Constantes
#define Numero_de_RPM 30 // Numero de vueltas del motor a contar.
#define Veces_a_Verificar 2 // Nº de veces que queremos que se verifique el dato antes de grabar.
#define Marchas 6 // Nº de marchas a programar.
#define CATODO_COMUN 1 // Tipo de display poner a 0 si es anodo común.
// Conexionado.
#byte port_b=6 // Dirección del puerto B (donde está conectado el display).
// ->Entradas
#define V_Encoder PIN_A4 // Cable del encoder de velocidad.
#define RPM_Encoder PIN_B0 // Cable del encoder de revoluciones.
#define Neutral PIN_A0 // Cable del punto muerto.
#define User_Button PIN_A5 // Pulsador del usuario.
#define Programar_Bit PIN_A6 // Jumper de programación.
// ->Salidas
#define LED_RPM_MAX PIN_A1 // Led de RPM máximas.
#define LED_CAMBIO_PROHIBIDO PIN_A2 // Led no bajar de marcha.
#define Punto_Display PIN_A3 // Led busy.
#define Depurador_bugs (if(input(Punto_Display)){output_low(Punto_Display);}else{output_high(Punto_Display);};)
#use rs232(baud=9600, xmit=User_button,rcv=Neutral) // Pines de envio y recepción para la reprogramación de codigo.
//Mapa con los led del display.
#if CATODO_COMUN
byte CONST LED_MAP[12] = {0x81,0xE6,0x48,0x42,0x26,0x12,0x10,0x86,0x00,0x02,0x7E,0x0C};
#elif
byte CONST LED_MAP[12] = {0x7E,0x18,0x6D,0x3D,0x1B,0x37,0x77,0x1E,0x7F,0x3F,0x01,0x4F};
#endif
// Variables globales.
int Vueltas_Del_Motor=0, Marcha=1, Veces_Verificado=0, RPM=0;
int Delay_Blinking=0;
int16 Periodo_RPM, Periodo_MIN;
int1 Contando_Vueltas_Del_Motor=0;
int1 Blinking=1; // Bit de parpadeo.
int1 Programado=0; // Se setea si está pogramado.
// Funciones usadas.
void programar(int relacion_de_cambio);
/* Por cada vuelta del motor salta la interrupción
-Mide el tiempo que ha tardado para sacar las RPM, ilumina los led de cambio.
-Compara las vueltas y los pulsos del piñon para sacar el desarrollo.
*/
#INT_EXT
void int_ext_isr(){
int Pulsos_Velocimetro,i;
int16 Periodo_anterior;
// Leemos el valor del contador de tiempo para sacar la velocidad del motor.
Periodo_RPM=get_timer1();
set_timer1(0); // Lo ponemos a 0 para sacar la siguiente cuenta.
// Sincronizamos las dos señales esperando a que los flancos cuincidan.
if(!input(V_Encoder)&&(Contando_Vueltas_del_motor==0)){
delay_us(200);
if(input(V_Encoder)){ // Si cuinciden,
Contando_Vueltas_del_Motor=1; // comenzamos a contar los pulsos.
Vueltas_del_motor=0;
set_timer0(0);
output_low(Punto_Display); //
}
}
if(Contando_Vueltas_del_motor){
if(Vueltas_del_motor==Numero_de_RPM){ // Verificamos que el motor ha dado las vueltas necesarias,
Pulsos_Velocimetro=get_timer0(); // Pillamos la cuenta de pulsos del velocimetro.
if(Programado){
for(i=1;i<=Marchas;i++){
if(Pulsos_Velocimetro==read_eeprom(i)){
Marcha=i;
}
}
}else{
Programar(Pulsos_Velocimetro);
}
Vueltas_del_motor=0; // Ponemos a 0 la cuenta.
Contando_Vueltas_del_motor=0; // Dejamos de medir.
output_high(Punto_Display); // Indicamos que ya hemnos dejado de medir.
}else{ // Si no se han sucedido los pulsos necesarios.
Vueltas_del_motor++; // seguimos contando.
}
}else{ // Si no estamos calculando el desarrollo calculamos las luces.
if(Periodo_Min>=Periodo_RPM){ // Si el motor va más chuscao de lo que queremos.
output_low(LED_RPM_MAX); // encendemos el led.
}else{
output_high(LED_RPM_MAX); // si no, lo apagamos.
};
output_high(LED_CAMBIO_PROHIBIDO);
if(Marcha>1){
// Calculamos las revoluciones que habría en la marcha anterior através del desarrollo.
Periodo_anterior=(Periodo_RPM/read_eeprom(marcha))*read_eeprom(marcha-1);
// Iluminamos el led si al descender de marcha superaramos las RPM programadas.
if(Periodo_anterior<Periodo_Min){
output_low(LED_CAMBIO_PROHIBIDO);
};
}
}
}
/* Brillo del display y bits de intermitencia.
*/
#INT_TIMER2
void int_tmr2(){
// Intermitencia
if(delay_blinking==10){
delay_blinking=0;
Blinking=!Blinking; // Intermitencia.
}else{
delay_blinking++;
};
}
/* Función para la programación del desarrollo en el dispositivo. */
void Programar(int Pulsos_Velocimetro){
// Verificamos la relación de desarrollo.
if((Pulsos_Velocimetro>(read_eeprom(Marcha-1)))&&(Pulsos_Velocimetro>0)){
if((Veces_Verificado==Veces_a_Verificar)){
write_eeprom(Marcha,Pulsos_Velocimetro); // La programamos,
port_b=LED_MAP[Marcha]; // y la mostramos durante
delay_ms(4000); // 4 segundos.
Marcha++;
Veces_Verificado=0;
if(Marcha>Marchas){
write_eeprom(0,0x55);
Programado=1;
Marcha=Marchas;
}
}else{
Veces_Verificado++;
}
}else{
Veces_Verificado=0;
};
}
/*Función para que el usuario establezca las luces de cambio.*/
void Establece_Luz_De_Cambio(){
int Numero, i;
RPM++; // Incrementamos las RPM
IF(RPM>19)
RPM=0;
// Las visualizamos parpadeando en el display.
if(RPM>9){
Numero=RPM-10;
output_low(Punto_Display);
}else{
Numero=RPM;
output_high(Punto_Display);
};
for(i=1;i<10;i++){
delay_ms(100);
port_b=LED_MAP[Numero];
delay_ms(100);
#if CATODO_COMUN
port_b=0xFF;
#elif
port_b=0x00;
#endif
};
// Calculamos el periodo seleccionado.
Periodo_Min=7500/RPM; // 7500=(60/(8*4))*(CLK/1000)
// Lo guardamos en la eeprom.
i=(&Periodo_MIN); // ->Ésto es pa guardar un int16
write_eeprom(11,*i); // en dos posiciones de la eeprom.
write_eeprom(12,*(i+1));
}
void main() {
// Variables.
int i;
// Configuracion del hardware.
setup_timer_0(RTCC_EXT_H_TO_L|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_16,200,16);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_EXT);
// Configuración de las entradas/salidas.
set_tris_b(0x01); //
set_tris_a(0xFF); //
// Test del display.
for(i=0;i<=11;i++){
port_b=LED_MAP[i];
delay_ms(100);
}
// Verificación para reprogramar desarrollos.
if(!input(User_Button)){ // Si se encuentra activo el bit,
port_b=LED_MAP[11];
Delay_ms(5000); // esperamos 5 segundos para confirmar,
if(!input(User_Button)){ // en caso afirmativo...
write_eeprom(0,0x00); // Establecemos la marca de chip virgen.
}
}
if((0x55==read_eeprom(0))){
Programado=1;
}
// Cargamos la configuración de luces de cambio.
i=(&Periodo_MIN); //-> Ésto es pa sacar un int16 de dos
(*i)=read_eeprom(11); // posiciones de la eeprom interna.
(*(i+1))=read_eeprom(12);
// Habilitamos las interrupciones para empezar con la ejecución.
enable_interrupts(GLOBAL);
// Bucle principal del programa.
while(TRUE){
// Si no estamos en punto muerto, mostramos la marcha.
if(input(Neutral)){
if(Programado==0){
if(Blinking){ // Parpadeando si está sin programar.
port_b=LED_MAP[Marcha];
}else{
#if CATODO_COMUN
port_b=0xFF;
#elif
port_b=0x00;
#endif
};
}else{
port_b=LED_MAP[Marcha]; // Fija si ya está programado-
}
}else{ // Si estamos en punto muerto mostramos la rayita.
port_b=LED_MAP[10];
delay_ms(20);
if(!input(Neutral)){ // Revisamos que esté fija.
Marcha=1; // si es así, la siguiente marcha será primera.
};
if(!input(User_button)){ // Si el usuario pulsa el boton, estando en punto muerto,
Establece_Luz_De_Cambio(); // pues es que quiere configurar las luces de cambio.
};
}
}
No hay comentarios:
Publicar un comentario