Управление периферией и потребляемой мощностью
Управление периферией и потребляемой мощностью
В даташите можно отыскать вот такую табличку:
Разумеется, что держать включенной неиспользуемую периферию незачем. Мы практически постоянно используем модуль 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 Комментариев
Рекомендуемые комментарии
Комментариев нет
Присоединяйтесь к обсуждению
Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.