Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

Посоветуйте алгоритм

Сб июл 21, 2012 09:19:53

Товарищи, нужна ваша помощь. Уже второй день бьюсь над проблемой
Вобщем устройство - кнопка старт\стоп для двигателя.
Алгоритм
-один раз нажали включилось ACC
-второй раз включилось зажигание
-третий раз всё выключилось
-если на любом этапе и нажат сцеплеие то включается стартер

Так вот никак невыходит описать алгоритм включения кнопки. Нужно как то переводить состояние кнопки из одного в другое. Кнопка если первое нажатие отрабатывает нормально, то дальше второе может не отработать, а может отработать и на этом остановиться. Кнопка подключена к выводу PINB.0 . Когда она нажата - у нас логический ноль.

Товарищи, может поможете новичку с кодом, а то уже аж руки опускаются....
Код:
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 20.07.2012
Author  :
Company :
Comments:


Chip type               : ATmega8
Program type            : Application
AVR Core Clock frequency: 4,000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*****************************************************/

#include <mega8.h>

#include <delay.h>

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here


}

#define ADC_VREF_TYPE 0x40

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned int adc_data;
// Read the AD conversion result
adc_data=ADCW;
// Place your code here

}

// Declare your global variables here
int time; // переменная для отсчёта времени
unsigned char OFF;
unsigned char ACC;
unsigned char ING;
unsigned char STARTER;
unsigned char status;
unsigned char rejim_avtomat; //  Состояние режима запуска авто
unsigned char rejim_ruchnoy;   // Сосстояние режима запуска авто
void _OFF (void)
{
PIND.0=0;
PIND.1=0;
PIND.2=0;
}

void _ACC (void)
{
PIND.0=0;
PIND.1=0;
PIND.2=1;
}

void _IGN (void)
{
PIND.0=0;
PIND.1=1;
PIND.2=1;
}

void _STARTER (void)
{
PIND.0=1;
PIND.1=1;
PIND.2=1;
}

void main(void)
{
// Declare your local variables here
                 
 
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P
//ПОРТ B  - все пины входы
//PIN0  - СТАРТ/СТОП кнопка. Нжата ПИН = 0, брошена, ПИН =1
//PIN1  -
//PIN2  -   
//PIN3  - концевик педали сцепления (сцепление выжато ПИН = 1, сцепление брошено ПИН=0
//PIN4  - лампа заряда АКБ (машина заглушена ПИН = 0, машина заведена ПИН  = 1
//PIN5  - Сигнал ЭБУ отключения стартера (Стартер крути ПИН = 1, стартер отключить - ПИН=0
//PIN6  - 

PORTB=0xFF;
DDRB=0x00;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
//ПОРТ D  - все пины выходы
//PIN0  -  Выход на реле стартера
//PIN1  -  выход на реле зажигания
//PIN2  -  Выход на реле ACC
//PIN3  - 
//PIN4  -
//PIN5  -
//PIN6  -
PORTD=0x00;
DDRD=0xFF;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 3,906 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x0F;
OCR1AL=0x42;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 31,250 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x8F;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

// Global enable interrupts
#asm("sei")
while (1)
 {
   if (PINB.0==0)
   {     
     delay_ms(50);
     if (PINB.0==1)
     {
      if(status==0)
       {   
        _ACC();
        status=1;
       
       }
       else if(status==1)
       {   
        _IGN();
        status=2;
       
        }
        else if(status==2)
        {
         _OFF();
         status=0;         
         }
     } 
     
   }

Re: Посоветуйте алгоритм

Сб июл 21, 2012 10:04:49

Да, собственно алгоритм простой:

1 - организуем переменную - счетчик нажатий кнопки;
2 - при первом нажатии проверяем счетчик, если он равен "0", то инкрементируем счетчик, ставим ловушку, если кнопка нажата, то возвращаемся на опрос состояния кнопки, если кнопка отжата, то проскакиваем ловушку, и после ловушки выдерживаем некоторую паузу, чтобы исключить дребезг, проверяем счетчик, если "1", то выполняем необходимые действия для включения АСС;
3 - при втором нажатии проверяем счетчик, если он равен "1", то инкрементируем счетчик, ... , проверяем счетчик, если "2", то выполняем необходимые действия для включения зажигания;
4 - при третьем нажатии проверяем счетчик, если он равен "2", то инкрементируем счетчик, ... , проверяем счетчик, если "3", то выполняем необходимые действия для выключения питания, обнуляем счетчик;
и т.д.

На счет сцепления не понятно, что значит на любом этапе? а если на скорости стоит? нужно тогда отслеживать и сцепление и нейтраль.
Можно, конечно в этой же переменной включать бит - флаг нажатого сцепления, и проверять нажатие кнопки маскируя этот бит.

Re: Посоветуйте алгоритм

Сб июл 21, 2012 10:19:35

так если на скорости стоит то как раз при выжатом сцеплении только и заведётся..

Re: Посоветуйте алгоритм

Сб июл 21, 2012 11:12:57

Тогда проверять флаг выжатого сцепления при счетчике равном "2", т.е. когда кнопка нажата второй раз, в этот момент и проверять сцепление, в других случаях наверно не стоит.

Re: Посоветуйте алгоритм

Сб июл 21, 2012 12:59:23

вот пытался написать, но так вообще ничего не выходит
Я и понимаю что алгоритм простой, но что то ну никак невыходит он у меня
Код:
// Global enable interrupts
#asm("sei")
while (1)
  {
   if (PINB.0==0) // если нажата кновпка
   { 
    if (status==0)  // проверяем в каком положении наш счётчик
     {
      status++;     // инкрементируем статус в первое положение
      if (PINB.0==0)       //   проверяем, если кнопка до сих пор нажата
      {
        while (PINB.0==0)    //заходим в замкнутый   цикл
         {
         }
               
         
      }
      else  //      иначе, если кнопка выходит что отжата
      {
       if (status==1)   //   проверяем статус,если равен 1
       {
        _ACC();      //   включаем acc
       }
      }
     
     
     }
     
     

Re: Посоветуйте алгоритм

Сб июл 21, 2012 13:31:24

Вот ещё один вариант попробовал написать.
Но в протеусе видно что нажал раз на кнопку, на выводе начинается моргание (вывод как всетомузыка работает)

и дальше сколько не нажимай - ничего не происходит. Где я ошибаюсь???
Код:
// Global enable interrupts
#asm("sei")
while (1)
  {
     if (PINB.0==0) // если нажата кновпка
      {
          delay_ms(100);
          if (PINB.0==0)  // если нажата кновпка
          {
             if (status==0)  // проверяем в каком положении наш счётчик
             {
               status=+1;     // инкрементируем статус в первое положение
               while (PINB.0==0) {} //ждём отжатия кнопки
             }
             else if (status==1)  // проверяем в каком положении наш счётчик
             {
               status=+1;     // инкрементируем статус в первое положение
               while (PINB.0==0) {} //ждём отжатия кнопки
             } 
             else if (status==2)  // проверяем в каком положении наш счётчик
             {
               status=+1;     // инкрементируем статус в первое положение
               while (PINB.0==0) {} //ждём отжатия кнопки
             }
             else if (status==3)  // проверяем в каком положении наш счётчик
             {
               status=0;     // инкрементируем статус в первое положение
               while (PINB.0==0) {} //ждём отжатия кнопки
             }
           }
   
      }
      if (status==0)
      {
       _OFF();
       }   
      else if (status==1)
      {
       _ACC();
       }
      else if (status==2)
      {
       _IGN();
       }
      else if (status==3)
      {
       _STARTER();
       }
  } 
 }

Re: Посоветуйте алгоритм

Сб июл 21, 2012 13:47:29

Думаю, лучше убрать первую проверку счетчика, а просто тупо его увеличивать, а потом когда он будет "3" обнулить его.
Както вот так должно быть, синтаксис исправь если чё, просто на си не пишу, поэтому примерно накидал.
Код:
// Global enable interrupts
#asm("sei")
while (1)
  {
   if (PINB.0==0) // если нажата кновпка
   {status++; 
      if (PINB.0==0)       //   проверяем, если кнопка до сих пор нажата
      {while (PINB.0==0){}}   //заходим в замкнутый   цикл
      else  //      иначе, если кнопка выходит что отжата
      {if (status==1){_ACC();}}   //   проверяем статус,если равен 1
      {if (status==2){_IGN();}}   //   проверяем статус,если равен 2
      {if (status==3){_OFF(); status==0;}}   //   проверяем статус,если равен 3
    }
   }

Re: Посоветуйте алгоритм

Сб июл 21, 2012 13:53:00

Проверка статуса должна происходить только когда нажимаем кнопку, а не все время проверяться в цикле, и задержку небольшую надо поставить после else, когда кнопка отжата.
В основном цикле можно по этому статусу определять в каком режиме находишься ACC, IGN или OFF, если это необходимо.

Re: Посоветуйте алгоритм

Сб июл 21, 2012 14:19:41

Вот поправил немного и добавил сброс счётчика если он больше 3.
Всё как бы отрабатывает но с глюками страшнейшими. Кнопка сначала включается, потом через раз потом чёрт зна что и с 10 го нажатия выключает всё таки всё.

Мне кажется это из за присвоения статусу признаков зажигания и т.д во время нажатой кнопки. Скорей всего наверное это нужно выносить в отдельное место.

вот приложил ещё прект в протеусе.

Код:
// Global enable interrupts
#asm("sei")
while (1)
  {   
   if (PINB.0==0) // если нажата кновпка
   {
      status++;
      if (status >3) //проверяем, если status больше 3, то присваиваем ему 0 (кнопка ывключена)
      {status=0;} 
      if (PINB.0==0)       //   проверяем, если кнопка до сих пор нажата
      {while (PINB.0==0){}}   //заходим в замкнутый   цикл
      else  //      иначе, если кнопка выходит что отжата
      delay_ms(200);   
      {if (status==0){_OFF();}}   //   проверяем статус,если равен 0
      {if (status==1){_ACC();}}   //   проверяем статус,если равен 1
      {if (status==2){_IGN();}}   //   проверяем статус,если равен 2
      {if (status==3){_STARTER();}}   //   проверяем статус,если равен 3
    }
     
  } 
 }
Вложения
start.zip
(23.03 KiB) Скачиваний: 859

Re: Посоветуйте алгоритм

Сб июл 21, 2012 14:34:20

Эврика :write: , только что перелистывал учебник по АВР и тут пришла идейка
По кнопке, теперь она отрабатывает как нужно. Теперь главное чтоб ничего не начало мешать в написании алгоритмов работы от концевиков лампы АКБ и концевика педали сцепления.

Код:
#asm("sei")
while (1)
  {   
   if (PINB.0==0) // если нажата кновпка
   {
      status++;
      if (status >3) //проверяем, если status больше 3, то присваиваем ему 0 (кнопка ывключена)
      {status=0;} 
      if (PINB.0==0)       //   проверяем, если кнопка до сих пор нажата
      {while (PINB.0==0){}}   //заходим в замкнутый   цикл
      else {} //      иначе, если кнопка выходит что отжата
   
    }
   
   
    switch (status)
    //Положение OFF
        {
        case 0:
                PORTD.0=0;
                PORTD.1=0;
                PORTD.2=0;
                PORTD.3=0;

        break;
    //Положение АСС
        case 1:
                PORTD.0=0;
                PORTD.1=0;
                PORTD.2=1;
                PORTD.3=0;
        break;
    //Положение IGN
        case 2:
                PORTD.0=0;
                PORTD.1=1;
                PORTD.2=1;
                PORTD.3=0;
        break;
    //Положение Стартер       
        case 3:
                PORTD.0=1;
                PORTD.1=1;
                PORTD.2=1;
                PORTD.3=0;
        break;
       default:
       ;
    }
  } 

Re: Посоветуйте алгоритм

Вс июл 22, 2012 10:42:00

Получается функция switch постоянно в цикле проверяет состояние status, так чтоли? Надо, чтобы она вызывалась только при нажатии кнопки, а то как-то очень хорошо получается, и тогда она мешать ничему не будет.

Re: Посоветуйте алгоритм

Вт июл 24, 2012 01:57:24

товарищи. перешёл к ещё одному элементу. Я то его сделал но может подскажете как его можно упростить. Чтоб контроллеру меньше вычислять.

Просто незнаю как в течении трёх секунд, во время кручения стартера, чтоб при погасании лампы зарядки АКБ или блокировки стартера он отключался. Как его опрашивать эти три секунды не нагружая его процик...

Код:
if (ruchnoy==0)     //если мы бытро нажали и бросили кнопку то переходм  автоматический режим
       {
       
           
           status=3;         //включаем стартер
           delay_ms(100);//ждём 100 милисекунд
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);} проверяем состояние лампы АКБ и стартера
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);} 
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           if((PINB.4==1)||(PINB.5==0)){status=2;engine=1;}else{delay_ms(100);}
           status=2;        //двигатель завёлся и оставляем включеным зажигание
           engine=1;
           ruchnoy=0;             
       }               
      else             
      {
         status=2;        //двигатель у нас уже выходит запущен, и стратер нельзя запускать
         engine=1;      //мы не даём ему запуститься и оставляем просто включеное зажигание
      }         //, и присваем признак заведённого мотора

Re: Посоветуйте алгоритм

Вт июл 24, 2012 11:44:34

Я бы подключил для этого дела таймер, и пускай он отсчитывает 3 секунды, а лампу зарядки АКБ повесил бы на внешнее прерывание со срабатыванием по переднему фронту, т.е. с "0" на "1", при погасании лампы зарядки, по-моему, на нее со стороны минуса приходит +12, по-этому думаю по переднему фронту, и процик вобще не в напряге. :beer:

Re: Посоветуйте алгоритм

Вт июл 24, 2012 12:11:16

Использовать можно любой таймер, даже 8 битный, разрешаем прерывания по переполнению этого таймера, прескалер можно вообще вручную написать, используя переменные как счетчики.
Например частота 8 МГц, получается: устанавливаем прескалер для таймера = 256, в обработчике прерывания таймера устанавливаем счетчик таймера TCNTx = 6, одну переменную используем как старший разряд счетчика и будем её увеличивать до 125, так получим 1 секунду, итого получим: 8000000 / 256 / (256-6) / 125 = 1 секунда, вторую переменную используем как счетчик секунд и увеличиваем её до 3, получим 3 секунды.

Re: Посоветуйте алгоритм

Вт июл 24, 2012 15:08:26

Да... тяжело быть программистом.. Я ещё в таймерах и прерываниях несовсем разобрался.
И ещё вопросик, мой код, он работает. Но вот в этот момент когда он будет выполняться он несильно перегрузит атмегу?

Re: Посоветуйте алгоритм

Вт июл 24, 2012 20:22:02

Может лучше тогда цикл организовать типа for, зачем столько одинаковых строк делать? Процик не перегрузится, в любом случае, он постоянно чтото выполняет, если не в спящем режиме. :hunger:
Тема закрыта