Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Глюки AVRStudio+WinAVR или в моей голове
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Чиппер
вот листинг моей программы , это грубо говоря пищалка против клопов ультро звуковая ,
должна настраиваться переменным резистором подключенным к порту а на нужной частоте.
Но факт в том что программа на каторой компелируется текст начинает глючить , то проходит через прерывание таймера Т1 по три раза , то скачет через строчку и появляется после нескольких
десятков нажатий F11 в разных местах. Самое интересное что эту же программу я заредил в VMLAB
Она и там показала ту же окалесицу. Я с этой бедой борюсь больше 2 лет ( а мне не смешно.)
Голова кругом!!! То-ли менять компилятор (я к этому то долгл приноравливался ) , То ли писать на Ассемблере. Я бы с Удовольствием выложил видео Файл Что эта программа вытворяет , если покажите куда.



#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


volatile unsigned char a;

#define INVBIT(x,y) (x^=(1<<y))


ISR(TIMER1_OVF_vect)
{

INVBIT(PORTB,PB1);// управление светодиод
INVBIT(PORTB,PB0);// управление светодиод
a=0;

}








void display(void);

int main(void)
{
TIFR =0;
TIMSK=0x04;// прерывание по перепол т1
TCCR1A=0;
TCCR1B=1;
TCNT1=65535-500;
sei();

SFIOR=0;
ADCSRA=0xe0;

SFIOR=0;
DDRA=0x00;//in
DDRB=0xff;//out
DDRC=0xff;//out
DDRD=0x00;//in

PORTA=0x00;
PORTB=0x01;
PORTC=0x00;
PORTD=0x00;


ADMUX=1;//vibor vhoda

horo:
ADMUX=1;
_delay_ms(1000);
ADCCompare=ADC;
ADCCompare=ADCCompare/3;
ADCCompare=500-ADCCompare;
TCNT1=65535-ADCCompare;

a=1;

horo1:


if (a==0)
{goto horo;}



goto horo1;





}

alexeyv
1. Какой чип?
2. Какая тактовая частота? В даташите написано тактовая на АЦП д.б. 50...200кГц, а у Вас делитель на 2.
3. Зачем постоянно выбираете 1-й канал? Одного раза разве не достаточно?
4. Так наверное будет и понятнее и проще:
Код
ADMUX=1;
while(1)
{
  if(a) continue;
  a=1;
  TCNT1 = 65535 - 500 + ADC/3;
  _delay_ms(1000);
}


5. А разве не надо опрашивать флаг ADIF что бы узнать об окончании конверсии?
Чиппер
Проц Mega16l , Тактовая частота 16 мегагерц .
Пытаюсь настроить колебания на частоту от 16килогерц до 50.
Динамик приходится качать в два раза чаще.
К порту В к выводам 0 и 1 подключены через 4 транзистора динамик и попарно он качается то одним
плечем то другим.
Проблемма в управлении, его нет.
Я создавал приблуды и посерьезнее но проблемма одна программа глючит.

TCNT1 = 65535 - 500 + ADC/3;
Согласно вашей формуле если за место ADC подставить 1000 то TCNT = FE25.

А из-за того что я разложил все действия результат оказался верным FF58.
я его проверял на калькуляторе.

Но вопрос не в этом а в чем писать и чем проверять программу ?
Winavr 2008 12 05
AvrStudio 4.18
Это то вчем я работаю.
Палыч
Цитата(Чиппер @ Dec 3 2012, 10:53) *
Пытаюсь настроить колебания на частоту от 16килогерц до 50.

Насколькоя понимаю - вы используете таймер в Normal mode. Это - мягко говоря, не лучшее решение: после переполнения и "дрыгания" ногами, Вы выставляете признак обновления счетчика таймера (переменная а), но в ветке обновления счетчика (метка horo) у Вас стоит задержка в целую секунду...
Логичнее использовать CTC mode. Да, и для генерации сигнала, вероятно, лучше использовать вывод ОС1х, предварительно настроив вывод таймера на него.

alexeyv
1. Если FCPU =16МГц, то необходимо поставить делитель АЦП равным 128 (тактовая на АЦП будет 125КГц)

2.
Цитата
TCNT1 = 65535 - 500 + ADC/3;
Согласно вашей формуле если за место ADC подставить 1000 то TCNT = FE25.

Странно!! А у меня получилось FF58.
Объясните мне разницу между
Код
TCNT1 = 65535 - 500 + ADC/3;

и
Код
ADCCompare=ADC;
ADCCompare=ADCCompare/3;
ADCCompare=500-ADCCompare;
TCNT1=65535-ADCCompare;


3. Где опрос флага ADIF и его сброс? Ваша проблема понятна - Вы считываете данные с АЦП тогда, когда еще нет точного результата конверсии

4. Для проверки алгоритма поставьте несколько констант вместо считывания с АЦП и проверьте зависимость выхода(частоты) от констант. Если на выходе будет нужная частота, то проблема в считывании показаний с АЦП.
Также, если есть к-либо отладочный порт (USART), можете вывести значения АЦП на ПК и посмотреть как они считываются/изменяются.

5. Если у вас задержки порядка секунды, зачем запускать АЦП во Free Runing? По окончании задержки запустите в одиночном измерении и дождитесь окончании конверсии
Чиппер
Цитата(Палыч @ Dec 3 2012, 21:22) *
Насколькоя понимаю - вы используете таймер в Normal mode. Это - мягко говоря, не лучшее решение: после переполнения и "дрыгания" ногами, Вы выставляете признак обновления счетчика таймера (переменная а), но в ветке обновления счетчика (метка horo) у Вас стоит задержка в целую секунду...
Логичнее использовать CTC mode. Да, и для генерации сигнала, вероятно, лучше использовать вывод ОС1х, предварительно настроив вывод таймера на него.
я поставил задержку в надежде что появится регулировка от ацп спасибо за подсказку.
с временем я что-то под ошибся .


Господа программисты посмотрите этот клипп и обьясните почему он себя так ведет.

не могу вставить пока , файл 1.5 мегабайта сайт не принимает
ILYAUL
Есть столько сайтов , что бы сбросить и дать ссылку
Чиппер
Нашел , скачивайте и посмотрите .
http://files.mail.ru/IF38YS

Цитата(alexeyv @ Dec 3 2012, 21:33) *
1. Если FCPU =16МГц, то необходимо поставить делитель АЦП равным 128 (тактовая на АЦП будет 125КГц)

2.

Странно!! А у меня получилось FF58.
Объясните мне разницу между
Код
TCNT1 = 65535 - 500 + ADC/3;

и
Код
ADCCompare=ADC;
ADCCompare=ADCCompare/3;
ADCCompare=500-ADCCompare;
TCNT1=65535-ADCCompare;


3. Где опрос флага ADIF и его сброс? Ваша проблема понятна - Вы считываете данные с АЦП тогда, когда еще нет точного результата конверсии

4. Для проверки алгоритма поставьте несколько констант вместо считывания с АЦП и проверьте зависимость выхода(частоты) от констант. Если на выходе будет нужная частота, то проблема в считывании показаний с АЦП.
Также, если есть к-либо отладочный порт (USART), можете вывести значения АЦП на ПК и посмотреть как они считываются/изменяются.

5. Если у вас задержки порядка секунды, зачем запускать АЦП во Free Runing? По окончании задержки запустите в одиночном измерении и дождитесь окончании конверсии


1 .Зачем мне включать делитель если частотой управляет формула?
2 .Разница лишь в том что если вашу формулу я вставляю в код программы и свой ,я получаю разные результаты.
3. Хорошая мысль Попробую после того как программа заработает.
4. Попробую.
5. Такая задержка это ошибка , я ее уже устранил .

Алексей тоже посмотрите ролик мне интересно ваше мнение.
alexeyv
Цитата
1 .Зачем мне включать делитель если частотой управляет формула?

Формула должна управлять выходной частотой для динамика, а не рабочей частотой от которой работает АЦП - не путайте понятия!!

Цитата
2 .Разница лишь в том что если вашу формулу я вставляю в код программы и свой ,я получаю разные результаты.

Не верю. Жаль мне сейчас не на чем проверить. Это всего лишь эквивалентные преобразования.

Цитата
3. Хорошая мысль Попробую после того как программа заработает.

Это надо сделать ДЛЯ того что бы программа заработала, причем правильно!!

По поводу ролика:
Какой режим оптимизации включен? При включенной оптимизации компилятор как раз выкинет все ваши присваивания и приведет все к виду:
TCNT1 = 65035 + _function_divide(ADC,3);
переменная ADCCompare также выкинется как лишняя.

Замечания по поводу алгоритма
1. Зачем вообще так часто сканировать номинал резистора или он быстро меняется. Достаточно это делать раз в секунду. Причем в Single-mode. Делать это в главном цикле в задержкой в 1 сек и ожиданием окончания конверсии после старта
2. Согласен с Палыч'ем - необходимо использовать тайммер в СТС режиме. В прерывании от него необходимо проверять не изменилось ли значение резистора и только после этого менять период работа таймера. Не изменилось - пусть себе дальше пашет. Использование ОС1х - не обязательно, надо смотреть как у Вас все подлючено и можно ли перебросить выводы.
Чиппер
Переделал вот листинг
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile unsigned int a; // èçìåíÿåìàÿ äëèòåëüíîñòü ìîðãàíèé
volatile unsigned int ADCCompare; //

#define SETBIT(x,y) (x|=(1<<y))
#define CLRBIT(x,y) (x&=~(1<<y))
#define INVBIT(x,y) (x^=(1<<y))
#define CHKBIT(x,y) (x&(1<<y))
#define BITON(x,y) (x&(1<<y))
#define BITOFF(x,y) (!(x&(1<<y)))



ISR(TIMER1_OVF_vect)
{

INVBIT(PORTB,PB1);//
INVBIT(PORTB,PB0);//
a=0;

}

// ((PIND & 0x04) == 0 ) ïðîâåðèòü åñëè 4 áèò = 0
// ((PIND & 0x04) != 0 ) ïðîâåðèòü åñëè 4 áèò = 1
// 7654 3210
// 1000 0000 = 80
// 0100 0000 = 40
// 0010 0000 = 20
// 0001 0000 = 10
// 0000 1000 = 08
// 0000 0100 = 04
// 0000 0010 = 02
// 0000 0001 = 01


int main(void)
{
TIFR =0;
TIMSK=0x04;// ïðåðûâàíèå ïî ïåðåïîë ò1
TCCR1A=0;
TCCR1B=1;
TCNT1=65535-500;
cli();

SFIOR=0;
ADCSRA=0xe7;

SFIOR=0;
DDRA=0x00;//in
DDRB=0xff;//out
DDRC=0xff;//out
DDRD=0x00;//in

PORTA=0x00;
PORTB=0x01;
PORTC=0x00;
PORTD=0x00;


ADMUX=1;//vibor vhoda



horo:

TCNT1=65535-(500-(ADC/3));
a=1;

horo1:


if ( ADIF==1)
{goto horo;}



goto horo1;
}



Оптимизацию сделал на ноль и на один тоже ставил
в листинге на строчке а=1 в программе проподает стрелка при значении CYCLE COUNTER 204 А ЕСЛИ НАЖАТЬ ПАУЗУ ЭТО ЖЕ ЗНАЧЕНИЕ УЖЕ РАВНО 3206010 , ПРИ ЧЕМ НИ КАКИЕ ТОЧКИ ОСТАНОВА РАССТАВЛЕННЫЕ В РАЗНЫХ МЕСТАХ ПРОГРАММЫ И ПРЕРЫВАНИЯ НЕ СРАБАТЫВАЮТ. КАК ТО РАЗ ДАЖЕ ОСТАНОВИ ПРОГРАММУ ГДЕ СТРЕЛА ВЫШЛА ЗА ЛИСТИНГ ПРОГРАММЫ . кАК ОТЛАЖИВАТЬ ПРОГРАММУ ВООБЩЕ НЕ ПОНЯТНО((
V.K
Вставьте:

asm("nop");

и на этой строке сделайте точку останова.

Помогает.
Чиппер
(( Попробывал Теже яйца только в профиль.
Я вот все думаю если есть этот Сайт Созданы эти микроконтроллеры есть этот глючный AVR Studio ,
Есть наверное прога в каторой все программируют отлаживают и в тихушку молчат . Это мое мнение.


Неужели в аське писать прогу , просто не понятно как представлять данные выходящие за значение одного байта, как совершать деление и др операции это же вчерашний век . Вот Блин, руки опускаются с такой перспективой.
_Артём_
Цитата(Чиппер @ Dec 8 2012, 14:46) *
этот глючный AVR Studio ,

В чём претензия к AVRStudio?

Цитата(Чиппер @ Dec 8 2012, 14:46) *
Есть наверное прога в каторой все программируют отлаживают и в тихушку молчат .

Есть такая программа, AVRStudio называется.
Есть и другие программы.

Цитата(Чиппер @ Dec 8 2012, 14:46) *
Вот Блин, руки опускаются с такой перспективой.

Дело всё в вашей программе - что она делать-то должна?
Что странно:
Код
horo:
ADMUX=1;
_delay_ms(1000);
ADCCompare=ADC;
ADCCompare=ADCCompare/3;
ADCCompare=500-ADCCompare;
TCNT1=65535-ADCCompare;

результат АЦП получается 1 раз в секунду, в зависимости от результата устанавливается "период" таймера. Остальное время прерывания переполнения возникают через 65536 циклов.
Может как-то так надо:

Код
volatile unsigned short Timer1ReloadValue=65535-500;
ISR(TIMER1_OVF_vect)
{

TCNT1=Timer1ReloadValue;
INVBIT(PORTB,PB1);// управление светодиод
INVBIT(PORTB,PB0);// управление светодиод
a=0;

}


Код
ADMUX=1;
_delay_ms(1000);
ADCCompare=ADC;
ADCCompare=ADCCompare/3;
ADCCompare=500-ADCCompare;
Timer1ReloadValue=65535-ADCCompare;




?
alexeyv
Где-то примерно так:
CODE

#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile unsigned int ADCCompare_new =0;
volatile unsigned int ADCCompare_old =0;

#define SETBIT(x,y) (x|=(1<<y))
#define CLRBIT(x,y) (x&=~(1<<y))
#define INVBIT(x,y) (x^=(1<<y))
#define CHKBIT(x,y) (x&(1<<y))
#define BITON(x,y) (x&(1<<y))
#define BITOFF(x,y) (!(x&(1<<y)))


ISR(TIMER1_COMPA_vect)
{
INVBIT(PORTB,PB1);//
INVBIT(PORTB,PB0);//
if(ADCCompare_new != ADCCompare_old)
{
OCR1A = ADCCompare_old = ADCCompare_new;
}
}


int main(void)
{
cli();

// Init TC1 - CTC Mode
TCCR1A = 0;
TCCR1B = (1<<WGM12) | (1<<CS10);
OCR1A = 510;
TCNT1 = 0;
TIMSK = (1<<OCIE1A);

// Init ADC
SFIOR=0;
ADCSRA = (1<<ADEN)|(0<<ADSC)|(0<<ADATE)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
ADMUX=1; //vibor vhoda

// Init Port's
DDRA=0x00; //in
DDRB=0xff; //out
DDRC=0xff; //out
DDRD=0x00; //in
PORTA=0x00;
PORTB=0x01;
PORTC=0x00;
PORTD=0x00;

TIFR = 0xFF;
sei();
while(1)
{
_delay_ms(1000);
ADCSRA |= (1<<ADSC); // Start ADC Conversion
while((ADCSRA & (1<<ADIF)) != 0x10);// Wait till conversion is complete
ADCCompare_new = 510 - (ADC/3); // Read the ADC Result
ADCSRA |= (1 << ADIF); // Clear ADC Conversion Interrupt Flag
}
}
TriD
Не вдаваясь в тонкости реализации программы, скажу, что студия эмулирует сишный код несколько своеобразно. При ошибках в коде может вообще убрать целые фрагменты кода, которые с точки зрения компилятора выполнять никогда не будут. Для получения полного представления того, что там накомпилилось из вашей программы, отлаживаейте ее в окне дизассемблера.
Чиппер
Цитата(TriD @ Dec 11 2012, 02:20) *
При ошибках в коде может вообще убрать целые фрагменты кода, которые с точки зрения компилятора выполнять никогда не будут.

Спасибо за подсказку , но вот вопрос что WinAVR считает ошибкой ? Я замечал что он не любит оператор
Goto .

Цитата(TriD @ Dec 11 2012, 02:20) *
При ошибках в коде может вообще убрать целые фрагменты кода, которые с точки зрения компилятора выполнять никогда не будут.

Спасибо за подсказку , но вот вопрос что WinAVR считает ошибкой ? Я замечал что он не любит оператор
Goto .
demiurg_spb
Понизьте уровень оптимизации до 0 или 1 тогда можно будет более-менее нормально шагать по си-коду.
А глюки-таки у вас в голове. Как вы себе представляете хождение по строчкам которых нет и в помине?
Ведь компилятор-то весьма и весьма умён и может очень и очень сильно оптимизировать.
TriD
Цитата(Чиппер @ Dec 13 2012, 17:06) *
Спасибо за подсказку , но вот вопрос что WinAVR считает ошибкой ? Я замечал что он не любит оператор
Goto .

Оператор goto вообще старайтесь не использовать, поверьте, всегда можно обойтись и без него (подробности ищите в инете).
Если включена оптимизация, то компилятор будет убирать из кода куски, которые по его мнению никогда не будут выполнены (даже если вы считаете не так). Подобные ситуации возникают, когда используются обычные переменные вместо volatile или неправильно сформировано условие выполнения кода. Все эти ситуации - это не синтаксические ошибки, поэтому и не определятся как ошибки.
Как вам правильно посоветовал demiurg_spb, понизьте уровень оптимизации, а еще лучше, отлаживайте свой код с помощью окна дизассемблера.
Чиппер
Еще один вопрос Синтаксис Глобальных переменных Как часто можно их использовать , а если как можно реже (использовать только в прерываниях) то почему?
demiurg_spb
Цитата(Чиппер @ Dec 22 2012, 04:48) *
Странный вопрос... Глобальные переменные нужно использовать только по мере их реальной необходимости. Точка.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.