Jump to content
Sign in to follow this  
  • entries
    8
  • comments
    7
  • views
    543

Управление периферией и потребляемой мощностью

parovoZZ

155 views

Управление периферией и потребляемой мощностью
В даташите можно отыскать вот такую табличку:

a_007.thumb.png.bc0e8d2ee46ddc3e6856cce897b60866.png

Разумеется, что держать включенной неиспользуемую периферию незачем. Мы практически постоянно используем модуль USI, периодически ADC и никогда таймеры. В МК есть специальный регистр, который позволяет управлять ТАКТИРОВАНИЕМ перечисленными модулями. Регистр называется PRR. По умолчанию при включении и сбросе вся периферия тактируется. Мы это исправим. Сразу после загрузки выключаем всё

PRR = 0xFF;                // Выключаем всю периферию

Необходимо записать "1" чтобы выключить и "0" чтобы включить. Необходимо также помнить, что при отключенном тактировании ни один регистр модуля не доступен!
Когда нам необходим модуль USI, включим его:

PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<ADC);

С ADC посложнее. У ADC в регистре ADCSRA необходимо поднять бит ADEN, чтобы блок ADC включился в работу. И наоборот - для выключения ADC в ADEN необходимо писать "0". Для чего? Даже при отсутствии тактирования, блок ADC потребляет энергию.
Также мы будем управлять частотой тактирования. Частота меняется с помощью предделителя

CLKPR = (1<<CLKPCE);                // Разрешить изменение прескалера тактовой частоты
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);            // Устанавливаем тактовую частоту 1 МГц

Измерение напряжения питания
Обязательный пункт в нашей программе как для контроля состояния батареи питания, так и для расчета коэффициента при вычислении температуры. Т.к. ADC ест очень много, то измерять будем как можно реже. Обязательно сразу после загрузки. Примем некую переменную, которую будем декрементировать с каждым измерением температуры и влажности. Если переменная байт, то максимальный период будет составлять 255 измерений от датчика. При 10 минутном интервале измерения параметров напряжение будем снимать каждые 2 суток. Ну вот и хорошо.
Обычно измерения на АЦП происходят следующим образом: шкала входного напряжения размечается от нуля и до референсного напряжения. Мы же перевернем всё с ног на голову и в качестве референсного напряжения будем использовать напряжение питания, а измерять будем внутренний источник референсного напряжения (в рассматриваемом МК он один и напряжение на нем примерно равно 1.1в). Также я с АЦП буду снимать только старшие 8 бит. При напряжении питания от 3-х вольт и ниже погрешность составит 11 мВ - этого более, чем достаточно. Функция инициализации

void ADC_Init (void)
{
    ADMUX =    (0<<REFS1) | (0<<REFS0) | ((0b100001)<<MUX0);            // Замеряем напряжение на внутреннем ИОН 1.1в
                                    // относительно опорного - напряжения питания
    ADCSRA =    (1<<ADEN) |                        // Разрешаем работу ADC
        (1<<ADIE) |                        // Разрешаем прерывание
        (0<<ADATE) |                        // Старт преобразования вручную
        (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);                // Прескалер = 2

    ADCSRB =    (1<<ADLAR);                        // Работаем только со старшими 8-ю битами
}

Даташит нас предупреждает, что именно при таком способе измерения необходимо сделать паузу в 1 мс для успокоения переходных процессов. Что ж, поставим инициализироваться нашему АЦП перед инициализацией трансивера. Производим замер

void ADC_Start_Conversion (void)
{
    ADCSRA =    (1<<ADEN) |                      
        (1<<ADIE) |                      
        (0<<ADATE) |                      
        (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0) |              
        (1<<ADSC);                        // Команда на запуск преобразования              
}

Забираем данные

uint8_t ADC_Get_Data (void)
{
     return ADCH;
}

Все выключаем

void ADC_Off (void)
{
    ADCSRA =    0;
}

Т.к. результат измерения напряжения питания мы получаем тогда, когда уже вовсю идет загрузка в трансивер данных, то все действия будем производить в обработчике прерывания от АЦП. И пусть трансивер подождет!

ISR(ADC_vect)
{
    data[6] = ADC_Get_Data();            // Получаем результат
    ADC_Off();                // Запрещаем работу ADC
    PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<ADC);    // Тактируем только USI
}

 



0 Comments


Recommended Comments

There are no comments to display.

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Add a comment...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...