Обсуждаем контроллеры компании Atmel.
Ответить

Снова проблема с переменными в прерываниях

Сб авг 12, 2023 14:54:01

Решил снять показания с dht-22 и вывести их на дисплей. При этом считываю показания датчика прерываниями int1. Но чтобы я не делал (врубал volatile, отключал оптимизацию) глобальная переменная i не меняется. Тестирую в протеусе 8. В качестве проверки вывожу на дисплей "5", но так как переменная не меняется, то остаётся "B". Прошу, помогите, я новичок. UPD: снял надпись "B", потому что она несколько раз должна была гасить "5", но по итогу на экране всё равно "1", то есть i вообще не меняется.
Код:
char data[5]={0, 0, 0, 0, 0};
volatile uint8_t lll=7;
int n=0;
ISR(INT1_vect)
{
   switch(pre)
   {
      case 2:
      pre=3;
      TCNT0=0;
      break;
      
      case 3:
      if (TCNT0>=80)
      {
         pre=4;
         position (1,20);
         str_send("1");
      }
      else
      {
         pre=99;
         position (1,20);
         str_send("2");
      }
      
      case 4:
      pre=5;
      TCNT0=0;
      //TIMSK|=(1<<TOIE0);
      break;
      
      case 5:
      if (TCNT0>=50)
      {
         pre=6;
         position (1,20);
         str_send("B");
         TCNT0=0;
      }
      else
      {
         pre=100;
         position (1,20);
         str_send("C");
      }
      break;
      
      case 6:
      if (TCNT0>=70)
      {
         data[2]|=(1<<lll);
      }
      if (lll!=0)
      {
         lll--;
         TCNT2=0;
          pre=5;
         TCNT0=0;
      }
      else
      {
         position(1, 20);
         str_send ("5");
         //n++;
         //i=7;
         if(n==5)
         {
            pre=7;
            TCNT0=0;
         }
         else
         {
            pre=5;
            TCNT0=0;
         }
      }
      break;
      
      case 7:
      if (TCNT0>=80)
      {
         pre=0;
         position(1, 20);
         str_send ("5");
         //TIMSK|=(1<<TOIE0);
         //TCNT0=250;
      }
      else
      {
         position(1, 20);
         str_send ("A");
      }
      break;
      
   }
}

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 12:07:08

kocheryzhka писал(а):глобальная переменная i не меняется.
Может потому что ее у вас нет.
Или я просто ее тут не вижу
kocheryzhka писал(а):char data[5]={0, 0, 0, 0, 0};
volatile uint8_t lll=7;
int n=0;

Выложите проект и протеус файлы, проще будет глянуть.
Так как то режет глаз изменение переменной pre внутри switch(pre).

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 12:52:56

kocheryzhka писал(а): Но чтобы я не делал (врубал volatile, отключал оптимизацию)

В первую очередь нужно ВКЛЮЧИТЬ оптимизацию и логику внутри своего кода.
И переменные называть нормально, и комментарии писать.
А так вообще нефига не ясно, что за дичь тут происходит, и самое главное, зачем?

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 13:05:00

codenamehawk писал(а):Так как то режет глаз изменение переменной pre внутри switch(pre).
Это нормальная конструкция. А режет глаз написание "как то" вместо "как-то" - это два разных смысла, для программиста неприемлемо игнорировать дефис.

Добавлено after 2 minutes 31 second:
Между case 3 и case 4 пропущен break;
Не знаю, что означает position(1, 20), но если это что-то типа строка-символ и автоматического сдвига нет, то высвечиваться всегда будет один символ.

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 15:15:17

Спасибо Мартиану, действительно забыл break. Ещё день назад победил i, и она теперь меняется, но с p не выходит. Сейчас вроде всё закомментировал подробно. Помогите, прошу. Вот весь код.
Код:
 
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#define E PD6
#define DHT PC0
uint8_t data[5]={0, 0, 0, 0, 0};
volatile uint8_t i=7;
volatile uint8_t p=0;
void E1 ()
{
   PORTD|=(1<<E);
}
void E0()
{
   PORTD&=~(1<<E);
}
void DHT1()
{
   PORTB|=(1<<DHT);
}
void DHT0()
{
   PORTB&=~(1<<DHT);
}
void writeD(unsigned int n)
{
   n<<=4;
   E1();
   PORTD&=~((1<<4)|(1<<5)|(1<<6)|(1<<7));
   PORTD|=n;
   E0();
}
void byte(unsigned int n, unsigned int b)
{
   if (b)
   {
      PORTD|=(1<<0);
   }
   else
   {
      PORTD&=~(1<<0);
   }
   
   writeD(n>>4);
   writeD(n);
}
void writeB(unsigned int n)
{
   n<<=4;
   E1();
   PORTB&=~((1<<4)|(1<<5)|(1<<6)|(1<<7));
   PORTB|=n;
   asm("nop");
   E0();
}
void byteb(unsigned int n, unsigned int b)
{
   if (b)
   {
      PORTD|=(1<<5);
   }
   else
   {
      PORTD&=~(1<<5);
   }
   
   writeB(n>>4);
   writeB(n);
}
void init_timer()
{
   TCCR0|=(1<<CS00);
   TCCR0|=(1<<CS02);
   TCCR0&=~(1<<CS01);
   TIMSK|=(1<<TOIE0);
}
void init_timer2()
{
   TCCR2|=(1<<CS20);
   TCCR2|=(1<<CS21);
   TCCR2|=(1<<CS22);
   TIMSK&=~(1<<TOIE2);
}
int status=0;
void str_send(char s[])
{
   for (int b=0; b<strlen(s); b++)
   {
      byteb(s[b],1);
   }
}
void position (unsigned int line, unsigned int column)
{
   unsigned int pos=(line*0x40+column)|0x80;
   byteb(pos, 0);
   //_delay_us(50);
}
int pre=20;
ISR(TIMER0_OVF_vect)
{
   switch(status)
   {
      case 0:
      writeB(3);
      status=1;
      TCNT0=250;
      break;
      
      case 1:
      //TCNT0=240;
      writeB(3);
      status=2;
      TCCR0=1;
      TCNT0=105;
      break;
      
      case 2:
      //TCCR0=1;
      //TCNT0=125;
      writeB(3);
      status=3;
      TCNT0=195;
      break;
      
      case 3:
      //TCNT0=195;
      writeB(2);
      status=4;
      TCNT0=195;
      break;
      
      case 4:
      //TCNT0=195;
      byteb(40, 0);
      status=5;
      TCNT0=195;
      break;
      
      case 5:
      //TCNT0=195;
       byteb(12, 0);
      status=6;
      TCNT0=195;
      break;
      
      case 6:
      //TCNT0=195;
      init_timer();
      byteb(1, 0);
      status=7;
      TCNT0=245;
      break;
      
      case 7:
      //TCNT0=195;
      byteb(6,0);
      status=8;
      TCCR0=1;
      TCNT0=205;
      break;
      
      case 8:
      status=9;
      pre=0;
      TCNT0=250;
      init_timer();
      //TIMSK&=~(1<<TOIE0);
   }
   switch (pre)
   {
      case 0: //прижимаем линию на 30 мс
      DDRD|=(1<<3);
      TCNT0=225;
      pre=1;
      break;
      
      case 1:
      DDRD&=~(1<<3); //отпускаем линию, включаем прерывания
      MCUCR|=(1<<ISC10);
      MCUCR&=~(1<<ISC11);
      GICR|=(1<<INT1);
      GIFR=(1<<INTF1);
      TCCR0=1;
      TIMSK&=~(1<<TOIE0);
      pre=2;
      break;
   }
}
ISR(INT1_vect)
{
   switch(pre)
   {
      case 2: //первое прерывание, отсчитываем 80 мкс
      pre=3;
      TCNT0=0;
      break;
      
      case 3:
      if (TCNT0>=80) //если датчик в ответ отпустил линию на 80 мкс, то всё хорошо
      {
         pre=4;
      }
      else
      {
         pre=99;
         position (1,20);
         str_send(" Error");
      }
      break;
      
      case 4:
      pre=5;
      TCNT0=0; //ожидаем первый бит 80 мкс
      break;
      
      case 5:
      if (TCNT0>=80) //если всё хорошо, то прерывание будет через 80 мкс, начало отсчёта сигнала "старт"
      {
         pre=6;
         TCNT0=0;
      }
      else
      {
         pre=100;
         position (1,20);
         str_send("Error");
      }
      break;
      
      case 6:
      if (TCNT0>=50) //если датчик прижал линию на >50 мкс, то начинаем фиксировать биты
      {
         pre=7;
         TCNT0=0;
      }
      else
      {
         pre=100;
         position (1,20);
         str_send("Error");
      }
      break;
      
      case 7:
      if (TCNT0>=70) //если больше 70 мкс, то "1"
      {
         data[p]|=(1<<i);
      }
      if (i!=0) //уменьшаем занчение i, отсчитывающей номер бита
      {
         i--;
         pre=6;
         TCNT0=0;
      }
      if (i==0)
      {
         p++; //если байт закончился, то начинаем следующий
         i=7;
         if (p==5)
         {
             pre=8; //если байты закончились, заканчиваем передачу
             TCNT0=0;
         }
         else
         {
            pre=6; //если нет, то заново переходим в 6
            TCNT0=0;
         }
      }
      break;
      
      case 8:
      if (TCNT0>=80) //если пауза 80 мкс, то заканчиваем передачу
      {
         pre=0;
         TIMSK|=(1<<TOIE0);
         TCNT0=250;
      }
      else
      {
         position(1, 20);
         str_send ("Error");
      }
      break;
   }
}
void lcd()
{
   while(status!=9);
   position (0, 0);
   str_send("Temperature:");
   position (1,0);
   str_send("Humidity:");
   position (0,20);
   str_send("Pressure:");
   //position (1,20);
   //str_send("Radiation:");
}
int main(void)
{
   sei();
   init_timer();
   DDRD|=(1<<5)|(1<<6);
   DDRB|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
   DDRD&=~(1<<3);
   
   TCNT0=235;
   lcd();
   //init_timer2();
   //TCNT2=240;
   while (1)
   {
   }
}

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 15:40:34

Сокращайте действия в перерывах. Например, работать с флагами и следить за флагами в основной программе. Теперь прерывание вероятно прерывается.

Оптимизируйте сравнения и действия. Не то чтобы оптимизатор этого не делал, но делайте по возможности вручную.
Код:
  if (i != 0) //уменьшаем занчение i, отсчитывающей номер бита
  {
    ...
  }
  if (i == 0)
  {
    ...
  }

просто введите else{}

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 15:46:12

я делал else, но надеялся на чудо, когда менял его на if. Типо, может он решил, что else относится к другому if. Не помогло. А как в данной программе контролировать флаги прерываний не внутри прерываний? Ведь в main нельзя угадать момент.

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 16:30:54

как уже сказали коллеги выше, продолжайте оптимизацию. Ловить блох в неоптимизированном коде лень. например:

Код:
if (i!=0) //уменьшаем занчение i, отсчитывающей номер бита
      {
         i--;
         pre=6;
         TCNT0=0;
      }
      if (i==0)
      {
         p++; //если байт закончился, то начинаем следующий
         i=7;
         if (p==5)
         {
             pre=8; //если байты закончились, заканчиваем передачу
             TCNT0=0;
         }
         else
         {
            pre=6; //если нет, то заново переходим в 6
            TCNT0=0;
         }
      }

очевидно же, что просится
Код:
if (i!=0) //уменьшаем занчение i, отсчитывающей номер бита
      {
         i--;
         pre=6;
      }
      if (i==0)
      {
         i=7;
         if (++p==5)
         {
             pre=8; //если байты закончились, заканчиваем передачу
         }
         else
         {
            pre=6; //если нет, то заново переходим в 6   
         }
      }
TCNT0=0;

Здесь, кстати, могут отработать оба условия, если i = 1

Далее:
Код:
switch(status)
   {
      case 0:
      writeB(3);
      status=1;
      TCNT0=250;
      break;
     
      case 1:
      //TCNT0=240;
      writeB(3);
      status=2;
      TCCR0=1;
      TCNT0=105;
      break;
     
      case 2:
      //TCCR0=1;
      //TCNT0=125;
      writeB(3);
      status=3;
      TCNT0=195;
      break;
...

Если везде status становится больше на 1, то почему его не инкрементировать после switch один раз, а не в каждом case?
Полагаю, даже такое сработает:
Код:
switch(status++) //а здесь написать комментарий, почему статус инкрементируется.
Последний раз редактировалось Martian Пн авг 14, 2023 16:40:31, всего редактировалось 2 раз(а).

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 16:35:20

не знаю, это не помогает. Оптимизацию подключил

Re: Снова проблема с переменными в прерываниях

Пн авг 14, 2023 16:39:33

это очень помогает, так как убирает ненужные строки, упрощает чтение (понимание кода), а также позволяют сделать логику менее ошибочной.
например, veso74 предложил else. В случае с i == 1 с else и без него логика выполнения меняется.

Оптимизация в компиляторе - это совершенно не то.

А вообще, возьмите и распишите всё блок-схемой.
Ответить