WinAvr в вопросах и ответах
- slavokhire5
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Пн сен 26, 2011 13:48:25
- Откуда: Харьков
Re: WinAvr в вопросах и ответах
Товарищи коты, а никто не подскажет мне, в каком документике почитать "потроха" функций записи/обновления еепром в winavr?
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
--------------------------
Пишу на Си за еду
- Реклама
Re: WinAvr в вопросах и ответах
В исходниках avr-libc, например, отсюда: http://avr-libc.sourcearchive.com/. В папке \libc\misc лежат исходники для всех функций работы с EEPROM.
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: WinAvr в вопросах и ответах
Здравствуйте.
Есть такая страшненькая программа:
Контроллер ATTiny 13A. Программа реализует программный ШИМ на трех вывода PB0, PB1, PB2. Задание для ШИМ берется из заранее сформированных массивов, в зависимости от напряжения на входе АЦП PB4. На PB3 висит кнопка, которая переводит это дело в спящий режим.
Программа работает, но есть один неясный момент. В обработчике прерывания по переполнению Таймера 0 сначала идет команда перевода выводов ШИМ в состояние входов:
Потом идет вызов функции, которая меняет значения на выводах ШИМ:
А потом идет команда перевода выводов ШИМ в состояние выходов:
Должно же быть наоборот: сперва делаем выводы выходами, потом меняем их состояние, потом делаем их входами. Правда, зачем нужен последний шаг (используемый в этой программе часто) тоже не понимаю. Пусть бы и оставались выводы в состоянии выходов, что в этом плохого. В общем, непонятно, как оно работает и зачем оно сделано так.
Есть такая страшненькая программа:
Спойлер
Код: Выделить всё
#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 в вопросах и ответах
Видимо здесь это оффтоп. Звиняйте, перетащу в другой раздел.
We do what we must because we can (c) GLaDOS
- Реклама
Re: WinAvr в вопросах и ответах
Коты, помогите, не могу отследить ошибку в течении уже недели. Пользуюсь: 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.
Так же есть вероятность, что произошло прерывание по USART (В векторе прерывания USART довольно таки большой код, там четыре if(), счетчик принятых символов и заполнение массива данных принятых по USART) а потом происходит прерывание по таймеру, но тогда тоже программа дождется прерывания USART и обработает прерывание по TC0. Но вот в одновременности прерываний я вообще не силен. 
9) Еще есть вариант, что я драйвер для TC0 написал корявый или программу.
Пишу здесь, вдруг у вас многоуважаемые коты была такая проблема и вы мне поможете непутевому.
PS: Я решил проблемму таким образов, я в теле вектора прерываний ограничил счетчик 255, вколотив условие:
Все стало работать нормально, но ведь это не решение. А если переменную svuntCounterTimer0 я объявлю под типом unsigned char, то опять раз в сто лет переменная svuntCounterTimer0 увеличивается не на 1. Пользуюсь драйвером очень просто, инициализирую его в начале программы, а потом снимаю параметры счетчика с помощью функции
Суть проблемы:
1) В векторе прерывания стоит счетчик unsigned int, который +1 каждые 10 микросекунд.
2) В определенный момент (бывает даже раз в 10 минут а бывает и чаще) заместо того, чтоб увеличится на единичку, он увеличивается на 256 или 257 (точнее не могу определить, так как не пользуюсь симулятором, ниже напишу почему.)
3) Из за этого, что счетчик скачен на +256 вся программа летит в преисподню (работает не корректно).
4) У меня по мимо прерывания таймера ТС0 еще есть прерывание по приему символов по USART.
5) Программа очень много и быстро принимает данные по USART (115200 бод) и поэтому не могу пользоваться симулятором, так как все работает отлично, а раз в 10 минут происходит хрень.
6) Я долго думал над этим, думал, может моя основная программа переписывает область памяти, в которой лежит счетчик прерываний, и поэтому он изменяется на большое число. Убрал все указатели в программе и проверил все массивы, чтоб они при заполнении данными не дай бог не вышли за предел своей области. Не помогло.
7) Может возникает одновременно прерывание по TC0 и USART. Почитал по этой проблемме, узнал, что у вектора прерывания таймера более высокий приоритет, и поидее, сначало таймер отработает, потом USART.
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 в вопросах и ответах
предположение: просмотрите места, где в программе вы ИСПОЛЬЗУЕТЕ значение своей переменной svuntCounterTimer0 - так как она не однобайтная (кстати, почему size_t а не uint16_t?) и меняется относительно часто, то обращение к ней даже на чтение должно быть атомарным. предполагаю, что переменная инкрементируется правильно, а вот ее обработка в основном коде иногда попадает на момент, когда между анализом батйтов вклинивается прерывание, меняющее их содержимое.
имхо, использование volatile переменных неоднобайтного размера - это весьма нехорошо... лично мне приходится делать в этих случаях примерно так:что совсем не красиво и не удобно
имхо, использование volatile переменных неоднобайтного размера - это весьма нехорошо... лично мне приходится делать в этих случаях примерно так:
Код: Выделить всё
volatile uint16_t my_volatile_var;
uint16_t temp;
ATOMIC_BLOCK(ATOMIC_RESTORE_STATE){
tmp = my_volatile_var;
}
if (tmp == 0) ...если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: WinAvr в вопросах и ответах
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 в вопросах и ответах
чтение многобайтной volatile-переменной должно быть атомарным, см. пример моего кода. добавьте внутрь getTimer0() ATOMIC_BLOCK и сообщите результат
авторитет - самый последний аргумент в программировании. по определению size_t и uint16_t разные типы, и совсем не факт, что они оба обязательно всегда будут означать 2 байта данных. не забивая голову, скажу, что правильным поведением будет использование правильного типа данных. size_t - это тип для результата sizeof() - вот для него и применяйте этот тип. а для данных, имеющих конкретную разрядность используйте типы соответствующей разрядности - логично и просто.
авторитет - самый последний аргумент в программировании. по определению size_t и uint16_t разные типы, и совсем не факт, что они оба обязательно всегда будут означать 2 байта данных. не забивая голову, скажу, что правильным поведением будет использование правильного типа данных. size_t - это тип для результата sizeof() - вот для него и применяйте этот тип. а для данных, имеющих конкретную разрядность используйте типы соответствующей разрядности - логично и просто.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: WinAvr в вопросах и ответах
DruidCat писал(а):чтение многобайтной volatile-переменной должно быть атомарным, см. пример моего кода. добавьте внутрь getTimer0() ATOMIC_BLOCK и сообщите результат
Завтра в железе обязательно проверю и отпишусь. Спасибо.
PS: По поводу типов данных, если не ошибаюсь, в 8, 16, 32, 64 битных архитектурах тип unsigned int будет иметь разную величину. Буду пользоваться правильной записью uint16_t - 16 бит.
Кот должен прожить жизнь без сожаления.
Re: WinAvr в вопросах и ответах
ARV вы волшебник, все заработало. Спасибо большое, я просто счастлив, так долго искал ошибку в коде, а оказалась проблема не в нем была.
PS: всем, кому интересно, выкладываю драйвер на таймер TC0, пользоваться им просто, там в хидер файле есть инструкция с примером.
PS: всем, кому интересно, выкладываю драйвер на таймер TC0, пользоваться им просто, там в хидер файле есть инструкция с примером.
- Вложения
-
- dc_timer0.c
- (3.9 КБ) 218 скачиваний
-
- dc_timer0.h
- (2.77 КБ) 223 скачивания
Кот должен прожить жизнь без сожаления.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: WinAvr в вопросах и ответах
а в чем же тогда?DruidCat писал(а): так долго искал ошибку в коде, а оказалась проблема не в нем была.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
-
codenamehawk
- Вымогатель припоя
- Сообщения: 528
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Re: WinAvr в вопросах и ответах
По мне так вся функция
лишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнить
возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.
(Возможно умный компилятор сам выкинет ненужное.)
Код: Выделить всё
uint16_t getTimer0(void)лишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнить
Код: Выделить всё
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
untCounterTimer0Buf = svuntCounterTimer0;
}
возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.
(Возможно умный компилятор сам выкинет ненужное.)
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: WinAvr в вопросах и ответах
возражу:codenamehawk писал(а):По мне так вся функцияКод: Выделить всё
uint16_t getTimer0(void)
лишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнитьКод: Выделить всё
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
untCounterTimer0Buf = svuntCounterTimer0;
}
возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.
(Возможно умный компилятор сам выкинет ненужное.)
1. если эта функция объявлена, как static, никакого лишнего времени на ее вызов не будет. если не-static, то да, пара-тройка лишних тактов будет
2. ATOMIC_BLOCK не может не понадобиться, т.к. проблема у автора была именно из-за его отсутствия, и он именно терял точность - в 256 раз примерно
в данных вопросах предполагать ничего не нужно, все ясно предельно точно.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: WinAvr в вопросах и ответах
Я про ошибку кода имел в виду алгоритм его. Если чесно, я про атомарный блок никогда не слышал. И с такой проблемой не сталкивался. Век живи, век учись!)
А по поводу функций, которые возвращают static переменные драйвера, я это сделал намеренно, чтоб инкапсулировать данные. И принципы С++ пытаюсь реализовать в С по мере моих знаний. Если есть другой способ это сделать, я с удовольствием его выслушаю и приму на вооружение. Я кстати пробовал дать права счетчику глобальные права и считывать данные напрямую с переменной, но к сожалению ошибка продолжала появляться. К сожалению, на мой взгляд, функции возвращающие скрытые данные работают медленней, нежели, если работать напрямую с данными, зато можно реализовывать модульное написание программы. Не нужно переделывать весь код в программе, а только в драйвере ТС0, а в основном ядре программы все останется неизменным. Но за это нужно платить быстродействием. Я хочу попробовать объявить функцию inline, но у меня не получается это сделать, тк я делаю все переменные static внутри драйвера. Вот бы сделать функцию inline и чтоб все скрыто было, думаю так бы все работало быстрее. Если я что то глупое сказал, не стесняйтесь, пишите. Я очень люблю учится и уважаю чужой опыт!)
PS: вот нарыл в интернете, правдо все на английском: http://www.gnu.org/savannah-checkouts/n ... tomic.html
А по поводу функций, которые возвращают static переменные драйвера, я это сделал намеренно, чтоб инкапсулировать данные. И принципы С++ пытаюсь реализовать в С по мере моих знаний. Если есть другой способ это сделать, я с удовольствием его выслушаю и приму на вооружение. Я кстати пробовал дать права счетчику глобальные права и считывать данные напрямую с переменной, но к сожалению ошибка продолжала появляться. К сожалению, на мой взгляд, функции возвращающие скрытые данные работают медленней, нежели, если работать напрямую с данными, зато можно реализовывать модульное написание программы. Не нужно переделывать весь код в программе, а только в драйвере ТС0, а в основном ядре программы все останется неизменным. Но за это нужно платить быстродействием. Я хочу попробовать объявить функцию inline, но у меня не получается это сделать, тк я делаю все переменные static внутри драйвера. Вот бы сделать функцию inline и чтоб все скрыто было, думаю так бы все работало быстрее. Если я что то глупое сказал, не стесняйтесь, пишите. Я очень люблю учится и уважаю чужой опыт!)
PS: вот нарыл в интернете, правдо все на английском: http://www.gnu.org/savannah-checkouts/n ... tomic.html
Кот должен прожить жизнь без сожаления.
-
l1tespirit
- Родился
- Сообщения: 1
- Зарегистрирован: Вс мар 23, 2014 13:27:59
Re: WinAvr в вопросах и ответах
У ОС Win 8.1 и Vista проблема с WinAVR заключается в не поддерживаемой msys-1.0.dll ОСх64, расположенной в папке \WinAVR\utils\bin
Следует скачать из инета dll и заменить в установленной папке старую dll на новую. Новая dll в инете в архиве msys-1.0-vista64.zip
Воспользуйтесь поиском.
Следует скачать из инета dll и заменить в установленной папке старую dll на новую. Новая dll в инете в архиве msys-1.0-vista64.zip
Воспользуйтесь поиском.
Re: WinAvr в вопросах и ответах
А вот интересно, где именно в проекте объявляется макрос?
Просто не объявляя данного макроса в программе, можно им пользоваться и он будет соответствовать тактовой частоте МК.
И еще вопрос, есть ли такой же макрос, который бы указывал на тип МК в проекте? Просто было бы удобно автоматически настраивать библиотеки.
Код: Выделить всё
#define F_CPU ........Просто не объявляя данного макроса в программе, можно им пользоваться и он будет соответствовать тактовой частоте МК.
И еще вопрос, есть ли такой же макрос, который бы указывал на тип МК в проекте? Просто было бы удобно автоматически настраивать библиотеки.
Кот должен прожить жизнь без сожаления.
Re: WinAvr в вопросах и ответах
Такие параметры определяются не в проекте, если об исходниках речь.
Параметры проекта определяются в среде разработки.
А при компиляции эти параметры передаются компилятору средой под соответствующими именами макросов (define-ов). Напрямую или через make-файл.
Вы, видать, не компилировали в ручную компилятором с командной строки - попробуйте и всё станет на свои места.
Про тип контроллера, на сколько я знаю, можно проверять определения типа __AVR_ATmega8__
В 6-ой студии, при запущенном сервере помощи, можно посмотреть тут или смотрите описание ключика -mmcu компилятора avr-gcc.
Параметры проекта определяются в среде разработки.
А при компиляции эти параметры передаются компилятору средой под соответствующими именами макросов (define-ов). Напрямую или через make-файл.
Вы, видать, не компилировали в ручную компилятором с командной строки - попробуйте и всё станет на свои места.
Про тип контроллера, на сколько я знаю, можно проверять определения типа __AVR_ATmega8__
В 6-ой студии, при запущенном сервере помощи, можно посмотреть тут или смотрите описание ключика -mmcu компилятора avr-gcc.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: WinAvr в вопросах и ответах
DruidCat писал(а):А вот интересно, где именно в проекте объявляется макрос?Код: Выделить всё
#define F_CPU ........
обычно этот макрос передается компилятору в командной строке параметром -D (кстати, так вы можете передать и какой-то свой макрос, если нужно). а вот о том, как этот параметр в командную строку попадает, обычно заботится IDE, а точнее - makefile
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: WinAvr в вопросах и ответах
Большое спасибо за помощь коты! 
Кот должен прожить жизнь без сожаления.


