Im having problems with Attiny85 programming. I am making something similar like this project. But i added function that every day on some time it turns on output - something like alarm clock. The real struggle is to make it active for longer time as one minute.. If current time is equals alarm time wake_HOUR==hour()& wake_MINUTE==minute()
then it will run only for a minute so I added changeable field for the time how long output should be active - for example 5 minutes despite 1 minute. I tried to make timer with millis()
and after those 5 minutes reset timer but this is where i stuck, because compiling for attiny it shows error, but if i use same code sample just for arduino then its working.. Code below:
#include <avr/sleep.h>
#include <TinyWireM.h>
#include <EEPROM.h>
#include "ssd1306.h"
#include "WDT_Time.h"
#define TIMEOUT 6000 //display timeout
#define UNUSEDPINA 1 //RESET
#define ALARM 4 //ALARM
#define BUTTONPIN 3 //GND
unsigned int wake_HOUR = 0; //Hours when it should wake up
unsigned int wake_MINUTE = 0; //Minutes when it should wake up
unsigned int wake_SECOND = 0; //Seconds when it should wake up - Not using
unsigned long ALARM_TIME; //How long alarm should be active- changable in display
unsigned long new_millis = 0; //Timer
unsigned long interval; //How long alarm should be active
extern volatile unsigned long timer0_millis;
unsigned int ACTIVE_ALARM = 0; //alarm activated?
#define SET_UP_BUTTON_THRESHOLD 100 //100k
#define UP_DOWN_BUTTON_THRESHOLD 600 //7k
#define PRESSED_BUTTON_THRESHOLD 1000 //NO resistance
// enum
typedef enum {
normal, sleeping
} run_status_t;
typedef enum {
time_mode, debug_mode, alarm_mode
} display_mode_t;
// button field constant
#define NO_FIELD 0
#define YEAR_FIELD 1
#define MONTH_FIELD 2
#define DAY_FIELD 3
#define HOUR_FIELD 4
#define MINUTE_FIELD 5
#define SECOND_FIELD 6
#define ALARM_HOUR_FIELD 7 //Alarm Hour
#define ALARM_MINUTE_FIELD 8 //Alarm Minute
#define ALARM_FIELD 9 //How long should alarm be active - minutes
#define SET_ALARM_FIELD 10 //Activate alarm
#define FIELD_COUNT 10
//#define ALARM_SECOND_FIELD 9
// variables
SSD1306 oled;
static uint32_t display_timeout = 0;
static run_status_t run_status = normal;
static display_mode_t display_mode = time_mode;
static display_mode_t last_display_mode = time_mode;
static bool time_changed = false;
static bool alarm_changed = false;
static uint8_t selected_field = NO_FIELD;
uint8_t wake_SET = 0;
//const char wake_BACK[15] = "GO BACK";
void setup() {
// setup input pins, also pullup unused pin for power saving purpose
pinMode(UNUSEDPINA, INPUT_PULLUP);
pinMode(BUTTONPIN, INPUT_PULLUP);
pinMode(ALARM, OUTPUT);
digitalWrite(ALARM, LOW);
interval = ALARM_TIME*60000;
// init time
init_time();
// init I2C and OLED
TinyWireM.begin();
oled.begin();
oled.fill(0x00); // clear in black
// init display timeout
set_display_timeout();
}
void loop() {
// detect and handle button input
check_button();
unsigned long currenTime = millis();
//unsigned long new_value;
//setMillis(new_value);
if (run_status == sleeping) {
// return to sleep mode after WDT interrupt
system_sleep();
} else { // not sleeping
if (millis() > display_timeout) { // check display timeout
enter_sleep();
} else { // normal flow
readRawVcc();
readRawTemp();
draw_oled();
} // normal flow
} // not sleeping
if (ACTIVE_ALARM==1)
{
if (wake_HOUR==hour()& wake_MINUTE==minute())
{
digitalWrite(ALARM, HIGH);
new_millis = millis();
}
else if (currenTime -new_millis <= interval)
{
new_millis = millis();
digitalWrite(ALARM, HIGH);
}
else if (currenTime -new_millis >= interval)
{
new_millis = 0;
digitalWrite(ALARM, LOW);
}}
else if (ACTIVE_ALARM==0)
{
new_millis = 0;
digitalWrite(ALARM, LOW);
}
}
//void setMillis(unsigned long new_millis){
// uint8_t oldSREG = SREG;
// cli();
// timer0_millis = new_millis;
// SREG = oldSREG;
//}
void enter_sleep() {
oled.fill(0x00); // clear screen to avoid show old time when wake up
oled.off();
delay(2); // wait oled stable
run_status = sleeping;
}
void wake_up() {
run_status = normal;
delay(2); // wait oled stable
oled.on();
// update display timeout
set_display_timeout();
}
void set_display_timeout() {
display_timeout = millis() + TIMEOUT;
}
/*
* UI related
*/
void draw_oled() {
if (display_mode != last_display_mode) {
oled.fill(0x00);
last_display_mode = display_mode;
}
oled.set_font_size(1);
if (display_mode == time_mode) {
// 1st row: print info
oled.set_pos(5, 0);
oled.print("TIME");
oled.set_pos(80, 0);
oled.print("AcALARM=");
oled.print(digitalRead(ACTIVE_ALARM));
oled.set_pos(80, 1);
oled.print("A_TIME=");
oled.print(digitalRead(ALARM_TIME));
oled.set_pos(80, 2);
oled.print("ALARM=");
oled.print(digitalRead(ALARM));
// 2nd row: print date
print_digit(7, 1, year(), (selected_field == YEAR_FIELD));
oled.write('-');
print_digit(7 + (5 * FONT_WIDTH), 1, month(), (selected_field == MONTH_FIELD));
oled.write('-');
print_digit(7 + (8 * FONT_WIDTH), 1, day(), (selected_field == DAY_FIELD));
// 3rd-4th rows: print time
oled.set_pos(30, 4);
oled.print("SET ALARM");
oled.set_pos(3, 5);
oled.print("HH:MM-->ALARM MIN");
oled.set_pos(95, 5);
oled.print("ON/OFF");
oled.set_font_size(2);
print_digit(0, 2, hour(), (selected_field == HOUR_FIELD));
oled.draw_pattern(2 * FONT_2X_WIDTH + 1, 2, 2, 2, 0b00011000);
print_digit(2 * FONT_2X_WIDTH + 5, 2, minute(), (selected_field == MINUTE_FIELD));
oled.draw_pattern(4 * FONT_2X_WIDTH + 6, 2, 2, 2, 0b00011000);
print_digit(4 * FONT_2X_WIDTH + 2 * FONT_WIDTH, 2, second(), (selected_field == SECOND_FIELD));
print_digit(0, 6, wake_HOUR, (selected_field == ALARM_HOUR_FIELD));
oled.draw_pattern(2 * FONT_2X_WIDTH + 1, 6, 2, 2, 0b00011000);
print_digit(2 * FONT_2X_WIDTH + 5, 6, wake_MINUTE, (selected_field == ALARM_MINUTE_FIELD));
print_digit(6 * FONT_2X_WIDTH + 2 * FONT_WIDTH, 6, ALARM_TIME, (selected_field == ALARM_FIELD));
print_digit(80, 6, ACTIVE_ALARM, (selected_field == SET_ALARM_FIELD));
}
else if (display_mode == debug_mode) { // debug_mode
print_debug_value(2, 'I', get_wdt_interrupt_count());
print_debug_value(3, 'M', get_wdt_microsecond_per_interrupt());
print_debug_value(4, 'V', getVcc());
print_debug_value(5, 'T', getRawTemp());
}
}
void print_digit(uint8_t col, uint8_t page, int value, bool invert_color) {
oled.set_pos(col, page);
if (invert_color) oled.set_invert_color(true);
if (value < 10) oled.write('0');
oled.print(value);
if (invert_color) oled.set_invert_color(false);
}
void print_debug_value(uint8_t page, char initial, uint32_t value) {
oled.set_pos(0, page);
oled.write(initial);
oled.set_pos(14, page);
oled.print(value);
}
// PIN CHANGE interrupt event function
ISR(PCINT0_vect) {
set_display_timeout(); // extent display timeout while user input
}
void check_button() {
int buttonValue = analogRead(BUTTONPIN);
if (buttonValue < PRESSED_BUTTON_THRESHOLD) { // button down
set_display_timeout(); // extent display timeout while user input
if (run_status == sleeping) {
// wake_up if button pressed while sleeping
wake_up();
} else { // not sleeping
if (buttonValue > UP_DOWN_BUTTON_THRESHOLD) { // down button
handle_adjust_button_pressed(-1);
} else if (buttonValue > SET_UP_BUTTON_THRESHOLD) { // up button
handle_adjust_button_pressed(1);
} else { // set button
handle_set_button_pressed();
}
} // not sleeping
} // button down
}
void handle_set_button_pressed() {
display_mode = time_mode; // always switch to time display mode while set button pressed
selected_field++;
if (selected_field > FIELD_COUNT) { // finish time adjustment
selected_field = NO_FIELD;
if (time_changed) {
wdt_auto_tune();
time_changed = false;
} //time changed
} // finish time adjustment
}
void handle_adjust_button_pressed(long value) {
if (selected_field == NO_FIELD) {
// toggle display_mode if no field selected
display_mode = (display_mode == time_mode) ? debug_mode : time_mode;}
else {
long adjust_value;
if (selected_field == YEAR_FIELD) {
// TODO: handle leap year and reverse value
adjust_value = value * SECS_PER_DAY * (leapYear(CalendarYrToTm(year())) ? 366 : 365);
}
else if (selected_field == MONTH_FIELD) {
// TODO: handle leap year and reverse value
adjust_value = value * SECS_PER_DAY * getMonthDays(CalendarYrToTm(year()), month());
}
else if (selected_field == DAY_FIELD) {
// TODO: handle leap year and reverse value
adjust_value = value * SECS_PER_DAY;
}
else if (selected_field == HOUR_FIELD) {
adjust_value = value * SECS_PER_HOUR;
}
else if (selected_field == MINUTE_FIELD) {
adjust_value = value * SECS_PER_MIN;
}
else if (selected_field == SECOND_FIELD) {
adjust_value = value;
}
else if (selected_field == ALARM_HOUR_FIELD)
{
if (wake_HOUR >= 23)
{
wake_HOUR=0;
}
else if (analogRead(BUTTONPIN) > UP_DOWN_BUTTON_THRESHOLD)
{ // down button
wake_HOUR--;
}
else if (analogRead(BUTTONPIN) > SET_UP_BUTTON_THRESHOLD)
{ // up button
wake_HOUR++;
}
}
else if (selected_field == ALARM_MINUTE_FIELD) {
if (wake_MINUTE >= 59)
{
wake_MINUTE=0;
}
else if (analogRead(BUTTONPIN) > UP_DOWN_BUTTON_THRESHOLD)
{ // down button
wake_MINUTE--;
}
else if (analogRead(BUTTONPIN) > SET_UP_BUTTON_THRESHOLD)
{ // up button
wake_MINUTE++;
}
}
else if (selected_field == ALARM_FIELD) {
if (ALARM_TIME >= 59) //MAX 1h
{
ALARM_TIME=0;
}
else if (analogRead(BUTTONPIN) > UP_DOWN_BUTTON_THRESHOLD)
{ // down button
ALARM_TIME--;
}
else if (analogRead(BUTTONPIN) > SET_UP_BUTTON_THRESHOLD)
{ // up button
ALARM_TIME++;
}
}
else if (selected_field == SET_ALARM_FIELD) {
if (ACTIVE_ALARM >= 1)
{
ACTIVE_ALARM=0;
}
else if (analogRead(BUTTONPIN) > UP_DOWN_BUTTON_THRESHOLD)
{ // down button
ACTIVE_ALARM--;
}
else if (analogRead(BUTTONPIN) > SET_UP_BUTTON_THRESHOLD)
{ // up button
ACTIVE_ALARM++;
}
}
adjustTime(adjust_value);
time_changed = true;
}
}
I would like to reset timer then when wake_hours&minutes and changeable alarm activation time interval = ALARM_TIME*60000
have passed.
if (ACTIVE_ALARM==1)
{
if (wake_HOUR==hour()& wake_MINUTE==minute())
{
digitalWrite(ALARM, HIGH);
new_millis = millis();
}
else if (currenTime -new_millis <= interval)
{
new_millis = millis();
digitalWrite(ALARM, HIGH);
}
else if (currenTime -new_millis >= interval)
{
new_millis = 0;
digitalWrite(ALARM, LOW);
}}
else if (ACTIVE_ALARM==0)
{
new_millis = 0;
digitalWrite(ALARM, LOW);
}
Any ideas what kind a timer/delay i could use to make my code work?
&&
instead of&
? The meanings are very very different.wake_HOUR==hour()& wake_MINUTE==minute()
part. Because in next line i declare that if the interval havent reached then output still is ONwake_HOUR==hour()
andwake_MINUTE==minute()
it's the same... :) ... [both&
and&&
have lower precedence than==
which allows rookie mistake to turn out ok]