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

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
slavokhire5
Прорезались зубы
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

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

Сообщение slavokhire5 »

Товарищи коты, а никто не подскажет мне, в каком документике почитать "потроха" функций записи/обновления еепром в winavr?
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Реклама
a_skr
Вымогатель припоя
Сообщения: 630
Зарегистрирован: Пн июн 14, 2010 13:07:29
Откуда: Жуковский

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

Сообщение a_skr »

В исходниках avr-libc, например, отсюда: http://avr-libc.sourcearchive.com/. В папке \libc\misc лежат исходники для всех функций работы с EEPROM.
Реклама
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

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

Сообщение WiseLord »

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

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

Сообщение baron_P »

Здравствуйте.
Есть такая страшненькая программа:
Спойлер

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

#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 1200000UL
#include<util/delay.h>
#include<avr/pgmspace.h>
#include<avr/sleep.h>


//Prototypes

//This function is called to switch on the LED at the
//Required stage of PWM cycle
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status);

//This function is used to initialise the new PWM cycle
void xyz(void);


volatile unsigned char e;
volatile unsigned char pwm[3]={0,8,8};
volatile unsigned char i=0;
volatile unsigned char k=0;
//PWM scale 0 - On 8 OFF
const unsigned char Blue[15] PROGMEM =  {0,8,8,0,0,8,0,6,2,3,6,1,4,5,7};
const unsigned char Red[15] PROGMEM =   {8,0,8,2,8,2,0,5,5,5,6,6,6,7,7};
const unsigned char Green[15] PROGMEM = {8,8,0,8,0,0,0,2,0,6,4,2,7,0,2};
volatile unsigned int counter =0;


int main(void)
{


   DDRB  &= ~((1<<3)|(1<<4)); //Switches and ADC
   PORTB |= (1<<3); //Switches
   PCMSK = 1<<PCINT3;//Configure PB3 as interrupt
   
   //ADC init
   
   ADMUX =  0b00100010; //ADC2,ADLAR,VCc
   ADCSRA = 0b10000010; //prescaled by 4
   
   //neglect first reading
   ADCSRA |= 1<<ADSC;
   while(ADCSRA&(1<<ADSC));//Wait
   i = ADCH;
   
   //Timer Initialisation
   TCCR0A = 0x00;
   TCCR0B = 0x02;//Prescaling
   TIMSK0 = 1<<TOIE0;//Overflow Interrupt Enabled
   sei();//Global Interrupts Enabled

   while(1)
   {
         
         
      i=0;
   
   
      ADCSRA |= 1<<ADSC;
      while(ADCSRA&(1<<ADSC));//Wait
      i = ADCH;
      
      
      
      i = i>>4;//Divide by 16
      if(i!=15)
      {
         pwm[0] = pgm_read_byte(&Blue[i]);
         pwm[1] = pgm_read_byte(&Red[i]);
         pwm[2] = pgm_read_byte(&Green[i]);
         counter = 0;
         k = 0;
      }
      _delay_ms(2);//Just a small delay
            
         
      
      if(!(PINB&(1<<3)))
      {
         _delay_ms(30);
         while(!(PINB&(1<<3))); //wait
         _delay_ms(30);
         
         
         TIMSK0 &= ~(1<<TOIE0);//Clear timer interrupt
         DDRB &=~(1<<0|1<<1|1<<2);
         GIFR |= 1<<PCIF;//Clear pending interrupt
         GIMSK |= 1<<PCIE;//Pin change interrupt enable
         MCUCR |= (1<<SE|1<<SM1);//Power down mode setting
         sleep_cpu(); //CPU halted till interrupt
         
      }
   
   }

   

}



ISR(TIM0_OVF_vect)
{
   
   
   DDRB &=~(1<<0|1<<1|1<<2);
   
   
   
   if(e==8)
   {
      e=0;
      xyz();
   }

   abc(pwm[0],pwm[1],pwm[2],e);
   DDRB |=(1<<0|1<<1|1<<2);
   e++;
   if(i==15)//Run mode
   {
      counter++;
      if(counter == 390)//500ms
      {
         counter = 0;
         if(k==14)
         k=0;
         else k++;
         pwm[0] = pgm_read_byte(&Blue[k]);
         pwm[1] = pgm_read_byte(&Red[k]);
         pwm[2] = pgm_read_byte(&Green[k]);
      }
   }
   
}

void xyz(void)
{
   
   PORTB |= (1<<0)|(1<<1)|(1<<2);
   
   
}


void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status)
{

   if((status==a))
   {
      PORTB&= ~(1<<0);
   }
   if((status==b))
   {
      PORTB&= ~(1<<1);
   }
   if((status==c))
   {
      PORTB&= ~(1<<2);
   }
   
}

ISR(PCINT0_vect)
{
   _delay_ms(30);
   while(!(PINB&(1<<3))); //wait
   _delay_ms(30);
   MCUCR = 0x00; //sleep disable
   GIMSK &= ~(1<<PCIE);//Pin change interrupt disable
   TIMSK0 = 1<<TOIE0;//Overflow Interrupt Enabled
         
         

}

Контроллер ATTiny 13A. Программа реализует программный ШИМ на трех вывода PB0, PB1, PB2. Задание для ШИМ берется из заранее сформированных массивов, в зависимости от напряжения на входе АЦП PB4. На PB3 висит кнопка, которая переводит это дело в спящий режим.
Программа работает, но есть один неясный момент. В обработчике прерывания по переполнению Таймера 0 сначала идет команда перевода выводов ШИМ в состояние входов:

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

DDRB &=~(1<<0|1<<1|1<<2);

Потом идет вызов функции, которая меняет значения на выводах ШИМ:

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

abc(pwm[0],pwm[1],pwm[2],e);

А потом идет команда перевода выводов ШИМ в состояние выходов:

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

DDRB |=(1<<0|1<<1|1<<2);

Должно же быть наоборот: сперва делаем выводы выходами, потом меняем их состояние, потом делаем их входами. Правда, зачем нужен последний шаг (используемый в этой программе часто) тоже не понимаю. Пусть бы и оставались выводы в состоянии выходов, что в этом плохого. В общем, непонятно, как оно работает и зачем оно сделано так.
We do what we must because we can (c) GLaDOS
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

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

Сообщение baron_P »

Видимо здесь это оффтоп. Звиняйте, перетащу в другой раздел.
We do what we must because we can (c) GLaDOS
Реклама
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

Коты, помогите, не могу отследить ошибку в течении уже недели. Пользуюсь: ATmega328P, 20 мГц, avr-toolchain 3.4.2.1573 (от создателей WinAVR). Написал простой драйвер на таймер TC0, исходный код драйвера во вложении.
Суть проблемы:
1) В векторе прерывания стоит счетчик unsigned int, который +1 каждые 10 микросекунд.
2) В определенный момент (бывает даже раз в 10 минут а бывает и чаще) заместо того, чтоб увеличится на единичку, он увеличивается на 256 или 257 (точнее не могу определить, так как не пользуюсь симулятором, ниже напишу почему.)
3) Из за этого, что счетчик скачен на +256 вся программа летит в преисподню (работает не корректно). :(
4) У меня по мимо прерывания таймера ТС0 еще есть прерывание по приему символов по USART.
5) Программа очень много и быстро принимает данные по USART (115200 бод) и поэтому не могу пользоваться симулятором, так как все работает отлично, а раз в 10 минут происходит хрень.
6) Я долго думал над этим, думал, может моя основная программа переписывает область памяти, в которой лежит счетчик прерываний, и поэтому он изменяется на большое число. Убрал все указатели в программе и проверил все массивы, чтоб они при заполнении данными не дай бог не вышли за предел своей области. Не помогло.
7) Может возникает одновременно прерывание по TC0 и USART. Почитал по этой проблемме, узнал, что у вектора прерывания таймера более высокий приоритет, и поидее, сначало таймер отработает, потом USART.
8) Так же есть вероятность, что произошло прерывание по USART (В векторе прерывания USART довольно таки большой код, там четыре if(), счетчик принятых символов и заполнение массива данных принятых по USART) а потом происходит прерывание по таймеру, но тогда тоже программа дождется прерывания USART и обработает прерывание по TC0. Но вот в одновременности прерываний я вообще не силен. :(
9) Еще есть вариант, что я драйвер для TC0 написал корявый или программу.

Пишу здесь, вдруг у вас многоуважаемые коты была такая проблема и вы мне поможете непутевому. :)

PS: Я решил проблемму таким образов, я в теле вектора прерываний ограничил счетчик 255, вколотив условие:

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

ISR (TIMER0_OVF_vect)                              //Прерывание по переполнению Т/С0
/////////////////////////////////////////////////////////////////////////////////////////
//---------- Р Е Р Ы В А Н И Е   Т / С 0----------------------------//
/////////////////////////////////////////////////////////////////////////////////////////
{
    if(svuntCounterTimer0 == 255)
       svuntCounterTimer0 = 0;
    else
       svuntCounterTimer0++;
     TCNT0 = csuchTimer0;                           //Выставляем счетчик на прервывание по выставленному времени.
}


Все стало работать нормально, но ведь это не решение. А если переменную svuntCounterTimer0 я объявлю под типом unsigned char, то опять раз в сто лет переменная svuntCounterTimer0 увеличивается не на 1. Пользуюсь драйвером очень просто, инициализирую его в начале программы

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

initTimer0();
, а потом снимаю параметры счетчика с помощью функции

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

size_t a = getTimer0();
Вложения
dc_timer0.h
(3.38 КБ) 187 скачиваний
dc_timer0.c
(4.44 КБ) 217 скачиваний
Кот должен прожить жизнь без сожаления.
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

предположение: просмотрите места, где в программе вы ИСПОЛЬЗУЕТЕ значение своей переменной svuntCounterTimer0 - так как она не однобайтная (кстати, почему size_t а не uint16_t?) и меняется относительно часто, то обращение к ней даже на чтение должно быть атомарным. предполагаю, что переменная инкрементируется правильно, а вот ее обработка в основном коде иногда попадает на момент, когда между анализом батйтов вклинивается прерывание, меняющее их содержимое.

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

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

volatile uint16_t my_volatile_var;

uint16_t temp;
ATOMIC_BLOCK(ATOMIC_RESTORE_STATE){
   tmp = my_volatile_var;
}
if (tmp == 0) ...
что совсем не красиво и не удобно
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

ARV писал(а):кстати, почему size_t а не uint16_t?

Я так в С++ пишу. Кстати ARV, я воспользовался твоим советом по поводу QT и Eclipse, сейчас там шпарю свой код. А по поводу uint16_t, буду так теперь делать, если ты говоришь что так грамотней, твой авторитет для меня не оспорим.
ARV писал(а): где в программе вы ИСПОЛЬЗУЕТЕ значение своей переменной svuntCounterTimer0

Я получаю из функции getTimer0() значение svuntCounterTimer0, присваиваю его переменной и уже с этой переменной произвожу математические операции.

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

static size_t               suntTCObuf = 0;   //Буфер значения счетчика таймера
size_t setADC(unsigned char uchADCCannel)      //Функция изменения АЦП. Задается номер канала от 0 до 7, возвращается результат измерений (от 1 до 1024) заданного канала.
/////////////////////////////////////////////////////////////////////////////////////////
//---------- E T   A D C------------------------------------//
/////////////////////////////////////////////////////////////////////////////////////////
{
   if(!svuntADCTacts)                     //Если счетчик тактов МК равен 0, то - это начало изменения канала АЦП.
   {
      unsigned char set_admux = ADMUX;      //Присваеваем переменной Регистор настройки канала АЦП
      set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));//Обнуляем биты регистра ADMUX
      if (uchADCCannel != 0)               //Если канал АЦП не равен 0, то...
         set_admux |= (1<< (uchADCCannel - 1));//Задаем регистру ADMUX бит канала АЦП
      ADMUX = set_admux;                  //Присваемваем настроенные биты регистру ADMUX
      svuntADCTacts = 7;//Иннициализируем счетчик тактов МК расчетной величиной (70 микросекунд)
      suntTCObuf = getTimer0();            //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
   }
   else                              //Если счетчик тактов не равен 0, значит, производится или завершается измерение АЦП
   {
      size_t untGetTimer0 = getTimer0();      //Присваеваем значение счетчика таймера Т/С0 переменной
      size_t untMinusTimer0 = 0;            //Создаем переменную, которая будет хранить колличество времени прошедшего с предыдущего посещения функции
      if(untGetTimer0 < suntTCObuf)      //Если счетчик таймера Т/С0 обнулился, то...
         untMinusTimer0 = 65535 - suntTCObuf + untGetTimer0;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
      else//Если нет, то...
         untMinusTimer0 = untGetTimer0 - suntTCObuf;//Расчитываем время прошедшее с предыдущего посещения функции таким образом

      if (svuntADCTacts <= untMinusTimer0)   //Если колличество шагов АЦП будет меньше или равно времени, то...
         svuntADCTacts = 0;               //Окончание обработки данных каналом АЦП
      else                           //если нет, то...
         svuntADCTacts = svuntADCTacts - untMinusTimer0;//Расчитываем счетчик шагов работы АЦП

      suntTCObuf = untGetTimer0;            //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
      if (svuntADCTacts == 0)               //Если нулевое значение счетчика тактов МК,то...
         return ((ADCL | ADCH << 8) + 1);   //Возвращаем значение АЦП +1 (Результат от 1 до 1024). Конец преобразования.
   }
   return 0;                           //Возвращаем 0 (т.е. преобразование еще не завершено)
}


Как то так, я по удалял из кода лишнее не связанного с вопросом (надеюсь лишнего не удалил). Эта функция принимает номер канала АЦП, и когда канал заканчивает преобразование, возвращает результат преобразования. А если функция возвращает 0, значит преобразование не завершено. Я не стал пользоваться прерыванием окончания преобразования АЦП, были на то причины. Код использования данной функции ниже. Кстати в данном случае переменная untGetTimer0 увеличивается на 256, а в другом случае (для других нужд я использовал драйвер ТС0), когда я пользуюсь драйвером ТС0, верхней части if, до else suntTCObuf уменьшается на 257 при следующем посещении функции. И время опроса этой функции куда быстрее, чем 10 микросекунд, я проверял, а при еще следующем посещении функции нормальное значение счетчика на +1 предшедствующему значению (нормальному а не к аномальному значению -257 +1).

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

#include         <avr/io.h>
#include         "dc_adc.h"               //Загружаем библиотеку настройки АЦП
#define          ADC_PORTS      8         //Колличество опрашиваемых каналов АЦП (не больше 8)

int main(void)
{
   initADC ();                           //Запускаем иннициализацию АЦП
   unsigned int   untADCData      = 0;      //Переменная, которая будет хранить данные АЦП
   unsigned char   uncADCPort      = 0;      //Переменная, которая будет задавать канал АЦП
   unsigned int   untADCMass[ADC_PORTS];      //Массив данных, в котором будут храниться данные АЦП
   for (unsigned char step = 0; step < ADC_PORTS; ++step)//Обуляем массив данных АЦП
      untADCMass[step]         = 0;

   while(1)                           //Бесконечный цикл
   {
      untADCData   = setADC(uncADCPort);      //Самая главная строчка, функция должна всегда быть on-line
      if (untADCData > 0)                  //Если функция возвращает 0, значит результат еще не получен от АЦП, если нет, то...
      {
         untADCMass[uncADCPort] = untADCData;//Присваеваем результат АЦП
         ++uncADCPort;                  //Задаем опрашивание другого канала АЦП
         if (uncADCPort >= ADC_PORTS)      //Условие не допущения превышения канала АЦП
            uncADCPort         = 0;      //Обнуляем канал АЦП
      }
   }
}

Как то так.
ARV писал(а):использование volatile переменных неоднобайтного размера - это весьма нехорошо...

Не знал, спасибо, буду знать и использовать. Но я думаю в этом случае не из за этого, так как unsigned сhar - 8 бит, я изменял на этот тип данной переменной svuntCounterTimer0, все равно происходит ошибка инкрементирования рано или поздно.
А может быть такое, что

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

untADCData   = setADC(uncADCPort);

В этот момент вызова функции происходит прерывание и инкрементирование? Что произойдет?

PS: Дело тут не в АЦП, я драйвер таймера ТС0 использую еще в двух местах кода для других нужд, и там так же глюки. Я долго искал ошибку в коде, пока не добрался до драйвера ТС0, что именно он голову парит. Но математика использования драйвера ТС0 одинаковая, а именно:

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

   if(.......)                     //Если счетчик тактов МК равен 0, то - это начало изменения канала АЦП.
   {
      suntTCObuf = getTimer0();            //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
        }
else                              //Если счетчик тактов не равен 0, значит, производится или завершается измерение АЦП
   {
      size_t untGetTimer0 = getTimer0();      //Присваеваем значение счетчика таймера Т/С0 переменной
      size_t untMinusTimer0 = 0;            //Создаем переменную, которая будет хранить колличество времени прошедшего с предыдущего посещения функции
      if(untGetTimer0 < suntTCObuf)      //Если счетчик таймера Т/С0 обнулился, то...
         untMinusTimer0 = 65535 - suntTCObuf + untGetTimer0;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
      else//Если нет, то...
         untMinusTimer0 = untGetTimer0 - suntTCObuf;//Расчитываем время прошедшее с предыдущего посещения функции таким образом

      if (svuntADCTacts <= untMinusTimer0)   //Если колличество шагов АЦП будет меньше или равно времени, то...
         ........;               //Окончание обработки данных каналом АЦП
      else                           //если нет, то...
         .......;//Расчитываем счетчик шагов работы АЦП
          }
Кот должен прожить жизнь без сожаления.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

чтение многобайтной volatile-переменной должно быть атомарным, см. пример моего кода. добавьте внутрь getTimer0() ATOMIC_BLOCK и сообщите результат

авторитет - самый последний аргумент в программировании. по определению size_t и uint16_t разные типы, и совсем не факт, что они оба обязательно всегда будут означать 2 байта данных. не забивая голову, скажу, что правильным поведением будет использование правильного типа данных. size_t - это тип для результата sizeof() - вот для него и применяйте этот тип. а для данных, имеющих конкретную разрядность используйте типы соответствующей разрядности - логично и просто.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

DruidCat писал(а):чтение многобайтной volatile-переменной должно быть атомарным, см. пример моего кода. добавьте внутрь getTimer0() ATOMIC_BLOCK и сообщите результат

Завтра в железе обязательно проверю и отпишусь. Спасибо.
PS: По поводу типов данных, если не ошибаюсь, в 8, 16, 32, 64 битных архитектурах тип unsigned int будет иметь разную величину. Буду пользоваться правильной записью uint16_t - 16 бит.
Кот должен прожить жизнь без сожаления.
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

ARV вы волшебник, все заработало. Спасибо большое, я просто счастлив, так долго искал ошибку в коде, а оказалась проблема не в нем была.
PS: всем, кому интересно, выкладываю драйвер на таймер TC0, пользоваться им просто, там в хидер файле есть инструкция с примером. :)
Вложения
dc_timer0.c
(3.9 КБ) 218 скачиваний
dc_timer0.h
(2.77 КБ) 223 скачивания
Кот должен прожить жизнь без сожаления.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

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

Мой уютный бложик... заходите!
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

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

Сообщение codenamehawk »

По мне так вся функция

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

uint16_t getTimer0(void)

лишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнить

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

     ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
     {
       untCounterTimer0Buf = svuntCounterTimer0;
     }

возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.


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

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

Сообщение ARV »

codenamehawk писал(а):По мне так вся функция

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

uint16_t getTimer0(void)

лишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнить

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

     ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
     {
       untCounterTimer0Buf = svuntCounterTimer0;
     }

возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.


(Возможно умный компилятор сам выкинет ненужное.)
возражу:
1. если эта функция объявлена, как static, никакого лишнего времени на ее вызов не будет. если не-static, то да, пара-тройка лишних тактов будет
2. ATOMIC_BLOCK не может не понадобиться, т.к. проблема у автора была именно из-за его отсутствия, и он именно терял точность - в 256 раз примерно :)

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

Мой уютный бложик... заходите!
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

Я про ошибку кода имел в виду алгоритм его. Если чесно, я про атомарный блок никогда не слышал. И с такой проблемой не сталкивался. Век живи, век учись!)
А по поводу функций, которые возвращают static переменные драйвера, я это сделал намеренно, чтоб инкапсулировать данные. И принципы С++ пытаюсь реализовать в С по мере моих знаний. Если есть другой способ это сделать, я с удовольствием его выслушаю и приму на вооружение. Я кстати пробовал дать права счетчику глобальные права и считывать данные напрямую с переменной, но к сожалению ошибка продолжала появляться. К сожалению, на мой взгляд, функции возвращающие скрытые данные работают медленней, нежели, если работать напрямую с данными, зато можно реализовывать модульное написание программы. Не нужно переделывать весь код в программе, а только в драйвере ТС0, а в основном ядре программы все останется неизменным. Но за это нужно платить быстродействием. Я хочу попробовать объявить функцию inline, но у меня не получается это сделать, тк я делаю все переменные static внутри драйвера. Вот бы сделать функцию inline и чтоб все скрыто было, думаю так бы все работало быстрее. Если я что то глупое сказал, не стесняйтесь, пишите. Я очень люблю учится и уважаю чужой опыт!)
PS: вот нарыл в интернете, правдо все на английском: http://www.gnu.org/savannah-checkouts/n ... tomic.html
Кот должен прожить жизнь без сожаления.
l1tespirit
Родился
Сообщения: 1
Зарегистрирован: Вс мар 23, 2014 13:27:59

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

Сообщение l1tespirit »

У ОС Win 8.1 и Vista проблема с WinAVR заключается в не поддерживаемой msys-1.0.dll ОСх64, расположенной в папке \WinAVR\utils\bin

Следует скачать из инета dll и заменить в установленной папке старую dll на новую. Новая dll в инете в архиве msys-1.0-vista64.zip
Воспользуйтесь поиском.
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

А вот интересно, где именно в проекте объявляется макрос?

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

#define F_CPU ........

Просто не объявляя данного макроса в программе, можно им пользоваться и он будет соответствовать тактовой частоте МК.
И еще вопрос, есть ли такой же макрос, который бы указывал на тип МК в проекте? Просто было бы удобно автоматически настраивать библиотеки.
Кот должен прожить жизнь без сожаления.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

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

Сообщение Kavka »

Такие параметры определяются не в проекте, если об исходниках речь.
Параметры проекта определяются в среде разработки.
А при компиляции эти параметры передаются компилятору средой под соответствующими именами макросов (define-ов). Напрямую или через make-файл.
Вы, видать, не компилировали в ручную компилятором с командной строки - попробуйте и всё станет на свои места. :)
Про тип контроллера, на сколько я знаю, можно проверять определения типа __AVR_ATmega8__
В 6-ой студии, при запущенном сервере помощи, можно посмотреть тут или смотрите описание ключика -mmcu компилятора avr-gcc.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

DruidCat писал(а):А вот интересно, где именно в проекте объявляется макрос?

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

#define F_CPU ........

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

Мой уютный бложик... заходите!
Аватара пользователя
DruidCat
Встал на лапы
Сообщения: 116
Зарегистрирован: Чт май 03, 2012 06:27:23
Откуда: Челябинск

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

Сообщение DruidCat »

Большое спасибо за помощь коты! :)
Кот должен прожить жизнь без сожаления.
Ответить

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