I am one of those few users that opened chrome://flags, and set:
Enable WebUSB support: disabled.
I already have installed a tool to program my Arduinos. I guess, it's the first thing most people install after aquiring an Arduino.
I also do not understand why i would ever use a cloud.
Perhaps i am "too oldskool".. using a browser to find what i search for, and (if it is code,) then download it.
When i want code, i do not care how i get it. Important is, that i can download it..
The bare product is what counts..
Posts made by core_c
-
RE: Browser-based firmware generator
-
RE: Message is send twice
About your battery level send question, here's some explanation:
The intention is to let your node sleep when nothing happens.
Only when the generator pin changes, it interrupts the sleep cycle, and wakes up the node. It then checks the current generator pin state and sends the appropriate message. Then it goes to sleep again.
However, it does not sleep forever. At regular intervals the battery level is send. So every BATTERY_REPORT_INTERVAL milliseconds the current sleep cycle ends (because the timer has counted down and reached its end), and the battery level is send.
The program keeps doing this: Sleep, and wake up if the pin changed, and/or wake up when the battery level should be send. -
RE: Message is send twice
@esawyja i made the changes for you in my post made earlier^^
-
RE: Message is send twice
@esawyja attachInterrupt() should only be done once, in the setup() function.
-
RE: Message is send twice
@esawyja You are right. I made a mistake. This should fix it:
Change this line:uint32_t sleep_time_left = battery_report_time - millis();
into this:
long sleep_time_left = battery_report_time - millis();
A variable of type long can hold a negative number, but an unsigned long (same as uint32_t) can never hold a negative number (because it is unsigned, no sign, no minus sign, no negative).
So, if (sleep_time_left < 0) will never be true.. That was the mistake.I was also wondering if the generator would produce interrupts without using attachInterrupt().
Without that, you can still poll the generator pin, and see if the value changed (what is happening now), but the sleep() cycle would not be interrupted when the pin changed.
To be on the safe side, i would also add the following to your code:void setup() { attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); }
Hopefully that'll make it work as intended.
-
RE: Message is send twice
@esawyja In your last program, your battery level is only send when the generator changed state.
Probably you want to let the battery report it's level at regular intervals, independent of the generator state.
Boots33 pointed out how to know if a message has been sent succesfully.
Here is a version of your sketch that does both things:#define RETRY_TIMES 3 #define RETRY_WAIT 10000 #define BATTERY_REPORT_INTERVAL 60000 int oldValue; uint32_t battery_report_time; volatile bool generator_pin_changed = false; volatile int generator_pin_value; void generator_pin_interrupt_handler() { generator_pin_changed = true; generator_pin_value = digitalRead(GENERATOR_PIN); } void setup() { oldValue = digitalRead(GENERATOR_PIN); sendGeneratorMsg(oldValue==HIGH?0:1); battery_report_time = millis() + BATTERY_REPORT_INTERVAL; attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); } void loop() { int value = digitalRead(GENERATOR_PIN); if (value != oldValue) { oldValue = value; if (value == LOW) { Serial.println("Generator RUNNING - SENDING"); sendGeneratorMsg(1); } else { Serial.println("Generator NOT running - SENDING...."); sendGeneratorMsg(0); } } long sleep_time_left = battery_report_time - millis(); if (sleep_time_left < 0) { battery_report_time = millis() + BATTERY_REPORT_INTERVAL; sleep_time_left = BATTERY_REPORT_INTERVAL; read_batt(); } sleep(digitalPinToInterrupt(GENERATOR_PIN), CHANGE, sleep_time_left); } void sendGeneratorMsg(int state) { for (int i=0; i<RETRY_TIMES; i++) { if (send(msgGENERATOR.set(state))) { Serial.println("Generator message sent"); return; } wait(RETRY_WAIT); } Serial.println("Failed to send generator message"); } void read_batt() { wait(15000); int sensorValue = analogRead(BATTERY_SENSE_PIN); float batteryV = sensorValue * volt_value; send(batt_msg.set(batteryV,2)); }
EDIT: I have changed ^^the code^^ with the suggestions i made in my next post.
-
RE: Browser-based firmware generator
the word "Generator" scores.
i personally like "MyGenerator" most.. -
RE: Message is send twice
@esawyja No, it does not matter if it's active low or active high. I was only thinking that it could be an oversight.. something wrong in code that someone (possibly) keeps missing because they are assuming that that part of the code is correct.
About what you said previously: "looks like it detects the change, but does not do anything":
Correct me if i'm wrong, but this looks like it detects, and does something:interupt 1 5429 MCO:BGN:INIT OK,TSP=1 1 Generator NOT running - SENDING.... 5441 TSF:MSG:SEND,11-11-0-0,s=6,c=1,t=2,pt=2,l=2,sg=0,ft=0,st=OK:0
After that, when the generator did not change state anymore, you will see a stream of only sleep/wake-up messages (a stream, because sleeptime is 0). I see that stream start at 5648.
In your current program, i'm curious if that second send() is really needed (the last send in the "send,wait(10000),send" sequence).
But anyway, your skills got it working.. -
RE: Building a LED status
I know 0.00001 about Vera (i know just the name), but i probably can help you light up an RGB LED.
Can you post any code you already have running on an Arduino?
I know there is a S_RGB_LIGHT message in MySensors.. So i guess: it is also known/recognized by Vera.shoot!
-
RE: Browser-based firmware generator
@rakeshpai The idea of creating a generator is really cool. There are many non-programmers out there, just wanting their sensor-network up and running.
I bet you finish this project, and make many people happy. Keep up the good work rakeshpai.
The awesome MySensors generator -
RE: Message is send twice
@esawyja I don't really know what your goal is, but is it correct to send a 1 if the generator is running, and to send a 0 when it's not running?
It seems more logical to send a 1 to enable a device, and 0 to disable it.Could it be that you disable the generator, and it simply is not responding anymore?
-
RE: Message is send twice
From your log i can see that your node goes to sleep, and immediately wakes up again.
I don't know the value of your SLEEP_TIME, but i guess it's not a value close to 0.
It looks like your sleep() cycle is interrupted by a change on your GENERATOR_PIN.
What if you inserted a short pause just before going to sleep, just after send(msgGENERATOR)?Another way to handle interrupts:
Your code uses an interrupt to detect changes of the generator status, but you handle possible changes outside the interrupt-handler (the code that is executed whenever there was a change on the pin). Your sleep function can exit in two ways: by interrupt OR by the SLEEP_TIME expiring. Your code does the same in both cases. Even if there was no change on the pin, but the timer expired, a message will be send.
If you only want to send a message when there was actually a change of signal on the pin, i would use an interrupt-handler that detects any change, and let the loop() code know about it.volatile bool generator_pin_changed = false; volatile int generator_pin_value; void generator_pin_interrupt_handler() { generator_pin_changed = true; generator_pin_value = digitalRead(GENERATOR_PIN); } void setup() { attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); } void loop() { if (generator_pin_changed) { generator_pin_changed = false; /* reset for next detection */ if (generator_pin_value == LOW) { Serial.println("Generator RUNNING"); send(msgGENERATOR.set(1)); } else { Serial.println("Generator NOT running - SENDING...."); send(msgGENERATOR.set(0)); } } wait(200); /* sleep again if the timer expired. stop sleeping if woken up by an interrupt. */ while (sleep(digitalPinToInterrupt(GENERATOR_PIN), CHANGE, SLEEP_TIME) < 0); }
-
RE: Running MySensors on ATTiny85
check!
funny.. Your post's image, and ebay's image, are both swapped horizontally.
Or is it the chinese printing it wrongly?EDIT: But they have the price just right
EDIT 2: Interesting topic tekka.
@Tinimini: What did you find out using an ATtiny85? any tests? any results?.. any problems? -
RE: Running MySensors on ATTiny85
of course!..
I know there is an (at least 1) AVR that doesn't even have RAM. So any code it runs, would have to be very optimized (registers is all one can use). That is no MCU one would use for a typical MySensors node.. true. But there are ATtiny's that can do a lot more.
I am interested in exploiting a device to the max. If it has 2 timers, and you never use one of them,.. that's a shame. It is one of the greatest features of an MCU: timers.
Everyone their own hobbyJust look at this tiny thing:
http://www.microchip.com/wwwproducts/en/ATTINY85
It's a marvel.. -
RE: Running MySensors on ATTiny85
i like it small..
"The smallest tinyAVR MCU measures only 1.5 mm x 1.4 mm." (Atmel website).
That is probably no good choice to use for a MySensors node (RAM?), but (for example) i could make any sensor an I2C sensor.
Or, if i need to detect interrupts for some hardware/sensor, i could use an ATtiny for that purpose (solely).
I guess i'll need to improve my soldering skills with the smallest one. -
RE: Running MySensors on ATTiny85
I myself was searching for ATtiny articles (Arduino & MySensors). I found not much (far less as i had expected).
I'm very interested in a ATtiny (and therefore i replied to this topic, so i'll get notifications -
RE: receive() a message while in low power mode?
I haven't tried it out for myself yet, so i can not give you my experiences but there is a controller that can do what you want.
This is what the myHouse controller says:https://sourceforge.net/p/my-house/wiki/faq/#how-is-the-mysensors-smart-sleep-handled-in-myhouse
-
RE: MySensors booth at Eindhoven Maker Faire!
That will be fun. Count me in! I'm looking forward to meet you geeks in person.
Let the nodes connect.. -
RE: π¬ myHouse
For me myHouse is by far the best controller i tried. I can configure it the way i want.. modules, widgets, nice graphs, webcams.. you name it! There are just so many options.
I did not yet try out all the things i like (like Slack bot, or running scripts, combining multiple sensors in one graph,.. etc.), but so far: i'm impressed.
My MySensors sensors (i'm not stuttering) are now being displayed in myHouse.
The only thing worth mentioning is: One should take time to read the documentation well before start changing the config file. It's not so hard to comprehend but i guess for some it can get complicated handling so many nested structures. A good editor, to change the config, can make things a lot easier (one that can collapse/expand, or even correct syntax).
I followed the instructions, created my own design/layout, got myself some API-keys, installed the software, and all worked the first time. And i had to learn about Linux as i went along because i'm a newbee Linux user. --help
Great job user2684.. -
RE: π¬ NodeManager
@Dencan That is a method i never even thought about Dencan.
Cool.. You tought me something. Thanks. I have to try it out for myself.
My first thought was jumping to the address of the RESET interrupt vector in memory.
It's located in the very first bytes at address 0.__asm__ __volatile__ ("jmp 0");
-
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
cool!..
I like that slim node. compact.
It's even more fun that it's all functioning. (y) -
RE: Help with sketch...
I did not know about the newPing.h library. (i can not find it when searching for it in the Arduino IDE).. so i googled it.
The example (for 15 sensors) confuses meCan't you just do something like this?
unsigned long pingTimer[SONAR_NUM]; unsigned int cm[SONAR_NUM]; boolean bigChange[SONAR_NUM]; void setup() { pingTimer[0] = millis() + 75; pingTimer[1] = pingTimer[0] + PING_INTERVAL; } void loop() { // your rest code here.. for (uint8_t i = 0; i < SONAR_NUM; i++) if (millis() >= pingTimer[i]) { pingTimer[i] += PING_INTERVAL; cm[i] = sonar.ping_cm(); bigChange[i] = ((doorDistance-(int)cm[i]) > 10)?true:false; } oneSensorCycle;
And adjust oneSensorCycle() to use bigChange[0] & bigChange[1] instead of bigChange_0 & bigChange_1
-
RE: Help with sketch...
Right BartE..
On this forum i read about someone connecting both USB and a power supply at the same time, and blew up his Arduino.
I do not know for sure what would happen, (never did that), but i'm not willing to test it out.. -
RE: Your workshop :)
@AWI "I soldered the thing myself so build quality is ...."
I guess the missing word is: "top", and the last dot is just interpunction. -
RE: Help with irrigation LCD display
great! it works.. happy++
The explanation:
There is the variable named inSetup.
Somewhere (outside any function) in the top of the sketch that variable is declared and at the same time initialized (given a value).
bool inSetup = true;
In the rest of the sketch, that variable's value is never changed: The value of inSetup is always the same, all the time. It's value simply remains the same.In every Arduino-sketch you're obligated to define two special functions, namely: setup() and loop(). If you don't have them in your sketch, the sketch would not compile.
The setup() function is executed only once. It is called at the beginning of any Arduino sketch. It's used to do things that only need to be done one time, like setting pins to input or output, or perhaps even displaying a startup text on a connected display.
The loop() function holds the code that is executed repeatedly. All of it's code is run, and when all that code is done executing (and the loop-code is finished), the Arduino just starts all that loop-code anew. Normally, it keeps on doing that until the power goes off.In your sketch's loop() function, there is a call to: goGetValveTimes();.
Code in the loop() is executed over and over again. That means, that also goGetValveTimes() is executed over and over again.Now suppose your LCD is full of text, already been displayed in other parts of the code.
Every loop() cycle will make a call to goGetValveTimes().
In that function named goGetValveTimes() is that block of code that is executed:if (inSetup) { lcd.print(F(" Updating ")); lcd.setCursor(0, 1); lcd.print(F(" Valve Data: ")); lcd.print(valveIndex); }
Code inside that block is always executed. It sets the cursor, and prints the valve data line.
It is always executed because the variable inSetup is always true.
Therefore no matter what was on your LCD, in every loop() cycle, that line on the display is overwritten with the valve data.. just as it is instructed to do.Another way to fix the problem, while keeping that block of code (displaying the valve data), is to set the value of variable inSetup to false at the right moment.
That way the code block is not executed anymore, and will no longer keep overwriting your text already on the display.
Probably the best moment to do that, is at the end of the setup() function. like so:void setup() { // at the end of your setup() function it would then look like this: goGetValveTimes(); } lcd.clear(); inSetup = false; }
I believe that explains what was going on in your sketch..
-
RE: Help with irrigation LCD display
Hi markcaso,
I only had a quick look at your code. I do not claim that what i see is the cause of your problems. What i posted, is just something illogical in code (for me).
A suggestion to test if it is true what i've posted: comment out the few lines of code that i think are the cause of your problem.. like so:/* if (inSetup) { lcd.print(F(" Updating ")); lcd.setCursor(0, 1); lcd.print(F(" Valve Data: ")); lcd.print(valveIndex); } */
If you then see more info being displayed, you at least know that is the spot where things are getting messed up.
I can not run your code as easily as you do.. i only see code on a webpage. For you it's easy enough to try it out.About the non-initialized variables being used in code; Here's a shortened snippet of your code:
void updateDisplay() { static unsigned long lastUpdateTime; if (state != lastDisplayState || millis() - lastUpdateTime >= 3000UL) {
The very first time those lines are executed, who can say what value lastUpdateTime may have? One can assume that the value will be 0 (after powering on the MCU), but maybe there was already a value in that exact memorylocation while the chip got some kind of soft-reset. In that case, the program will behave differently. (meaning: it does not do what you expected).
It is better to assign values to variables before using them in code (i.e. comparing them with some specific value).
As an example: If lastUpdateTime would have a value of 0xFFFFFFFF (decimal 4294967295), one could have to wait a long time before (millis() - lastUpdateTime >= 3000UL) ! up to 49.7 days (using a calculator here, assuming millis()==0).I am a super newbee too. i spent a lot of time debugging my very first gateway & sensornode. (got it working today!!!). I know only about digital electronics (i mean: using it), and really really know very little about analog stuff. There are a lot of very good experts on electronics here on this forum. If we (try to) help eachother out, everybody makes progress and both will be successful.
-
RE: Help with irrigation LCD display
In case the newly printed text is shorter than the text already on the display, probably yes.
Another thing i see in the program, is that not all variables are initialized with a value before they are used in comparisons. For example: lastUpdateTime and lastDisplayState are two of those.
Another advice: Create functions that are compact. It makes it much easier to read, and therefore easier to debug.. especially for other people (and even for yourself, after not looking at your own code for a while). -
RE: Help with irrigation LCD display
Your variable named inSetup is initialized like this:
bool inSetup = true;
That value is never changed in your code. However, it is used in the function:
void goGetValveTimes()
like this:
if (inSetup) {
lcd.print(F(" Updating "));
lcd.setCursor(0, 1);
lcd.print(F(" Valve Data: "));
lcd.print(valveIndex);
}I think some other texts are printed on the LCD, but every time that text is overwritten by ^^that little piece of code.. and you always see that Valve Data.
-
RE: π¬ NodeManager
I have a BMP280 sensor (as far as i know, they are quite similar). At first it seemed like the sensor was not detected. After inspecting the datasheet, i found out that the address could be selected (one of 2 possibilities).
Here's the text from the datasheet:Connecting SDO to GND results in slave
address 1110110 (0x76); connection it to VDDIO results in slave address 1110111 (0x77)Some people change the library code, but (like in my case), i only needed to connect the SDO pin to +3.3V.
At first i did not connect the SDO pin at all, and my sensor was not reporting at all. That was because of this:
The SDO pin cannot be left floating; if left floating, the
IΒ²C address will be undefined.Perhaps those issues can be the cause of your problems ksga?
-
RE: Gateway just another sensor node?
@hek I found that out while testing my very first/current gateway. Also, it is no good idea to define MY_DISABLED_SERIAL. (sssst, don't tell anyone i did that).
..but still, it's assuring to have my findings confirmed by an expert. -
RE: Your workshop :)
Nice to see in what environment others spend their time.
There are a lot of electronic hobbyists out there! They have more (and more) stuff than coders.
I hope that bjornhallberg has a nice desk by now.. -
RE: Software I2C slave for Arduino Uno & TFT shield (+code)
Thanks gohan..
This forum is a great source of inspiration. Lots of examples of people and their own projects, and/or problems they encounter(ed).
I'm fairly new to MySensors & Arduino, but i have a lot of experience with Atmel AVR. At this time, i'm more reading than writing: absorbing info first. Hopefully i can help out others too sometimes.. it's cool to share knowledge.I already have 10 Arduino YΓΊns & 2 Raspberries at my disposal (they belong to friends i'm helping out).
It would be fun to find a sensible application to combine a MySensors radio network (or perhaps multiple networks), and the IOT-capabilities of the YΓΊn(s) & Raspberries.
But that's another project.. -
Software I2C slave for Arduino Uno & TFT shield (+code)
I created a software I2C-slave implementation for an Arduino Uno with a TFT-shield.
The TFT occupies all pins of the Arduino Uno.
The Uno's default designated (hardware) I2C pins can not be used, because they connect to the TFT's pins that control RESET & CS. If the hardware I2C would be used, the TFT would behave irratic.
I do not use the TFT's SD card, so i can use 2 of those pins for the (software) IΒ²C bus.
Arduino pins used: 11 = SCL, 12 = SDA.
This software I2C bus operates at a +5V level.
Therefore connect the TFT I2C-slave at the high level side of the Logic Level Converter.I made a demo sketch for the slave, and a demo sketch for any other Arduino that acts as the master. The demo is simple: It just sends 5 float values to the slave, which displays it on the TFT.
Codesize is small and fast. It should not be hard to adjust the code to your own needs. The part of the code you edit, is normal Arduino code.Here's the I2C-slave TFT in action on my MySensors node, displaying the measurements:
Here is the sketch of the I2C-slave TFT:
// TFT #include <Adafruit_GFX.h> #include <UTFTGLUE.h> UTFTGLUE tft(0x9341,A2,A1,A3,A4,A0); #if !defined(SmallFont) extern uint8_t SmallFont[]; #endif #define BLACK 0x0000 #define WHITE 0xFFFF // I2C #define I2C_SLAVE_ADDRESS 73 #define SCL_BIT PB3 #define SDA_BIT PB4 #define I2C_DDR DDRB #define I2C_OUT PORTB #define I2C_IN PINB extern "C" { volatile uint8_t byteN; volatile uint8_t I2C_data; volatile union u_floatarray { uint8_t b[20]; float f[5]; } I2C_values; void InComingData(void) { I2C_values.b[byteN] = I2C_data; byteN++; if (byteN % 4 == 0) { uint8_t v = (byteN >> 2) - 1; uint8_t r = v * 8; tft.setCursor(80, r); tft.println(I2C_values.f[v]); } } void OutGoingData(void) { // nothing } } void setup() { tft.begin(); tft.InitLCD(); tft.setFont(SmallFont); tft.fillScreen(WHITE); if (tft.height() > tft.width()) tft.setRotation(1); tft.setTextColor(BLACK,WHITE); //black on white, instead of transparent chars.. tft.setTextSize(1); tft.setCursor(0, 0); tft.println("Temperature:"); tft.println(" Humidity:"); tft.println(" UV-index:"); tft.println("Light Level:"); tft.println(" Pressure:"); TIMSK0 = 0; __asm__ __volatile__ ( "cli" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "cbi %[I2COUT], %[SCLBIT]" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "cbi %[I2COUT], %[SDABIT]" "\n" :: [I2CDDR] "I" (_SFR_IO_ADDR(I2C_DDR)), [I2COUT] "I" (_SFR_IO_ADDR(I2C_OUT)), [SCLBIT] "I" (SCL_BIT), [SDABIT] "I" (SDA_BIT) ); } void loop() { __asm__ __volatile__ ( "HandleTransaction:" "\n" "rcall I2C_activity" "\n" "brtc HandleTransaction" "\n" "StartCondition:" "\n" "ldi R16, 0" "\n" "sts byteN, R16" "\n" "rcall wait_SCL_low" "\n" "rcall slave_readByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "mov R19, R18" "\n" "lsr R19" "\n" "cpi R19, %[SLAVE_ADDR]" "\n" "brne StopCondition" "\n" "rcall slave_writeACK" "\n" "andi R18, 0b00000001" "\n" "brne MasterRead" "\n" "MasterWrite:" "\n" "rcall slave_readByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "rcall slave_writeACK" "\n" "sbi %[I2CDDR], %[SCLBIT]" "\n" "sts I2C_data, R18" "\n" "call InComingData" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "rjmp MasterWrite" "\n" "MasterRead:" "\n" "sbi %[I2CDDR], %[SCLBIT]" "\n" "call OutGoingData" "\n" "lds R18, I2C_data" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "rcall slave_writeByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "rcall slave_readACK" "\n" "breq MasterRead" "\n" "StopCondition:" "\n" "rjmp DoneTransaction" "\n" "I2C_activity:" "\n" "in R16, %[I2CIN]" "\n" "andi R16, (1<<%[SCLBIT] | 1<<%[SDABIT])" "\n" "ac1:" "in R17, %[I2CIN]" "\n" "andi R17, (1<<%[SCLBIT] | 1<<%[SDABIT])" "\n" "cp R16, R17" "\n" "breq ac1" "\n" "clh" "\n" "clt" "\n" "sbrs R16, %[SCLBIT]" "\n" "rjmp ac2" "\n" "sbrs R17, %[SCLBIT]" "\n" "rjmp ac2" "\n" "sbrs R17, %[SDABIT]" "\n" "set" "\n" "sbrc R17, %[SDABIT]" "\n" "seh" "\n" "ac2:" "ret" "\n" "slave_readByte:" "\n" "ldi R18, 0b00000001" "\n" "rb1:" "rcall wait_SCL_high" "\n" "in R19, %[I2CIN]" "\n" "rcall I2C_activity" "\n" "brts rb2" "\n" "brhs rb2" "\n" "sec" "\n" "sbrs R19, %[SDABIT]" "\n" "clc" "\n" "rol R18" "\n" "brcc rb1" "\n" "clz" "\n" "clh" "\n" "rb2:" "ret" "\n" "slave_writeByte:" "\n" "ldi R19, 8" "\n" "wb1:" "lsl R18" "\n" "brcs wb2" "\n" "sbi %[I2CDDR], %[SDABIT]" "\n" "wb2:" "brcc wb3" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "wb3:" "rcall wait_SCL_high" "\n" "rcall I2C_activity" "\n" "brts wb4" "\n" "brhs wb4" "\n" "dec R19" "\n" "brne wb1" "\n" "wb4:" "cbi %[I2CDDR], %[SDABIT]" "\n" "ret" "\n" "skipPulse:" "\n" "rcall wait_SCL_high" "\n" "wait_SCL_low:" "\n" "sbic %[I2CIN], %[SCLBIT]" "\n" "rjmp wait_SCL_low" "\n" "ret" "\n" "wait_SCL_high:" "\n" "sbis %[I2CIN], %[SCLBIT]" "\n" "rjmp wait_SCL_high" "\n" "ret" "\n" "slave_writeACK:" "\n" "sbi %[I2CDDR], %[SDABIT]" "\n" "rcall skipPulse" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "ret" "\n" "slave_readACK:" "\n" "rcall wait_SCL_high" "\n" "sez" "\n" "sbic %[I2CIN], %[SDABIT]" "\n" "clz" "\n" "rcall wait_SCL_low" "\n" "ret" "\n" "DoneTransaction:" "\n" :: [I2CIN] "I" (_SFR_IO_ADDR(I2C_IN)), [I2COUT] "I" (_SFR_IO_ADDR(I2C_OUT)), [I2CDDR] "I" (_SFR_IO_ADDR(I2C_DDR)), [SCLBIT] "I" (SCL_BIT), [SDABIT] "I" (SDA_BIT), [SLAVE_ADDR] "M" (I2C_SLAVE_ADDRESS), "e" (InComingData), "e" (OutGoingData), [I2C_data] "label" (I2C_data), [byteN] "label" (byteN) ); }
Here is a demo I2C-master sketch that sends the 5 floats:
#include <Wire.h> #define SLAVE_ADDRESS 73 union u_floatarray { uint8_t b[20]; float f[5]; } I2C_values; void setup() { // test values: temperature, humidity, UV-index, light level, pressure I2C_values.f[0] = 20.3; I2C_values.f[1] = 48.8; I2C_values.f[2] = 2.4; I2C_values.f[3] = 345.0; I2C_values.f[4] = 1019.7; pinMode(LED_BUILTIN, OUTPUT); Wire.begin(); } void loop() { delay(4000); digitalWrite(LED_BUILTIN, HIGH); Wire.beginTransmission(SLAVE_ADDRESS); for (uint8_t n=0; n<20; n++) if (Wire.write(I2C_values.b[n]) != 1) break; Wire.endTransmission(); digitalWrite(LED_BUILTIN, LOW); }
-
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
The Arduino language reference says about "analogReference()": Configures the reference voltage used for analog input (i.e. the value used as the top of the input range).
To me that means: Any reading you make, after setting the analogReference once, will use the same reference.
So, if you are unsure, or if you want to be sure,.. Just set the analogReference before taking any new sample (for another sensor).If you have ANY other sample to make, from -some- device, and you know what maximum voltage it will return (that is: the voltage that is to be sampled),.. set the analogReference to the best fit, and then make the sample. Just be sure that the analogReference value can at least hold the maximum voltage to be sampled. In other words: If you have some device that outputs (say) 2 Volts, it will be incorrect to set the analogReference to 1.1V, because the input voltage could be higher than the reference voltage (and you can never sample values that exceed 1.1V).
Once the sample has been taken (and you have your 10-bit sample), you just have to know what that sample represents.
If, in your code, you never set the analogReference at all, the default input signal can be up to 5V. With a 10-bit sample resolution (1024 possible values), that means: 5 Volts / 1024 steps = 0.0048828125 Volt per sample-step. You can still sample voltages of 1 Volt,.. no problem.. but over an analogReference set to 5V, the maximum samplevalue is just a fifth of what could fit in 10 bits. In other words: The precision you measure will go down by a factor of 5.Because i know from the datasheet that the UVM30A will always produce a maximum voltage of 1 Volt, i set the analogReference to a value that fits best. It turns out that analogReference(INTERNAL) is quite good for sampling voltages that never exceed 1 Volt.
In your case: If your battery reports greater voltages than 1.1V, simply set the analogReference to DEFAULT (5V) before taking a sample from the battery.
I just checked the Arduino Reference: It seems not possible to put a voltage greater than 5V on the AREF pin. I have no experience with measuring battery voltages (yet). But i know the Arduino can be powered with more than 5V.
What i want to say is: If you would have a sensor that outputs 2.3 Volts maximum, you could put 2.3V on the AREF pin of the Arduino, set analogReference(EXTERNAL), and make samples that are prefectly suited for that sensor. -
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
I stripped the code to only include the UV measurement.
Hopefully it helps you out a bit.// Print debug information (test versions), (or not; in the final version) #define DEBUG_PRINT // print debug information when this line is uncommented (and the next line is commented) //#undef DEBUG_PRINT // (vice versa) //=================================================== // UVM30A ultraviolet detector. // The sensor's VCC is connected to +5V // // At first glance, the datasheet is not entirely making sense: // "θΎεΊη΅ε" translates to "Output voltage", with a value of: DC 0β1V. // So the sensor will never output/measure the 2 highest values listed in the graph & table of the datasheet (1079 and 1170+). // The datasheet explains it: "(ε―ΉεΊ UV ζζ° 0-10)" translates to "(corresponding to UV index 0-10)". Fair enough. // // "ζ΅θ―η²ΎεΊ¦" translates to: "Test accuracy", with a value of: Β±1 UV INDEX // That is not very accurate on a range 0-10. Example: if the real UV-index is 4, you could measure 3, or 5. // For that reason we take an average of multiple samples, to get a better measurement. // The sensor's (analog) output is connected to the Arduino Nano's at pin 14 (A0) #define UV_PIN 14 // The list of UV index thresholds (in mV). const int UV_threshold[12] = {50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; // in units of mV // The read value is a 10-bit value, ranging from 0 to 2^10-1 (0 to 1023). // The reference voltage on the input pin is set to 1.1V. // That voltage is spread out over the 1024 possible values of a sample. // So our achieved resolution equals (1.1 Volts / 1024) = 0.00107421875 Volt. // The UVM30A sensor datasheet lists all UV-index values according to measured milli-Volts. const float SAMPLE_TO_MV = (1.1*1000)/1024; // mV per sample-resolution uint16_t UV_value; uint16_t UV_index; // the UV index uint16_t UV_index_f; // the fractional part of the UV index // Compiler directives for averiging the UV-sensor readings // (Change the values of UV_AVERAGE_T & UV_AVERAGE_N according to your own taste). #define UV_AVERAGE_T 4000 // Sample interval duration in milliseconds.. (1 <= T <= 60000) #define UV_AVERAGE_N 10 // ..During that interval, N samples are taken, and averaged. (1 <= N <= 100, must be <>0) #if UV_AVERAGE_T < 1 // Sanity check. It must be dummy proof #define UV_AVERAGE_T 1 #endif #if UV_AVERAGE_N < 1 // Sanity check. It must be dummy proof #define UV_AVERAGE_N 1 // This value must be <>0 at all times, because we divide by it #endif // calculate once, use many times in the loop() const float UV_AVERAGE_N_RP = 1.0 / UV_AVERAGE_N; const uint32_t UV_AVERAGE_D = UV_AVERAGE_T * UV_AVERAGE_N_RP; //=================================================== //=================================================== // Process a UV measurement: // read an average value from the UV detector. // The average consists of N samples taken during a T milliseconds interval. //=================================================== void processUV() { // Set the reference voltage for sampling // For our ATmega328 Nano: INTERNAL = 1.1V, DEFAULT = 5V // After using analogReference(), the first few samples may not be accurate (according to the Arduino language reference), // and that is why we read a few dummy samples before starting the actual measurement. // NOTE: If you change the next statement, beware to adjust the value of SAMPLE_TO_MV too. analogReference(INTERNAL); for (int i=0; i<10; i++) UV_value = analogRead(UV_PIN); // ignore the possibly inaccurate samplevalues. #ifdef DEBUG_PRINT Serial.print("UV raw values: ["); #endif uint32_t average = 0; for (int i=0; i<UV_AVERAGE_N; i++) { #ifdef DEBUG_PRINT UV_value = analogRead(UV_PIN); Serial.print(UV_value); Serial.print(" "); average += UV_value; #else average += analogRead(UV_PIN); #endif delay(UV_AVERAGE_D); } UV_value = average * UV_AVERAGE_N_RP; #ifdef DEBUG_PRINT Serial.print("] avg: "); Serial.print(UV_value); #endif // We must convert sample-values into mV-values before we look up the UV-index. UV_value *= SAMPLE_TO_MV; #ifdef DEBUG_PRINT Serial.print(" mV: "); Serial.print(UV_value); #endif // determine the UV index if (UV_value < UV_threshold[0]) { // too low value or invalid value (in case the sensor is wrongly connected it always returns 0) UV_index = 0; UV_index_f = 0; } else { for (UV_index=11; UV_index>0; UV_index--) { if (UV_value >= UV_threshold[UV_index]) break; } // calculate fractional part of the UV-index if (UV_index == 11) { // already at the maximum level; Displaying a fraction is meaningless UV_index_f = 0; } else { UV_index_f = map(UV_value, UV_threshold[UV_index],UV_threshold[UV_index+1], 0,9); // one decimal, so a number ranging 0 to 9 } } float UV_index_float = UV_index + (UV_index_f*0.1); // that is the same as /10 #ifdef DEBUG_PRINT Serial.print(" UV index: "); Serial.println(UV_index_float); #endif } void setup() { // By default the Arduino sets all pins as input at startup, // so there is no need to explicitly set the pinMode pinMode(UV_PIN, INPUT); #ifdef DEBUG_PRINT // debug purposes Serial.begin(9600); #endif } void loop() { // UV measurement processUV(); // just some delay for (int i=0; i<5; i++) delay(1000); }
I edited my post.
The reason is that i'm using an Arduino Uno & Arduino YΓΊn in my own project.
The Nano's pin numbering is quite different: pin named A0 is numbered 14.
If You copy/paste the code, and run it, it would look something like this:UV raw values: [351 353 339 343 349 349 334 346 338 347 ] avg: 344 mV: 369 UV index: 2.50 UV raw values: [344 344 344 348 343 341 349 346 345 349 ] avg: 345 mV: 370 UV index: 2.50 UV raw values: [348 345 309 343 342 346 315 346 343 346 ] avg: 338 mV: 363 UV index: 2.40 UV raw values: [330 317 343 340 343 343 341 338 342 341 ] avg: 337 mV: 362 UV index: 2.40 UV raw values: [338 337 312 337 335 335 336 299 342 338 ] avg: 330 mV: 354 UV index: 2.30
-
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
@sundberg84 You mention that you have an ATmega328.
In your sketch setup() function you set the reference voltage value:
analogReference(INTERNAL);
According to the Arduino Language Reference pages, [https://www.arduino.cc/en/Reference/AnalogReference](link url)
, on an ATmega328 that will set the analog reference value to 1.1V.
Any 10-bit sample taken by that ATmega328 will spread 1.1V out over 1024 values. In your code, you do the calculation using 3.3V as the AREF. That will produce 3 times smaller samplevalues as intended.I see quite some people using code derived from the UV-example-sketch.
The code is a bit tricky, and in my opinion: not correct.*) In your own code, you convert samplevalues to mV values: Very good. That should be done. The example does not do that.
*) The piece of code that returns the UV-index does this:
for (i=0; i<12; i++) if (voltage <= uvIndexValue[i]) { UV=float(i); break; }
It returns a value that is 1 index too high. (try it: 317 mV will return UV=2).
But later a fractional part of the UV-index is calculated, which corrects the initial (too high) value://calculate 1 decimal if possible if (i > 0) { float vRange = float(uvIndexValue[i] - uvIndexValue[i - 1]); float vCalc = voltage - uvIndexValue[i - 1]; UV += (1.0f / vRange) * vCalc - 1.0f; }
At first glance it looks like the value UV will even get bigger (UV+=something), but it turns out that always a negative number is added to UV.
(1.0f / vRange) * vCalc - 1.0f is always negative. So something is subtracted from the initial value UV.
It's a bit counter intuitive...I've seen other people's projects where they removed the fractional/decimal part from their code (unlike your code). Their sensors will therefore always be interpreted with a full 1 UV-index value too high.
*) Correct me if i'm wrong, but the example code calculates a UV-index with a one-decimal precision. But the value sent to the gateway, is sent in 2 decimals. Wouldn't it be enough to do:
send(msgUV.set(UVindex, 1));
Here are bits of my own code. I use the Arduino map() function to calculate the decimal for me.
Perhaps others find it easier to read too.:const int UV_threshold[12] = {50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; // in units of mV const float SAMPLE_TO_MV = (1.1*1000)/1024; // mV per sample-resolution uint16_t UV_index; // the UV index uint16_t UV_index_f; // the fractional part of the UV index ... // determine the UV index if (UV_value < UV_threshold[0]) { // too low value or // invalid value (sensor is wrongly connected? => always 0) UV_index = 0; UV_index_f = 0; } else { for (UV_index=11; UV_index>0; UV_index--) if (UV_value >= UV_threshold[UV_index]) break; // calculate fractional part of the UV-index if (UV_index == 11) { // already at the maximum level; // Displaying a fraction is meaningless UV_index_f = 0; } else { UV_index_f = map(UV_value, UV_threshold[UV_index],UV_threshold[UV_index+1], 0,9); // one decimal, so a number ranging 0 to 9 } } float UV_index_float = UV_index + (UV_index_f/10.0);