CodeVision AVR в вопросах и ответах

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

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

Сообщение WiseLord »

DataLife писал(а):Так вот, "фантомы" из правого разряда переходят на соседний левый!
Я уже выше писал про возможную "инерционность" светоидодов. Колько скоро недавно выяснилось, что для управления разрядами используются ключи на npn-транзисторах.. попробуйте резисторы на базы таких транзисторов уменьшить раз в 10 (до приблизительно килоома). Просто параллельно напаять, как вариант. Вдруг именно где-то в этих цепях появляется задержка?

У меня-то и на в 5 раз большей частоте работало без "засветок", но я без транзисторных ключей делал.
Реклама
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

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

Сообщение zero648 »

DataLife писал(а):Да, там скорее всего опечатка. Там выбраны резисторы 56к и 15к (56/15 = 3,733).
Как это опечатка?, все праливно, коэф. с резиками 56к и 15к будет 4.73, а формула така: (56+15)/15=4.73
Реклама
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

WiseLord, с кодом, который ниже, индикация работает шикарно, на частоте счётчика таймера2 в 1Мгц (делитель на 8 ). И всё на тех же транзисторах и резисторах.
Тут именно откуда-то берутся "фантомы" соседних разрядов. Браться им там неоткуда аппаратно, только программно. А разряды перечисляются операторами if...

zero648, прошу прощения, был не прав по поводу расчёта коэффициента, но с подобранными резисторами верно ...
Последний раз редактировалось DataLife Вт авг 05, 2014 17:40:05, всего редактировалось 1 раз.
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

DataLife писал(а):ARV, стало кое-что поясняться. Сделал обычный "счётчик": на индикатор выводятся каждые две секунды i++;
Постараюсь доходчиво объяснить. Имеем такую картинку: четыре разряда, например выводится значение 2015: [2][0][1][5]. Так вот, "фантомы" из правого разряда переходят на соседний левый! На двоечке силуэт ноля, на ноле (хоть и не видно) есть единичка, на единице - пятёрка. Когда "счётчик" тикает - это хорошо заметно.

Получается косяк теперь скорее ряде операторов if, мне так видится... :dont_know:
чудны дела твои, господи :)))

а на 5-ке видно след от первой 2-ки?

смотрю я ваш код и не понимаю, откуда такой эффект. ну не должно бы вроде быть его... пока не понимаю вообще...

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

Мой уютный бложик... заходите!
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

ARV, чуднее некуда ...
Да, на последнем разряде "фантом" первого. Всё по кругу.
По поводу гашения ноля и точки - пока что хочу заставить работать код так (или даже без гашения ноля и точки), после оптимизировать ...
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Реклама
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

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

Сообщение zero648 »

DataLife, у Вас фантомы крутятся по кругу вроде шлейфа, возможно где-то в коде происходит накладка, а именно, сначала включаете разряд, а потом выводите в порт сегменты следующего по очереди разряда, или наоборот, выводите в порт сегменты, а потом переключаете разряд. Чтобы не было накладок, выключайте разряды и гасите сегменты, а потом уже выводите/включайте сегменты и разряд или наоборот.
Реклама
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

zero648, дык всё так и есть ...

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTD=0x00;                      // гасим сегменты
     PORTB &= ~((1<<0)|(1<<1)|(1<<2)|(1<<3));   // гасим все разряды
     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)
     
     if (count == 0) PORTB |= (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB |= (1<<1);             
     if (count == 2) PORTB |= (1<<2);
     if (count == 3) PORTB |= (1<<3);
     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
    }
Может кого наталкнёт на мысль, но я попробовал строчку, где гасятся разряды, перекинуть в конец функции и "фантомы" исчезли, но сегменты горят в пол-накала. PORTD=0x00; убрал из кода.
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

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

Сообщение Pink-Pank »

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTB=0x00;                      // гасим сегменты
     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)
     
     if (count == 0) PORTB = (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB = (1<<1);             
     if (count == 2) PORTB = (1<<2);
     if (count == 3) PORTB = (1<<3);
     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
    }
Fucking static initialization order fiasco
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

Pink-Pank, было бы всё так просто. Пробовал и так. Не то ... :dont_know:
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

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

Сообщение Pink-Pank »

прямо точно так пробовали? И что не то?
Fucking static initialization order fiasco
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

Прям-прям точно так ...
Спойлер

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

#include <mega8.h>
#include <delay.h>

//Объявляем переменные

//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};

volatile char adc_data[4];
volatile unsigned int ADC_volt;                                      
    
/** ФУНКЦИЯ ПРЕОБРАЗОВАНИЯ **/
    
void data_convert(unsigned int value)
    {
     unsigned char tmp;   // переменная для временного хранения данных преобразования
     
     tmp = value / 1000;
     adc_data[0] = SEGMENTE[tmp];
     tmp = value % 1000 / 100;
     adc_data[1] = SEGMENTE[tmp];
     tmp = value % 100 / 10;
     adc_data[2] = SEGMENTE[tmp];
     tmp = value % 10;
     adc_data[3] = SEGMENTE[tmp];
     
    }

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTB=0x00;   // гасим сегменты, для перестраховки

     PORTD = adc_data[count];           // выводим в порт код цифры (сегменты)
     
     
     if (count == 0) PORTB |= (1<<0);             // перечисляем выводимые разряды, не выводим "ноль" в первом разряде
     if (count == 1) PORTB |= (1<<1);             //включаем точку во втором разряде
     if (count == 2) PORTB |= (1<<2);
     if (count == 3) PORTB |= (1<<3);
     count++;                           // включаем следующий разряд
     if (count == 4) count = 0;
    }


void ADC_result(void)
{
        unsigned int adc_tmp;

        ADCSRA |= 0x40; //начинаем измерение
        while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
        ADCSRA |=0x10;
        adc_tmp=ADCW;
        ADC_volt=(float)adc_tmp*4645/10000;     // не задумываемся над вычислениями
}

// Обработчик прерывания по переполнению таймера2
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
  ind_update();           
}

void main(void)
{
 PORTB=0x00;
 DDRB|=(1<<0)|(1<<1)|(1<<2)|(1<<3); // настройка на выход. 4 разряда

 PORTD=0x00;
 DDRD=0xFF;                         // настройка на выход всего порта
 
 ADCSRA = 0x86; //0b10000110 - предделитель на 64, прерывания запрещены, ADC включён
 ADMUX = 0x40; //0b01000000 - AVCC , ACD0, ADLAR off

 TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
 TCCR2 |= (1 << CS21);  // предделитель таймера2 на 8 

 
#asm ("sei") // глобально разрешаем прерывания.
while (1)
      {
      ADC_result(); 
      data_convert(ADC_volt);
      delay_ms(500);
      } 
}
Всё те же фантомы на соседних разрядах не дают мне покоя ...

Видны "фантомы":
Изображение

Дабы не говорили, что возможна проблема в железе, вот другая программа, где нет засветки фантомами и прочей гадостью (первый разряд "0" потушен не правильно, оттого немного виден, это не "фантом")
Изображение
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

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

Сообщение Pink-Pank »

Могу предположить следующее:
1. Обработчик таймера очень шустрый.
2. Преобразование результата в десятичное очень медленное.
3. Во время вычисления и записи нового индицируемого значения обработчик от таймера продолжает брать результаты с той же области памяти и выводить их на экран.
4. Отсюда вполне вероятен случай, когда обработчик может вывести часть старого результата преобразования и часть нового.
5. Предлагаю создать два массива для вывода. Один - старое значение выводит таймер. Другой - новое записываемое. После записи они меняются назначением.
6. Не знаю точно про Ваши фантомы - не видел (хотя бы видео сняли что ли на телефон и выложили сюда). Но уверен, что такая ошибка у Вас имеет место быть, хотя ее проявление будет редким (и обычно в младшем разряде), но все же иногда заметным.
7. Лучше организовать небольшое время свечения индикатора, затем - небольшое время в выключенном состоянии (Dead time). Затем обработка следующего разряда. Это для того, что светодиоды не выключаются мгновенно, а продолжают гореть какое-то время после выключения (да и выключение транзистора не моментальное), а Вы не дожидаясь полного погашения тут же вносите новое значение в следующий разряд (и, как следствие, частично в предыдущий) - отсюда и фантомы. Сделайте еще одно прерывание по совпадению где-то в районе 3/4 максимального значения счетчика и в этом прерывании гасите все разряды. Это будет Вам Dead tiime.
Fucking static initialization order fiasco
Rtmip
Держит паяльник хвостом
Сообщения: 963
Зарегистрирован: Чт апр 03, 2014 23:16:55
Откуда: Россия

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

Сообщение Rtmip »

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

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

/** ФУНКЦИЯ ПРЕОБРАЗОВАНИЯ **/ 
void data_convert(unsigned int value)
успевает срабатывать таймер и почти после каждой строчки

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

adc_data[0] = SEGMENTE[tmp];
идет прерывание.
Как временная мера, запретить прерывание во время работы функции преобразования и посмотреть что будет?
P.S. если сказал глупость, прошу прощения :oops:
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

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

Сообщение Pink-Pank »

Если запретить прерывания, то индикатор на этот период потухнет. Будут моргания табло.
Fucking static initialization order fiasco
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

Сообщение Аlex »

Pink-Pank писал(а):

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTB=0x00;                      // гасим сегменты
     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)
     
     if (count == 0) PORTB = (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB = (1<<1);             
     if (count == 2) PORTB = (1<<2);
     if (count == 3) PORTB = (1<<3);
     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
    }
Тогда уж так:

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTB=0x00;                      // гасим сегменты
     
     if (count == 0) PORTB = (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB = (1<<1);             
     if (count == 2) PORTB = (1<<2);
     if (count == 3) PORTB = (1<<3);

     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)

     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
В Вашем случае, PORTB=0x00; - бесполезная операция + информация на сегментах отображается ещё до выбора следующего индикатора, а это - прямой путь к засветке.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

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

Сообщение Pink-Pank »

Можно кратко? Не соглашусь :))
Fucking static initialization order fiasco
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

Аlex писал(а):Тогда уж так:

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTB=0x00;                      // гасим сегменты
     
     if (count == 0) PORTB = (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB = (1<<1);             
     if (count == 2) PORTB = (1<<2);
     if (count == 3) PORTB = (1<<3);

     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)

     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
не соглашусь. рассмотрим работу функции:
1. вход в функцию: индикатор отображает 0-й разряд, count = 1.
2. PORTB = 0; - гасим индикатор
3. цепочкой if-ов ВКЛЮЧАЕМ СЛЕДУЮЩИЙ разряд, т.е. зажигаем в 1-ом разряде то, что выводилось ранее в PORTD, т.е. инфу для 0-го разряда!!! это и есть подсветка соседнего знакоместа
4. PORTD = adc_data[count]; - обновляем сегменты, т.е. теперь в 1-ом знакоместе светится то, что и должно
5. вычисляем count для следующего знакоместа.

таким образом в предлагаемом алгоритме ГАРАНТИРУЕТСЯ подсветка сегментов!!!

безусловно правильный алгоритм:
1. гасим ВСЕ РАЗРЯДЫ
2. обновляем СЕГМЕНТЫ
3. включаем СЛЕДУЮБЩИЙ разряд
Последний раз редактировалось ARV Ср авг 06, 2014 08:02:12, всего редактировалось 1 раз.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

Сообщение Аlex »

Тьфу, блин. Прошу прощения за мою невнимательность, порты разные :oops:
Да, всё верно, всё должно работать.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

Сообщение Аlex »

Мне показалось, что в этом куске кода :

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

     PORTB=0x00;                      // гасим сегменты
     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)
порт один и тот-же, т.к. в комментарии написано "гасим сегменты" :)
В таком случае, вот вариант:

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

void ind_update (void)
    {
     static unsigned char count = 0; 
     
     PORTD=0x00;                      // гасим сегменты
     
     if (count == 0) PORTB = (1<<0);             // определяем какой разряд должен гореть (ИМХО, тут копать нужно)
     if (count == 1) PORTB = (1<<1);             
     if (count == 2) PORTB = (1<<2);
     if (count == 3) PORTB = (1<<3);

     PORTD = adc_data[count];                                // выводим в порт код цифры (сегменты)

     count++;                      // включаем следующий разряд
     if (count == 4) count = 0;
Погасили сегменты, включили общий, зажгли сегменты.

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

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

Сообщение ARV »

почему бы не сделать так:

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

static char count = 0;
// гасим все 
PORTB=0;
// вычисляем следующую позицию
if(++count >= 4) count = 0;
// обновляем сегменты
PORTD = adc_data[count];
// включаем индикацию
PORTB = 1 << count;
во-первых, кратко и понятно записано
во-вторых, между гашением и зажиганием проходит довольно много времени на вычисления, что дает гарантию отсутствия "эффектов" из-за "медленного" погасания светодиодов (запирания транзисторов - если применяли что-то типа П213 :))) )
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Ответить

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