I originally had this code for an ESP8266 project and I've adapted it to my current project. Originally I had 3 Pin Change Interrupt inputs for 3 sensors that would send a code to the ESP8266 and they worked as expected.
Now, the only pin responding to any input is pin 7 (PB2). My output data goes to PB3 when pin 7 (PB2) goes high and it should do the same for the other input pins 3,5,6, but nothing happens (verified with Oscope).
The interrupt library I'm using is
GitHub - GreyGnome/EnableInterrupt: New Arduino interrupt library, designed for Arduino Uno/Mega 2560/Leonardo/Due which doesn't require an ISR routine.
I'm using the Sparkfun Tiny AVR Programmer
I've gotten to the point where I've confused myself about bit shifting
assignments to registers as you'll see in comments to myself, however even using pinmode() hasn't helped. The enableINTs() function sets the register bits. setup() is where I attempt to set Inputs.
Currently there's no circuit, just the chip in the programmer and a jumper from Vcc I touch to the pins while watching the output on pin 3 with my scope.
What am I missing/doing wrong? (other than forgetting to attach my code)
/**
ATtiny85 (2MHz) (APR 2022)
**/
// TIP -- Enable CKOUT and then use the scope to view the clock frequency on pin 5/6
// Use AVRDudess 2.13 GUI to set/chg these.
// Default Fuses L=0x62 H=0xDF E=0xFF
// CKOUT Enabled L=0x22 H=0xDF E=0xFF
// ATMEL ATTINY 25/45/85
//
// +-\/-+
// <> RESET 1| |8 Vcc
// DATA OUT <> Ain3 (D3) PB3 2| |7 PB2 (D2) Ain1 <> pirSensorA
// pirSensorD <> Ain2 (D4) PB4 3| |6 PB1 (D1) pwm1 <> pirSensorB
// GND 4| |5 PB0 (D0) pwm0 <> pirSensorC
// +----+
#include <avr/io.h>
#include <avr/sleep.h> // Sleep Modes
#include <avr/power.h> // Power management
#include <avr/delay.h> // Delay for < 8MHz _delay_us / _delay_ms
#include <avr/interrupt.h> // Conflict with EnableInterrupt.h??
#include <EnableInterrupt.h> // Easy to use interrupts for ATtiny (GreyGnome)
#include <avr/wdt.h>
#define BODS 7 // BOD Sleep bit in MCUCR
#define BODSE 2 // BOD Sleep enable bit in MCUCR
#define PIRsensorD 3 // pin 3 / PCINT4 / PB4
#define PIRsensorC 5 // pin 5 / PCINT0 / PB0
#define PIRsensorB 6 // pin 6 / PCINT1 / PB1
#define PIRsensorA 7 // pin 7 / PCINT2 / PB2
#define DATA PB3 // pin 2 Output pulses to TX module
#define F_CPU 2000000UL // 2 MHz (Set in code below to 2Mhz)
volatile int state = LOW; // Used in PinChgInt ISR
volatile int Awakened = LOW;
volatile uint8_t seconds = 0; // Used in Timer ISR
volatile uint8_t DelayBeforeSleeping = 45; // Time in seconds to delay before turning off ESP01
uint8_t mcucr1, mcucr2;
int delaycnt = 0; // Interval counter
int bit = 0;
int runonce = 0;
// code = 0001 0001 0101 0000 0101 0101 0;
bool code[25]={0,0,0,1, 0,0,0,1, 0,1,0,1, 0,0,0,0, 0,1,0,1, 0,1,0,1, 0}; // Harborfreight motion sensor code
//###########################################################################################################################################//
void setup () {
// Change CPU Freq. Page 33, Table 6-15
cli();
CLKPR = (1<<CLKPCE);
//CLKPR = ((0<<CLKPS3) |(0<<CLKPS2) |(1<<CLKPS1) | (1<<CLKPS0)); // 1Mhz
//CLKPR = ((0<<CLKPS3) |(0<<CLKPS2) |(0<<CLKPS1) | (1<<CLKPS0)); // 4Mhz
CLKPR = ((0<<CLKPS3) |(0<<CLKPS2) |(1<<CLKPS1) | (0<<CLKPS0)); // 2Mhz
sei();
DDRB |= (1<<DATA); // set PB1 as Output for data pulses
// Set pins as inputs
DDRB |= ((0 << PIRsensorA) | (0 << PIRsensorB) | (0 << PIRsensorC) | (0 << PIRsensorD));
// Which is correct? Want Input/should be ZERO.
/*
DDRB &= ~(1 << PIRsensorA); //_INPUT PB2 port (pin 7)
DDRB &= ~(1 << PIRsensorB); //_INPUT PB1 port (pin 6)
DDRB &= ~(1 << PIRsensorC); //_INPUT PB0 port (pin 5)
DDRB &= ~(1 << PIRsensorD); //_INPUT PB4 port (pin 3)
DDRB |= (1 << PIRsensorA); //_INPUT PB2 port (pin 7)
DDRB |= (1 << PIRsensorB); //_INPUT PB1 port (pin 6)
DDRB |= (1 << PIRsensorC); //_INPUT PB0 port (pin 5)
DDRB |= (1 << PIRsensorD); //_INPUT PB4 port (pin 3)
*/
goToSleep();
}
//###########################################################################################################################################//
void loop() {
// This condition is for repeat triggers while awake.
if ((state == HIGH) && (Awakened == HIGH)) {
TIMSK &= ~(1 << OCIE1A); // DISABLE 1-second TIMER
// Disable interrupts to avoid a loop
// Interrupts re-enabled below if condition goes LOW.
disableInterrupt(PIRsensorA);
disableInterrupt(PIRsensorB);
disableInterrupt(PIRsensorC);
disableInterrupt(PIRsensorD);
if(PINB & ((1 << PB4) | (1 << PB2) | (1 << PB1) | (1 << PB0))) {
while(PINB & ((1 << PB4) | (1 << PB2) | (1 << PB1) | (1 << PB0))) {
sendcode();
}
state = LOW;
seconds = 0;
}
}
// This is condition after waking from Sleep.
if ((state == HIGH) && (Awakened == LOW)){
TIMSK &= ~(1 << OCIE1A); // DISABLE 1-second TIMER, sensors could be on longer than 30 seconds
Awakened = HIGH;
seconds = 0;
}
// This condition happens when all sensors have gone LOW
if(state == LOW){
enableInterrupt(PIRsensorA|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorB|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorC|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorD|PINCHANGEINTERRUPT, trigger, RISING);
TIMSK |= (1 << OCIE1A); //Re-enable 1 second timer interrupt.
sei();
}
}
//###########################################################################################################################################//
void sendcode(void){
if (runonce == 0) { // Was for testing in main loop
runonce = 0;
// Send bitsream 6 times
for(int cnt=1;cnt<=6;cnt++){
for(bit=0;bit<=24;bit++) {
if (code[bit] == 1) {
PORTB |= (1 << DATA); //_HIGH_
_delay_us(4790);
PORTB &= ~(1 << DATA); //_LOW_
_delay_us(1600);
}
else {
PORTB |= (1 << DATA); //_HIGH_
_delay_us(1600);
PORTB &= ~(1 << DATA); //_LOW_
_delay_us(4790);
}
}
_delay_us(24000); // Delay between pulse streams, if too short fails to get decoded.
}
}
}
//###########################################################################################################################################//
void enableINTs(void){
PCMSK |= (1 << PCINT0); //Set pin 5(PB0/D0) to be interrupt pin
PCMSK |= (1 << PCINT1); //Set pin 6(PB1/D1) to be interrupt pin
PCMSK |= (1 << PCINT2); //Set pin 7(PB2/D2) to be interrupt pin
PCMSK |= (1 << PCINT4); //Set pin 3(PB4/D4) to be interrupt pin
GIFR |= (1 << PCIF); //Clear any outstanding interrupts
GIMSK |= (1 << PCIE); //Enable Pin Change interrupts
enableInterrupt(PIRsensorA|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorB|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorC|PINCHANGEINTERRUPT, trigger, RISING);
enableInterrupt(PIRsensorD|PINCHANGEINTERRUPT, trigger, RISING);
}
//###########################################################################################################################################//
void trigger(void) {
//state = !state; // Toggle "state"
state = HIGH; // For Clarity
seconds = 0;
}
//###########################################################################################################################################//
void goToSleep()
{
cli(); //Disable Interrupts
TIMSK &= ~(1 << OCIE1A); //Disable Timer
GIFR |= (1 << PCIF); //Clear any outstanding interrupts
enableINTs(); //Set Pin Change interrupts before we sleep, or coma!
ACSR |= _BV(ACD); //disable the analog comparator
ADCSRA &= ~_BV(ADEN); //disable ADC
Awakened = LOW;
mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector
mcucr2 = mcucr1 & ~_BV(BODSE);
MCUCR = mcucr1; // WTF?
MCUCR = mcucr2; // WTF? This overwrites previous line!
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_all_disable(); // power off ADC, Timer 0 and 1, serial interface
GIFR |= (1 << PCIF); //Clear any outstanding interrupts
sleep_enable();
sei(); //Enable Interrupts
sleep_cpu(); //Interrupt during sleep runs trigger() from here FIRST, then returns here.
GIMSK = 0x00; //disable INT0
sleep_disable();
power_all_enable(); //Power everything back on
state = HIGH;
Awakened = LOW;
seconds = 0;
}
//###########################################################################################################################################//
ISR(TIM1_COMPA_vect)
{
delaycnt++;
if(seconds <= DelayBeforeSleeping) seconds++;
else {
TIMSK &= ~(1 << OCIE1A); // DISABLE 1-second TIMER
}
}