WinAvr в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
mastech
Грызет канифоль
Сообщения: 269
Зарегистрирован: Чт мар 11, 2010 17:45:37
Откуда: г.фрязино

Re: WinAvr в вопросах и ответах

Сообщение mastech »

ARV писал(а):может, надо после if фгурными скобочками обозначить условно-выполняемый блок с вашими портянками? кстати, сами портянки неплохо бы функциями сделать
в скобки убирал вылазит ошибка. в учебниках не нашел такого примера- этот if-else заключен в скобки другого if

и как их сделать функциями?
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение ARV »

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

static void portyanka(void){
      PORTB |= (1 « PB0); // здесь нормально работает
      _delay_ms(50); //ножка дрыгается
      PORTB &= ~(1 « PB0);
      _delay_ms(50);
}

while(1){
   if (rc5.dataOK){ // приняты данные
      portyanka();
      if (rc5.command==1){
         if (CheckBit(PINA, 0)){
            cbi(PORTA, 0); //если включен отключаем
            portynka();
         } else {
            sbi(PORTA, 0);
         }
      }
   }

   rc5.dataOK = 0;
}
как-то так. но за логикой работы кода я не следил, так что возможно сильно его исказил :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
mastech
Грызет канифоль
Сообщения: 269
Зарегистрирован: Чт мар 11, 2010 17:45:37
Откуда: г.фрязино

Re: WinAvr в вопросах и ответах

Сообщение mastech »

ARV писал(а):как-то так. но за логикой работы кода я не следил, так что возможно сильно его исказил :)))
хороша портянка) вечером опробую)

еще вопросы:

если команда cbi отключает. а комада sbi включает что делает команда CheckBit?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение ARV »

mastech писал(а):что делает команда CheckBit?
судя по названию ПРОВЕРЯЕТ состояние бита :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
Эиком - электронные компоненты и радиодетали
mastech
Грызет канифоль
Сообщения: 269
Зарегистрирован: Чт мар 11, 2010 17:45:37
Откуда: г.фрязино

Re: WinAvr в вопросах и ответах

Сообщение mastech »

почему компилятор ругается на: static void portyanka(void) --- ../main.c:130:14: error: invalid storage class for function 'portyanka'
зачем нужен класс static?

а на void portyanka(void) нет, чем они отличаются?
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение ARV »

Подозреваю, портянку вы впендюрили внутрь main. Если это не так, код в студию.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
mastech
Грызет канифоль
Сообщения: 269
Зарегистрирован: Чт мар 11, 2010 17:45:37
Откуда: г.фрязино

Re: WinAvr в вопросах и ответах

Сообщение mastech »

ARV писал(а):Подозреваю, портянку вы впендюрили внутрь main. Если это не так, код в студию.
вынул портянку из маин и статик заработал) и все таки зачем именно статик воид, почему не обойтись просто воид?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение ARV »

а вы скомпилируйте со static и без него и сравните размер кода.

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

Мой уютный бложик... заходите!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: WinAvr в вопросах и ответах

Сообщение baron_P »

Господа, есть глупый вопрос. Точнее даже проблема. Вот такая тестовая программка:
Спойлер

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

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL

unsigned char test = 0;


void main(void)
{
  
  
  //первые 4 вывода обоих портов выходы
  DDRD = 0b00001111;
  PORTD = 0b00001111;

  DDRB = 0b00001111;
  PORTB = 0b00001111;

  TCCR0A = 0x00;  //нормальный режим работы т/с0
  TCCR0B |= (1 << CS01);  //предделитель 256
  TIMSK |= (1 << TOIE0);  //разрешение прерывания по переполнению т/с0
      

  sei();  //разрешение прерываний  

  while(1)
  {
    PORTD ^= (1 << PD0);  //инверсия PD0 - проблема в этой строчке!
	PORTB ^= (1 << PB0);  //инверсия PB0
	
	//приращение тестовой переменной
	test++;
	if (test == 255) test = 0;
  }
}


ISR(TIMER0_OVF_vect)  //прерывание по переполнению т/с0
{
  PORTD ^= (1 << PD3);  //инверсия PD3
}
Зачем оно? В основном цикле что-то делаем с переменными и выводами. В это время на PD3 должен генерироваться меандр. Если не обращаться к порту Д, все работает. Если сделать как в приведенном коде (с инверсией PD0), меандр превращается в это:
Изображение
Как запись чего-то в порт (на другой вывод) может влиять на генератор в прерывании?
We do what we must because we can (c) GLaDOS
a_skr
Вымогатель припоя
Сообщения: 630
Зарегистрирован: Пн июн 14, 2010 13:07:29
Откуда: Жуковский

Re: WinAvr в вопросах и ответах

Сообщение a_skr »

что есть PORTD ^= (1 << PD0); ?
1. считать порт в регистр
2. изменить в регистре бит
3. записать регистр в порт
догадайтесь, что будет, если между 1 и 2 или между 2 и 3 возникнет прерывание, которое выполняет аналогичные действия с этим же портом.

в Вашем случае простейший вариант - запретить прерывания на время выполнения этой строчки.
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: WinAvr в вопросах и ответах

Сообщение baron_P »

Понято, спасибо. В программе обращений к порту Д много, вокруг каждого запрет/разрешение втыкать - текст страшненький будет. Придется это дело в функцию запихать как-то , хех. Но, главное, грабли найдены.
We do what we must because we can (c) GLaDOS
a_skr
Вымогатель припоя
Сообщения: 630
Зарегистрирован: Пн июн 14, 2010 13:07:29
Откуда: Жуковский

Re: WinAvr в вопросах и ответах

Сообщение a_skr »

правильный вариант - включить аппаратное дергание ножкой по таймеру.

еще вариант (плохой - непереносимость кода, не со всеми портами сработает):
не инвертировать бит, а устанавливать и очищать, что при включенной оптимизации сведется к одной инструкции sbi / cbi.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: WinAvr в вопросах и ответах

Сообщение Kavka »

baron_P, контроллер какой?
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: WinAvr в вопросах и ответах

Сообщение baron_P »

Попробовал оба варианта - второй, естественно, красивше.
Контроллер ATTiny2313. Смысл программы: собираем с порта Б сигналы, анализируем. При некоторых условиях выдаем соответствующие сигналы на порт Д. При этом на одном из выводов порта Д должен генерироваться меандр (примерно 2 кГц), который поступает на один из выводов порта Б. Наличие этого меандра - одно из условий, по которым выставляются сигналы порта Д. В общем, эта штука имитирует контроллер защит привода Arteh MDC2.
Вариант с прерываниями:
Спойлер

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

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#define PROT_OFF ((1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0))  //защиты кроме FL
#define IN_ON (1 << PB6)  //сигнал ON
#define PROTFL_OFF (1 << PB5)  //защита FL
#define DELAY 10  //задержка проверки сигналов защиты FL
#define N_COUNT 20  //число контрольных испульсов FL

void error_lock(void);  //блокировка привода и установка соотв. флага при срабатывании защит

char error = 0;  //сбрасываем флаг срабатывания защит
volatile char error_fl = 0;  //сбрасываем флаг срабатывания  защиты FL
volatile char counter_fl = 0;  //счетчик импульсов FL
volatile char counter_error_fl = 0;  //счетчик неверных импульсов FL

void main(void)
{
  //выходы |ON|, |FL|, ~ON, ~PROT, RD
  DDRD |= (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0);
  //1 на |ON|, ~ON
  PORTD |= (1 << PD4) | (1 << PD2);

  //входы ON, FL, CP, EE, TG, OS, OC
  DDRB &= ~((1 << PB6) | (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));

  TCCR0A = 0x00;  //нормальный режим работы т/с0
  TCCR0B |= (1 << CS01);  //предделитель 256
      
  wdt_reset();  //сброс WDT
  wdt_enable(WDTO_120MS);  //перезагрузки через 128 мс без сброса WDT

  sei();  //разрешение прерываний  

  while(1)
  {
    //Защиты не сработали?
	if (((PINB & PROT_OFF) == PROT_OFF) & (error == 0))  //защиты не сработали?
	{
	  
	  cli();  //запрет прерываний
	  PORTD |= (1 << PD1) | (1 << PD0);  //1 на ~PROT, RD
	  sei();  //разрешение прерываний
	  
	  if ((PINB & IN_ON) == IN_ON)  //команда на включение пришла?
	  {
	    
		cli();  //запрет прерываний
		PORTD &= ~((1 << PD4) | (1 << PD2));  //включение привода и индикации
        sei();  //разрешение прерываний        

		TIMSK |= (1 << TOIE0);  //разрешение прерывания по переполнению т/с0
		
		if (error_fl != 0)  //защита от обрыва возбуждения сработала?
		{
		  error_lock();
		}
	  }
	  else
	  {
	    
		cli();  //запрет прерываний
		PORTD |= (1 << PD4) | (1 << PD2);  //выключение привода и индикации
		sei();  //разрешение прерываний
		
		if (error == 0)
		  {
		  TIMSK &= ~(1 << TOIE0);  //запрет прерывания по переполнению т/с0
		  PORTD &= ~(1 << PD3);  //0 на |FL|
		  }
	  }
	}
	else  //если сработали
	{
	  error_lock();
	}
	wdt_reset();  //сброс WDT
  }
}

void error_lock(void)
{
  
  cli();  //запрет прерываний
  //1 на  |ON|, ~ON
  PORTD |= (1 << PD4) | (1 << PD2);
  //0 на ~PROT, RD
  PORTD &= ~((1 << PD1) | (1 << PD0));
  sei();  //разрешение прерываний
  
  error = 1;  //выставляем флаг срабатывания защиты
}

ISR(TIMER0_OVF_vect)
{
  char in_s = 0;  //сигнал на выходе генератора
  char out_s = 0;  //сигнал на входе генератора
  
  PORTD ^= (1 << PD3);  //инверсия |FL| xor'ом
  
  for (char i = 0; i<DELAY; i++)  //задержка перед проверкой соответствия сигналов
    asm volatile ("nop"::);
  
  in_s = PINB;  //запись значения на входе
  out_s = PIND;  //запись значения на выходе
  
  counter_fl++;  //увеличиваем счетчик импульсов
  
  //Cигналы на вх и вых не совпадают?
  if (((in_s & (1 << PB5)) >> PB5) != ((out_s & (1 << PD3)) >> PD3))
    {
	counter_error_fl++;  //увеличиваем счетчик ошибок
	}
  
  if (counter_fl >= N_COUNT)  //если число импульсов равно заданному
    {
	counter_fl = 0;  //обнуляем счетчик
	
	if (counter_error_fl > (N_COUNT >> 1))  //если число ошибок более половины
	  error_fl = 1;  //выставляется флаг ошибки
    }
}
Вариант с аппаратным дерганьем вывода:
Спойлер

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

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#define PROT_OFF ((1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0))  //защиты кроме FL
#define IN_ON (1 << PB6)  //сигнал ON
#define PROTFL_OFF (1 << PB5)  //защита FL
#define DELAY 10  //задержка проверки сигналов защиты FL
#define N_COUNT 20  //число контрольных испульсов FL

void error_lock(void);  //блокировка привода и установка соотв. флага при срабатывании защит
void fl_generator_off(void);  //выключение генератора сигнала |FL|

char error = 0;  //сбрасываем флаг срабатывания защит
volatile char error_fl = 0;  //сбрасываем флаг срабатывания  защиты FL
volatile char counter_fl = 0;  //счетчик импульсов FL
volatile char counter_error_fl = 0;  //счетчик неверных импульсов FL

void main(void)
{
  //выходы |ON|, |FL|, ~ON, ~PROT, RD
  DDRD |= (1 << PD4) | (1 << PD5) | (1 << PD2) | (1 << PD1) | (1 << PD0);
  //1 на |ON|, ~ON
  PORTD |= (1 << PD4) | (1 << PD2);

  //входы ON, FL, CP, EE, TG, OS, OC
  DDRB &= ~((1 << PB6) | (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));

  TCCR0A = 0x00;  //нормальный режим
  TCCR0B |= (1 << CS01);  //предделитель 256
  OCR0B = 0x00;  //ноль в регистре сравнения B
      
  wdt_reset();  //сброс WDT
  wdt_enable(WDTO_120MS);  //перезагрузки через 128 мс без сброса WDT

  sei();  //разрешение прерываний  

  while(1)
  {
    //Защиты не сработали?
	if (((PINB & PROT_OFF) == PROT_OFF) & (error == 0))  //защиты не сработали?
	{
	  
	  PORTD |= (1 << PD1) | (1 << PD0);  //1 на ~PROT, RD
	  	  
	  if ((PINB & IN_ON) == IN_ON)  //команда на включение пришла?
	  {
	    
		PORTD &= ~((1 << PD4) | (1 << PD2));  //включение привода и индикации
        
		TIMSK |= (1 << TOIE0);  //разрешение прерывания по переполнению т/с0
        TCCR0A |= (1 << COM0B0);  //инверсия PD5 по совпадению т/с0 с OCR0B

		if (error_fl != 0)  //защита от обрыва возбуждения сработала?
		{
		  error_lock();  //блокируем привод, выставляем флаг защиты
		}
	  }
	  else
	  {
	    
		PORTD |= (1 << PD4) | (1 << PD2);  //выключение привода и индикации
				
		fl_generator_off();  //выключение генератора сигнала |FL|
	  }
	}
	else  //если сработали
	{
	  error_lock();  //блокируем привод, выставляем флаг защиты
	  fl_generator_off();  //выключение генератора сигнала |FL|
	}
	wdt_reset();  //сброс WDT
  }
}


void error_lock(void)
{
  //1 на  |ON|, ~ON
  PORTD |= (1 << PD4) | (1 << PD2);
  //0 на ~PROT, RD
  PORTD &= ~((1 << PD1) | (1 << PD0));
    
  error = 1;  //выставляем флаг срабатывания защиты
}


void fl_generator_off(void)
{  
  if (error_fl == 0)  //если не сработала защита |FL|
  {
    TIMSK &= ~(1 << TOIE0);  //запрет прерывания по переполнению т/с0
	TCCR0A &= ~(1 << COM0B0);  //выкл. инверсия PD5 по совпадению т/с0 с OCR0B
	PORTD &= ~(1 << PD5);  //0 на |FL|
  }
}


ISR(TIMER0_OVF_vect)
{
  char in_s = 0;  //сигнал на выходе генератора
  char out_s = 0;  //сигнал на входе генератора
  
  for (char i = 0; i<DELAY; i++)  //задержка перед проверкой соответствия сигналов
    asm volatile ("nop"::);
  
  in_s = PINB;  //запись значения на входе
  out_s = PIND;  //запись значения на выходе
  
  counter_fl++;  //увеличиваем счетчик импульсов
  
  //Cигналы на вх и вых не совпадают?
  if (((in_s & (1 << PB5)) >> PB5) != ((out_s & (1 << PD5)) >> PD5))
    {
	counter_error_fl++;  //увеличиваем счетчик ошибок
	}
  
  if (counter_fl >= N_COUNT)  //если число импульсов равно заданному
    {
	counter_fl = 0;  //обнуляем счетчик
	
	if (counter_error_fl > (N_COUNT >> 1))  //если число ошибок более половины
	  error_fl = 1;  //выставляется флаг ошибки
    }
}
We do what we must because we can (c) GLaDOS
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: WinAvr в вопросах и ответах

Сообщение Kavka »

А может, таки, нафиг read-modify-write, а?

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

ISR(TIMER0_OVF_vect)  //прерывание по переполнению т/с0
{
  PIND = (1 << PD3);  //инверсия PD3
}
СпойлерRTFM :kill:
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение WiseLord »

А что при этом произойдёт с PD0-PD2,PD4-PD7?

Или здесь тоже аппаратный хак сродни тому, как сбрасываются некоторые биты в ноль путём записи их в единицу (например, в АЦП, ADIF бит регистра ADCSRA)?

P.S. В интернете нагуглил цитату якобы из даташита
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn.
, но в самих даташитах её не вижу.

P.P.S. В даташите на ATtiny2313 такое есть, на ATmega8, Atmega16 - нет.
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение Alexeyslav »

Это новая фишка доступная в свежих контроллерах вроде ATMEGA8A, ATMEGAx8A и т.д.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение WiseLord »

Ещё раз повторюсь, в даташите на ATmega8A (и на простую ATmega8/8L) такого нет. Но есть в ATtiny2313.

Может, лучше не рисковать, используя такой потенциально непереносимый код?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: WinAvr в вопросах и ответах

Сообщение baron_P »

От read-modify-write я отошел, путем втыкания аппаратной инверсии порта. В моем случае этого достаточно. Но буду иметь в виду и этот вариант.
We do what we must because we can (c) GLaDOS
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение WiseLord »

Забавно... Прогуглив этот вопрос наткнулся на одно своего рода исследование:
У автора получился вариант с PORTx |= (1<<bit) самым быстрым. Вдвое быстрее чем запись в PINx.
Ответить

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