i am trying to make an alarm clock with esp8266 and ws2812b leds. On alarm time it must call the sunrise() function. The sunrise() function works fine when i put it directly in the loop function. But it doesn't work in alarm trigger.
if (AlarmData.AlarmOn[Current.Day])
{
if (!AlarmActive)//do not enter this routine if alarm already active
{
if (Current.Hour == AlarmData.Hour[Current.Day])
{
if (Current.Minute == AlarmData.Minute[Current.Day])
{
if (Current.Second > 0 && Current.Second < 3)
{
AlarmActive = true;
sunrise();
alarmTriggerTime = micros();
Serial.println("Its time for your alarm!");
}
}
}
}
}
My code is below. thanks in advance for your help
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include "EEPROMAnything.h"
#include "get_time.h"
#include "OTA.h"
#include <stdio.h>
#include <stdint.h>
#include "web_portal.h"
#include "ESP8266TimerInterrupt.h"
#include "restore_factory_settings.h"
#include "FastLED.h"
#define NUM_LEDS 60
#define DATA_PIN 5
// Define the array of leds
CRGB leds[NUM_LEDS];
#define timeZone 3
#define TenSecs 10000000
#define OneMin 60000000
#define TenMins 600000000
#define TIMER_INTERVAL_MS 1000
ESP8266Timer ITimer;
int timer;
int alarmTriggerTime;
struct CurrentTime Current;
bool AlarmActive;
struct AlarmDataStruct AlarmData;
int WiFiTimer;
char factory_settings_stored [3];
bool OneSecoundPassed;
void ICACHE_RAM_ATTR TimerHandler(void)
{
OneSecoundPassed = true;
}
void setup() {
Serial.begin(115200);
Serial.println("Booting");
EEPROM.begin(512);
EEPROM_readAnything(150, factory_settings_stored);
if (memcmp(&factory_settings_stored, "YES", 3) != 0)
{
restore_factory_settings();
}
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(0);
WiFi.mode(WIFI_STA);
WiFiManager wm;
bool response;
response = wm.autoConnect("AutoConnectAP"); // anonymous ap
if (!response) {
Serial.println("Failed to connect");
// ESP.restart();
}
else {
//if you get here you have connected to the WiFi
Serial.println("Lets Go");
}
start_server();
SetupOTA();
setup_time(timeZone);
Current = Current_Time();
EEPROM_readAnything(100, AlarmData);
Serial.print("Alarm set for ");
Serial.print(AlarmData.Hour[Current.Day]);
Serial.print(":");
Serial.println(AlarmData.Minute[Current.Day]);
timer = micros();
WiFiTimer = timer;
// Interval in microsecs
if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler))
{
Serial.println("Starting ITimer OK, millis() = " + String(millis()));
}
else
{
Serial.println("Can't set ITimer correctly. Select another freq. or interval");
}
}
void loop() {
if (!AlarmActive)
{
ArduinoOTA.handle();
handle_client();
if ((micros() - WiFiTimer) > TenMins) // check if wifi connection lost and if so try to reconnect
{
if (WiFi.status() != WL_CONNECTED)
{
ESP.restart(); //try to reconnect rather than resetting
}
WiFiTimer = micros();
}
if (OneSecoundPassed)
{
updateLocalTime();
OneSecoundPassed = false;
}
//update current hour from NTP server
if ((micros() - timer) > TenMins)
{
Current = Current_Time();
timer = micros();
}
}
if (AlarmActive)
{
if ((micros() - alarmTriggerTime) > TenMins)
{
AlarmActive = false; //if alarm active for 10mins and no one switches it off then do it auto
}
}
if (AlarmData.AlarmOn[Current.Day])
{
if (!AlarmActive)//do not enter this routine if alarm already active
{
if (Current.Hour == AlarmData.Hour[Current.Day])
{
if (Current.Minute == AlarmData.Minute[Current.Day])
{
if (Current.Second > 0 && Current.Second < 3)
{
AlarmActive = true;
sunrise();
alarmTriggerTime = micros();
Serial.println("Its time for your alarm!");
}
}
}
}
}
else
{
if (!AlarmActive)
{
}
}
}
void updateLocalTime () {
Current.Second++;
if (Current.Second >= 60)
{
Current.Second = 0;
Current.Minute++;
if (Current.Minute >= 60)
{
Current.Minute = 0;
Current.Hour++;
if (Current.Hour >= 24)
{
Current.Hour = 0;
Current.Day++;
if (Current.Day >= 7)
{
Current.Day = 0;
}
}
}
}
char tempTime[6];
if (Current.Minute < 10 && Current.Second < 10)
{
sprintf(tempTime, "0%d:0%d", Current.Minute, Current.Second);
}
else if (Current.Minute < 10)
{
sprintf(tempTime, "0%d:%d", Current.Minute, Current.Second);
}
else if (Current.Second < 10)
{
sprintf(tempTime, "%d:0%d", Current.Minute, Current.Second);
}
else
{
sprintf(tempTime, "%d:%d", Current.Minute, Current.Second);
}
}
void sunrise() {
static const uint8_t sunriseLength = 30; //(min)
static const uint8_t interval = (sunriseLength * 60) / 256;
static const uint8_t binterval = (sunriseLength * 60) / 256;
// current gradient palette color index
static uint8_t heatIndex = 0; // start out at 0
static uint8_t brIndex = 0;
// HeatColors_p is a gradient palette built in to FastLED
// that fades from black to red, orange, yellow, white
// feel free to use another palette or define your own custom one
CRGB color = ColorFromPalette(HeatColors_p, heatIndex);
fill_solid(leds, NUM_LEDS, color); // fill the entire strip with the current color
EVERY_N_SECONDS(binterval) {
if (brIndex < 255) {
FastLED.setBrightness(brIndex);
brIndex++;
}
}
EVERY_N_SECONDS(interval) {
if (heatIndex < 255) {
heatIndex++;
}
}
FastLED.show();
}
Your sunrise function should be called over and over, every call changes the LED color a slight bit. This is why it works then you put it into the loop function.
However, you have guarded it so that it is specifically only called once - so now it is called, sets the LEDs to the dimmest setting possible, and is not called again.
What you need to do is separate this out into two parts: One that detects when to activate sunrise, and one that is continuously called when it is time. F.ex:
void loop()
{
/* stuff */
if (AlarmData.AlarmOn[Current.Day])
{
if (!AlarmActive) // do not enter this routine if alarm already active
{
if (Current.Hour == AlarmData.Hour[Current.Day])
{
if (Current.Minute == AlarmData.Minute[Current.Day])
{
if (Current.Second > 0 && Current.Second < 3)
{
AlarmActive = true;
alarmTriggerTime = micros();
Serial.println("Its time for your alarm!");
}
}
}
}
}
if (AlarmActive)
sunrise();
}
#define CLK 2
#define DT 3
#define SW 4
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
int counter = 0;
int currentStateCLK;
int lastStateCLK;
int lastCLK,cnt=0,btnState,lastPress=0;
String currentDir ="";
unsigned long lastButtonPress = 0;
char *mainmenu[] ={"SET MODE","SET TEMP","SET HUMD","SERVO","RESET"};
char *setmode[] ={"INCUBATOR","HATCHER","BACK"};
void setup() {
// Set encoder pins as inputs
Wire.begin();
Wire.beginTransmission(0x27);
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.home(); lcd.clear();
Serial.begin(9600);
lastStateCLK = digitalRead(CLK);
delay(100);
if(EEPROM_READ(0)==NULL){
SET_MODE();
}
Serial.print(EEPROM_READ(0));
}
void loop(){
disp();
rot();
}
void disp(){
lcd.setCursor(0,0);
lcd.print(" KGF");
}
void rot() {
int lim=sizeof(mainmenu)/2;
Serial.print(lim);
currentStateCLK = digitalRead(CLK);
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentStateCLK) {
counter --;
if(counter<0){
counter=lim-1;
}
}
else {
// Encoder is rotating CW so increment
counter ++;
if(counter>lim-1){
counter=0;
}
lcd.print(mainmenu[counter]);
}
lastStateCLK = currentStateCLK;
int btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(counter==0){
SET_MODE();
}
}
}
lastButtonPress = millis();
}
delay(1);
}
void SET_MODE(){
int lim=sizeof(setmode)/2;
int currentCLK = digitalRead(CLK);
if (currentCLK != lastCLK && currentCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentCLK) {
cnt --;
if(cnt<0){
cnt=lim-1;
}
}
else {
// Encoder is rotating CW so increment
cnt ++;
if(cnt>lim-1){
cnt=0;
}
}
lcd.print(setmode[cnt]);
}
lastCLK = currentCLK;
btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(setmode[cnt]=="BACK"){
exit(0);
}
lcd.clear();
lcd.setCursor(0, 1);
EEPROM_WRITE(0,setmode[cnt]);
lcd.print("DONE");
}
lastPress = millis();
}
delay(1);
}
void EEPROM_WRITE(int addrOffset, const String &strToWrite)
{
byte len = strToWrite.length();
EEPROM.write(addrOffset, len);
for (int i = 0; i < len; i++)
{
EEPROM.write(addrOffset + 1 + i, strToWrite[i]);
}
}
String EEPROM_READ(int addrOffset)
{
int newStrLen = EEPROM.read(addrOffset);
char data[newStrLen + 1];
for (int i = 0; i < newStrLen; i++)
{
data[i] = EEPROM.read(addrOffset + 1 + i);
}
data[newStrLen] = '\0';
return String(data);
}
I want to call the SET_MODE() function in the loop from rot() function, I am building a menu based program so the SET MODE menu should redirect to the SET_MODE() function, and as I will be adding more menu and sub-menus how can I perform this task.
The SET_MODE() function doesn't work in loop I do not know why, it only works when I all it under void loop() directly.
I have a project I'm working on with an LCD screen, two buttons, and a potentiometer, it's a binary calculator. When I reach screenState == 3 I am attempting to change the digits so i can keep track of them and add an 8 bit number with another 8 bit number, while tracking overflow. However, whenever I begin to use the button which the input == 0 it moves the cursor, and then my next button cycles through the screens again. Input == 0 should only change the value between 0 and 1 for whatever lcd.cursor value I'm. How can i adjust that one value without changing screens?
#include <LiquidCrystal.h>
LiquidCrystal lcd(11, 10, 5, 4, 3, 2);
const int numInputs = 2;
const int inputPins[numInputs] = {13, 12};
// tracks screen state
int screenState = 0;
int prevScreenState = 0;
int binaryValue = 0;
// tracks if we are on the right screen to acceptInput and if our value is 0 or 1
bool canAcceptInput = false;
bool valIsZero = false;
int inputState[numInputs];
int lastInputState[numInputs] = {LOW,LOW};
bool inputFlags[numInputs] = {LOW,LOW};
int inputCounter[numInputs];
int cursorPosX = 0;
int cursorPosY = 0;
int blinkingPosX = cursorPosX;
int blinkingPosY = cursorPosY;
unsigned long lastDebounceTime[numInputs] = {0,0};
long debounceDelay = 50;
void setup() {
for(int i = 0; i < numInputs; i++) {
pinMode(inputPins[i], INPUT);
digitalWrite(inputPins[i], HIGH); // pull-up 20k
}
Serial.begin(9600);
lcd.begin(16, 2);
}
void loop() {
setInputFlags();
resolveInputFlags();
}
void setInputFlags() {
for(int i = 0; i < numInputs; i++) {
int reading = digitalRead(inputPins[i]);
if (reading != lastInputState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != inputState[i]) {
inputState[i] = reading;
if (inputState[i] == HIGH) {
inputFlags[i] = HIGH;
}
}
}
lastInputState[i] = reading;
}
}
void resolveInputFlags() {
for(int i = 0; i < numInputs; i++) {
if(inputFlags[i] == HIGH) {
// Input Toggle Logic // all invoked upon bttn press
inputCounter[i]++;
updateScreenState(i);
printString(i);
inputFlags[i] = LOW;
}
}
}
void updateScreenState(int input) {
// input 0 = State 0 and 1
if(input == 0) {
if(screenState > 2 & screenState < 19) {
canAcceptInput = true;
binaryValue = 1;
updateScreenValues();
}
else if (screenState == 1) {
//screenState = 0;
binaryValue = 0;
updateScreenValues();
}
else {
//screenState = 2;
binaryValue = 1;
}
// input 1 = State 2 to 6
}else if(input == 1) {
// we have 20 max screen states, this cycles through them using button 2
if(screenState == 0 || screenState == 1 || screenState > 19) {
screenState = 2;
updateScreen();
}else{
screenState++;
updateScreen();
}
}
}
void setCursorValues( int cursorX, int cursorY) {
lcd.setCursor(cursorX, cursorY);
cursorPosX = cursorX;
cursorPosY = cursorY;
}
void updateScreenValues() {
if(canAcceptInput == true) {
if(binaryValue == 0 ){
lcd.print("0");
}
if(binaryValue == 1) {
lcd.print("1");
binaryValue = 0;
}
}
}
// void update -----------------------------------------------------------------------------
void updateScreen() {
// welcome screen -----------------------------
if(screenState == 2){
canAcceptInput = false;
lcd.clear();
setCursorValues(0, 0);
lcd.print("Welcome Screen");
setCursorValues(0, 1);
lcd.print("Press Bttn 1");
}
// start of byte 1 screen ----------------------------------------------------------------
if(screenState == 3){
canAcceptInput = true;
lcd.clear();
setCursorValues(0, 0);
lcd.print("Byte 1 Screen");
setCursorValues(0, 1);
lcd.print(" 0000 0000 ");
//move cursor to MSD and blink
setCursorValues(3, 1);
lcd.blink();
}
//if screenState changes, so will the cursorValues-----------
if(screenState == 4) {
setCursorValues(4, 1);
}
if(screenState == 5) {
setCursorValues(5, 1);
}
if(screenState == 6) {
setCursorValues(6, 1);
}
if(screenState == 7) {
setCursorValues(9, 1);
}
if(screenState == 8) {
setCursorValues(10, 1);
}
if(screenState == 9) {
setCursorValues(11, 1);
}
if(screenState == 10) {
setCursorValues(12, 1);
}
//start of byte 2 screen -------------------------------------------------------
if(screenState == 11){
lcd.clear();
setCursorValues(0, 0);
lcd.print("Byte 2 Screen");
setCursorValues(0, 1);
lcd.print(" 0000 0000 ");
setCursorValues(3, 1);
lcd.blink();
}
//if screenState changes, so will the cursorValues-----------
if(screenState == 12) {
setCursorValues(4, 1);
}
if(screenState == 13) {
setCursorValues(5, 1);
}
if(screenState == 14) {
setCursorValues(6, 1);
}
if(screenState == 15) {
setCursorValues(9, 1);
}
if(screenState == 16) {
setCursorValues(10, 1);
}
if(screenState == 17) {
setCursorValues(11, 1);
}
if(screenState == 18) {
setCursorValues(12, 1);
}
if(screenState == 19){
lcd.clear();
setCursorValues(0, 0);
lcd.print("Solution Screen");
lcd.noCursor();
}
if(screenState == 20){
lcd.clear();
setCursorValues(0, 0);
lcd.print("Contrast Screen");
}
}
void printString(int output) {
Serial.print("Input ");
Serial.print(output);
Serial.print(" was pressed ");
Serial.print(inputCounter[output]);
Serial.println(" times.");
Serial.print("screenState = ");
Serial.println(screenState);
Serial.print("binaryValue = ");
Serial.println(binaryValue);
Serial.print("cursorPosX = ");
Serial.print(cursorPosX);
Serial.print(" cursorPosY = ");
Serial.println(cursorPosY);
Serial.print('\n');
}
First of all, I copied/paste th code to see if it compliles in Arduino IDE, and it does, so I guess it's not a C++ related issue but maybe something more Atmel Studio or linker related.
I recently decided to switch from Arduino IDE to Atmel Studio to develop and program Arduino boards.
I have this project where I use a .h/.c library that I wrote, which is located in "../Lib". I have added the library with "Add existing item" and "Add as Link", because I wanted to work with the original code not a copy (a few things still need to be added to it)
A first it builded without any problem, but then I added an extra function in the library called "determineWinningPosition()". Now compilation returns an error :
D:\Google Drive\ISIB\5 - Mecatronic\Controller_v5_AS\Controller_v5_AS\Controller_v5\Sketch.cpp(76,28): error: 'determineWinningPositions' was not declared in this scope
determineWinningPositions();
The function prototype is declared in the library header "LetMeOut.h" :
#include <Arduino.h>
#include <Wire.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <EEPROM.h>
#include <stdlib.h>
// Key words
#define MOTOR1 (0)
#define MOTOR2 (1)
#define MAX_SPEED (15)
#define SIZE_RAND_SEQ (100)
#define BUTTON_TIMEOUT (10) // -> 1s
#define WINNING_POS_TOLERANCE (3)
#define GLOBAL_STATE_SIZE (7)
#define STATE0 (3)
#define STATE1 (2)
#define STATE2 (0)
#define STATE3 (1)
#define START (5)
#define STOP (10)
#define CHANGE_SPEED (15)
#define INIT_POS (20)
#define START_SPEED (25)
#define RESET_CMD (30)
#define GO_TO_POS (35)
#define UNLOCK_DOOR (40)
#define LOCK_DOOR (45)
#define CHANGE_WINNING_POS (50)
#define TRUE (1)
#define FALSE (0)
#define EEPROM_1 (0)
#define EEPROM_2 (1)
// Pins
#define DIR_M1 (A0)
#define DIR_M2 (A1)
#define EN_M1 (A2)
#define EN_M2 (A3)
#define SCL_PIN (A4)
#define SDA_PIN (A5)
#define STARTED_PIN (2)
#define A1_PIN (3)
#define B1_PIN (4)
#define A2_PIN (5)
#define CTL_M1 (6)
#define B2_PIN (7)
#define START_PIN (8)
#define STOP_M2 (9)
#define SUCCEED_PIN (10)
#define CTL_M2 (11)
#define STOP_M1 (12)
#define DOOR_PIN (13) // LED
// Prototypes
void Timer1_ISR(void);
void receiveEvent(int howMany);
void requestEvent();
void initI2C(void);
void initMotors(void);
void initEncoder(void);
void initDirectionTimer(void);
void setMotorSpeed(uint8_t motor, uint8_t motorSpeed, uint8_t dir);
void setAllMotorSpeed(uint8_t motorSpeed);
void stopMotor(uint8_t motorID);
void stopAllMotors (void);
void startMotor(uint8_t motorID);
void startAllMotors (void);
void buttonManager(void);
void directionManager(void);
void i2cCommandManager(void);
void printPosition(bool b);
void goToPosition(uint8_t position1_, uint8_t position2_);
void readEncoder(void);
void determineWinningPositions(void);
The function is implemented in "LetMeOut.cpp" :
#include "LetMeOut.h"
extern uint8_t directionChangeCounter1, directionChangeCounter2;
extern uint8_t directionChangeCounterTopValue1;
extern uint8_t directionChangeCounterTopValue2;
extern bool direction1;
extern bool direction2;
extern bool counterChanged;
extern uint8_t button1Counter;
extern bool button1CounterStarted;
extern uint8_t button2Counter;
extern bool button2CounterStarted;
extern volatile uint8_t startButtonCounter;
extern volatile bool startButtonCounterStarted;
extern uint8_t cmd[3];
extern uint8_t globalState[GLOBAL_STATE_SIZE];
extern bool newCmd;
const uint8_t randomSeq[SIZE_RAND_SEQ] = {9, 15, 8, 10, 10, 10, 17, 12, 6, 16, 6, 8, 14, 15, 19, 15, 9, 20, 13, 17, 7, 15, 13, 15, 5, 7, 10, 6, 8, 9, 14, 9, 19, 11, 15, 17, 17, 7, 18, 12, 8, 20, 12, 11, 6, 16, 19, 17, 16, 10, 14, 14, 18, 13, 5, 20, 17, 10, 17, 12, 15, 12, 16, 12, 12, 18, 18, 19, 13, 16, 6, 7, 16, 17, 12, 11, 19, 12, 19, 13, 15, 18, 5, 7, 8, 8, 16, 16, 8, 14, 17, 17, 13, 6, 6, 8, 7, 10, 20, 13};
extern uint8_t index1;
extern uint8_t index2;
extern uint8_t speedSetting;
extern volatile bool started;
extern bool initDone;
extern bool doorUnlocked;
extern volatile bool currentA1, currentB1, currentA2, currentB2;
extern volatile int currentState1, previousState1, currentState2, previousState2, position1, position2;
extern volatile bool printPos;
extern uint8_t winningPosition1;
extern uint8_t winningPosition2;
extern volatile bool succeed;
extern volatile bool motor1Started;
extern volatile bool motor2Started;
extern int* winningPositionList1;
extern int* winningPositionList2;
/************************************************************************************************/
/********************************** Interrupts and Callbacks ************************************/
/************************************************************************************************/
// Interrupt service routine called at every timer 1 overflow : every 100 ms
// Used to measure time between every speed changes and to implement a timeout every 1s to prevent
// the user from "machine gunning" the buttons
void Timer1_ISR(void)
{
// Increase both counters used for speed changes and notify the loop() there's been a change
directionChangeCounter1++;
directionChangeCounter2++;
counterChanged = 1;
// Prevent the user from "machine gunning" the buttons
if (button1CounterStarted)
{
button1Counter++;
if (button1Counter >= BUTTON_TIMEOUT)
{
button1CounterStarted = 0;
button1Counter = 0;
}
}
if (button2CounterStarted)
{
button2Counter++;
if (button2Counter >= BUTTON_TIMEOUT)
{
button2CounterStarted = 0;
button2Counter = 0;
}
}
// Debounce START_PIN
if (startButtonCounterStarted)
{
startButtonCounter++;
if (startButtonCounter >= 2)
{
startButtonCounterStarted = 0;
startButtonCounter = 0;
}
}
}
// Callback function that defines the behaviour in case of some received I2C bytes
void receiveEvent(int howMany)
{
// Read the incoming bytes
cmd[0] = Wire.read();
if (Wire.available())
cmd[1] = Wire.read();
if (Wire.available())
cmd[2] = Wire.read();
// Get rid of any other unread message
while (Wire.available() != 0)
{
Wire.read();
}
// Notify the loop() that there's a new command to be handled
newCmd = 1;
}
// Callback function that defines the behaviour in case of a received request
// for a global state update -> send the global state to the Rapsberry Pi
void requestEvent()
{
// Prepare the message to be sent
globalState[0] = started;
globalState[1] = succeed;
globalState[2] = speedSetting;
globalState[3] = doorUnlocked;
globalState[4] = initDone;
globalState[5] = winningPosition1;
globalState[6] = winningPosition2;
// Send the global state to the raspberry pi
for (int i=0; i<GLOBAL_STATE_SIZE; i++)
{
Wire.write(globalState[i]);
}
}
/************************************************************************************************/
/********************************** Initializations *********************************************/
/************************************************************************************************/
// Initialize the I2C
void initI2C(void)
{
Wire.begin(0x18);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
// Disable internal pullup
digitalWrite(SCL_PIN, LOW);
digitalWrite(SDA_PIN, LOW);
}
// Motor control related intializations
void initMotors(void)
{
// Initialize timer 0 to generate a square wave on OC0A (CTL_M1 - D6)
// Toggle OC0A on compare match (non-PWM mode), WF gen CTC mode
TCCR0A = _BV(COM0A0) | _BV(WGM21);
// Prescale = 1024 => period = 2 * 64us * (OCR0A+1);
TCCR0B = _BV(CS02) | _BV(CS00);
// Set initial value of compare (sets the frequency)
OCR0A = MAX_SPEED;
// => Changing OCR0A value will set frequency of the square wave and thus the motors speed
// Initialize timer 2 to generate a square wave on OC2A (CTL_M2 - D11)
// Toggle OC2B on compare match (non-PWM mode), WF gen CTC mode
TCCR2A = _BV(COM2A0) | _BV(WGM21);
// Prescale = 1024 => period = 2 * 64us * (OCR2A+1);
TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
// Set initial value of compare (sets the frequency)
OCR2A = MAX_SPEED;
// => Changing OCR0A value will set frequency of the square wave and thus the motors speed
// Set the correct modes and initialize all the pins that are necessary for motor control
pinMode(CTL_M1, OUTPUT);
pinMode(CTL_M2, OUTPUT);
pinMode(DIR_M1, OUTPUT);
pinMode(DIR_M2, OUTPUT);
pinMode(EN_M1, OUTPUT);
digitalWrite(EN_M1, LOW);
pinMode(EN_M2, OUTPUT);
digitalWrite(EN_M2, LOW);
}
// Initialize pins and interrupts for the encoder
void initEncoder(void)
{
// Configure pin change interrupts (PCINT) on A1, B1, A2 and B2
// -> PCIE2 group
PCICR = _BV(PCIE2);
// Configure PCIE2 interrupt mask
PCMSK2 = _BV(PCINT19) | _BV(PCINT20) | _BV(PCINT21) | _BV(PCINT23);
pinMode(A1_PIN, INPUT);
pinMode(B1_PIN, INPUT);
pinMode(A2_PIN, INPUT);
pinMode(B2_PIN, INPUT);
}
// Initialize timer1 to overflow every 100 ms (used for timing related things)
void initDirectionTimer(void)
{
// Timer 1 config : normal mode
TCCR1A = 0;
// Prescaler 64 ; CTC mode
TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12);
TIMSK1 = 0b00000010;
// Initiate Timer 1 and compare A value
TCNT1 = 0;
OCR1A = 25000; // overflow every 100ms
}
/************************************************************************************************/
/****************************** Motor-related functions *****************************************/
/************************************************************************************************/
// Set the speed of a particular motor
void setMotorSpeed(uint8_t motor, uint8_t motorSpeed, uint8_t dir)
{
// Make sure the speed isn't too fast
if (motorSpeed < MAX_SPEED)
motorSpeed = MAX_SPEED;
// Set the speed by setting OCRxA and the direction by setting DIR_Mx pin
if (motor == MOTOR1)
{
OCR0A = motorSpeed;
digitalWrite(DIR_M1, dir);
}
else if (motor == MOTOR2)
{
OCR2A = motorSpeed;
digitalWrite(DIR_M2, dir);
}
}
// Set the speed of both motors at the same time
void setAllMotorSpeed(uint8_t motorSpeed)
{
// Make sure the speed isn't too fast
if (motorSpeed < MAX_SPEED)
motorSpeed = MAX_SPEED;
OCR0A = motorSpeed;
OCR2A = motorSpeed;
}
// Stop a particular motor by setting its "Not_EN" pin
void stopMotor(uint8_t motorID)
{
if (motorID == MOTOR1)
{
digitalWrite(EN_M1, HIGH);
}
else
{
digitalWrite(EN_M2, HIGH);
}
}
// Stop all motors by setting their "Not_EN" pin
void stopAllMotors (void)
{
digitalWrite(EN_M1, HIGH);
digitalWrite(EN_M2, HIGH);
}
// Start a particular motor by clearing its "Not_EN" pin
void startMotor(uint8_t motorID)
{
if (motorID == MOTOR1)
{
digitalWrite(EN_M1, LOW);
}
else
{
digitalWrite(EN_M2, LOW);
}
}
// Start all motors by clearing their "Not_EN" pin
void startAllMotors (void)
{
digitalWrite(EN_M1, LOW);
digitalWrite(EN_M2, LOW);
}
/************************************************************************************************/
/********************************** Other functions *********************************************/
/************************************************************************************************/
// Check is the player has pushed the button to stop the needles
// and implement corresponding behavior
void buttonManager(void)
{
// Has player pushed button 1 ?
if (!digitalRead(STOP_M1))
{
// If we're not in a button timeout period, stop the motors
if (!button1CounterStarted)
{
stopMotor(MOTOR1);
motor1Started = 0;
button1CounterStarted = 1;
}
}
else
{
if (!button1CounterStarted)
{
startMotor(MOTOR1);
motor1Started = 1;
}
// Keep the motor stopped during the timeout period
else
{
stopMotor(MOTOR1);
motor1Started = 0;
}
}
// Has player pushed button 2 ?
if (!digitalRead(STOP_M2))
{
// If we're not in a button timeout period, stop the motors
if (!button2CounterStarted)
{
stopMotor(MOTOR2);
motor2Started = 0;
button2CounterStarted = 1;
}
}
else
{
if (!button2CounterStarted)
{
startMotor(MOTOR2);
motor2Started = 1;
}
// Keep the motor stopped during the timeout period
else
{
stopMotor(MOTOR2);
motor2Started = 0;
}
}
if (!digitalRead(STOP_M1) && !digitalRead(STOP_M2))
{
bool won1 = 0, won2 = 0;
// Check if needle 1 is in a winning position
for (int i=0; i<2*WINNING_POS_TOLERANCE+1; i++)
{
if (position1 == winningPositionList1[i])
{
won1 = 1;
break;
}
}
// Check if needle 2 is in a winning position
for (int i=0; i < 2*WINNING_POS_TOLERANCE+1; i++)
{
if (position2 == winningPositionList2[i])
{
won2 = 1;
break;
}
}
// If both are winnin, the player won
if (won1 && won2)
{
digitalWrite(DOOR_PIN, HIGH);
doorUnlocked = TRUE;
Serial.println("WINNER");
succeed = 1;
started = 0;
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
// Make sure all motors are stopped (in case the switches has been pushed between the previous "if" and this one
// (happened once...)
stopAllMotors();
}
}
}
// Manages the direction changes
// This function is called whenever on of the direction change counter value has changed
void directionManager(void)
{
uint8_t newSpeed;
// Check if our counter has overflowed
if (directionChangeCounter1 >= directionChangeCounterTopValue1)
{
// Switch the direction
direction1 = !direction1;
// Reset the counter
directionChangeCounter1 = 0;
// Find the next value in the randomSeq array -> time intervals are random
index1 = (index1+1)%SIZE_RAND_SEQ;
directionChangeCounterTopValue1 = randomSeq[index1];
// Modify the speed according to the time value
// long time value <=> faster speed
// short time value <=> slower speed
if (directionChangeCounterTopValue1 < 10)
newSpeed = speedSetting + 4;
else if (directionChangeCounterTopValue1 < 15)
newSpeed = speedSetting + 2;
else
newSpeed = speedSetting;
setMotorSpeed(MOTOR1, newSpeed, direction1);
}
// Same as for motor 1...
if (directionChangeCounter2 >= directionChangeCounterTopValue2)
{
direction2 = !direction2;
directionChangeCounter2 = 0;
index2 = (index2+1)%SIZE_RAND_SEQ;
directionChangeCounterTopValue2 = randomSeq[index2];
if (directionChangeCounterTopValue2 < 10)
newSpeed = speedSetting + 4;
else if (directionChangeCounterTopValue2 < 15)
newSpeed = speedSetting + 2;
else
newSpeed = speedSetting;
setMotorSpeed(MOTOR2, newSpeed, direction2);
}
}
// Defines how the uC reacts to i2c commands from raspberry pi server
void i2cCommandManager(void)
{
// Did we get any command from the server ?
if (newCmd)
{
// Serial.print("i2c = ");
// Serial.print(cmd[0]);
// Serial.print(" ");
// Serial.print(cmd[1]);
// Serial.print(" ");
// Serial.println(cmd[2]);
switch (cmd[0])
{
case CHANGE_SPEED : // Change the speed
speedSetting = cmd[1];
setAllMotorSpeed(speedSetting);
Serial.print("speed = ");
Serial.println(speedSetting);
break;
case START : // Start and reset the game (unused, replaced by START_SPEED)
startAllMotors();
started = 1;
succeed = 0;
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
motor1Started = 1;
motor2Started = 1;
digitalWrite(DOOR_PIN, LOW);
doorUnlocked = FALSE;
Serial.println("START");
break;
case STOP : // Stop the game
stopAllMotors();
started = 0;
digitalWrite(STARTED_PIN, started);
motor1Started = 0;
motor2Started = 0;
Serial.println("STOP");
break;
case INIT_POS : // Calibrate the encoder according to the needles positions the user typed on the html form
position1 = cmd[1];
position2 = cmd[2];
initDone = TRUE;
Serial.print("Init Pos = ");
Serial.print(position1);
Serial.print(" ");
Serial.println(position2);
break;
case START_SPEED : // Reset, start and set the speed
startAllMotors();
started = 1;
succeed = 0;
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
motor1Started = 1;
motor2Started = 1;
digitalWrite(DOOR_PIN, LOW);
doorUnlocked = FALSE;
Serial.print("START SPEED = ");
speedSetting = cmd[1];
setAllMotorSpeed(speedSetting);
Serial.print("speed = ");
Serial.println(speedSetting);
break;
case RESET_CMD : // Reset the game without starting it
stopAllMotors();
succeed = 0;
started = 0;
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
motor1Started = 0;
motor2Started = 0;
digitalWrite(DOOR_PIN, LOW);
doorUnlocked = FALSE;
Serial.println("RESET");
break;
case GO_TO_POS : // Make the needles go to a certain position
Serial.print("Go to pos ");
Serial.print(cmd[1]);
Serial.print(" ");
Serial.println(cmd[2]);
goToPosition(cmd[1], cmd[2]);
break;
case UNLOCK_DOOR : // Unlock the door
digitalWrite(DOOR_PIN, HIGH);
doorUnlocked = TRUE;
Serial.println("Unlock the door");
break;
case LOCK_DOOR : // Lock the door
digitalWrite(DOOR_PIN, LOW);
doorUnlocked = FALSE;
Serial.println("Lock the door");
break;
case CHANGE_WINNING_POS : // Redefine the winning position, which is written on the EEPROM to keep it when the uC has been stopped
winningPosition1 = cmd[1];
winningPosition2 = cmd[2];
EEPROM.write(EEPROM_1, winningPosition1);
EEPROM.write(EEPROM_2, winningPosition2);
determineWinningPositions();
Serial.print("Change win. pos. to (");
Serial.print(cmd[1]);
Serial.print(",");
Serial.print(cmd[2]);
Serial.println(")");
break;
}
newCmd = 0;
}
}
// Print the current needles position for debug purposes
void printPosition(bool b)
{
if (printPos && b)
{
Serial.print(position1);
Serial.print(" ");
Serial.println(position2);
printPos = 0;
}
}
// Make the needles go to the position the user submitted on the html form
void goToPosition(uint8_t position1_, uint8_t position2_)
{
// Set the speed pretty slow and make sure the motors are started
setAllMotorSpeed(45);
startAllMotors();
bool okPos1 = 0, okPos2 = 0;
// turn the needles clockwise until the both reach the desired position
while(!(okPos1 && okPos2))
{
if (position1 == position1_)
{
stopMotor(MOTOR1);
okPos1 = 1;
}
if (position2 == position2_)
{
stopMotor(MOTOR2);
okPos2 = 1;
}
}
setAllMotorSpeed(speedSetting);
}
// Determine the new motor position when there's been a change on the encoder pins
void readEncoder(void)
{
// The binary combinations of A1 and B1 is always, in decimal :
// 3 2 0 1 3 2 0 1 3 2 0 1 ... when the motor is rotating clockwise
// 1 0 2 3 1 0 2 3 1 0 2 3 ... when the motor is rotating anticlockwise
// Knowing this we can deduce from A1-B1 combinations which way the motor is turning
currentA1 = digitalRead(A1_PIN);
currentB1 = digitalRead(B1_PIN);
// Serial.print(currentA1);
// Serial.print(currentB1);
// Serial.print(" ");
currentState1 = ((char)currentA1<<1) + currentB1;
if (currentState1 != previousState1)
{
if (currentState1 == STATE0)
{
if (previousState1 == STATE3)
{
position1++;
if (position1 == 60)
position1 = 0;
}
else if (previousState1 == STATE1)
{
position1--;
if (position1 == -1)
position1 = 59;
}
}
if (currentState1 == STATE1)
{
if (previousState1 == STATE0)
{
position1++;
if (position1 == 60)
position1 = 0;
}
else if (previousState1 == STATE2)
{
position1--;
if (position1 == -1)
position1 = 59;
}
}
if (currentState1 == STATE2)
{
if (previousState1 == STATE1)
{
position1++;
if (position1 == 60)
position1 = 0;
}
else if (previousState1 == STATE3)
{
position1--;
if (position1 == -1)
position1 = 59;
}
}
if (currentState1 == STATE3)
{
if (previousState1 == STATE2)
{
position1++;
if (position1 == 60)
position1 = 0;
}
else if (previousState1 == STATE0)
{
position1--;
if (position1 == -1)
position1 = 59;
}
}
previousState1 = currentState1;
printPos = 1;
}
currentA2 = digitalRead(A2_PIN);
currentB2 = digitalRead(B2_PIN);
// Serial.print(currentA2);
// Serial.println(currentB2);
currentState2 = ((char)currentA2<<1) + currentB2;
if (currentState2 != previousState2)
{
if (currentState2 == STATE0)
{
if (previousState2 == STATE3)
{
position2++;
if (position2 == 60)
position2 = 0;
}
else if (previousState2 == STATE1)
{
position2--;
if (position2 == -1)
position2 = 59;
}
}
if (currentState2 == STATE1)
{
if (previousState2 == STATE0)
{
position2++;
if (position2 == 60)
position2 = 0;
}
else if (previousState2 == STATE2)
{
position2--;
if (position2 == -1)
position2 = 59;
}
}
if (currentState2 == STATE2)
{
if (previousState2 == STATE1)
{
position2++;
if (position2 == 60)
position2 = 0;
}
else if (previousState2 == STATE3)
{
position2--;
if (position2 == -1)
position2 = 59;
}
}
if (currentState2 == STATE3)
{
if (previousState2 == STATE2)
{
position2++;
if (position2 == 60)
position2 = 0;
}
else if (previousState2 == STATE0)
{
position2--;
if (position2 == -1)
position2 = 59;
}
}
previousState2 = currentState2;
printPos = 1;
}
}
void determineWinningPositions(void)
{
int firstPos = winningPosition1-WINNING_POS_TOLERANCE;
if (firstPos < 0)
firstPos =+ 60;
for (int i=0; i<(2*WINNING_POS_TOLERANCE+1); i++)
{
winningPositionList1[i] = (firstPos+i)%60;
}
firstPos = winningPosition2-WINNING_POS_TOLERANCE;
if (firstPos < 0)
firstPos =+ 60;
for (int i=0; i<(2*WINNING_POS_TOLERANCE+1); i++)
{
winningPositionList2[i] = (firstPos+i)%60;
}
}
The header is included at the beginning of "Sketch.cpp" :
#include <Arduino.h>
#include "LetMeOut.h"
ISR(TIMER1_COMPA_vect );
ISR(PCINT2_vect );
bool debug = 0;
uint8_t directionChangeCounter1 = 0, directionChangeCounter2 = 0;
uint8_t directionChangeCounterTopValue1 = 10;
uint8_t directionChangeCounterTopValue2 = 10;
bool direction1 = 0;
bool direction2 = 0;
bool counterChanged = 0;
uint8_t button1Counter = 0;
bool button1CounterStarted = FALSE;
uint8_t button2Counter = 0;
bool button2CounterStarted = FALSE;
volatile uint8_t startButtonCounter = 0;
volatile bool startButtonCounterStarted = FALSE;
uint8_t cmd[3] = {0,0,0};
uint8_t globalState[GLOBAL_STATE_SIZE];
bool newCmd = 0;
uint8_t index1 = 0;
uint8_t index2 = 64;
uint8_t speedSetting = MAX_SPEED;
volatile bool started = 0;
bool initDone = FALSE;
bool doorUnlocked = FALSE;
volatile bool currentA1, currentB1, currentA2, currentB2;
volatile int currentState1, previousState1, currentState2, previousState2, position1, position2;
volatile bool printPos = 0;
uint8_t winningPosition1;
uint8_t winningPosition2;
volatile bool succeed = 0; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
volatile bool motor1Started = 0;
volatile bool motor2Started = 0;
int* winningPositionList1;
int* winningPositionList2;
void setup()
{
Serial.begin(2000000);
Serial.println("****************************************************************");
Serial.println("******************** L'horloge déjantée ************************");
Serial.println("************* Eric Bohnes - ISIB 2017-2018**********************");
Serial.println("****************** Master 2 Electronique ***********************");
Serial.println("****************** Cours de Mécatronique ***********************");
Serial.println("*****Collaboration avec l'Escape Game LET ME OUT Bruxelles *****");
Serial.println("****************************************************************\n\n");
initMotors();
initDirectionTimer();
initI2C();
initEncoder();
// Set the player's STOP buttons on INPUT_PULLUP
pinMode(STOP_M1, INPUT_PULLUP);
pinMode(STOP_M2, INPUT_PULLUP);
pinMode(SUCCEED_PIN, OUTPUT);
pinMode(STARTED_PIN, OUTPUT);
// Enable global interrupts
interrupts();
pinMode(START_PIN, INPUT_PULLUP);
stopAllMotors();
winningPosition1 = EEPROM.read(EEPROM_1);
winningPosition2 = EEPROM.read(EEPROM_2);
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
winningPositionList1 = (int*)malloc((2*WINNING_POS_TOLERANCE+1)*sizeof(int));
winningPositionList2 = (int*)malloc((2*WINNING_POS_TOLERANCE+1)*sizeof(int));
determineWinningPositions();
}
void loop()
{
// If the player didn't succeed yet, check we must change a direction or if the player pushed a button
if (!succeed)
{
// Check if it's time to change direction
if (counterChanged)
directionManager();
// If the game is started, poll the buttons
if (started)
buttonManager();
// Set the parameter TRUE for debugging purposes
printPosition(FALSE);
}
i2cCommandManager();
if (!digitalRead(START_PIN))
{
if (!startButtonCounterStarted)
{
startAllMotors();
started = 1;
succeed = 0;
digitalWrite(STARTED_PIN, started);
digitalWrite(SUCCEED_PIN, succeed);
motor1Started = 1;
motor2Started = 1;
doorUnlocked = FALSE;
digitalWrite(DOOR_PIN, LOW);
Serial.println("Started by pin");
startButtonCounterStarted = TRUE;
startButtonCounter = 0;
}
}
}
ISR(TIMER1_COMPA_vect)
{
Timer1_ISR();
}
ISR(PCINT2_vect)
{
readEncoder();
}
As I said before, I copied/pasted the sketch in Arduino IDE and it compiles without any errors with this tool. When trying to compile with Atmel Studio, I tried to build/rebuild the solution, the sketch itself, with and without cleaning first, still get the error.
Here is a solution explorer printscreen :
Any clue would be appreciated !
Best regards.
Eric
This question already has answers here:
What are forward declarations in C++?
(8 answers)
Closed 5 years ago.
Im working with Arduino IDE, which doesn't allow nested functions, or calling a function before it had been declared(it doesnt jump to find it)..
In my code, I need either one or the other..
Also, making it all one big function does not work because when i check back to an earlier sensor, i have to write what to do if yes and if no over and over forever.
Here, im trying to sense light, if theres light, go to the PIR sensor, if not, run light sensor again. now if the PIR senses motion twice in 3.5 sec, check color, if not, check light.
Now the color senses color and clasifies it(r g or b). now it checks for PIR again and if there's movement, it check color again and checks pir again. now if the pir doesnt sense movement, it sends to the lines to serial..
I declared some functions before I used them(print lines) but some of them not because i get stuck in a loop.
When i check light, if its positive, i run the PIR,so i would need to declare the pir function before ligth. but in the pir, if its negative(no movement), i run light sensor, implying that i should declare light sensor before pir.
Im stuck in that loop...
int lightPin = A0;
int valLight = 0;
int ledTrans = 2;
int pirTrans = 3;
int pirPin = 4;
int pirState = LOW;
int CalTime = 30;
int colorTrans = 5;
int s2 = 6;
int s3 = 7;
int OUTpin= 8;
boolean RD= false;
boolean GD = false ;
boolean BD = false;
int rfPin = 9;
void setup() {
pinMode(A0,INPUT);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,INPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,INPUT);
pinMode(9,OUTPUT);
Serial.begin(9600);
}
void printlines();
void pirSensor();
void colorSensor();
void pirSensor2();
void lightSensor() {
//light sensor
valLight = analogRead(A0);
delay(1000);
if (valLight >= 300) {
ledTrans = HIGH;
pirTrans = HIGH;
pirSensor();
} else {
delay(8000);
}
}
void pirSensor() {
// Calibration
for ( byte i = 0; i < 30; i++) {
delay(1000);
}
// Check PIR state
int pirState = digitalRead(2);
delay(1500);
pirState = digitalRead(2);
if (pirState == HIGH) {
colorTrans = HIGH;
colorSensor();
} else if (pirState == LOW) {
pirState = LOW;
lightSensor();
}
}
void colorSensor(){
//Check Color reads pulse for RGB
// void checkred
digitalWrite(s2, LOW);
digitalWrite(s3, LOW);
unsigned int RW = 255 - (pulseIn(OUTpin, LOW)/ 400 - 1); // turns into 0-255
delay(6000);
// void checkgreen
digitalWrite(s2,LOW);
digitalWrite(s3,HIGH);
unsigned int GW = 255 - (pulseIn(OUTpin, LOW)/ 400 - 1);
delay(6000);
// void checkblue
digitalWrite(s2, HIGH);
digitalWrite( s3, HIGH);
unsigned int BW = 255 - (pulseIn(OUTpin, LOW) / 400 - 1);
delay(6000);
// seeing which color I got(r g or b)
if (RW > BW && RW > GW){
RD = true;
delay(7000);
} else if (GW > RW && GW > BW){
GD = true;
delay(7000);
} else if (BW > RW && BW > GW){
BD = true;
delay(4000);
}
}
void pirSensor2(){
pirState = digitalRead(2);
delay(1500);
pirState = digitalRead(2);
if(pirState = HIGH){
colorSensor();
}else{
printlines();
}
}
void printlines(){
if(RD){
Serial.print("RED DETECTED");
} else if(GD){
Serial.print("GREEN DETECTED");
}else if(BD){
Serial.print("BLUE DETECTED");
}else if(RD && GD){
Serial.print("RED & GREEN DETECTED");
}else if(RD && BD){
Serial.print("RED & BLUE DETECTED");
}else if(BD && GD){
Serial.print("GREEN & BLUE DETECTED");
}else if(RD && GD && BD){
Serial.print("RED, GREEN, BLUE DETECTED");
}
delay(7000);
}
You can declare a function before you define it:
void setup();
Then you can call it:
setup();
...and somewhere later in the file you can write its definition:
void setup() {
// implementation here
}