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

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

Добавлено: Вт окт 07, 2014 20:26:40
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)
   {
   }
}

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

Добавлено: Вт окт 07, 2014 20:44:08
ARV
кажется я вам уже советовал избавиться от формирования символов из чисел в обработчиках прерываний... тем более при помощи обращения к функциям. хотите помощи - слушайте советы.

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

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

Добавлено: Вт окт 07, 2014 21:33:05
orinoko
Попробуйте переписать на асме. должно влезть

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

Добавлено: Вт окт 07, 2014 22:16:27
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 разберитесь.
Можно еще оптимизировать, но и так влезет.

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

Добавлено: Ср окт 08, 2014 05:42:37
ks0
Gisteresis писал(а): Буквально немного нехватает памяти.
А чего не хватает, флеша или ОЗУ?
Если ОЗУ то проще от массивов избавиться и сделать обычные switch.

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

Добавлено: Ср окт 08, 2014 07:09:14
Pink-Pank
Можно еще без всяких переделок попробовать изменить уровень оптимизации на больший в настройках проекта. ;) Правда, после этого программа бывает работает не так, как при стандартном уровне оптимизации. )

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

Добавлено: Ср окт 08, 2014 08:18:13
Gisteresis
AVR, вы советовали мне. Но я не понимаю чем это поможет? Ну перенесу я код из одного места в другое. Памяти от этого прибавится?

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

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

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

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

Вообще у меня приличный опыт программирования под комп. Микроконтроллеры конечно имеют свою специфику. Пока плохо ее понимаю. Можете что нибудь рекомендовать на эту тему? Книжечку, статью, советы...
В комповых прогах массив по объему ничем не отличается от такого же количества переменных. В МК есть разница?

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

Добавлено: Ср окт 08, 2014 08:23:17
Pink-Pank
Чтобы понимать МК - только ассемблер и доскональное изучение даташита. )) А проект CV можете выложить в архиве? )

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

Добавлено: Ср окт 08, 2014 08:31:23
Gisteresis
Могу. Вечером сделаю.
Цель проекта. Обычный ампер вольтметр. Но я как то проектов под Си не нашел, поэтому написал сам. Уже и плата готова. Тем более хотелось написать самому, чтобы получить опыт.

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

Добавлено: Ср окт 08, 2014 08:43:55
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)]; Я думаю эти строки и заняли всю память, к тому-же они дублируются, а не сделанны подпрограммой

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

Добавлено: Ср окт 08, 2014 08:51:58
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. Умножение разложить на степени двойки, а деление - отсечкой младшего байта? Кстати, сам компилятор это сделает, без потуг со стороны писателя.

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

Добавлено: Ср окт 08, 2014 08:54:06
pyzhman
WandererSc писал(а): Например temp = temp << 1; можно заменить на temp<<=1;
или вот cDec += 1; ---> cDec++;
Никакого смысла в этом нет, ассемблерный код будет одинаковый, выигрыша в памяти не даст.
PS. Извинйте за оверпост.

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

Добавлено: Ср окт 08, 2014 08:54:46
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 уже будет хватать. А вот с флеш надо будет думать. Правильно подметили - деление много сжирает.

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

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

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

ulVoltsSum/sCounterVSum
хотя бы не прописывать каждый раз, а присвоить значение временной переменной и с ней уже оперировать.

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

Добавлено: Ср окт 08, 2014 09:15:15
Pink-Pank
Так она локальная все равно.. Что бы ее не покуречить?

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

char cDec = 0;
volatile

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

Добавлено: Ср окт 08, 2014 09:25:55
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.
Если мы будем саму переменную сдвигать то она повредится и при следующем выводе будет шлак.

Я понимаю, что проблема в привычке программирования под комп. Ваши советы лучше всяких мануалов продвигают понимание. Респект.

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

Добавлено: Ср окт 08, 2014 09:32:02
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")
}

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

Добавлено: Ср окт 08, 2014 11:28:12
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)

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

Добавлено: Ср окт 08, 2014 11:39:51
Pink-Pank
Кстати, вынос деления на число за скобки в CV почему-то тоже увеличивало размер. А цикл - да, должно быть меньше

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

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