Перейти к содержанию
  • записей
    8
  • комментариев
    7
  • просмотров
    1 780

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


parovoZZ

720 просмотров

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

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 Комментариев


Рекомендуемые комментарии

Комментариев нет

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Добавить комментарий...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
×
×
  • Создать...