Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: динамическая индикация
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
RicLab
Добрый день
Необходим совет.
на 4-х разрядный 7-сегментый индикатор выводиться произвольное число 0-9999, необходимо во втором разряде включать децимиальную точку т.е. 0,0-999,9.
как я понимаю необходимо создать ещё один массив цифр только с точкой, но как сделать что бы этот массив использовалься только для второго разряда или для любого другого?

код для CVAVR
Код
Chip type           : ATtiny2313
Clock frequency     : 8,000000 MHz
Memory model        : Tiny
External SRAM size  : 0
Data Stack size     : 32
*****************************************************/

#include <tiny2313.h>
#include <delay.h>

#define digit1 PORTD.5 // разряд 4
#define digit2 PORTD.4 // разряд 3
#define digit3 PORTD.1 // разряд 2
#define digit4 PORTD.0 // разряд 1

flash char digits []= {       //создаём массив с цифрами
0x3F,                   //0
0x06,                   //1
0x5B,                   //2
0x4F,                   //3
0x66,                   //4
0x6D,                   //5
0x7D,                   //6
0x07,                   //7
0x7F,                   //8
0x6F,                   //9
0x40,                   //знак минуса
0x00                    //пустота
};                
char digit_out[4], cur_dig;  //переменные для работы с LED

unsigned int indication;    //переменная для хранения чисел
unsigned int x;
void recoding(void) {       //функция для перекодировки из hex в dec
if (indication<10000)       //начинаем преобразование если число < 1000 так как 4-х разрядный LED
{        
digit_out[0]=indication%10;     //Делим на 10, остаток записываем в масив 1-разряд    
indication=indication/10;               //Оставляем 3 разряда                        
digit_out[1]=(indication%10);   //Делим на 10, остаток записываем в масив 2-разряд    
indication=(indication/10);                //Оставляем 2 разряда                    
digit_out[2]=indication%10;     //Делим на 10, остаток записываем в масив 3-разряд
indication=(indication/10);                //Оставляем 1 разряда                    
digit_out[3]=indication%10;     //Делим на 10, остаток записываем в масив 4-разряд  
}                                          
}                                          

//таймер 0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB=0x00;       //чтобы предотвратить эффект “тени” на соседних индикаторах
switch (cur_dig){
case 0:{digit1=0; digit2=0; digit3=0; digit4=1; break;};  //подаём питание на разряд 1, гасим остальные разряды
case 1:{digit4=0; digit2=0; digit1=0; digit3=1; break;};  //подаём питание на разряд 2, ггасим остальные разряды
case 2:{digit3=0; digit1=0; digit4=0; digit2=1; break;};  //подаём питание на разряд 3, гасим остальные разряды
case 3:{digit2=0; digit3=0; digit4=0; digit1=1; break;};  //подаём питание на разряд 3, гасим остальные разряды
}
PORTB=digits[digit_out[cur_dig]];    //выводим с каждым срабатыванием таймера число с массива в порт В, но не для всех разрядов сразу

cur_dig++;                                           //с каждым срабатыванием таймера, увеличиваем переменную cur_dig на 1
if(cur_dig==4) cur_dig=0;                  //если cur_dig = 4 обнуляем  

}
void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Func2=In Func1=In Func0=In
// State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port D initialization
// Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=Out Func0=Out
// State6=T State5=0 State4=0 State3=P State2=P State1=0 State0=0
PORTD=0x0C;
DDRD=0x33;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x01;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;

// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;

// Global enable interrupts
#asm("sei")
while (1)
      {
      x++;
      delay_ms(100);
      if(x>9999) x=0;
      indication=x;
      recoding();
      };
}

laughing.gif
ukpyr
В буфере индикации можно хранить не цифры а символы в 8-сегментном формате. Тогда простановка точки - простая операция очистки/установки бита сегмента H.
RicLab
поясните?
в массиве они и так находяться в 8 сегментном формате т.е.

Код
flash char digits []= {       //создаём массив с цифрами
0x3F,                   //0      0b00111111
0x06,                   //1      0b00000110
0x5B,                   //2      0b01011011
0x4F,                   //3      0b01001111
0x66,                   //4      0b01100110
0x6D,                   //5      0b01101101
0x7D,                   //6      0b01111101
0x07,                   //7      0b00000111
0x7F,                   //8      0b01111111
0x6F,                   //9      0b01101111
0x40,                   //знак минуса
0x00                    //пустота
};



пардон, неправильно понял про буфер.

rezident
Цитата(RicLab @ Jan 24 2011, 19:23) *
в массиве они и так находяться в 8 сегментном формате т.е.
У вас все символы в таблице без точки. Добавьте к этой таблице еще одну, где все символы с точкой.
RicLab
читайте начало темы.
rezident
Я прочитал. С самого начала. Вам был дан совет оперировать не бинарным значением из таблицы, а кодом символа. При этом можно использовать управляющую последовательность для формирования буфера вывода. Когда код символа "точка" дает указание подменить следующий за ним символ на его бинарное значение, содержащее точку. Для этого либо нужна вторая таблица, которая содержит бинарные значения с точкой, либо отдельная операция, которая накладывает маску на бинарное значение, считанное из таблицы так, чтобы при выводе десятичная точка светилась.
RicLab
извиняюсь я не совсем понял как это воплотить в коде.
можете привести пример?
toweroff
Цитата(RicLab @ Jan 24 2011, 17:49) *
извиняюсь я не совсем понял как это воплотить в коде.
можете привести пример?

старший бит в массиве digits - это точка?
тогда простая операция
Код
char b;
b = digits[x];
if (decimal_point)
{
    b |= 0x80;
}

rezident
Нет времени и желания, чтобы кормить вас бесплатной "рыбой". Могу только объяснить, как сделать "удочку" самому.
В прерывании выводите в порт значения массива digit_out, без извлечения его из таблицы. Значениями, извлеченными из таблицы, этот массив заполняйте заранее. При заполнении используйте какой-либо признак "наличия точки" по которому на бинарное значение, извлеченное из таблицы, накладывайте маску для включения точки.
RicLab
т.е. например если нужно вывести второй разряд с точкой делаем так

Код
if (indication<10000)       //начинаем преобразование если число < 1000 так как 4-х разрядный LED
{        
digit_out[0]=indication%10;     //Делим на 10, остаток записываем в масив 1-разряд    
indication=indication/10;               //Оставляем 3 разряда                        
digit_out[1]=((indication%10)|= 0x80);  //Делим на 10, остаток записываем в масив 2-разряд    
indication=(indication/10);                //Оставляем 2 разряда                    
digit_out[2]=indication%10;     //Делим на 10, остаток записываем в масив 3-разряд
indication=(indication/10);                //Оставляем 1 разряда                    
digit_out[3]=indication%10;     //Делим на 10, остаток записываем в масив 4-разряд  
}

Сергей Борщ
QUOTE (RicLab @ Jan 24 2011, 17:16) *
т.е. например если нужно вывести второй разряд с точкой делаем так
Сделайте еще один шаг:

CODE
digit_out[0]=digits[indication%10];
indication=indication/10;               //Оставляем 3 разряда                        
digit_out[1]=digits[indication%10] | 0x80;
а из вывода чтение digits уберите.
RicLab
Спасибо за подсказку biggrin.gif
проверил работает.


Код
void recoding(void) {       //функция для перекодировки из hex в dec
if (indication<10000)       //начинаем преобразование если число < 1000 так как 4-х разрядный LED
{        
digit_out[0]=digits[indication%10];     //Делим на 10, остаток извлекаем из таблицы записываем в 1-разряд    
indication=indication/10;               //Оставляем 3 разряда                        
digit_out[1]=digits[indication%10]| 0x80;  //Делим на 10, остаток извлекаем из таблицы накладываем маску записываем в 1-разряд
indication=(indication/10);                //Оставляем 2 разряда                    
digit_out[2]=digits[indication%10];     //Делим на 10, остаток извлекаем из таблицы записываем в 3-разряд
indication=(indication/10);                //Оставляем 1 разряда                    
digit_out[3]=digits[indication%10];     //Делим на 10, остаток извлекаем из таблицы записываем в 4-разряд
}                                          
}                                          

//таймер 0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB=0x00;       //чтобы предотвратить эффект “тени” на соседних индикаторах
switch (cur_dig){
case 0:{digit1=0; digit2=0; digit3=0; digit4=1; break;};  //подаём питание на разряд 1, гасим разряд 3
case 1:{digit4=0; digit2=0; digit1=0; digit3=1; break;};  //подаём питание на разряд 2, гасим разряд 1
case 2:{digit3=0; digit1=0; digit4=0; digit2=1; break;};  //подаём питание на разряд 3, гасим разряд 2  
case 3:{digit2=0; digit3=0; digit4=0; digit1=1; break;};  //подаём питание на разряд 3, гасим разряд 2      
}

PORTB=digit_out[cur_dig];    //выводим с каждым срабатыванием таймера число с массива в порт В, но не для всех разрядов сразу

cur_dig++;                                           //с каждым срабатыванием таймера, увеличиваем переменную cur_dig на 1
if(cur_dig==4) cur_dig=0;                  //если cur_dig = 4 обнуляем  

}


но появилась слабая засветка соседних разрядов.
_Pasha
Цитата(RicLab @ Jan 24 2011, 19:00) *
но появилась слабая засветка соседних разрядов.

А что переключает разряды? На время выдачи след. символа обычно гасятся и аноды/катоды разрядов.
RicLab
с проблемой разобрался, причина в неправильной настройке таймера.
слишком высокая частота преключения разрядов, видимо транзисторы в цепи общих катодов не успевали до конца закрыться.
поменял частоту переключения.
Код
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

частота моргания каждого разряда получилась примерно 123 Гц, засветов нет. biggrin.gif
Сергей Борщ
QUOTE (RicLab @ Jan 25 2011, 05:33) *
слишком высокая частота преключения разрядов, видимо транзисторы в цепи общих катодов не успевали до конца закрыться. поменял частоту переключения.
Одно из двух - либо вы нашли экстремально медленные транзисторы середины 50-х годов, либо вы их некорректно включили.
RicLab
это германиевые что-ли? biggrin.gif
вот схема Нажмите для просмотра прикрепленного файла

может стоит добавить резистор 100к в цепь базы на общий.
Сергей Борщ
QUOTE (RicLab @ Jan 25 2011, 12:29) *
вот схема
Не маловат ли базовый ток 45мкА? Уменьшите резистор до 1К.
RicLab
возможно, прикинул по грубым расчётам нужно около 4,7кОм.
rezident
Цитата(RicLab @ Jan 25 2011, 15:29) *
может стоит добавить резистор 100к в цепь базы на общий.
Это ничего не даст, только лишний расход резисторов. Резистор Б-Э следует брать 4,7кОм. Последовательно с базой 2,2кОм, если управляющий сигнал уровня 5В или 1,2кОм, если он уровня 3,3В.
RicLab
что то тема начала уходить в область схемотехники, а не программирования.
МП41
В процедуре смены разряда я сначала гашу все сегменты, потом выключаю все разряды без проверки какой из них был активным, делаю маленькую паузу, вывожу новую информацию на сегменты и потом включаю нужный разряд. Эта пауза даёт возможность транзистору выйти из насыщения.
Сергей Борщ
QUOTE (RicLab @ Jan 25 2011, 15:19) *
что то тема начала уходить в область схемотехники
Форум как бы профессиональный. Негоже криво спроектированное железо лечить затычками в программе.
rezident
Цитата(RicLab @ Jan 25 2011, 18:19) *
что то тема начала уходить в область схемотехники, а не программирования.
Дык потому, что программистские проблемы вроде уже решены
Цитата(RicLab @ Jan 24 2011, 21:00) *
проверил работает.
Но остались схемотехнические недоработки
Цитата(RicLab @ Jan 24 2011, 21:00) *
но появилась слабая засветка соседних разрядов.


RicLab
Цитата
Форум как бы профессиональный. Негоже криво спроектированное железо лечить затычками в программе.

такую схему включения я подсмотрел на плате ME EasyAVR5.

Цитата
Но остались схемотехнические недоработки

сейчас всё работает, не думаю что динамическая индикация должна производиться с частотой несколько килогерц.
50-60 Гц вполне достаточно, а 123Гц более чем достаточно.
rezident
Цитата(RicLab @ Jan 25 2011, 21:27) *
50-60 Гц вполне достаточно, а 123Гц более чем достаточно.
100Гц это необходимый минимум. Это хорошо понимают, например, инженеры-конструкторы электронных табло wink.gif
ukpyr
Цитата
100Гц это необходимый минимум.
почему ? 60-70Гц нормально
rezident
Цитата(ukpyr @ Jan 25 2011, 22:33) *
почему ? 60-70Гц нормально
Для статической картинки, меняющейся редко (раз в секунду или реже), может и нормально. А вот для электронного табло или бегущей строки ... Вы делали электронное табло?
RicLab
Цитата
почему ? 60-70Гц нормально

порог инерционности человеческого глаза, в ЭЛТ развертка идет с частотой 50-60Гц.

Цитата
Для статической картинки, меняющейся редко (раз в секунду или реже), может и нормально. А вот для электронного табло или бегущей строки ... Вы делали электронное табло?

Если бы я делал электронное табло у меня не возникали бы вопросы.
МП41
Цитата(RicLab @ Jan 26 2011, 01:01) *
порог инерционности человеческого глаза, в ЭЛТ развертка идет с частотой 50-60Гц.

Меньше будет мелькать при съёмке камерой wink.gif
RicLab
Цитата
Меньше будет мелькать при съёмке камерой

такой задачи у меня не было rolleyes.gif
Сергей Борщ
QUOTE (RicLab @ Jan 26 2011, 01:01) *
в ЭЛТ развертка идет с частотой 50-60Гц.
В отличие от ЭЛТ и ЖКИ светодиоды не обладают инерционностью. Попробуйте в полумраке перемещать взгляд вдоль такого индикатора - увидите очень неприятное мельтешение. И чем ниже частота, тем при меньшей скорости движения взгляда мельтешение будет заметно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.