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

Обсуждаем контроллеры компании Atmel.
Ответить
kocheryzhka
Родился
Сообщения: 4
Зарегистрирован: Сб авг 12, 2023 14:39:28

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

Сообщение kocheryzhka »

Решил снять показания с 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; 
		
	}
}
Реклама
codenamehawk
Вымогатель припоя
Сообщения: 532
Зарегистрирован: Вт фев 09, 2010 17:52:26

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

Сообщение codenamehawk »

kocheryzhka писал(а):глобальная переменная i не меняется.
Может потому что ее у вас нет.
Или я просто ее тут не вижу
kocheryzhka писал(а):char data[5]={0, 0, 0, 0, 0};
volatile uint8_t lll=7;
int n=0;
Выложите проект и протеус файлы, проще будет глянуть.
Так как то режет глаз изменение переменной pre внутри switch(pre).
Реклама
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

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

Сообщение metan »

kocheryzhka писал(а): Но чтобы я не делал (врубал volatile, отключал оптимизацию)
В первую очередь нужно ВКЛЮЧИТЬ оптимизацию и логику внутри своего кода.
И переменные называть нормально, и комментарии писать.
А так вообще нефига не ясно, что за дичь тут происходит, и самое главное, зачем?
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

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

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

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

Сообщение kocheryzhka »

Спасибо Мартиану, действительно забыл 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)
	{
	}
}

Реклама
veso74
Поставщик валерьянки для Кота
Сообщения: 1916
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

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

Сообщение veso74 »

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

Оптимизируйте сравнения и действия. Не то чтобы оптимизатор этого не делал, но делайте по возможности вручную.

Код: Выделить всё

  if (i != 0) //уменьшаем занчение i, отсчитывающей номер бита
  {
    ...
  }
  if (i == 0)
  {
    ...
  }
просто введите else{}
Реклама
kocheryzhka
Родился
Сообщения: 4
Зарегистрирован: Сб авг 12, 2023 14:39:28

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

Сообщение kocheryzhka »

я делал else, но надеялся на чудо, когда менял его на if. Типо, может он решил, что else относится к другому if. Не помогло. А как в данной программе контролировать флаги прерываний не внутри прерываний? Ведь в main нельзя угадать момент.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

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

Код: Выделить всё

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 раза.
kocheryzhka
Родился
Сообщения: 4
Зарегистрирован: Сб авг 12, 2023 14:39:28

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

Сообщение kocheryzhka »

не знаю, это не помогает. Оптимизацию подключил
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

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

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

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

Вернуться в «AVR»