Arduino - create dynamic rules - arduino

I want to create a program for arduino in order to be able to add and remove rules controlling some pins, whenever i want and not hardcode them.
For example a rule like this:
if pin1=HIGH and pin2=LOW then pin3=HIGH
i want to turn into this:
if(pin1 == HIGH && pin2 == LOW){
digitalWrite(pin3, HIGH);
}
Lets say we pass the rule via the command line as a string.
How could i convert this string into a rule? Is something like this possible?

Your second piece of code:
if(pin1 == HIGH && pin2 == LOW){
digitalWrite(pin3, HIGH);
}
is compiled by your IDE into machine code. That machinecode is then uploaded to the Arduino and then executed.
Therefore you cannot just send some string like this
if pin1=HIGH and pin2=LOW then pin3=HIGH
to the Arduino because after your programm transformed that into the desired form the complete IDE and compiler stuff is missing on the Arduino side. And a C++ compiler tool chain is big - several tens of megabytes! There is no place for that on the Arduino.
What you can do: Invent a simple language for your rules and develop an interpreter for that which then runs on the Arduino.
Perhaps you also don't need to reinvent the wheel - Google for simple BASIC interpreters running on the AVR CPUs and adapt one of them.

What you are asking for is possible but with much work on your part.
Approach 1 (think big):
What you are looking for is a software implementation equivelant to how PAL's (programmable array logic) and CPLD's (complex programmable logic device) operate. If you read this article, you will get some ideas on how this is done in hardware:
Wikipedia article on PLD's
A PAL can create arbitray combinational logic rules between a set of inputs and outputs, i.e. anything you can express as a logical equation of AND's, OR's and NOT's can be programmed. It is programmed by "burning" a set of fuses that connect the inputs to logics gates and then to outputs. What is uploaded to these devices is just a set of 0's and 1's.
You could implement such a thing in software with an array of 0's and 1's to represent the fuses. The hard code would run over the array and calculate the output. You would need to develop the method to load the array with the correct fuses.
A common method by which PAL's are programmed is with the language VHDL. The compiler for this language takes an expression like yours and translates it to the set of AND's, OR's and NOT's that the PAL can use. A search will yield endless discussion of this language, for example:
A VHDL tutorial
You would have to create the compiler that takes the text input and determines the fuses. You would be undertaking some significant tasks:
a domain specific language parser (I can recommend ANTLR),
a PAL compiler (I can't recommend anyone do this themselves), and
the Arduino code to emulate a PAL.
By the time you create your own equivalent of VHDL and PAL's, you'll probably be thinking you could have just put a PAL chip on a proto board and been done.
Approach 2 (more practical):
The simpler method to achieve the same result is a truth table. A truth table is the equivalent of some set of logical expressions. To implement a truth table, translate your logic expressions to a table with one row for each input case. Here is an example of a truth table of two inputs that drive an output:
IN1 IN2 OUT
0 0 1
0 1 0
1 0 1
1 1 1
The code for such a truth table implementation looks like this:
const int IN1 = 6;
const int IN2 = 7;
const int OUTA = 13;
byte table[4] = {1, 0, 1, 1};
void loop() {
int in1;
int in2;
byte outbit;
size_t ix;
//
in1 = digitalRead(IN1);
in2 = digitalRead(IN2);
ix = in2 * 2 + in1;
outbit = table[ix];
digitalWrite(OUTA, outbit);
}
The complete expression of the logic rules is the array of 4 bytes. To "program" an new output equation, you just send a new set of 4 values, for your specific equation you send "0 0 1 0". Your program would receive the list of values and store them in the table array. As soon as the new values/rules are stored, the function of the output would change.
This type of programmable logic is feasible as long as you have enough RAM to store the table. For 4 inputs you just need 16 values, for 5 you need only 32.
Your question raises a keen point in electronics design: you need to pick the right device for the right problem. Code is not always better or easier. Avoid the hammer-nail trap (when your only tool is a hammer every problem looks like a nail). A PAL/CPLD and microcontroller are a powerful combination.

To add to the truth table approach mentioned by #jdr5ca, it's a good idea to understand the controller used in the arduino as well as using the ardiuno libraries.
Pins 0 to 7 are port D and pins 8 to 15 port B. Each port is represented as three single byte registers - PORT_ which is output/bias resistor, PIN_ which is input state and DDR_ which is direction. When you call digitalRead(pin) the code sees which range the pin is in, reads PIN_ for that port, then bit-shifts and masks the value to give just that pin's state. Which is handy for reading one pin at a time, but a less convenient than if you're reading several.
So if you create a truth table with 256 entries, you can write the output of pins 8 to 15 from the values of inputs 0 to 7 using a single line, rather than decoding the registers to pins then encoding them again:
byte table[256] = {0};
void loop() {
PORTB = table[PIND];
}
You can then add something to read from the serial and load new values into the table on the fly.

Related

What does lcd.setPWM(color, i) do in ARDUINO?

I have a code I have to rewrite, I'm pretty new at Arduino and I've come across the "lcd.setPWM(color, i) statement and I don t really know what it does, and I couldn t quite find it online.
setPWM(color,i) can be used to adjust the Pulse-width modulation frequency, which determines how many full 'pulses' per second are generated by the Controller.
This function will be used to control the color range that you want to select. Probably with a for loop like in:
for(int i=0; i<255; i++){
lcd.setPWM(color, i);
delay(5);
}
The 256 range is probably because of the typically 256-cubed (8 bits in three color channels with values of 0–255) for encode colors.

Arduino - 5 questions for real Wire.write() and Wire.read() explanation

I Googled this a lot, and it seems that I am not the only one having problems with really understanding Wire.write() and Wire.read(). Being novice, I almost never use libraries that are already written by somebody, I try to create my class for module in order to truly understand how this module works and to learn how to manipulate with it. I've read few books and too many tutorials, but I could summarise these in two:
a) all tutorials are just showing the very basics of how to use these methods and b) they don't actually explain the steps, like everything is totally self explanatory. Call me stupid, but I have the feeling like somebody told me that 1 + 1 = 2, and then gave me some polynomial equation to solve :(
All book examples and almost all tutorials look like this imaginary example:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.endTransmission(); // end this
//To read
Wire.requestFrom(Module_Address, 3); //Read three registers
Wire.read(); //Read first register
Wire.read(); //Read second register
Wire.read(); //Read third register
And that's it about reading.
When it comes to writing, it's even worse:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.write(something); //Write to first register
Wire.write(something); //write to second register
Wire.endTransmission(); // end this
So far, working with ANY module I got, it was NEVER that easy. Usually, every register has more than one "option" inside. For example, lets say that imaginary module has First read register like this:
ADDRESS | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0
data Byte1 | mute .| option2.........|.....................option3.......................
To read only option 3, I would use this code:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(module_address, 1);
byte readings = Wire.read() & 0x1F; //0x1F is hexadecimal of binary 0001111 for option 3 in register 1
QUESTION 1
What does this '&' after Wire.read() REALLY means? (I know that it points to option within register, but I do not really understand this, why is it there)
QUESTION 2
Why the previous problem isn't written anywhere? So many tutorials, so many books, but I "discovered" it by accident when I tried to figure out how one library was working.
QUESTION 3
Imagine that hypothetical module has third register in write mode looking like this:
ADDRESS | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0
data Byte3 | write flag.......| option2.........|......................option3........
How to write flag without affecting option 2 and option 3? Or in other words, how to write to register 3's write flag? If I take 11000000 could affect because maybe I do not know what exactly option 2 and 3 do, or I do not wish to interfere with default setup.
QUESTION 4
Certain modules have to be written in binary-coded decimal. Let's say, that you have a timer and you wish to set 17 seconds for countdown to 0.And to do that, you need to write number 17 to register one, but number should be binary-coded decimal. 17 as binary-coded is: 0001 0111. But when you do this:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.write(00010111);
Wire.endTransmission();
You get different number, 13 or 10 (can't recall what number, I know it was wrong).
However, when doing this conversion: 17/10*16 + 17%10 it writes correct number 17.
Yes, I also accidentally found this out. BUT, where is this equation from? I searched (obviously wrong) as much as I could, but there was nothing about it. So, how did somebody come with this equation?
QUESTION 5
Probably a dumb off-topic question, BUT:
should Arduino library be written in a way that others could find it difficult to figure out the idea behind it? In other words, to figure out what the developer was exactly doing? I remember that one person used a lot of messy code to read something from sensor and then formula to convert it from binary-coded decimal to print it to Serial Monitor, while the same thing could be done with simply
Serial.print(read_byte, HEX);
It's not that I am smarter (or better) than them, I just don't understand why somebody would write a complex code when there is no(really) need for that.
Thanks a lot for any help :)
Questions 1. - 4.: Are all covered by Bit Manipulation tutorial on AVRFreaks forum Tutorials. So in short:
1) The & is used for bit masking in this case.
2) If you look for "Bit manipulation" then there are loads of Tutorials.
3) It's possible by Bit manipulation. How? For in memory variable just use bit masking. To clear two bits: var &= 0b00111111 to set two bits: var |= 0b11000000. If you don't have register value, you have to Read & Modify & Write it back. If you can't read the value (for example it's internal address like for eeproms) you have to have this value in memory anyways.
4) In C++ numbers starting by zero are in Octal base. If you want binary, you have to use 0b00010111. For the HEX base you have to use 0xFF. This is not explicitly mentioned in that tutorial, but both are used here.
5) It should be as clear as possible. But for the begginers without good knowlege of C++ it's hard anyway. For me is most difficult to read the code without indentation or even worst with bad indentation, bad variable names. The libraries are usually written by advanced users, so it's not so hard to understand with some background like knowing the datasheet for used MCUs and so on.
BTW: wrong comments are also bad for understanding:
//0x1F is hexadecimal of binary 0001111 for option 3 in register 1
The value 0x1F is definitely not 0001111 in binary but 00011111 (or better: 0b00011111)

Arduino, Passing array pointer/reference(?) into function, but getting bad data?

TL;DR I think I'm passing my array into a function wrongly, and thus the data thats read from it is not right causing it to possibly mangle Arduino memory.
Full code can be found >here<
After a bit of reading, I'm still a tad confused the best way to go about passing an array into a function and modifying its data within that function.
So far these 2 questions sort of helped, and thus allowed my code to compile; but after a bit of testing I'm having issues whereby the data I would be expecting to see is not being read back correctly when I'm within the function.
Array/pointer/reference confusion
Passing an array by reference in C?
The basic program...
It lights up 3 LED strips with a base colour purple (after an initial fade each light one by one), then makes a sort of colours trail effect (7 pixels long) trace along the strip, and loop back from the beginning again.
Video can be seen here of the effect https://www.youtube.com/watch?v=S8tVfFfsiqI
I'm going to do the same effect but I have since tried to re-factor my code so that its easier for everyone to adjust the parameters of the colours.
Original source code can be found here >Click to View< (feel free to copy/modify/use the code how ever you want, its for anyone to use really, all in good fun)
What I'm trying to do now...
So the goal now is to re-factor the code from above so that its easier to set the Trail effect colour based on the user's preferences. Thus I want to define the colour of the trail elsewhere, and then have each instance of the trail just passed into function that handles updating it (this is done without using classes, just Structs and Arrays, as thats confusing for non programmery types which this code is aimed for)
//Setting up Trail effect length
#define TRAIL_LENGTH 7
typedef struct Color {
byte r;
byte g;
byte b;
};
typedef struct TrailPixel {
uint16_t position;
Color color;
};
//Function Prototypes
void trailEffectForward (Adafruit_NeoPixel &strip, struct TrailPixel (*trailArray)[TRAIL_LENGTH] );
//Make the arrays
TrailPixel trailLeft[TRAIL_LENGTH];
TrailPixel trailBottom[TRAIL_LENGTH];
TrailPixel trailRight[TRAIL_LENGTH];
So as you can see from the above, I create two Structs, and then make 3 arrays of those structs. I then populate the "position" value of each of the trail effects with...
for (int i = 0; i < TRAIL_LENGTH; i++) {
trailLeft[i].position = i + 5; //start just off the strip
trailBottom[i].position = 15 - i; //start off screen, but timed in a way so to look like the Left and Right trails converge onto the bottom at the same time
trailRight[i].position = i + 5; //start just off strip
}
Later on in the code, I call the function that I want to process the effect, and I hand off the details of the array to it. I want to have inside this function, to commands to update the pixel colour on the light strip and then update the position for next time.
BUT Things get mangled really fast to the point where my Arduino reboots every few seconds and colours aren't behaving as expected.
Here how I currently call the trail effect function...
trailEffectForward ( stripBottom , &trailBottom );
Once in there to try and figure out whats going on, I added some serial output to check the values.
void trailEffectForward(Adafruit_NeoPixel &strip, TrailPixel (*trailArray)[TRAIL_LENGTH]) {
Serial.println("---------------------");
Serial.println(trailArray[0]->position);
Serial.println(trailArray[1]->position);
Serial.println(trailArray[2]->position);
Serial.println(trailArray[3]->position);
Serial.println(trailArray[4]->position);
Serial.println(trailArray[5]->position);
Serial.println(trailArray[6]->position);
I would EXPECT if things worked according to plan, I would see the numbers
---------------------
15
14
13
12
11
10
9
But what I end up having is this :(
---------------------
15
5
5
43
1000
0
0
The full code that is currently in a state of Work In Progress can be found http://chiggenwingz.com/quads/ledcode/quad_leds_v0.2workinprogress.ino
Note: I've commented out a lot of the meat that applies colour to the pixels as I trying to narrow down what was going wrong. Basically I would be expecting the output as listed above to stop happening.
Once again feel free to use any of the code in your own projects :)
Okie it looks I found my answer from here [ Passing an array of structs in C ]
So the function was this previously...
void trailEffectForward(Adafruit_NeoPixel &strip, TrailPixel (*trailArray)[TRAIL_LENGTH])
and is now this
void trailEffectForward(Adafruit_NeoPixel &strip, struct TrailPixel trailArray[TRAIL_LENGTH] )
Got rid of the whole pointer/reference fun stuff. Had to put the word "struct" there I believe.
So when I call the function, I was previously using...
trailEffectForward ( stripBottom , &trailBottom );
but now I use this
trailEffectForward ( stripBottom , trailBottom );
I no longer have mangled data, and everything apperars to be working happily again.
Hopefully this helps someone out there in the years to come :)

Can an Arduino sample audio in microseconds for 1-4 kHz?

I've just hooked up a electret microphone to an Arduino, and I'd like to sample between the ranges of 1 kHz and 4 kHz.
I understand this is limited to the machine code and the ADC, so I'm trying to keep the sketch simple.
Is it possible to sample between these frequencies with the sketch below?
const int analogPin = 0;
int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
int mn = 1024;
int mx = 0;
for (int i = 0; i < 5; ++i) {
int val = analogRead(analogPin);
mn = min(mn, val);
mx = max(mx, val);
}
if (mx-mn >= 50) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
}
Arduino is a prototyping platform consisting of a number of hardware boards plus a software abstraction layer. For a question like this, it is useful to consider the capabilities of the underlying hardware, as these provide the ultimate limits. I'll assume you are using Arduino Uno/Nano, the story is different for Due.
According to the datasheet, each ADC reading (beyond the first one) takes 13 ADC clock cycles. ADC clock (different from the MCU) clock is derived by dividing the system clock by some factor, at least 2. So at 16Mhz board this amounts to 0.6 million samples per second. So far so good. However, that's not the end of the story, you still need to read the data. If you use interrupts, even if you do something very simple, experience suggests that you will lose about 100 clock to interrupt processing. Now you are down to 126K samples/second. But this is a theoretical maximum.
The datasheet states that for maximum accuracy for the ADC requires 50kHz - 200kHz ADC clock. In the Arduino code (in wiring.c), a division factor of 128 is chosen:
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
This means that each conversion takes 128*13 = 1764 clocks, which yields a theoretical maximum of 10K samples per second. It is a little bit worse than that given that the readAnalog() function does something beyond just starting the ADC conversion and waiting for it to finish, but it shouldn't be too much worse. This doesn't involve your code of course: any processing you do on the results of readAnalog() will make it more difficult to capture more samples. But yes, to capture at 4Khz you will need to make sure that you code spends less than 1.5k clock cycles/sample, which should be doable. Note that if you are doing five readings like you are doing in the code you posted, the maximum capture rate will be 2kHz if your code does very little.
As far as how to capture the data, you need to make deal with the fact that microphones without amplification will not give you 0-5V readings that you might expect if you are using analogRead(). In fact, microphone output voltages swing from positive to negative, however, the negative voltages will not be picked up by the ADC, and show up as just zeros, unless you give your microphone a voltage offset.
I am not exactly sure what your code that compares minimum amplitude to maximum amplitude is supposed to be doing. Are you wanting to digitize the audio? In this case you need to save all the amplitude readings collected from analogRead(), and then you can run FFTs on them on another computer: Arduino is most likely not going to be fast enough to do frequency analysis on the data.
I have heard, or rather remember reading, that the ADC could handle up to 10k-samples per second, so it should be OK up to 5 kHz. However, I have not tried this nor do I have a link to back it up at the moment.
Just try and see.
Now I know some of the Arduino library functions are slow, notably the DigitalRead/Write that has overhead of hundreds of cycles. Most of this is the sanity checking that allows people to just perform DigitalRead/Write without thinking much about setting everything up.
However, to squeeze out the maximum performance you could look into writing your own AnalogRead that is optimized for your use case.
At least some links on the subject:
Pin I/O performance (JeeLabs)
C++ Template method for faster access (JeeLabs)
I happen to have just tried this using an Arduino Uno and similar code to yours and I've been able to sample an average of 8000 times a second. That is the Nyquist frequency for 4 kHz so you're good but not much margin for error.

How do you watch for changes in the least significant bit?

I'm working with Arduino and am beginning to work with port registers. I love the speed increases and ability to change multiple ports at the same time. However, I don't know how to watch for a single pin changing using the port registers. (I think it can be done with bitmath, but I don't even know how to start with that.)
So when I check my port register I should get something like this:
PINB = B000xxxxx
Where x are my pin values. Any of those pins could have changed. I want to know when just the rightmost (least significant?) bit has changed. How can I use bitmath to check that just the last one has switched from a 0 to a 1?
"Bitmath" is indeed the answer to the problem. In your case: x & 0x01 will "mask" all but the lowest bit. The result can be compared to 0 or 1 at your wish.
Common idioms are:
x & 0x01 // get only the lowest bit
x & ~0x01 // clear only the lowest bit
x & 0xFE // same: clear only the lowest bit
x | 0x01 // set the lowest bit (others keep their state)
To find out if the bit has changed, you need the previous value, which you mask out as the others have said --
int lastValue = PINB & 0x01;
Then in your code you do
int currentValue = PINB & 0x01;
to get the LSB of the current pin value.
To determine if there was a change to the bit you want the "exclusive OR" (^) operator -- it is "true" if and only if the two bits are different.
if (lastValue ^ currentValue) {
// Code to execute goes here
// Now save "last" as "current" so you can detect the next change
lastValue = currentValue;
}

Resources