Страница 1 из 1

Динамическая индикация, проблемка

Добавлено: Сб сен 26, 2009 18:07:38
a_sergeevich
Возникла у меня проблема,прямо таки стоупор какой-то.
Дело вот в чем, начал я изучать динамическую индикацию и в принципе всё мне с ней понятно вот мой учебный код динамической индикации:

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

#define _pic16f877    // зададим тип процессора
#include <pic>    // подключим файл описаний

__CONFIG(LVPDIS & UNPROTECT & PWRTDIS & WDTDIS & XT);

// таблица знакогенератора
const unsigned char CODE_TABLE[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};    

unsigned char buffer[9]={1,2,3,4,5,6,7,8,9};    // буфер индикатора
unsigned char PTR;    // указатель буфера

void    main(void)
{

    // настроим порты на выход
    TRISB = 0b11110000;    // для дешифратора знакомест (4 младших разряда)
    TRISD = 0b00000000;    // для символа

    PORTD = 0;        // очистим индикатор
    PTR = 0;        // начало буфера
    PORTB = 0b00001111;    // установим последний разряд индикатора

    OPTION = 0b10000010;    // запишем байт настройки в регистр OPTION
    INTCON = 0;        // Выключить все прерывания и сбросить T0IF
    TMR0 = 0;        // Сброс TMR0

    T0IE = 1;        // Разрешить прерывания от TMR0
    GIE = 1;        // Разрешить все прерывания

    
    // зациклим программу
cycle:;
    goto cycle;


}

// обработка прерываний
void interrupt all(void)
{

    PORTD = 0;    // очистим индикатор
    PORTB++;    // установим следующее знакоместо для отображения
    PORTD = CODE_TABLE[buffer[PTR]];    // выведем на индикатор
    PTR++;        // установим указатель на следующий символ
         
    if(PTR == 10) { PTR = 0; PORTB = 0b00001111; } //проверим, не кончился ли массив для вывода на индикатор

    T0IF = 0;    // сбросим флаг прерывания
}
Тут просто выводятся цифры от 1 до 9 на АЛС318 т.е ничего сложного.Теперь ближе к делу или проблеме. Во время всех этих изучений возник вопрос, а как вывести на тот же АЛС318 не 9-ти значное число, а допустим 16-ти,например 1,2,3,4,5,6,7,8,9,0,9,8,7,6,5,4., т.е получится должно, что то типа бегущей строки или эффекта скроллинга.
Я попытался сделать это следующим образом.

в обработчике прерывания изменил и добавил

if(PTR == 10) { PORTB = 0b00001111; }
if(PTR == 16) { PTR = 0; PORTB = 0b00001111; }
но такой способ не прокатывает показания накладываются друг на друга и получается белебирда.
Я ставил задержку, что-бы понаблюдать как все происходит и при включенной задержке я четко вижу как последовательно загораются цифры от 1 до 9 затем от 0 до 4.Нутром чую, что надо наверное как-то организовать, что-то типа паузы между частями,но как это сделать ну никак не врублюсь, вроде придет мысль и думаю ну вот сейчас заработает, а оно не работает результат тот же одни показания накладываются на другие. :cry:
Может хоть кто нибудь направить в нужном направлении куда капать, только по подробнее если можно.

Компилятор используемый мной для этого примера HITECH-PICC.
Дешифратор 74145
МК PIC16F877A

Файл для протеуса:

Добавлено: Сб сен 26, 2009 18:23:37
ARV
прочтите статеечки на моем сайте - я писал, опираясь на AVR, но Си он и в африке Си, а проблема у вас именно с алгоритмом... так что почитайте - вдруг поможет?

Добавлено: Сб сен 26, 2009 21:12:22
dosikus
Заполняй буфер в главном цикле а не в прерывании .
Заполнил {1,2,3,4,5,6,7,8,9} - тебе это вывело , задержка, затем {2,3,4,5,6,7,8,9,0}задержка, затем {3,4,5,6,7,8,9,0,8} и т.д .
Задержкой меняешь скорость перемещения .

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

    // зациклим программу 
cycle:; 
    goto cycle;
Кошмар.....
Видать с бэйсика перешел ?
Хоть это и одно и то же , но можно же было :

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

 while(1)
  {
     }

Добавлено: Сб сен 26, 2009 22:15:47
Аlex
dosikus, разницы нет никакой, кому как удобнее. Скомпилированый код в обоих случаях одинаковый. Никакого кошмара нет в этом.

a_sergeevich, ваш код стек переполняет, ищите косяки.

Добавлено: Сб сен 26, 2009 23:02:17
a_sergeevich
Да не переходил я с бейсика :) ну просто так написал, обычно всегда и пишу while(1) { }.

Так сейчас буду пробовать переварить инфу по буферам. :)

Добавлено: Сб сен 26, 2009 23:26:08
a_sergeevich
ARV, статья про динамическую индикацию отличная, спасибо.

Добавлено: Вс сен 27, 2009 09:33:46
dosikus
Аlex писал(а):dosikus, разницы нет никакой, кому как удобнее. Скомпилированый код в обоих случаях одинаковый. Никакого кошмара нет в этом.

a_sergeevich, ваш код стек переполняет, ищите косяки.
Уважаемый , о том что разницы нет и я писал - иль вы только шапки всегда читаете ? 8)
Кошмар именно в goto , увидев это новичок подумает
что можно этот оператор везде юзать...
И вообще все это было шуткой а не наездом, извиняюсь что смайл не влепил , думал догадаетесь сами... :)) :)) :)) :))

Добавлено: Вс сен 27, 2009 09:40:12
dosikus
a_sergeevich писал(а):Да не переходил я с бейсика :) ну просто так написал, обычно всегда и пишу while(1) { }.

Так сейчас буду пробовать переварить инфу по буферам. :)
В прерывании сканируется буфер - на определенное знакоместо проецируется определенный элемент буфера, одно прерывание -один элемент. И так все элементы . Период обновления всего индикатора должен быть более 25 Гц . Нам надо создать анимацию - где каждый кадр это состояние буфера на момент вывода кадра .... Думаю дальше сам разберешься .
Сайт ARV в помощь . Спасибо ему за это говорю.

Добавлено: Вс сен 27, 2009 14:15:30
ARV
dosikus писал(а): Кошмар именно в goto , увидев это новичок подумает что можно этот оператор везде юзать...
вы будете наверное удивлены, но оператор goto действительно можно везде юзать :))) и порой без него получается много хуже, чем с ним... хотя принято считать этот оператор "неприличным" :)))

Добавлено: Пн сен 28, 2009 21:47:16
a_sergeevich
И так пережевав все советы, вот, что у меня получилось, сразу оговорюсь, на задержку в цикле не обращайте внимание, такая нужна для протеуса, что бы не мелькало , да и индикатор 8-ми разрядный т.к 9-ти в протеусе нету.
Код

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

#define _pic16f877
#define  buf_size 20
#include <pic>

__CONFIG (LVPDIS & UNPROTECT & PWRTDIS & WDTDIS & XT);

const unsigned char CODE_TABLE[10] = 
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f
};

unsigned char buffer[buf_size];
unsigned char buffer2[buf_size]={1,2,3,4,5,6,7,8,9,4,5,3,6,2,1,0,3,4,5,7
};
unsigned char PTR;
unsigned int i = 0, j=0, z;
int s=0;

void main (void) 
{
    

    TRISB = 0b11110000;
    TRISD = 0b00000000;
    PORTD = 0;
    PTR = 0;
    PORTB = 0b00001111;
    OPTION = 0b10000010;
    INTCON = 0;
    TMR0 = 0;
    T0IE = 1;
    GIE = 1;

    while (1)
    {
        for(i=0;i<=9;i++)
        {
            buffer[i] = buffer2[j];
            
            j++;
            
            if (j==buf_size+1) { s= -1; break;
            }
        }
        
        s=s+1;
        j=s;
        
        
        
        
        
        

        for(z=0; z<=30000; z++);
    }
}


    void interrupt all (void)
    {
        PORTD = 0;
        PORTB++;
        PORTD = CODE_TABLE[buffer[PTR]];
        PTR++;

        if(PTR==9) {PTR = 0; PORTB = 0b00001111;
        }
        T0IF = 0;
    }
Всё работает, единственное не хочет отображать последнюю цифру, никак не пойму почему.[/code]

Re: Динамическая индикация, проблемка

Добавлено: Чт июл 14, 2011 22:31:49
Ant1Player
Поднимаю тему :) т.к. нужна помощь..
вот кусока кода под АВР

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

interrupt [EXT_INT1] void ext_int1_isr(void)
{
imp++;
}

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
 if (nom_temp<3) nom_temp++; else nom_temp=1;
 switch (nom_temp)
 {
  case 1: {if (kmh>99) display((kmh/100)%10,3); break;}
  case 2: {if (kmh>9)  display((kmh/10)%10,2);break;}
  case 3: {display(kmh%10,1);break;}
 }
}

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
kmh=imp*9/5;
переделываю его под пик,с индикацией разобрался, но встрял с импульсами, это спидометр, считывает импульсы, но я так понимаю их надо считывать таймером, но не въезжаю как, можно плз показать как это сделать, с коментами..как разбить км\ч по сегментам разберусь..а вот с импульсами.. :(
P.S. датчик с двумя контактами, 1 на массу второй в МК