In the last post First Steps - Intel Edison Arduino
I managed to get the Intel Edison running on both Laptop and Computer.
I was able to upload the blink sketch and run it.
The sketch doesn't run at bootup, but that's expected (there is a tweak to make it auto-run).
Test Sketch
I have a sketch that uses One Wire, I2C LCD, and some Inputs and Outputs.
This is my "go-to" test sketch for a new IDE or board, and it's only fair I throw it at the Intel Edison.
/* LCD Display of max and min temperatures using an I2C display. Allows setting of the Temp Trigger between TempMin and TempMax using a pot. DS18B20 Temperature chip on pin 2 4k7 pullup between pin 2 and +5v. Reads temp and records the highest and lowest readings. Assumes a read time of 1sec, and goes back to loop to wait for the 1 sec to be up before reading the data. This allows the sketch to do other time critical tasks rather than using delay(1000) which holds up other process'es. Uses a 16x2 I2C LCD Backlight Display The LCD Connections are: GND to GND VCC to +5v SDA to A4 (Arduino) SCL to A5 (Arduino) Arduino Pin assignments Pin D0 Rx Pin D1 Tx Pin D2 Temp sensor DS18B20 data pin with 4k7 external pullup resistor to +5v Pin D3 Buzzer (Low to operate) Pin D4 Pin D5 Pin D6 Pin D7 Pin D8 Pin D9 Pin D10 Pin D11 Relay (High to operate) Pin D12 Pushbutton (with onboard pullup) Pin D13 On board Led Pin A0 Rotary sensor (pot) Pin A4 (SDA) to SDA Pin A5 (SCL) to SCL Created by Mark Beckett References: ------------------------------------------------ http://www.arduino.cc/en/Tutorial/LiquidCrystal ------------------------------------------------ Version 0.1 Initial Code started Apr 2014 (using previous code) 0.2 May 2014 Tidy outstanding issues --------------------------------------------------- To Do : */ // include the library code: #include <LiquidCrystal_I2C.h> #include <OneWire.h> #include <Wire.h> #include <string.h> // initialize the library with the numbers of the interface pins LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display //inputs const int TempSensor = 2; // Tempsensor name const int Pushbutton = 12; // Pushbutton const int RotarySensor = A0; // RotarySensor (Range = 0-1023) //Outputs const int Buzzer = 3; // Pin 3 Buzzer Output const int Relay = 11; // Pin 11 Relay Output const int LED = 13; // Pin 13 On Board LED // DS18B20 Temperature chip i/o OneWire ds(TempSensor); // TempSensor on pin 2 byte i; byte present = 0; byte data[12]; byte addr[8]; word TReading; byte HighByte, LowByte; int SignBit, Tc_dec, Tc_100, Whole, Fract; int HWhole, HFract; //High reading int LWhole, LFract; //Low reading boolean Sign, LSign, HSign; //sign for the readings 1= positive long ReadStartTime; long ConvTime = 1000; //Time for a conversion to take place at 9 bit resolution boolean ConvIssued = false; //Signals a reading has been started // General Purpose boolean FirstReading = true; // Flag used to set temps to the first reading int TempReading; // Temp reading as + or - figure int TempMin = 10; // min temp you can set using the rotary sensor int TempMax = 40; // max temp you can set using the rotary sensor //LCD Scrolling message char LCDMessage[8] ; // 7 char (0-6) scrolling message plus a null. byte MessageStartPosition =0; byte MessageStringCount; byte LCDPosition =0; char MessageString[] = "Current Temperature "; // message to be scrolled int ScrollDelay = 300; // Delay for the char scrolling. long LastScroll =0; // timer used in the delay //Settings int HighTempOn = 29; // High Temperature On setting int HighTempOff = (HighTempOn -3); // High Temperature Off setting (4 deg below the HighTempOn) boolean SetMode = LOW; // SetMode goes HIGH when setting temp boolean BuzzerMode = LOW; // Buzzer Mode is ON, Goes HIGH to turn OFF // Button handling variables boolean ButtonState = HIGH; // records the Button State unsigned long LastButtonCheck = 0; // Time the Buttons were last checked. unsigned long ButtonPressTime = 0; // Time the last button was pressed. int ButtonCount = 0; // Button counter int ButtonTimeout = 10000; // Timeout after button is pressed. (10 secs) //------------------------------------------------ void setup() { // set up the LCD's number of rows and columns: lcd.init(); // initialize the lcd Wire.begin(); // for the One Wire device //Serial.begin(57600); // remove the '//' at the start to output to serial lcd.clear(); lcd.noCursor(); // Tell the library not to flash the cursor lcd.backlight(); // Turn on the backlight //Define the pins pinMode(TempSensor, INPUT); pinMode(Pushbutton, INPUT); pinMode(RotarySensor, INPUT); pinMode(Buzzer, OUTPUT); digitalWrite(Buzzer, HIGH); // Turn OFF the Buzzer pinMode(Relay, OUTPUT); digitalWrite(Relay, LOW); // Turn OFF the Relay pinMode(LED, OUTPUT); digitalWrite(LED, LOW); // Turn OFF the LED //digitalWrite(LCDBack, HIGH); // Print a message to the LCD. lcd.setCursor(0,0); // First position (0) and first line (0) lcd.print (" Initialising"); lcd.setCursor(0,1); // First position (0) and second line (1) lcd.print (" M.Beckett 2014"); delay(1800); // check the outputs digitalWrite(Buzzer, LOW); digitalWrite(Relay, HIGH); digitalWrite(LED, HIGH); delay(200); digitalWrite(Buzzer, HIGH); digitalWrite(Relay, LOW); digitalWrite(LED, LOW); findDevices(); // Call the routine to check if there are any One Wire devices LastScroll = millis(); // check the time for the LCD message to be seen ReadTemp(); delay(5000-((millis())- (LastScroll))); // this should end up as 1.5 secs lcd.clear(); LastScroll=0; LCDScrollingMessage(); } void loop() /* This runs after setup and continuously loops or runs Code can be entered here, or as in this example a means of calling the other routines. */ { ReadTemp(); // Sets ConvIssued. Compares millis() with [ReadStartTime] and [ConvTime] before collecting the reading. Check_Buttons(); // Check for a button press (it will call the ProcessButton routine) RelayControl(); // Turn Relay on/off LEDControl(); // Turn LED on/off BuzzerControl(); // Turn the Buzzer on/off DisplayTemp(); // Display the current temperature if (SetMode == HIGH) // change the Temp setting { Read_RotarySensor(); // Read the potentiometer value DisplaySetTemp(); // Display the set points if ((millis()-ButtonPressTime) > ButtonTimeout) { SetMode = LOW; // SetMode is 'unset' since the button was pressed long ago lcd.clear(); // clear the message that was bigger than 7 characters } } else { MaxMinUpdate(); // Update the High and Low temperature HighLowTemp(); // Display the High and Low temperatures DisplayMessage(); // Display the scrolling message LCDScrollingMessage(); // The construct for the message } } void ReadTemp() { /* The process of reading the temp involves telling the device to process a reading There is a setup time between the command and the data being available at the register. This depends on the resolution, but with the 9 bit resolution it is approx 750mS. Rather than slow everything down, we issue the command and then return. When we come back, we check if it has been (long ConvTime = 1000 in mS) between command and current. If it has we read the register. */ if (ConvIssued != true) { ds.reset(); ds.select(addr); ds.write(0x44,1); // start conversion ConvIssued = true; // We have asked for data ReadStartTime = millis(); // note the time we asked for temperature (so we know when to come back) } if (ConvIssued && (millis() - ReadStartTime) >= ConvTime) { /* This is the delay....The program should do the reset, and come back when the time is up. */ present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad } else { return; //either there was no conversion issued, or time is too soon. } for ( i = 0; i < 9; i++) // we need 9 bytes { data[i] = ds.read(); } LowByte = data[0]; HighByte = data[1]; TReading = (HighByte << 8) + LowByte; SignBit = TReading & 0x8000; // test most sig bit if (SignBit) // negative { Sign = 1; TReading = (TReading ^ 0xffff) + 1; // 2's comp } Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25 if (SignBit) //negative { TempReading = (0 - Tc_100); } else { TempReading = Tc_100; } Whole = Tc_100 / 100; // separate off the whole and fractional portions Fract = Tc_100 % 100; // the two lines below force the fraction portion to e 1 decimal place ie 23.7 rather than 23.73 Fract =Fract /10; Fract = Fract *10; ConvIssued = false; // means we got a reading back } void MaxMinUpdate() { /* Update the Max and Min settings using the last reading If the temp is negative, then the comparison flips More work required on the Highest reading if the previous High was in negative figures, and it goes above zero. Perhaps converting the High/Low temp storage to use the sign int, rather than a two part figure. */ if (FirstReading == true && Tc_100 != 0000) //Temp is negative ; make LWhole and LFrac into 4 digit number { //Serial.print (Whole,DEC); // if you uncomment this it will go to the serial monitor //Serial.print (Fract, DEC); // if you uncomment this it will go to the serial monitor LWhole = Whole; LFract = Fract; LSign = SignBit; HWhole = Whole; HFract = Fract; HSign = SignBit; FirstReading = false; } if (SignBit) //negative { if (Tc_100 > ((LWhole *100) + LFract)) { LWhole = Whole; LFract = Fract; LSign = SignBit; } if (Tc_100 < ((HWhole *100) + HFract)) { HWhole = Whole; HFract = Fract; HSign = SignBit; } } if (SignBit == false) //positive { if (Tc_100 < ((LWhole *100) + LFract)) { LWhole = Whole; LFract = Fract; LSign = SignBit; } if (Tc_100 > ((HWhole *100) + HFract)) { HWhole = Whole; HFract = Fract; HSign = SignBit; } } } void HighLowTemp() /* This displays the highest and lowest temp Displays over two lines | L -xx.x| |-xx.xx H -xx.x| */ { // Top line lcd.setCursor(10,0); lcd.print("L"); // first position (10) and first line (0) displays | Temp L -xx.x| lcd.setCursor(11,0); // 12th position (11) and first line (0) if (LSign) { lcd.print("-"); } else { lcd.print(" "); } lcd.setCursor(12,0); // 13th position (12) and first line (0) if (LWhole <10) { lcd.print(" "); } lcd.print(LWhole); lcd.setCursor(14,0); // 15th position (14) and first line (0) lcd.print("."); lcd.setCursor(15,0); // 16th position (15) and first line (0) if (LFract <10) { lcd.print("0"); } // Bottom line lcd.print(LFract); lcd.setCursor(10,1); // 11th position (10) and second line (1) lcd.print("H "); lcd.setCursor(11,1); // 12th position (11) and second line (1) if (HSign) { lcd.print("-"); } else { lcd.print(" "); } lcd.setCursor(12,1); // 13th position (12) and second line (1) if (HWhole <10) { lcd.print(" "); } lcd.print(HWhole); lcd.setCursor(14,1); // 15th position (14) and second line (1) lcd.print("."); lcd.setCursor(15,1); // 16th position (15) and second line (1) if (HFract <10) { lcd.print("0"); } lcd.print(HFract); } void DisplayTemp() // This displays the current temp { lcd.setCursor(0,1); // First position (0) and second line (1) if (Sign) { lcd.print("-"); } else { lcd.print(" "); } lcd.setCursor(1,1); // 2nd position (1) and second line (1) if (Whole <10) { lcd.print(" "); } lcd.print(Whole); lcd.setCursor(3,1); // 4th position (3) and second line (1) lcd.print("."); lcd.setCursor(4,1); // 5th position (4) and second line (1) if (Fract <10) { lcd.print("0"); } lcd.print(Fract); } void DisplayMessage() // This displays the 7 chars of the message on the first line { lcd.setCursor(0,0); lcd.print(LCDMessage); } void RelayControl() { //Relays are ON when the ouput pin is HIGH unless we are setting the temp using the rotarysensor if (SetMode == LOW) // only control the Relay when we aren't setting temp { if (Whole >= HighTempOn) // reading is greater or equal to the ON setting { digitalWrite(Relay,HIGH); } if (Whole <= HighTempOff) // reading is lower or equal to the OFF setting { digitalWrite(Relay,LOW); } } else { digitalWrite(Relay,LOW); } } void LEDControl() { // This turns on the LED if (Whole >= HighTempOn) // reading is greater or equal to the ON setting { digitalWrite(LED,HIGH); // LED on } if (Whole <= HighTempOff) // reading is lower or equal to the OFF setting { digitalWrite(LED,LOW); // LED off } } void BuzzerControl() { //Buzzer is ON when the ouput pin is LOW unless we are setting the temp using the rotary sensor if (SetMode == LOW) // only control the Buzzer when we aren't setting temp { if (Whole >= HighTempOn) // reading is greater or equal to the ON setting { digitalWrite(Buzzer,LOW); // Buzzer is ON } if (Whole <= HighTempOff) // reading is lower or equal to the OFF setting { digitalWrite(Buzzer,HIGH); // Buzzer is OFF BuzzerMode = LOW; // Reset the Buzzer mode as the temp is below the OFF setting } } else { digitalWrite(Buzzer,HIGH); // Buzzer is OFF } if (BuzzerMode == HIGH) // turn off the buzzer as the button was pressed to silence it. { digitalWrite(Buzzer,HIGH); // Buzzer is OFF } } void Check_Buttons() /* This routine checks the timer (LastButtonCheck) and if necessary reads the button input If the button is detected, it waits until it counts it 5 times at the set time rate. This prevents button bounce from triggering and ensures the button is pressed. Once a valid button press has been detected, it starts a timer (ButtonPressTime) */ { if (millis() - LastButtonCheck > 5) // Reads button state every 5mS and then updates button counts { ButtonState = digitalRead(Pushbutton); LastButtonCheck = millis(); if (ButtonState == LOW) { ButtonCount ++; // Increment the Count by 1 if (ButtonCount > 5) // the button should be LOW for 5x5mS = 25mS { // Button has been pressed for longer than 25mS so its valid ButtonPressTime = millis(); // set the Button press timer ButtonCount = 0; ProcessButton(); // Do something with the valid button press } } else // Button is HIGH { ButtonCount =0; // Reset the counter as the button has been released } } } void ProcessButton() // this processes what the valid button press does. Called from Check_Buttons { if (BuzzerMode == LOW && (digitalRead(Buzzer)) == LOW) //Buzzer is ON { BuzzerMode = HIGH; return; } if (SetMode == LOW) { SetMode = HIGH; // SetMode is 'set' since the button press was valid } } void Read_RotarySensor() { if (SetMode == HIGH) // Reads the rotary position sensor { int val = analogRead(RotarySensor); HighTempOn = map(val, 0, 1023, TempMin, TempMax); // AnalogRead is between 0 and 1023, we need to set it between the HighTempon and HighTempOff HighTempOff = (HighTempOn -3); // The -3 means the Low Temp will be 3 degrees lower than the set temperature } } void LCDScrollingMessage() { /* This demonstrates how to scroll a portion of the LCD The basic principle is to construct a message, find the length of the message. You then grab xx chars from the message to display. Each time you loop, you shift along the message one place and grab xx chars, and repeat. When you reach the end of the message, start grabbing from the beginning. A space at the end of the message, makes the message look correct on the LCD as it loops. Don't let the loop run too fast. */ MessageStringCount = (sizeof(MessageString))-1; // Last character in a string is a null, which is counted. Serial.println(MessageStringCount,DEC); if ((millis()-LastScroll) >=ScrollDelay) { for (i = 0; i <7; i++) //there is room for 7 chars (i = 0 to 6) { LCDPosition = MessageStartPosition +i; if (LCDPosition >= MessageStringCount) { LCDPosition = LCDPosition - MessageStringCount; } LCDMessage[i] = MessageString[LCDPosition]; } LCDMessage[7] = 0; //terminate the string with a null MessageStartPosition +=1; if (MessageStartPosition >= MessageStringCount) { MessageStartPosition =0; } LastScroll = millis(); } } void DisplaySetTemp() /* This shows the highest and lowest temp Displays over two lines *** Counting starts at zero *** | L -xx.x| |-xx.xx H -xx.x| */ { lcd.setCursor(10,0); // first position (10) and first line (0) lcd.print("L"); // displays | Temp L -xx.x| lcd.setCursor(11,0); // 12th position (11) and first line (0) lcd.print(" "); lcd.setCursor(12,0); // 13th position (12) and first line (0) if (HighTempOff <10) { lcd.print(" "); } lcd.print(HighTempOff); // variable HighTempOff lcd.setCursor(14,0); // 15th position (14) and first line (0) lcd.print("."); lcd.print("0"); lcd.setCursor(10,1); lcd.print("H "); lcd.setCursor(11,1); lcd.print(" "); lcd.setCursor(12,1); // 13th position (12) and second line (1) lcd.print(HighTempOn); // variable HighTempOn lcd.setCursor(14,1); // 15th position (14) and second line (1) lcd.print("."); lcd.print("0"); // this displays the LCD message which is 7 characters long lcd.setCursor(0,0); lcd.print("*SetTemp*"); } void findDevices() { /* This routine is called once to find any One Wire devices and obtain their address. Once the address is found it is checked to to see if it is a Temperature Sensor (hex 28 or 0x28) */ if ( !ds.search(addr)) { ds.reset_search(); } if ( addr[0] != 0x28) { lcd.clear(); lcd.setCursor(0,0); lcd.print(" No Temp Sensor"); lcd.setCursor(0,1); lcd.print("Check connection"); delay(5000); return; } }
We use this in the Futureintech 'Introduction to Arduino' to show the pupils how you can connect various bits together and have them interact to display stuff.
It was purposely written to be followed by almost anyone (even me )
Before uploading to the Edison I connected the items to an Arduino and fired it up.
Sure enough all the bits worked (the buzzer needed new selloptape to quieten it ..)
The next job was to connect it to the version1 Grove base plate I had.
I'd brought this some time ago thinking that the Grove system would be useful for teaching pupils, and it is.
Ultimately we went with a slightly different version due to costs and we connect directly to our Arduino's without the base plate.
For whatever reason I have only one lead (Plans to fix that are on the way), so some improvisation was required.
I did have a bunch of Grove end to individual sockets and some long header pins.
I decided that the LCD could be connected easily, the pushbutton using the lead, and the Temperature sensor and rotary pot via 6 header pins.
(it's not very nice so no photo ...)
I can worry about the buzzer and relay later ....
Hook it all up, apply power .... and no smoke ....
Click Upload and it comes up with some warnings and a fatal error.
Some ID 10 T forgot to include the LiquidCrystal_I2C library.
Add that to the libraries folder and restart the IDE.
Click Upload and more warnings, but it does transfer it, and the display blanks then comes up with
Initialising
M.Beckett 2014
Unfortunately it doesn't want to detect the temperature sensor, so the sketch gives the warning.
No Temp Sensor
Check connection
The scrolling is pausing slightly, so there is something in the timing that is affecting it.
I'm using Millis() and I suspect some more digging is required.
It could be that it can't detect the DS18B20, and I'll need to compare it on an Arduino to see.
The sketch only checks for the DS18B20 at startup, so I need a way to restart the sketch.
I also need to resolve the warning about the I2C library in case it might be having some effect.
I2C and Edison
I've found a few posts on the internet regarding I2C and Edison.
They all relate to earlier images, and the cure was more for the Linux side, rather than Arduino.
The latest Arduino IDE has the Edison as an optional board, so surely there should be support.
Doing some digging lead me to this.
An Arduino LCD library using the PCF8574 I2C adapter.
The Library Manager will allow you to load LiquidCrystal_PCF8574
A few changes are required to the sketch
// initialize the library with the numbers of the interface pins //LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_PCF8574 lcd(0x27); // set the LCD address to 0x27 for a 16 chars and 2 line display // set up the LCD's number of rows and columns: //lcd.init(); // initialize the lcd lcd.begin(16, 2); // LiquidCrystal_PCF8574 initialize the lcd //lcd.backlight(); // Turn on the backlight lcd.setBacklight(255); // LiquidCrystal_PCF8574 backlight control
The good news is that it compiles without any warnings, so there must be some differences in the .h file
Running the sketch
I've been doing some digging and it seems that the download process causes it to run the sketch.
The Edison seems to be put into a 'download over the Serial port mode', and part of that then executes the sketch.
Thats fine .... but what happens if you reset or stop the sketch.
Normally a reset of the Arduino board (power or the reset button) will restart the sketch as it boots up.
For the Edison we are talking about one 'program' running under the OS.
When we play with the Raspberry Pi we generally use Shell scripts (.sh) or Python scripts (.py) and these have their own handler/launcher.
The file is modified to be an executable, but simply running it doesn't do anything. (well except annoy it)
We can use the 'exec' command
That reply was sort of 'go-away' ... but it still didn't run.
You'll note that it also stopped the current session as you need to Login again.
In among the various things I tried adding a period (part of my redirection attempts)
It's kept running, and you can hit Ctrl C to make the shell return, and it keeps running.
I've tried running it with exec /sketch/sketch.elf & to make it run in the background, but it won't run.
One Wire
I've now spent two days trying to get the Intel Edison to detect the DS18B20 which is a One Wire device.
No matter what I do, change or use, it just will not detect it.
I've tried the Intel Arduino IDE and ver 1.8.1 and used the inbuilt examples.
I've removed the Grove base plate and fitted it directly onto an Arduino, and it works.
This means there is nothing wrong with my connections, leads, or the actual device.
So it seems to point back to how the Edison is dealing with the pins when it translates, or a severe timing issue.
I've also seen talk about which OneWire.h it uses and conflicts ....
It seems that I'm not the only person having issues going back a while.
While it was on the Arduino, I removed the sensor and rebooted it to check if the scrolling message paused.
It just carried on fine so it's not the missing sensor causing the pauses.
So ....
Be prepared that your Edison may not run the same sketch as an Arduino.
Hopefully our two Intel experts may be able to assist
Latest Arduino IDE
Normally I don't subscribe to the very latest release, but in this case there are some great advantages.
The IDE has a board detect, which is very useful to confirm you are indeed talking to the board.
What I don't like with the newer releases is where they splatter the files.
Arduino started out as a simple set of files, that would even run from a memory stick.
Now it seems they have the program wherever you install it, but once you run it it dumps files in
C:\Users\xxxxxxx\AppData\Local\Arduino15 (where xxxxx is the user login name)
This is fine if you are the only user, but it also makes it hard to copy the whole installation onto your laptop, or back it up.
Why??
You should be careful of the default settings.
I save my files into one of two directories based on version 023 or the later 1.0 version.
I normally don't bother checking for updates ... (why change for the sake of change)
You may wish to set Verbose during upload and the compiler warnings.
The dangerous one is that the Save when Verifying or Uploading is ticked by default.
It overwrote my file I started with, and luckily I'm in the habit of copying the line and commenting it out until I want to delete it.
I'm sure I'll find out about Code Folding and the Interface Scale one day.
Voltage
When the LCD fired up, the contrast was quite low.
I had to get the meter out (twice now) and check, and it was 4.05 volts which explains the contrast difference.
I did read that despite using a 5v switching regulator the 5v is OR'ed and therefore you can expect 4.4v instead of 5v.
So that explains the drop, but if I recall the Arduino board has control over which source and it happily supplies 5v ....
So if you have some voltage critical aspects of your hardware, just be aware that there could be a difference.
I've still to find out what some of the jumpers do, and a picture of the board with these highlighted would be a nice.
Where to now
Well I obviously need to get the temperature sensor working, and I might be able to do something along the lines of the RPi.
It will need a python script and to pass data between the two programs.
Mark
This started as a simple blog, but has now grown over a few posts, so an index is appropriate.
Top Comments