Ну вот.. "всего лишь" за месяц я научился считать импульсы. Сбоев вроде бы нет. Точнее есть: при использовании кнопок, при недостаточном усилии, бывает неустойчивый контакт. от этого многократные срабатывания. Надеюсь, что на герконах такого не будет.
Также предполагаю, что тут не паханное поле для оптимизации.
Ну и вот он. Счетчик импульсов на PCINT:
PHP код:
/* Pin to interrupt map:
D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
Я собираюсь использовать PB0 (холодная) PB1 (горячая). это пины 8 и9 на плате UNO
При вызове обработчика любого прерывания бит глобального разрешения прерываний I регистра SREG (status register - регистр состояния) сбрасывается в "0"и только по завершении обработки прерывания снова устанавливается в "1"
и разрешает начать обработку следующего прерывания в очереди.
Чтобы установить ручками этот бит существует функция sei(), а чтобы сбросить - cli().
При запуске программы этот бит всегда сброшен и чтобы прерывания срабатывали его нужно установить (вызвать sei()).
к выводам 8 и 9 ардуины (PortB0 и 1) подключены через кнопки к +5, со стороны пинов подтянуты резисторами к земле
*/
#include <avr/interrupt.h>
volatile uint16_t Hot_Count, Cold_Count;
uint16_t Hot, Cold, view;
void setup() {
PCICR = 0b00000001; // включаем прерывания PCINT0. цитата из даташита Bit 0 – PCIE0: Pin Change Interrupt Enable. Any change on any enabled PCINT[7:0] pin will cause an interrupt.
DDRB = 0b00111100; // пины 0 и 1 порта B - это входы, все остальное - выходы.
PORTB = 0x00; // отключаем подтяжку на всех пинах. входы 0 и 1 подтянуты к земле через резистор,и к +5v через кнопку.
PCMSK0 = 0b00000011; // Создаем маску для PCINT0, чтобы реагировать только на пины 0 и 1. Т.к. на остальных могут быть релешки и не нужно дергать прерыывание при их срабатывании.
sei();
Serial.begin(9600);
Serial.print("I'm ready\n\r"); //Для отладки, пишем что ардуинка жива.
}
ISR(PCINT0_vect) { // Кто-то дернул прерывание на portb
if ((PINB & (1 << PB0)) == 1 && Cold_Count == 0) { //Если это PB0(8 пин), то нужно добавить 10л к холодной воде. второй частью проверяем, что мы это срабатывание еще не учитывали.
Cold_Count = 1; // сообщаем в основной цикл, что было срабатывание геркона на холодной воде.
}
if ((PINB & (1 << PB0)) == 0 && Cold_Count == 2) { //Если это PB0(8 пин) перешел в ноль и при этом стоит флаг состояния "учтено", то нужно обнулить флаг, для последующего учета, при переходе в еденицу
Cold_Count = 0;
}
if ((PINB & (1 << PB1)) == 2 && Hot_Count == 0) { //Если это PB1(9 пин), то делаем то же самое с горячей водой.
Hot_Count = 1;
}
if ((PINB & (1 << PB1)) == 0 && Hot_Count == 2) {
Hot_Count = 0;
}
}
void loop() {
// put your main code here, to run repeatedly:
if ( (millis() % 500) == 0) { //каждые 500мс проверяем, что нам нужно посчитать. Т.к. считаем мы один раз в полсекунды - дрябезг нам не страшен.
if (Cold_Count == 1) { //если надо посчитать холодную воду
Cold += 10; //добавляем к счетчику холодной воды 10л.
Cold_Count = 2; //ставим флаг в состояние "учтено"
view = 1;
}
if (Hot_Count == 1) { // то же самое для горячей воды
Hot += 10;
Hot_Count = 2;
view = 1;
}
}
if ( view == 1) {
Serial.print("Hot: ");
Serial.print(Hot);
Serial.print("\n\r");
Serial.print(" Cold: ");
Serial.println(Cold);
Serial.print("\n\r");
view = 0;
}
}
Желающие могут адаптировать его под модуль аквалог. а я буду думать над передачей данных по clunet.