How to fill array with values from analogRead on arduino. every second arduino reads value from analog0 and i want to put these readings to array.
Let's say you want to read up to 100 values, do this:
1. Poor technique (uses blocking code with delay()):
//let's say you want to read up to 100 values
const unsigned int numReadings = 100;
unsigned int analogVals[numReadings];
unsigned int i = 0;
void setup()
{
}
void loop()
{
analogVals[i] = analogRead(A0);
i++;
if (i>=numReadings)
{
i=0; //reset to beginning of array, so you don't try to save readings outside of the bounds of the array
}
delay(1000); //wait 1 sec
}
Note: you cannot make the number in brackets too large. Ex: analogVals[2000] will not work because it takes up too much RAM.
PS. This is pretty basic stuff that Arduino covers in their help on the website. Please reference here from now on for questions like this, and give it a shot yourself first: http://arduino.cc/en/Reference/HomePage --> click on "array" under "Data Types."
2. Alternate method (also a poor technique, since it uses blocking code with delay()):
//let's say you want to read up to 100 values
const unsigned int numReadings = 100;
unsigned int analogVals[numReadings];
void setup()
{
}
void loop()
{
//take numReadings # of readings and store into array
for (unsigned int i=0; i<numReadings; i++)
{
analogVals[i] = analogRead(A0);
delay(1000); //wait 1 sec
}
}
UPDATE: 6 Oct. 2018
3. Best technique (non-blocking method--no delay!):
//let's say you want to read up to 100 values
const unsigned int numReadings = 100;
unsigned int analogVals[numReadings];
unsigned int i = 0;
void setup()
{
Serial.begin(115200);
}
void loop()
{
static uint32_t tStart = millis(); // ms; start time
const uint32_t DESIRED_PERIOD = 1000; // ms
uint32_t tNow = millis(); // ms; time now
if (tNow - tStart >= DESIRED_PERIOD)
{
tStart += DESIRED_PERIOD; // update start time to ensure consistent and near-exact period
Serial.println("taking sample");
analogVals[i] = analogRead(A0);
i++;
if (i>=numReadings)
{
i = 0; //reset to beginning of array, so you don't try to save readings outside of the bounds of the array
}
}
}
4. Professional-type approach (non-blocking method, avoids global variables by passing around pointers instead, uses C stdint types, and uses static variables to store local, persistent data):
// Function prototypes
// - specify default values here
bool takeAnalogReadings(uint16_t* p_numReadings = nullptr, uint16_t** p_analogVals = nullptr);
void setup()
{
Serial.begin(115200);
Serial.println("\nBegin\n");
}
void loop()
{
// This is one way to just take readings
// takeAnalogReadings();
// This is a way to both take readings *and* read out the values when the buffer is full
uint16_t numReadings;
uint16_t* analogVals;
bool readingsDone = takeAnalogReadings(&numReadings, &analogVals);
if (readingsDone)
{
// Let's print them all out!
Serial.print("numReadings = "); Serial.println(numReadings);
Serial.print("analogVals = [");
for (uint16_t i=0; i<numReadings; i++)
{
if (i!=0)
{
Serial.print(", ");
}
Serial.print(analogVals[i]);
}
Serial.println("]");
}
}
// Function definitions:
//---------------------------------------------------------------------------------------------------------------------
// Take analog readings to fill up a buffer.
// Once the buffer is full, return true so that the caller can read out the data.
// Optionally pass in a pointer to get access to the internal buffer in order to read out the data from outside
// this function.
//---------------------------------------------------------------------------------------------------------------------
bool takeAnalogReadings(uint16_t* p_numReadings, uint16_t** p_analogVals)
{
static const uint16_t NUM_READINGS = 10;
static uint16_t i = 0; // index
static uint16_t analogVals[NUM_READINGS];
const uint32_t SAMPLE_PD = 1000; // ms; sample period (how often to take a new sample)
static uint32_t tStart = millis(); // ms; start time
bool bufferIsFull = false; // set to true each time NUM_READINGS have been taken
// Only take a reading once per SAMPLE_PD
uint32_t tNow = millis(); // ms; time now
if (tNow - tStart >= SAMPLE_PD)
{
Serial.print("taking sample num "); Serial.println(i + 1);
tStart += SAMPLE_PD; // reset start time to take next sample at exactly the correct pd
analogVals[i] = analogRead(A0);
i++;
if (i >= NUM_READINGS)
{
bufferIsFull = true;
i = 0; // reset to beginning of array, so you don't try to save readings outside of the bounds of the array
}
}
// Assign the user-passed-in pointers so that the user can retrieve the data if they so desire to do it this way
if (p_numReadings != nullptr)
{
*p_numReadings = NUM_READINGS;
}
if (p_analogVals != nullptr)
{
*p_analogVals = analogVals;
}
return bufferIsFull;
}
Sample Serial Monitor output from the last code just above:
Begin
taking sample num 1
taking sample num 2
taking sample num 3
taking sample num 4
taking sample num 5
taking sample num 6
taking sample num 7
taking sample num 8
taking sample num 9
taking sample num 10
numReadings = 10
analogVals = [1023, 1023, 1023, 1023, 1023, 687, 0, 0, 0, 0]
taking sample num 1
taking sample num 2
taking sample num 3
taking sample num 4
taking sample num 5
taking sample num 6
taking sample num 7
taking sample num 8
taking sample num 9
taking sample num 10
numReadings = 10
analogVals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
More reading/study:
My thorough answer on how to do time-stamp-based bare-metal cooperative multi-tasking: Best way to read from a sensor that doesn't have interrupt pin and requires some time before the measurement is ready
Arduino's very basic but extremely useful "Blink Without Delay" tutorial: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
Related
I have to send an integer counter as 'num' through XBee (in API mode) from Arduino. For this purpose I have to convert this integer to String and then to uint8_t array as it is needed in API frame to transmit.
Apart from other details I've converted my integer to string like
String str;
int num = 0;
char cstr[16];
void loop() {
num++;
str = String(num);
str.toCharArray(cstr,16);
Serial.println(cstr); // this shows the correct result, means int is converted to String correctly
uint8_t data[] = {cstr}; // passing String to uint8_t array
XBeeAddress64 addr64 = XBeeAddress64();
addr64.setMsb(0x00000000);
addr64.setLsb(0x00000000);
ZBTxRequest zbTx = ZBTxRequest(addr64, data, sizeof(data));
xbee.send(zbTx);
int count = sizeof(data);
for (int i = 0; i < count; i++) {
if (i == (count-1)) {
Serial.print(data[i]); // here it prints "104" of ASCII which is equal to "h"
}
}
}
It also transmit it as like that Serial print i.e. ('104').
Please point out if I am making any mistake and guide me if I didn't do it as required.
First get rid of those cstr and String:
int num = 0;
//char cstr[16];
char data[16] = {'\0'}; // Initialize data array
void setup() {
}
void loop() {
num++;
//str = String(num);
//str.toCharArray(cstr,16);
itoa (num, data, 10);
Serial.println(data);
// To get the number of elements in the array use
uint8_t datalen = strlen(data);
// Black box see lib for details
XBeeAddress64 addr64 = XBeeAddress64();
addr64.setMsb(0x00000000);
addr64.setLsb(0x00000000);
ZBTxRequest zbTx = ZBTxRequest(addr64, data, datalen);
xbee.send(zbTx);
// Print test
Serial.println("Content of data: ");
Serial.print(data);
Serial.print(" datalen: ");
Serial.print(datalen);
}
This should work as you expect. To copy an array you would use strcpy (or memcopy with malloc and free), to get the number of elements use strlen.
EDIT:
Here is a tested code (just copy andpaste and first replace only the include to your xbee lib:
#include "Xbee.h" //-> Change to your xbee lib
uint16_t num = 0;
char xdata[16] = {'\0'};// Initialize data array
char numbuf[16] = {'\0'}; // initialize number buffer
long currentMillis = 0;
void setup() {
Serial.begin(115200);
currentMillis = millis();
}
void loop() {
if (millis() - currentMillis > 1000) { // 1 sec timer to prevent overflow due to hammering xbee with data -> tune to your stable transmission
num++;
itoa (num, numbuf, 10); // Num buffer
strcpy(xdata, numbuf); // Copy content of num buffer to data array
Serial.println(xdata);
// To get the number of elements in the array use
uint16_t datalen = strlen(xdata);
// Black box see lib for details
XBeeAddress64 addr64 = XBeeAddress64();
addr64.setMsb(0x00000000);
addr64.setLsb(0x00000000);
ZBTxRequest zbTx = ZBTxRequest(addr64, data, datalen);
xbee.send(zbTx);
// Print test
Serial.print("Content of xdata: ");
Serial.print(xdata);
Serial.print(" datalen: ");
Serial.println(datalen);
currentMillis = millis(); // reset timer
}
}
The result in serial monitor is:
1
Content of xdata: 1 datalen: 1
2
Content of xdata: 2 datalen: 1
3
Content of xdata: 3 datalen: 1
4
Content of xdata: 4 datalen: 1
....
864
Content of xdata: 864 datalen: 3
865
Content of xdata: 865 datalen: 3
866
Content of xdata: 866 datalen: 3
So all works as expected, no 104 or similar. Please first copy paste - test it - and then your additions
I am coding SSD display using 2 cascaded shift registers. I am using a mikroC for PIC compiler. I can display a static sequence of numbers upto 4 digits with my code Static Display of 4 Numbers
#define SHIFT_CLOCK PORTB.F1 //Clock Connection of 74HC595 SSD Driver
#define SHIFT_LATCH PORTB.F3 //Latch Connection of 74HC595 SSD Driver
#define SHIFT_DATA PORTB.F2 //Data Connection of 74HC595 SSD Driver
char array4[4] = {6, 91, 79, 102}; //Display 1234 on SSD
char digit[4] = {0xFE, 0xFD, 0xFB, 0xF7}; //Switch on the SSD digits one by one
char i,j,temp,flag1,flag2;
void InitTimer0()
{
OPTION_REG = 0x86;
TMR0 = 6;
INTCON = 0xA0;
}
void latch595()
{
SHIFT_LATCH = 1;
Delay_us(1);
SHIFT_LATCH = 0;
}
void shiftdata595(unsigned char _shiftdata)
{
int i;
unsigned char temp;
temp = _shiftdata;
i=8;
while (i>0)
{
if (temp.F7==0)
{
SHIFT_DATA = 0;
}
else
{
SHIFT_DATA = 1;
}
temp = temp<<1;
SHIFT_CLOCK = 1;
SHIFT_CLOCK = 0;
i--;
}
}
void Interrupt()
{
if (TMR0IF_bit)
{
TMR0IF_bit = 0;
TMR0 = 6;
flag1 = 1;
flag2 = 1;
}
}
void main()
{
TRISB = 0;
TRISC.F1 = 1;
InitTimer0();
while (1)
{
if (PORTC.F1==0)
{
if (flag2==1)
{
shiftdata595(digit[i]);
i++;
if(i==4)
{
i=0;
}
if (flag1==1)
{
shiftdata595(array4[j]);
latch595();
j++;
if (j==4)
{
j=0;
}
}
}
}
else if(PORTC.F1==1)
{
shiftdata595(0);
shiftdata595(0);
latch595();
}
}
}
If I add more digits to the array4[], say upto 9, I will need to scroll the digits to the left sequentially.
I tried shifting the array by
temp = array4[0];
for (n=1; n<8; n++)
{
array4[j-1] = array[j];
}
array[9] = temp;
I hoped that this code will left shift the array and the display will scroll, but all I am getting is a jumbled up display. If I add a delay, I can see that the numbers are getting displayed but without scrolling.
Is the basic algorithm faulty or can it be used by modifying the code?
I did figure out the problem with my code. The loop was wrong. I am using two 74HC595 in cascaded mode. One controls the digits(common cathode) and other controls the segments. Since there is only one data line that passes on the information to the digits as well as the segments, the timing of the digits advancement and the segments needs to be coordinated. The entire problem was that I was unnecessarily concentrating on the timing part which was coordinated but instead, I should have concentrated on the loop condition which advances the segments and then left shifts the array.
On friend pointed out that I need to write down the data values on a piece of paper for each loop and that solved the problem. Instead of feeding the loop the length of the array manually like array4[8] or array4[10], I used the sizeof() function and then after the first four iterations of the loop, left shifted the array one place. Now the scrolling works perfect.
Here is the updated and working code,
shiftdata595(array4[tmp7]);
latch595();
Delay_ms(32);
tmp7++;
if (tmp7>=4)
{
tmp7=0;
tmp1 = sizeof(array4)/sizeof(array4[0]);
tmp2 = array4[0];
for (n=1;n<tmp1;n++)
{
array4[n-1] = array4[n];
}
array4[tmp1-1] = tmp2;
}
I have been trying to write a code to basically add points to a score whenever I pressed a button while a certain amount of time is running down. The problem I am finding is that it doesn't detect when the button is pressed while the time is decreasing, in fact it can only detect when the time starts to decrease and then it doesn't matter at which state the button is it will continue to add to the score. Anyway here is the main code:
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
score += 10;
Serial.println(score);
}
time--;
Serial.println(time);
}
}
}
And here is the full code if needed:
int button01 = 4;
int button02 = 3;
int button03 = 2;
int buttonState01 = 0;
int buttonState02 = 0;
int buttonState03 = 0;
float time;
int score;
void setup() {
score = 0;
time = 0;
pinMode(button01, INPUT);
pinMode(button02, INPUT);
pinMode(button03, INPUT);
Serial.begin(9600);
}
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
}
}
You should read the status of a button inside the while loop. Like this:
while(time > 0)
{
buttonState02 = digitalRead(button02);
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
And in your code, there is no logic to add points to the score.
A hardware interrupt would do exactly what you need.
Attach an interrupt routine to the pin your button is linked to, and get it to set the 'score' variable. Make sure you introduce some sort of timeout to avoid button-bounce (I.e. set LastTimeIncremented when you increase the score, and only increment score if LastTimeIncremented is more than 1 second ago)
This way the score will always be set regardless of what else the program may be doing.
Information on this can be found in the Arduino https://www.arduino.cc/en/Reference/attachInterrupt
The example on that page would do exactly what you want, just replace 'blink' with 'incrementScore' and you're pretty much done
const byte ledPin = 13;
const byte interruptPin = 2;
int score = 0;
int increment = 1;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), incScore, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void incScore() {
score = score+increment;
// add anti-bounce functionality here
}
For some context, I’m working on what is basically “Simon” for an Arduino project. I’m using an ATMEGA2560 and editing the code with Atmel Studio 6.1. The project uses the random number generator to create the sequence for the button input, which is where I’m running into trouble.
My current method of adding some variance is to use a timer interrupt to seed the random number, by incrementing a number to be processed through an equation. However, the timer simply doesn’t work – and the number doesn’t increment. Am I doing anything wrong with initialization, or is something else at fault?
Code:
#define F_CPU 1000000UL // 1 MHz, for timer
#include <avr/io.h> // normal stuff
#include <avr/interrupt.h> // timer interrupt
#include <util/delay.h> // easy delay functions
#include <stdlib.h> // random function
// global var that timer uses
volatile uint8_t count;
// function prototypes
int generateSeq(); // generates random number
int getRandomNumber(); // also generates random number (?)
int main(void)
{
// variables
int sequence[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // actual sequence
int terms = 0; // terms in sequence
int gameState = 0;
int ifWrong = 0; // if sequence is wrong
// timer interrupt (WHAT AM I DOING WRONG)
TCCR0A |= (1<<CS02)|(1<<CS00);
TIMSK0 |= (1<<TOIE0);
TCNT0 = 0;
count = 1;
sei();
while(1)
{
// actual "game" part
while(gameState == 1)
{
// generate term in sequence
// 1 = up, 2 = right, 3 = down, 4 = left
if(ifWrong == 0)
{
sequence[terms] = generateSeq(); // call sequence function
terms++;
}
}
}
}
// random seed for sequence generator (something wrong here?)
ISR(TIMER0_OVF_vect)
{
count++;
if(count >= 255)
{
count = 1;
}
}
int generateSeq() // function to generate sequence
{
// equation is currently a placeholder
int r2 = (int)rand() * (int)count;
int num = r2 * count;
return (num % 4) + 1;
}
gameState is 0, and never changed, so none of the generateSeq() code is called.
You also have a serious problem with sequence[terms] in that you don't check if terms is between 0 and 7. You will run off the end of the array.
The code below is part of a larger project. The intent is to flash an led with a variable on time, reset the on time and accumulate the total "on" time. The on time is changed each time the "on" period has elapsed.
Code below appears to successfully change the "on" time at the end of each "on" time period, but does not accumulate the total time.
I expected ledtime to equal LED_ON on the first pass (for example 1000) and then equal the previous ledtime + LED_ON (for example 1000 + 2538 = 3528) on the second pass etc.
Instead ledtime is always equal to the current LED_ON, so it appears ledtime is always set to zero on each pass, which I don't understand.
I'm new at arduino/C programming and suspect I'm missing something pretty simple/obvious, but have played with this for awhile with no resolution (including moving the ledtime = etc statements to various areas within the blink routine).
long ledtime;
const int LED_PIN = 13;
const int grnled = 11;
unsigned long LED_ON = 800; //milliseconds
int LED_OFF = 2000;
int redled = 10;
int yellowled = 12;
unsigned long ms; //time from millis()
unsigned long msLast;
unsigned long mslast2;//last time the LED changed state
boolean ledState; //current LED state
void setup(void)
{
pinMode(grnled, OUTPUT);
pinMode(redled,OUTPUT);
pinMode(yellowled,OUTPUT);
Serial.begin(9600);
}
void loop(void)
{
while(millis()<5000) {
digitalWrite(redled,HIGH);
digitalWrite(yellowled,LOW);
}
while (millis() >(5000) && millis()< 20000){
ms = millis();
blinkLED();
}
if (millis() > 20000 && millis() < 30000) {
digitalWrite(redled,HIGH);
}
if (millis() > 30000) {
digitalWrite(yellowled,HIGH);
digitalWrite(redled, LOW);
}
}
void blinkLED(void)
{
if (ms - msLast > (ledState ? LED_ON : LED_OFF)) {
digitalWrite(grnled, ledState = !ledState);
msLast = ms;
long ledtime = ledtime + LED_ON; //this does not work
Serial.println("ledtime = ");
Serial.println(ledtime);
if (ms-mslast2> LED_ON) {
LED_ON = random(500,5000); //this works
LED_OFF = 2000;
mslast2 = ms;
Serial.println("LED_ON = ");
Serial.println(LED_ON);
}
}
}
I'm not very sure of what you're trying to do, but with the line you commented, you create a local variable ledtime which has the same name of your global one. And because it's local to your function, it gets erased at the end of your function.
So first initialize ledtime at 0 at its declaration,
Then try to replace this line by
ledtime += LED_ON;