Помогите ужать програаму, немного не влезает в ATTiny13

Обсуждаем контроллеры компании Atmel.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

Мяяяяу
Помогите ужать программу АмперВольтметра на ATTiny13.
Буквально немного нехватает памяти.
Индикация динамическая в прерывании таймера.
В прерывании АЦП преобразования условных единиц в цифры на дисплее. Дисплей 4х2 семисегментный.
До этого проект был только для вольтметра, памяти соответственно хватало.
Спойлер

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

#include <tiny13a.h>
#include <delay.h>

// Declare your global variables here

void wr_reg(char cData)
{
    char temp = cData;
    char i=0;
    for(i=0; i<8; i++)
    {
        PORTB.1 = (temp & 0x80);
        #asm("nop");
        PORTB.0 = 1;
        #asm("nop");        
        PORTB.0 = 0;
        temp = temp << 1;
    }
}

void latch_reg()
{
    #asm("nop");
    PORTB.2 = 1;
    #asm("nop");         
    PORTB.2 = 0;
}

char cSeg[]={
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111  // 9
};

char cDec = 0;
volatile char cDigit[][2] = {
{0,0b00000001},{0,0b00000010},{0,0b00000100},{0,0b00001000},
{0,0b00010000},{0,0b00100000},{0,0b01000000},{0,0b10000000}};
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
    wr_reg(cDigit[cDec][1]);
    wr_reg(cDigit[cDec][0]);
    //wr_reg(~cSeg[cDec]);
    latch_reg();
    cDec += 1;
    if( cDec > 7 )
        cDec = 0; 
        
    TCNT0 = 0;
}

#define FIRST_ADC_INPUT 2
#define LAST_ADC_INPUT 3
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
#define ADC_VREF_TYPE 0x00

unsigned long ulVoltsSum = 0;
char sCounterVSum = 0;

unsigned long ulAmpersSum = 0;
char sCounterASum = 0;

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
adc_data[input_index]=ADCW;
// Select next ADC input
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
   input_index=0;
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;

if( input_index == 3 )
{
    ulVoltsSum += 5000UL*adc_data[input_index]/1024;
    sCounterVSum++;
    if( sCounterVSum == 255 )
    {
        cDigit[0][0] = ~cSeg[((ulVoltsSum/sCounterVSum/1000)%10)];
        cDigit[1][0] = ~cSeg[((ulVoltsSum/sCounterVSum/100 )%10)];
        cDigit[2][0] = ~cSeg[((ulVoltsSum/sCounterVSum/10  )%10)];
        cDigit[3][0] = ~cSeg[((ulVoltsSum/sCounterVSum/1   )%10)];
        ulVoltsSum = 0;
        sCounterVSum = 0;        
    } 
}

if( input_index == 2 )
{   
    ulAmpersSum += 5000UL*adc_data[input_index]/1024;
    sCounterASum++;
    if( sCounterASum == 255 )
    {
        cDigit[4][0] = ~cSeg[((ulAmpersSum/sCounterASum/1000)%10)];
        cDigit[5][0] = ~cSeg[((ulAmpersSum/sCounterASum/100 )%10)];
        cDigit[6][0] = ~cSeg[((ulAmpersSum/sCounterASum/10  )%10)];
        cDigit[7][0] = ~cSeg[((ulAmpersSum/sCounterASum/1   )%10)];
        ulAmpersSum = 0;
        sCounterASum = 0;        
    }
}
                 
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
}


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 B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out 
// State5=T State4=T State3=T State2=T State1=T State0=0 
PORTB=0x00;
DDRB=0x07;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 9400,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Clear on compare match
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x05;
TCNT0=0x00;
OCR0A=0x20;
OCR0B=0x00;

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

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x04;

// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;

// ADC initialization
// ADC Clock frequency: 73,438 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: Off, ADC1: Off, ADC2: On, ADC3: On
DIDR0&=0x03;
DIDR0|=0x24;
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCF;

#asm("sei")

   while(1)
   {
   }
}
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18678
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

кажется я вам уже советовал избавиться от формирования символов из чисел в обработчиках прерываний... тем более при помощи обращения к функциям. хотите помощи - слушайте советы.

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
orinoko

Сообщение orinoko »

Попробуйте переписать на асме. должно влезть
Мучитель микросхем
Сообщения: 410
Зарегистрирован: Чт ноя 13, 2008 16:33:42

Сообщение vdavid »

Если хватит 63 (или 64) измерений вместо 255 (а их таки достаточно), то элементарно:
Спойлер

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

unsigned int ulVoltsSum = 0;
char sCounterVSum = 0;

unsigned int ulAmpersSum = 0;
char sCounterASum = 0;

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
unsigned char i;
static unsigned char input_index=0;
// Read the AD conversion result
adc_data=ADCW;
// Select next ADC input
if (++input_index > LAST_ADC_INPUT)
   input_index=FIRST_ADC_INPUT;
ADMUX=ADC_VREF_TYPE +input_index;

if( input_index == 2 )
{
    ulVoltsSum += adc_data;
    sCounterVSum++;
    if( sCounterVSum == 64 )
	
    {
        ulVoltsSum=(5000UL*ulVoltsSum)/1024/64;
        ulVoltsSum=(5000UL*ulVoltsSum)/1024/64;
        i=4;
        while (i>0) {
           cDigit[i][0] = ~cSeg[ulVoltsSum%10];
           ulVoltsSum /=10;
           i--;
        } 
/*
        cDigit[0][0] = ~cSeg[((ulVoltsSum/1000)%10)];
        cDigit[1][0] = ~cSeg[((ulVoltsSum/100 )%10)];
        cDigit[2][0] = ~cSeg[((ulVoltsSum/10  )%10)];
        cDigit[3][0] = ~cSeg[((ulVoltsSum/1   )%10)];
*/
        ulVoltsSum = 0;
        sCounterVSum = 0;        
    } 
}

if( input_index == 3 )
{   
    ulAmpersSum += adc_data;
    sCounterASum++;
    if( sCounterASum == 64 )
    {
        ulAmpersSum=(5000UL*ulAmpersSum)/1024/64;
        i=8;
        while (i>3) {
           cDigit[i][0] = ~cSeg[ulAmpersSum%10];
           ulAmpersSum /=10;
           i--;
        }
/*			  
        cDigit[4][0] = ~cSeg[((ulAmpersSum/1000)%10)];
        cDigit[5][0] = ~cSeg[((ulAmpersSum/100 )%10)];
        cDigit[6][0] = ~cSeg[((ulAmpersSum/10  )%10)];
        cDigit[7][0] = ~cSeg[((ulAmpersSum/1   )%10)];
*/
        ulAmpersSum = 0;
        sCounterASum = 0;        
    }
}
                 
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
}
Заодно зачем adc_data массив?
Ну и с input_index разберитесь.
Можно еще оптимизировать, но и так влезет.
Реклама
Эиком - электронные компоненты и радиодетали
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Gisteresis писал(а): Буквально немного нехватает памяти.
А чего не хватает, флеша или ОЗУ?
Если ОЗУ то проще от массивов избавиться и сделать обычные switch.
Реклама
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

Можно еще без всяких переделок попробовать изменить уровень оптимизации на больший в настройках проекта. ;) Правда, после этого программа бывает работает не так, как при стандартном уровне оптимизации. )
Fucking static initialization order fiasco
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

AVR, вы советовали мне. Но я не понимаю чем это поможет? Ну перенесу я код из одного места в другое. Памяти от этого прибавится?

vdavid, спасибо попробую.
adc массив только потому что это сгенерировал генератор кода. По этому поводу прошу не бить, понимаю что генератором пользоваться неприлично и все такое.
Что бы вы еще оптимизировали? (это мне для общего развития)

ks0, компилятор говорит что РАМ, но увеличиваю рам чтобы все глобальные переменные влезли. Потом появляется окно в котором говорится что мы вылезли за пределы 512слов... что то порядка 546слов получалось. (В общем более одного килобайта)

Pink-Pank. Пишу в CVAVR, там и так по умолчанию максимум стоит.

На чистый асм переходить не хочется.

Вообще у меня приличный опыт программирования под комп. Микроконтроллеры конечно имеют свою специфику. Пока плохо ее понимаю. Можете что нибудь рекомендовать на эту тему? Книжечку, статью, советы...
В комповых прогах массив по объему ничем не отличается от такого же количества переменных. В МК есть разница?
Последний раз редактировалось Gisteresis Ср окт 08, 2014 08:29:55, всего редактировалось 1 раз.
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

Чтобы понимать МК - только ассемблер и доскональное изучение даташита. )) А проект CV можете выложить в архиве? )
Fucking static initialization order fiasco
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

Могу. Вечером сделаю.
Цель проекта. Обычный ампер вольтметр. Но я как то проектов под Си не нашел, поэтому написал сам. Уже и плата готова. Тем более хотелось написать самому, чтобы получить опыт.
Друг Кота
Аватара пользователя
Сообщения: 4077
Зарегистрирован: Вс мар 22, 2009 17:31:41

Сообщение WandererSc »

Gisteresis писал(а):Вообще у меня приличный опыт программирования под комп.
Вот в этом и проблема.
На микроконтроллере важно не что-бы код был красивый, а занимал мало памяти и быстро выполнялся.

Например temp = temp << 1; можно заменить на temp<<=1;
или вот cDec += 1; ---> cDec++;

а лучше
wr_reg(cDigit[cDec][1]);
wr_reg(cDigit[cDec][0]);
//wr_reg(~cSeg[cDec]);
latch_reg();
cDec += 1;
if( cDec > 7 )
cDec = 0;

написать так (но это под сомнением)
wr_reg(cDigit[cDec&0b111][1]);
wr_reg(cDigit[cDec&0b111][0]);
//wr_reg(~cSeg[cDec]);
latch_reg();


cDigit[0][0] = ~cSeg[((ulVoltsSum/sCounterVSum/1000)%10)]; Я думаю эти строки и заняли всю память, к тому-же они дублируются, а не сделанны подпрограммой
Раз reset, два reset - полyчи на диске bad !
Тpанзистоp p-n-p. Plug-n-Play ?
У кого что сбоит, тот о том и говорит.
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

Сначала хотел было посоветовать убрать нопы в функции вывода. А потом увидел ЭТО:

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

        cDigit[0][0] = ~cSeg[((ulVoltsSum/sCounterVSum/1000)%10)];
        cDigit[1][0] = ~cSeg[((ulVoltsSum/sCounterVSum/100 )%10)];
        cDigit[2][0] = ~cSeg[((ulVoltsSum/sCounterVSum/10  )%10)];
        cDigit[3][0] = ~cSeg[((ulVoltsSum/sCounterVSum/1   )%10)];
:shock:
Ещё бы не хватало памяти!!! Это деление всё и сжирает. Не интереснее ли вместо /10 написать *2560 и /256. Умножение разложить на степени двойки, а деление - отсечкой младшего байта? Кстати, сам компилятор это сделает, без потуг со стороны писателя.
Docendo discimus
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

WandererSc писал(а): Например temp = temp << 1; можно заменить на temp<<=1;
или вот cDec += 1; ---> cDec++;
Никакого смысла в этом нет, ассемблерный код будет одинаковый, выигрыша в памяти не даст.
PS. Извинйте за оверпост.
Последний раз редактировалось pyzhman Ср окт 08, 2014 08:54:54, всего редактировалось 1 раз.
Docendo discimus
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

Например temp = temp << 1; можно заменить на temp<<=1;
или вот cDec += 1; ---> cDec++;
Компилятор вообще-то и то, и то скомпилирует в одно и то же. Это просто разные формы записи одного и то же.

А вот это место вызывает сомнения:

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

void wr_reg(char cData)
{
    char temp = cData;
    char i=0;
    for(i=0; i<8; i++)
    {
        PORTB.1 = (temp & 0x80);
        #asm("nop");
        PORTB.0 = 1;
        #asm("nop");        
        PORTB.0 = 0;
        temp = temp << 1;
    }
}
Вообще можно PORTB.1 = (cData & 0x80); сразу написать..

у тини 13 всего 64 байта ОЗУ. С учетом вызова функций и стека - того меньше. Можно вот этот массив константный запихнуть во флеш:

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

flash char cSeg[]={
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111  // 9
};


RAM уже будет хватать. А вот с флеш надо будет думать. Правильно подметили - деление много сжирает.
Последний раз редактировалось Pink-Pank Ср окт 08, 2014 09:14:48, всего редактировалось 1 раз.
Fucking static initialization order fiasco
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

Тогда cData придётся курёчить, а вдруг она еще как-то там в теле используется? Если же нет, то, конечно, проще сразу её двигать.
Ещё:
вот это

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

ulVoltsSum/sCounterVSum
хотя бы не прописывать каждый раз, а присвоить значение временной переменной и с ней уже оперировать.
Docendo discimus
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

Так она локальная все равно.. Что бы ее не покуречить?

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

char cDec = 0;
volatile
Fucking static initialization order fiasco
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

Функция wr_reg используется для записи в регистр 74HC595. Их на плате 2 штуки и используются для динамической индикации на семисегментниках. Первый выводит число, второй активирует декаду.
Чтобы проще было декады активировать я создал структуру

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

volatile char cDigit[][2] = {
{0,0b00000001},{0,0b00000010},{0,0b00000100},{0,0b00001000},
{0,0b00010000},{0,0b00100000},{0,0b01000000},{0,0b10000000}};
первое значение это значение декады, а второе это адрес декады.

Далее это используется в таймере. Который поочередно активирует декады. Он занимается только динамическим выводом.
Pink-Pank писал(а): Зачем в конце temp = temp << 1?
Так это нужно для вывода на ногу и потом в регистр 595.
Если мы будем саму переменную сдвигать то она повредится и при следующем выводе будет шлак.

Я понимаю, что проблема в привычке программирования под комп. Ваши советы лучше всяких мануалов продвигают понимание. Респект.
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

cData не повредится - она локальная. Функции передается значение, а не ссылка на переменную.

latch_reg() - проще от этой функции вообще избавиться и кинуть ее код сразу в прерывание - больше нигде она не используется.

unsigned long ulVoltsSum = 0;
char sCounterVSum = 0;

unsigned long ulAmpersSum = 0;
char sCounterASum = 0;

adc_data[]

аналогично, volatile, либо засовываете их в само прерывание с модификатором static

Вывод на дисплей можно организовать несколько иначе. Можно цифры для вывода хранить в BCD формате (в два раза меньше места займут в ОЗУ), а преобразование их в нужный код индикатора делать непосредственно перед выводом. Получится довольно быстро и экономно.

Обнуление регистров периферии при инициализации также можно выкинуть - там и так нули будут при сбросе.
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
можно выкинуть и при прошивке просто не ставить фьюз DIV8

еще немного больше скорости и меньше места, если сделать так:

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

flash char cSeg[]={
~0b00111111, // 0
~0b00000110, // 1
~0b01011011, // 2
~0b01001111, // 3
~0b01100110, // 4
~0b01101101, // 5
~0b01111101, // 6
~0b00000111, // 7
~0b01111111, // 8
~0b01101111  // 9
};

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

if( sCounterVSum == 255 )
    {
        cDigit[0][0] = cSeg[((ulVoltsSum/sCounterVSum/1000)%10)];
        cDigit[1][0] = cSeg[((ulVoltsSum/sCounterVSum/100 )%10)];
        cDigit[2][0] = cSeg[((ulVoltsSum/sCounterVSum/10  )%10)];
        cDigit[3][0] = cSeg[((ulVoltsSum/sCounterVSum)%10)];
        ulVoltsSum = 0;
        sCounterVSum = 0;        
    }
Т.е. инверсию сразу применили к константам.

А еще можно вот так упростить, чтобы переменную не тискать. ;)

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

if( sCounterVSum == 0 )
    {   
        cDigit[0][0] = cSeg[((ulVoltsSum/256000)%10)];
        cDigit[1][0] = cSeg[((ulVoltsSum/25600)%10)];
        cDigit[2][0] = cSeg[((ulVoltsSum/2560)%10)];
        cDigit[3][0] = cSeg[(ulVoltsSum/256%10)];
        sCounterVSum = 0;        
    } 
Странно, но в CV сдвиг на 8 занимает в памяти программ больше места, чем деление на 256.. )

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

DIDR0&=0x03;
DIDR0|=0x24;
меняем просто на

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

DIDR0=0x24;
Вот такой код у меня уже влез. Единственное, в настройках проекта поставил поменьше размер стека (14 байт). как раз ровно под его размер.
Спойлер

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

#include <tiny13a.h>
#include <delay.h>

void wr_reg(char cData)
{
    char i=0;
    for(i=0; i<8; i++)
    {
        PORTB.1 = (cData & 0x80);
        #asm("nop");
        PORTB.0 = 1;
        #asm("nop");        
        PORTB.0 = 0;
        cData = cData << 1;
    }
}

flash char cSeg[]={
~0b00111111, // 0
~0b00000110, // 1
~0b01011011, // 2
~0b01001111, // 3
~0b01100110, // 4
~0b01101101, // 5
~0b01111101, // 6
~0b00000111, // 7
~0b01111111, // 8
~0b01101111  // 9
};

volatile char cDigit[][2] = {
{0,0b00000001},{0,0b00000010},{0,0b00000100},{0,0b00001000},
{0,0b00010000},{0,0b00100000},{0,0b01000000},{0,0b10000000}};

interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
    static char cDec = 0;

    wr_reg(cDigit[cDec][1]);
    wr_reg(cDigit[cDec][0]);
    //wr_reg(~cSeg[cDec]);
    #asm("nop");
    PORTB.2 = 1;
    #asm("nop");         
    PORTB.2 = 0;
    cDec += 1;
    if( cDec > 7 )
        cDec = 0; 
}

#define FIRST_ADC_INPUT 2
#define LAST_ADC_INPUT 3
#define ADC_VREF_TYPE 0x00

volatile unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];  

volatile unsigned long ulVoltsSum = 0;
volatile char sCounterVSum = 0;

volatile unsigned long ulAmpersSum = 0;
volatile char sCounterASum = 0;

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
adc_data[input_index]=ADCW;
// Select next ADC input
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
   input_index=0;
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;

if( input_index == 3 )
{
    ulVoltsSum += 5000UL*adc_data[input_index]/1024;
    sCounterVSum++;
    if( sCounterVSum == 0 )
    {   
        cDigit[0][0] = cSeg[((ulVoltsSum/256000)%10)];
        cDigit[1][0] = cSeg[((ulVoltsSum/25600)%10)];
        cDigit[2][0] = cSeg[((ulVoltsSum/2560)%10)];
        cDigit[3][0] = cSeg[(ulVoltsSum/256%10)];
        sCounterVSum = 0;        
    } 
}

if( input_index == 2 )
{   
    ulAmpersSum += 5000UL*adc_data[input_index]/1024;
    sCounterASum++;
    if( sCounterASum == 0 )
    {
        cDigit[4][0] = cSeg[((ulAmpersSum/256000)%10)];
        cDigit[5][0] = cSeg[((ulAmpersSum/25600)%10)];
        cDigit[6][0] = cSeg[((ulAmpersSum/2560)%10)];
        cDigit[7][0] = cSeg[((ulAmpersSum/256)%10)];     
        sCounterASum = 0;   
    }
}
                 
// Start the AD conversion
ADCSRA|=0x40;
}


void main(void)
{

// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out 
// State5=T State4=T State3=T State2=T State1=T State0=0 
DDRB=0x07;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 9400,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Clear on compare match
// OC0B output: Disconnected
TCCR0B=0x05;
OCR0A=0x20;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x04;

// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;

// ADC initialization
// ADC Clock frequency: 73,438 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: Off, ADC1: Off, ADC2: On, ADC3: On
DIDR0 = 0x24;
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCF;

#asm("sei")
}
Fucking static initialization order fiasco
Контактная информация:
Мучитель микросхем
Сообщения: 410
Зарегистрирован: Чт ноя 13, 2008 16:33:42

Сообщение vdavid »

Ну Вы, блин, даете (с) :)
Вполне очевидно, что это:

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

        cDigit[0][0] = cSeg[((ulVoltsSum/256000)%10)];
        cDigit[1][0] = cSeg[((ulVoltsSum/25600)%10)];
        cDigit[2][0] = cSeg[((ulVoltsSum/2560)%10)];
        cDigit[3][0] = cSeg[(ulVoltsSum/256%10)];
        sCounterVSum = 0;        
    } 
Нужно поменять на что-то такое:

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

        unsigned int u;
.....
       ulVoltsSum += ADCW;
.....
        u=(5000UL*ulVoltsSum)/1024/256;
        i=4;
        while (i>0) {
           cDigit[i][0] = ~cSeg[u%10];
           u /=10;
           i--;
        } 
Зачем нужно стадо длинных делений, когда их можно заменить на 16-ти битные?
Не знаю, как в CV, а в GCC-AVR код из моего первого поста:

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

Device: attiny13a

Program:     812 bytes (79.3% Full)
(.text + .data + .bootloader)

Data:         36 bytes (56.3% Full)
(.data + .bss + .noinit)
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

Кстати, вынос деления на число за скобки в CV почему-то тоже увеличивало размер. А цикл - да, должно быть меньше
Fucking static initialization order fiasco
Контактная информация:
Мучитель микросхем
Сообщения: 410
Зарегистрирован: Чт ноя 13, 2008 16:33:42

Сообщение vdavid »

Pink-Pank Почему увеличило, вопрос понятный, но для меньшего "разуточнения" результата здесь важно соблюсти последовательность операций, т.е. сначала таки нужно умножить.
Ведь толковый компилятор что должен сделать? Правильно, на этапе компиляции посчитать, что 5000/1024 = 4. Но мы ведь хотим умножить не на 4, а на 4.88. Не знаю, так ли поступил CV. (GCC так не делает, но ведь в дальнейшем могут допилить).
Уменьшение же размера кода произошло главным образом не из-за цикла. Важнее переход к 16-ти битным операциям.
Ответить

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