My favorite activity is sleeping. I often turn off my alarm to keep sleeping, but because of that, I sometimes arrive late to places. That is why I wanted to make an alarm for my project that would be harder for me to turn off, so I thought of an alarm that tries to escape.
My boyfriend always says I am like a hamster (small and easily scared), so I thought I would love for my project to be shaped like a hamster to make it funny.
I think I could do the electronics with a Xiao, use molds to make the hamster shape, and laser cutting for the internal structure, as well as 3D printing. I also want to make an interface to set the alarms.
This is a bit of what I think I could do, but as I advance in the Fab path, I will clarify my ideas.
Systems integrating my project:
Plan for the next weeks:
The first thing I did was test the Real-Time Clock (RTC) sensor for my hamster alarm clock, since with this reading the hamster will start ringing. This uses I2C communication.
I used the dedicated pins on the XIAO (SDA and SCL). The microcontroller requests information from a specific address (e.g., 0x68), and the RTC responds by sending packets of bytes representing seconds, minutes, and hours.
The image below shows the registers through which the RTC operates; you can find this map in the datasheet.
#include <stdio.h>
#include "hardware/i2c.h"
#include "pico/binary_info.h"
// Hardware Configuration
#define I2C_PORT i2c1
#define PIN_SDA 6
#define PIN_SCL 7
#define DS3231_ADDR 0x68
// BCD conversion functions
uint8_t bcdToDec(uint8_t val) { return ((val / 16 * 10) + (val % 16)); }
void setup() {
Serial.begin(115200);
// Wait for serial monitor
while (!Serial && millis() < 3000);
// Initialize I2C
i2c_init(I2C_PORT, 100 * 1000);
gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
// Active pull-ups
gpio_pull_up(PIN_SDA);
gpio_pull_up(PIN_SCL);
Serial.println("--- MODO LECTURA: Reloj DS3231 Activo ---");
}
void loop() {
uint8_t reg = 0x00; // Start recording (seconds)
uint8_t data[3]; // Buffer for [0]=sec, [1]=min, [2]=hours
i2c_write_blocking(I2C_PORT, DS3231_ADDR, ®, 1, true);
int bytes_read = i2c_read_blocking(I2C_PORT, DS3231_ADDR, data, 3, false);
if (bytes_read < 0) {
Serial.println("Error: No se detecta el reloj. Revisa cables.");
} else {
// Convert data from BCD to Decimal
uint8_t segundos = bcdToDec(data[0]);
uint8_t minutos = bcdToDec(data[1]);
uint8_t horas = bcdToDec(data[2] & 0x3F); // Mask for 24h format
Serial.print("\nHora actual: ");
if (horas < 10) Serial.print('0');
Serial.print(horas);
Serial.print(':');
if (minutos < 10) Serial.print('0');
Serial.print(minutos);
Serial.print(':');
if (segundos < 10) Serial.print('0');
Serial.print(segundos);
Serial.print("\t");
}
delay(1000);
}
Later, to be able to dodge people when they try to catch it, I tested the Sharp analog sensors.
The Sharp sensor is connected as follows: the blue arrow can also be connected to a programming pin so that we can activate and deactivate it in operation; having it connected to VCC, the sensor will always be active.
const int sensorPin = A2;
void setup() {
Serial.begin(115200);
// Use the native resolution of the RP2350 (12-bit)
analogReadResolution(12);
pinMode(sensorPin, INPUT);
Serial.println("GP2Y0E02A Sensor ready...");
}
void loop() {
// 1. Read raw value (0 - 4095)
int rawValue = analogRead(sensorPin);
// 2. Convert to Voltage (3.3V Reference)
float voltage = rawValue * (3.3 / 4095.0);
// 3. Calculate distance in cm using the datasheet slope
// Using the linear equation: y = mx + b
// Based on datasheet points: (0.55V, 50cm) and (2.2V, 4cm)
float distanceCm = (voltage - 2.2) * (50.0 - 4.0) / (0.55 - 2.2) + 4.0;
Serial.print("Voltage: ");
Serial.print(voltage, 2);
Serial.print("V | Distance: ");
// 4. Range validation and output
if (distanceCm > 55) {
Serial.println("Fuera de rango (Lejos)");
} else if (distanceCm < 3) {
Serial.println("Fuera de rango (Cerca)");
} else {
Serial.print(distanceCm, 1);
Serial.println(" cm");
}
delay(100);
}
Additionally, to be able to turn off the alarm, I thought I could use a capacitive sensor to detect when a hand is near. For more information about how I did this, you can check my WEEK 09.
long result; // Stores the total sum of samples
int analog_pin = A2; // Receiver pin where capacitance is measured
int tx_pin = D10; // Transmitter pin
void setup() {
// Configures the transmitter pin as data output
pinMode(tx_pin, OUTPUT);
Serial.begin(115200);
delay(1000);
}
long tx_rx() {
int read_high; // Variable for reading with active pulse
int read_low; // Variable for reading with deactivated pulse
int diff; // Difference between charge and discharge
long sum = 0; // Accumulator for all samples
int N_samples = 100; // Number of measurements to average and reduce noise
for (int i = 0; i < N_samples; i++) {
digitalWrite(tx_pin, HIGH);
read_high = analogRead(analog_pin);
delayMicroseconds(100);
digitalWrite(tx_pin, LOW);
read_low = analogRead(analog_pin);
diff = read_high - read_low;
sum += diff;
}
return sum; // Returns the total of the 100 samples
}
void loop() {
result = tx_rx();
// Converts the summed value (approx range 15000-25000) to a scale of 0 to 1024
long mapped_result = map(result, 15000, 25000, 0, 1024);
Serial.print("Raw (Crudo): ");
Serial.print(result);
Serial.print(" | Mapped (Escalado): ");
Serial.println(mapped_result);
delay(50);
}
I'm going to use small DC motors for when I escape, so do the following; for more information you can see my WEEK 10.
For my DC motor, I made the H-bridge using the TB67H451AFNG; this is the schematic of my H-bridge.
const int IN1 = 27; // PINS WHERE WE ARE GOING TO CONNECT THE MOTOR INPUTS
const int IN2 = 28;
void setup() { // We configure both pins as OUTPUT
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
detenerMotor();
}
void loop() {
moverMotor(200); // We move the motor at a power of
// in one direction for 2 seconds
delay(2000);
detenerMotor();// We stop the motor
delay(1000);
moverMotor(-200);// We start turning in the other direction
delay(2000);
detenerMotor();
delay(1000);
}
void moverMotor(int velocidad) {
if (velocidad > 0) {
analogWrite(IN1, velocidad); // Function to make it turn to the right
analogWrite(IN2, 0);// Sends IN2 to 0, so that one has no signal
} else if (velocidad < 0) {
analogWrite(IN1, 0); // Sets IN1 to 0, so that one has no signal
analogWrite(IN2, abs(velocidad));// Function to make it turn to the left
} else {
detenerMotor();
}
}
void detenerMotor() {
analogWrite(IN1, 0);// Sets both IN to 0 so the motor does not turn
analogWrite(IN2, 0);
}