// ATtiny85 Frequency Divider by 1.3
// Input: Square wave 0-1kHz on PB2 (pin 7)
// Output: Square wave with frequency/1.3 and 50% duty cycle on PB1 (pin 6)
#define INPUT_PIN PB2 // Pin 7 (physical pin)
#define OUTPUT_PIN PB1 // Pin 6 (physical pin)
volatile unsigned long lastEdgeTime = 0;
volatile unsigned long inputPeriod = 0;
volatile bool newPeriodAvailable = false;
volatile unsigned long outputPeriod = 0;
volatile unsigned long outputHalfPeriod = 0;
volatile unsigned long outputLastToggle = 0;
volatile bool outputState = false;
// Timeout handling for low frequencies
#define TIMEOUT_THRESHOLD 200000 // 200ms = 5Hz minimum
volatile unsigned long lastValidInput = 0;
void setup() {
// Set pin modes
pinMode(INPUT_PIN, INPUT_PULLUP);
pinMode(OUTPUT_PIN, OUTPUT);
// Initialize output
digitalWrite(OUTPUT_PIN, LOW);
// Enable Pin Change Interrupt for PB2
GIMSK |= (1 << PCIE); // Enable Pin Change Interrupts
PCMSK |= (1 << PCINT2); // Enable interrupt on PB2
// Initialize timer for microsecond timing
// Timer0 is used by Arduino functions like micros()
sei(); // Enable global interrupts
}
void loop() {
unsigned long currentTime = micros();
// Check if we have a new input period measurement
if (newPeriodAvailable) {
// Calculate output period (input period * 1.3)
outputPeriod = (inputPeriod * 13) / 10; // Multiply by 1.3
outputHalfPeriod = outputPeriod / 2; // 50% duty cycle
// Reset output timing
outputLastToggle = currentTime;
outputState = false;
digitalWrite(OUTPUT_PIN, LOW);
lastValidInput = currentTime;
newPeriodAvailable = false;
}
// Timeout check - if no valid input for more than 200ms (5Hz), stop output
if (outputPeriod > 0 && (currentTime - lastValidInput) > TIMEOUT_THRESHOLD) {
outputPeriod = 0;
outputState = false;
digitalWrite(OUTPUT_PIN, LOW);
}
// Generate output square wave with 50% duty cycle
if (outputPeriod > 0) {
if (currentTime - outputLastToggle >= outputHalfPeriod) {
outputState = !outputState;
digitalWrite(OUTPUT_PIN, outputState);
outputLastToggle = currentTime;
}
}
}
// Pin Change Interrupt Service Routine
ISR(PCINT0_vect) {
static unsigned long prevEdgeTime = 0;
static bool lastState = HIGH;
unsigned long currentTime = micros();
bool currentState = digitalRead(INPUT_PIN);
// Detect rising edge (assuming input is pulled up, so LOW to HIGH transition)
if (lastState == LOW && currentState == HIGH) {
if (prevEdgeTime > 0) {
inputPeriod = currentTime - prevEdgeTime;
// Validate period (should be between 1ms and 1000ms for 0-1kHz range)
if (inputPeriod >= 1000 && inputPeriod <= 1000000) {
newPeriodAvailable = true;
}
}
prevEdgeTime = currentTime;
}
lastState = currentState;
}
/*
Pin connections for ATtiny85:
- Pin 1 (PB5/RESET): Leave unconnected or use for programming
- Pin 2 (PB3): Not used
- Pin 3 (PB4): Not used
- Pin 4 (GND): Ground
- Pin 5 (PB0): Not used
- Pin 6 (PB1): OUTPUT - Connect your output load here
- Pin 7 (PB2): INPUT - Connect your input square wave here
- Pin 8 (VCC): Power supply (1.8V to 5.5V)
Frequency range:
- Input: 0-1kHz (1000µs to 1000000µs period)
- Output: Input frequency ÷ 1.3 (so 0-769Hz approximately)
- Duty cycle: 50% on output
Note: This code uses pin change interrupts to measure the input period
and generates the output using timing loops. For very low frequencies
(below ~10Hz), you might want to add a timeout mechanism.
*/