I've been following this tutorial to create an Arduino PID Temperature Controller.
I can increase the set temperature by rotating the rotary encoder clockwise however I can't decrease the set temperature even when I rotate the encoder anticlockwise. Can someone help explain what I'm doing wrong :)
EDIT: the enconder works fine, I've tested it seperately but this code doesn't work. Thanks
The code is:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <PIDController.h>
#include "max6675.h"
// Define Rotary Encoder Pins
#define CLK_PIN 3
#define DATA_PIN 4
#define SW_PIN 2
// MAX6675 Pins
#define thermoDO 8
#define thermoCS 9
#define thermoCLK 10
// Mosfet Pin
#define mosfet_pin 11
// Serial Enable
#define __DEBUG__
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
/*In this section we have defined the gain values for the
* proportional, integral, and derivative controller I have set
* the gain values with the help of trial and error methods.
*/
#define __Kp 30 // Proportional constant
#define __Ki 0.7 // Integral Constant
#define __Kd 200 // Derivative Constant
int clockPin; // Placeholder por pin status used by the rotary encoder
int clockPinState; // Placeholder por pin status used by the rotary encoder
int set_temperature = 1; // This set_temperature value will increas or decreas if when the rotarty encoder is turned
float temperature_value_c = 0.0; // stores temperature value
long debounce = 0; // Debounce delay
int encoder_btn_count = 0; // used to check encoder button press
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); // Create an instance for the MAX6675 Sensor Called "thermocouple"
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// Create an instance for the SSD1306 128X64 OLED "display"
PIDController pid; // Create an instance of the PID controller class, called "pid"
void setup() {
#ifdef __DEBUG__
Serial.begin(9600);
#endif
pinMode(mosfet_pin, OUTPUT); // MOSFET output PIN
pinMode(CLK_PIN, INPUT); // Encoer Clock Pin
pinMode(DATA_PIN, INPUT); //Encoder Data Pin
pinMode(SW_PIN, INPUT_PULLUP);// Encoder SW Pin
pid.begin(); // initialize the PID instance
pid.setpoint(150); // The "goal" the PID controller tries to "reach"
pid.tune(__Kp, __Ki,__Kd); // Tune the PID, arguments: kP, kI, kD
pid.limit(0, 255); // Limit the PID output between 0 and 255, this is important to get rid of integral windup!
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
#ifdef __DEBUG__
Serial.println(F("SSD1306 allocation failed"));
#endif
for (;;); // Don't proceed, loop forever
}
//
display.setRotation(2); //Rotate the Display
display.display(); //Show initial display buffer contents on the screen -- the library initializes this with an Adafruit splash screen.
display.clearDisplay(); // Cleear the Display
display.setTextSize(2); // Set text Size
display.setTextColor(WHITE); // set LCD Colour
display.setCursor(48, 0); // Set Cursor Position
display.println("PID"); // Print the this Text
display.setCursor(0, 20); // Set Cursor Position
display.println("Temperatur"); // Print the this Text
display.setCursor(22, 40); // Set Cursor Position
display.println("Control"); // Print the this Text
display.display(); // Update the Display
delay(2000); // Delay of 200 ms
}
void set_temp()
{
if (encoder_btn_count == 2) // check if the button is pressed twice and its in temperature set mode.
{
display.clearDisplay(); // clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // set the diplay cursor
display.print("Set Temp."); // Print Set Temp. on the display
display.setCursor(45, 25); // set the cursor
display.print(set_temperature);// print the set temperature value on the display
display.display(); // Update the Display
}
}
void read_encoder() // In this function we read the encoder data and increment the counter if its rotaing clockwise and decrement the counter if its rotating counter clockwis
{
clockPin = digitalRead(CLK_PIN); // we read the clock pin of the rotary encoder
if (clockPin != clockPinState && clockPin == 1) { // if this condition is true then the encoder is rotaing counter clockwise and we decremetn the counter
if (digitalRead(DATA_PIN) != clockPin) set_temperature = set_temperature - 3; // decrmetn the counter.
else set_temperature = set_temperature + 3; // Encoder is rotating CW so increment
if (set_temperature < 1 )set_temperature = 1; // if the counter value is less than 1 the set it back to 1
if (set_temperature > 150 ) set_temperature = 150; //if the counter value is grater than 150 then set it back to 150
#ifdef __DEBUG__
Serial.println(set_temperature); // print the set temperature value on the serial monitor window
#endif
}
clockPinState = clockPin; // Remember last CLK_PIN state
if ( digitalRead(SW_PIN) == LOW) //If we detect LOW signal, button is pressed
{
if ( millis() - debounce > 80) { //debounce delay
encoder_btn_count++; // Increment the values
if (encoder_btn_count > 2) encoder_btn_count = 1;
#ifdef __DEBUG__
Serial.println(encoder_btn_count);
#endif
}
debounce = millis(); // update the time variable
}
}
void loop()
{
read_encoder(); //Call The Read Encoder Function
set_temp(); // Call the Set Temperature Function
if (encoder_btn_count == 1) // check if the button is pressed and its in Free Running Mode -- in this mode the arduino continiously updates the screen and adjusts the PWM output according to the temperature.
{
temperature_value_c = thermocouple.readCelsius(); // Read the Temperature using the readCelsius methode from MAX6675 Library.
int output = pid.compute(temperature_value_c); // Let the PID compute the value, returns the optimal output
analogWrite(mosfet_pin, output); // Write the output to the output pin
pid.setpoint(set_temperature); // Use the setpoint methode of the PID library to
display.clearDisplay(); // Clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // Set the Display Cursor
display.print("Cur Temp."); //Print to the Display
display.setCursor(45, 25);// Set the Display Cursor
display.print(temperature_value_c); // Print the Temperature value to the display in celcius
display.display(); // Update the Display
#ifdef __DEBUG__
Serial.print(temperature_value_c); // Print the Temperature value in *C on serial monitor
Serial.print(" "); // Print an Empty Space
Serial.println(output); // Print the Calculate Output value in the serial monitor.
#endif
delay(200); // Wait 200ms to update the OLED dispaly.
}
}
If you can increment the set temperature it means that the statement
(clockPin != clockPinState && clockPin == 1)
is true and:
(digitalRead(DATA_PIN) != clockPin)
is false. So if you rotate the enconder anticlockwise you should guarantee that
(clockPin != clockPinState && clockPin == 1)
is still true and
(digitalRead(DATA_PIN) != clockPin)
is true.
Perhaps this is a little bit obvious but you can start debugging there. Sorry if my english is not clear.
Related
I am using a zumo bot with a reflectance sensor used to follow a black line. I want to use an arduino to make the zumo bot stop once it gets a certain distance from an obstacle.
I have an ultrasonic sensor (HC-SR04) which ive connected to the bot.
Both of these tasks work independently but once i merge the code together(so it follows the line aswell as stoping when it detects an object using the ultrasonic sensor), it doesn't work properly.. (the zumo bot no longer follows the line)
I THINK it is to do with the pulsein() function blocking any other tasks but not sure.
My code is below. Can anyone help please?
#include <ZumoShield.h>
ZumoBuzzer buzzer;
ZumoReflectanceSensorArray reflectanceSensors;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
int lastError = 0;
// This is the maximum speed the motors will be allowed to turn.
// (400 lets the motors go at top speed; decrease to impose a speed limit)
const int MAX_SPEED = 400;
#define echoPin A4
#define trigPin A5
// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
void setup()
{
reflectanceSensors.init();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// Initialize the reflectance sensors module
// Wait for the user button to be pressed and released
button.waitForButton();
// Turn on LED to indicate we are in calibration mode
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
digitalWrite(13, LOW);
// Wait for the user button to be pressed and released
button.waitForButton();
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Arduino UNO R3");
}
void loop()
{
unsigned int sensors[6];
// Get the position of the line. Note that we *must* provide the "sensors"
// argument to readLine() here, even though we are not interested in the
// individual sensor readings
int position = reflectanceSensors.readLine(sensors);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Our "error" is how far we are away from the center of the line, which
// corresponds to position 2500.
int error = position - 2500;
// Get motor speed difference using proportional and derivative PID terms
// (the integral term is generally not very useful for line following).
// Here we are using a proportional constant of 1/4 and a derivative
// constant of 6, which should work decently for many Zumo motor choices.
int speedDifference = error / 4 + 6 * (error - lastError);
lastError = error;
// Get individual motor speeds. The sign of speedDifference
// determines if the robot turns left or right.
int m1Speed = MAX_SPEED + speedDifference;
int m2Speed = MAX_SPEED - speedDifference;
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
if (m1Speed > MAX_SPEED)
m1Speed = MAX_SPEED;
if (m2Speed > MAX_SPEED)
m2Speed = MAX_SPEED;
motors.setSpeeds(m1Speed, m2Speed);
//if (distance <20){
// motors.setSpeeds(0,0);
// }
////////////////////////////////////////////
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Displays the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
} ```
Of course pulseIn is blocking function. Arduino project is open source, you can easily check source code
Here is C equivalent countPulseASM function which does measurement.
unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
unsigned long width = 0;
// wait for any previous pulse to end
while ((*port & bit) == stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to start
while ((*port & bit) != stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (++width == maxloops)
return 0;
}
return width;
}
If you need measure pulse length in non blocking way, use hw counters.
I have this code that I am using to play a sound effect where I used a program called wav2c to convert a .wav file to number values that I put into a header file that I use in the code to generate the sound. I currently have it programmed to play the audio upon uploading it to the Arduino with an LED being activated along with it and staying lit for just the duration of the sound effect. I am trying to program it so that the sound and LED only activate when I am pressing a button. I have the pin the button is plugged into already programmed in but I'm not sure how to have it control the audio and LED as stated above. I don't have much experience with programming or Arduino so any help is much appreciated! I am using an Arduino Mega 2560.
The code
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#define SAMPLE_RATE 20000
#include "Test.h"
int ledPin = 2;
int speakerPin = 9; // Can be either 3 or 11, two PWM outputs connected to Timer 2
const byte pinSwitch1 = 3;
volatile uint16_t sample;
byte lastSample;
void stopPlayback()
{
digitalWrite(ledPin, LOW);
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
if (sample >= sounddata_length) {
if (sample == sounddata_length + lastSample) {
stopPlayback();
}
else {
if(speakerPin==11){
// Ramp down to zero to reduce the click at the end of playback.
OCR2A = sounddata_length + lastSample - sample;
} else {
OCR2B = sounddata_length + lastSample - sample;
}
}
}
else {
if(speakerPin==11){
OCR2A = pgm_read_byte(&sounddata_data[sample]);
} else {
OCR2B = pgm_read_byte(&sounddata_data[sample]);
}
}
++sample;
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
if(speakerPin==11){
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = pgm_read_byte(&sounddata_data[0]);
} else {
// Do non-inverting PWM on pin OC2B (p.155)
// On the Arduino this is pin 3.
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2B = pgm_read_byte(&sounddata_data[0]);
}
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match) (p.133)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK1 |= _BV(OCIE1A);
lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
sample = 0;
sei();
}
void setup()
{
pinMode( pinSwitch1, INPUT );
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
startPlayback();
}
void loop()
{
while (true);
}
The header file referenced in the code with the numeric values to create the audio.
#ifndef _HEADERFILE_H // Put these two lines at the top of your file.
#define _HEADERFILE_H // (Use a suitable name, usually based on the file name.)
const int sounddata_length=32000;
//const int sounddata_sampleRate=20000;
const unsigned char sounddata_data[] PROGMEM = {
15,1,49,0,150,0,138,0,219,255,133,0,176,0,15,1,210,
//There are many lines of more numbers in between that I cut out to save space
};
#endif // _HEADERFILE_H // Put this line at the end of your file.
The following changes will allow you to start playback whenever there is a falling edge on your switch pin. You may need to tweak to avoid switch 'bouncing'.
Firstly, add a global variable to record the last switch state:
int lastSwitchState;
Change your setup() to
void setup() {
pinMode(pinSwitch1, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
lastSwitchState = digitalRead(pinSwitch1);
}
and your loop() function to
void loop() {
delay(50);
int switchState = digitalRead(pinSwitch1);
if (switchState != lastSwitchState) {
lastSwitchState = switchState;
if (switchState == LOW) {
startPlayback();
}
}
}
Interrupts vs polling
Instead of polling the switch pin inside the main loop(), you could use interrupts. You would use attachInterrupt() to do this. Interrupts are only available on certain pins, however, and the above approach is conceptually simpler I think.
I am using a ITG3200(Sparkfun breakout board) for my project. I was trying to boost the sample rate of ITG3200 to over 2K HZ. I have already soldered two 2.2K pull-up resistors on the sensor and close the clockin pads. I encountered a few problems here. It was connected to a Arduino Uno.
The highest sample rate I can achieve was around 500 Hz. I have changed the clock to 400K. However, without doing that, I should still get something over 1000 Hz, right? I attached my code below.
Any comments or suggestions would be greatly appriecated!
#include <SPI.h>
#include <Wire.h>
// Pin definitions - Shift registers:
int enPin = 13; // Shift registers' Output Enable pin
int latchPin = 12; // Shift registers' rclk pin
int clkPin = 11; // Shift registers' srclk pin
int clrPin = 10; // shift registers' srclr pin
int datPin = 8; // shift registers' SER pin
int show = 0;
int lastMax = 0;
//This is a list of registers in the ITG-3200. Registers are parameters that determine how the sensor will behave, or they can hold data that represent the
//sensors current status.
//To learn more about the registers on the ITG-3200, download and read the datasheet.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;//0x15
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;
//This is a list of settings that can be loaded into the registers.
//DLPF, Full Scale Register Bits
//FS_SEL must be set to 3 for proper operation
//Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter
char DLPF_CFG_0 = 0;//1
char DLPF_CFG_1 = 0;//2
char DLPF_CFG_2 = 0;//4
char DLPF_FS_SEL_0 = 8;
char DLPF_FS_SEL_1 = 16;
char itgAddress = 0x69;
// Some of the math we're doing in this example requires the number of bargraph boards
// you have connected together (normally this is one, but you can have a maximum of 8).
void setup()
// Runs once upon reboot
{
// Setup shift register pins
pinMode(enPin, OUTPUT); // Enable, active low, this'll always be LOW
digitalWrite(enPin, LOW); // Turn all outputs on
pinMode(latchPin, OUTPUT); // this must be set before calling shiftOut16()
digitalWrite(latchPin, LOW); // start latch low
pinMode(clkPin, OUTPUT); // we'll control this in shiftOut16()
digitalWrite(clkPin, LOW); // start sck low
pinMode(clrPin, OUTPUT); // master clear, this'll always be HIGH
digitalWrite(clrPin, HIGH); // disable master clear
pinMode(datPin, OUTPUT); // we'll control this in shiftOut16()
digitalWrite(datPin, LOW); // start ser low
// To begin, we'll turn all LEDs on the circular bar-graph OFF
digitalWrite(latchPin, LOW); // first send latch low
shiftOut16(0x0000);
digitalWrite(latchPin, HIGH); // send latch high to indicate data is done sending
Serial.begin(230400);
//Initialize the I2C communication. This will set the Arduino up as the 'Master' device.
Wire.begin();
//Read the WHO_AM_I register and print the result
char id=0;
id = itgRead(itgAddress, 0x00);
Serial.print("ID: ");
Serial.println(id, HEX);
//Configure the gyroscope
//Set the gyroscope scale for the outputs to +/-2000 degrees per second
itgWrite(itgAddress, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0));
//Set the sample rate to 100 hz
itgWrite(itgAddress, SMPLRT_DIV, 0);
}
void loop()
// Runs continuously after setup() ends
{
static int zero = 0;
// Create variables to hold the output rates.
int xRate, yRate, zRate;
float range = 3000.0;
int divisor;
divisor = range / 8;
//Read the x,y and z output rates from the gyroscope.
xRate = int(float(readX()) / divisor - 0.5) * -1;
yRate = int(float(readY()) / divisor - 0.5) * -1;
zRate = int(float(readZ()) / divisor - 0.5);
//Print the output rates to the terminal, seperated by a TAB character.
Serial.print(xRate);
Serial.print('\t');
Serial.print(yRate);
Serial.print('\t');
Serial.println(zRate);
Serial.print('\t');
// Serial.println(zero);
// fillTo(zRate);
//Wait 10ms before reading the values again. (Remember, the output rate was set to 100hz and 1reading per 10ms = 100hz.)
// delay(10);
}
// This function will write a value to a register on the itg-3200.
// Parameters:
// char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
// char registerAddress: The address of the register on the sensor that should be written to.
// char data: The value to be written to the specified register.
void itgWrite(char address, char registerAddress, char data)
{
//Initiate a communication sequence with the desired i2c device
Wire.beginTransmission(address);
//Tell the I2C address which register we are writing to
Wire.write(registerAddress);
//Send the value to write to the specified register
Wire.write(data);
//End the communication sequence
Wire.endTransmission();
}
//This function will read the data from a specified register on the ITG-3200 and return the value.
//Parameters:
// char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
// char registerAddress: The address of the register on the sensor that should be read
//Return:
// unsigned char: The value currently residing in the specified register
unsigned char itgRead(char address, char registerAddress)
{
//This variable will hold the contents read from the i2c device.
unsigned char data=0;
//Send the register address to be read.
Wire.beginTransmission(address);
//Send the Register Address
Wire.write(registerAddress);
//End the communication sequence.
Wire.endTransmission();
//Ask the I2C device for data
Wire.beginTransmission(address);
Wire.requestFrom(address, 1);
//Wait for a response from the I2C device
if(Wire.available()){
//Save the data sent from the I2C device
data = Wire.read();
}
//End the communication sequence.
Wire.endTransmission();
//Return the data read during the operation
return data;
}
//This function is used to read the X-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int xRate = readX();
int readX(void)
{
int data=0;
data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
data |= itgRead(itgAddress, GYRO_XOUT_L);
return data;
}
//This function is used to read the Y-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int yRate = readY();
int readY(void)
{
int data=0;
data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
data |= itgRead(itgAddress, GYRO_YOUT_L);
return data;
}
//This function is used to read the Z-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int zRate = readZ();
int readZ(void)
{
int data=0;
data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
data |= itgRead(itgAddress, GYRO_ZOUT_L);
return data;
}
void fillTo(int place) {
int ledOutput = 0;
if(place > 8)
place = 8;
if(place < -8)
place = -8;
if(place >= 0) {
for (int i = place; i >= 0; i--)
ledOutput |= 1 << i;
} else {
ledOutput = 32768;
for (int i = place; i <= 0; i++)
ledOutput |= (ledOutput >> 1);
}
// Serial.println(ledOutput);
digitalWrite(latchPin, LOW); // first send latch low
shiftOut16(ledOutput); // send the ledOutput value to shiftOut16
digitalWrite(latchPin, HIGH); // send latch high to indicate data is done sending
}
void shiftOut16(uint16_t data)
{
byte datamsb;
byte datalsb;
// Isolate the MSB and LSB
datamsb = (data & 0xFF00) >> 8; // mask out the MSB and shift it right 8 bits
datalsb = data & 0xFF; // Mask out the LSB
// First shift out the MSB, MSB first.
shiftOut(datPin, clkPin, MSBFIRST, datamsb);
// Then shift out the LSB
shiftOut(datPin, clkPin, MSBFIRST, datalsb);
}
500Hz means 2ms for each iteration of your loop() function. Your loop function is reading from Wire and writing to the Serial port, which may take more time than 2ms, depending on what you're sending and what your baud rate is.
Judging from your baud rate (230400), it may take roughly 0.5ms to send each measurement (estimated at 12 characters each) if there is no flow control from the other side. Try writing to serial less frequently to see if your performance goes up.
I tested the serial writes, the I2C port and the clock speed. Found the major issues were the redundant communication to i2c. For instance, the 6 bits data can be read in one round of i2c communication. I refered the code below:
https://raw.githubusercontent.com/ControlEverythingCommunity/ITG3200/master/Arduino/ITG-3200.ino
In addition, using Teensy is also helpful.
The speed of the output was checked by using the oscilloscope with the I2C debug function.
I currently have an arduino LCD and one SPDT switch connected to my board. The the common pin of the SPDT is grounded and the outer pins are each connected to a digital input. My program should increment and decrement the counter being printed to the LCD screen. I have one input working that increments the counter I do not know how to implement code for the input to decrement the counter. Code posted below.
Thank you
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5,4,3,2);
const byte buttonPin = 8;
int counter = 0; // set your counter to zero to begin with
byte buttonState; // the current reading from the input pin
byte lastButtonState = HIGH; // the previous reading from the input pin
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup()
{
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
lcd.begin(16, 2); // for 2x16 lcd display
}
void loop() {
// read the state of the switch into a local variable:
byte reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from HIGH to LOW), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) >= debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
counter ++;
Serial.println(counter);
lcd.setCursor(0, 1);
lcd.print(counter);
}
}
}
lastButtonState = reading;
}
You cannot simply connect one pole of a switch to an input pin an other to the ground. This will detect LOW but when when you are suppose to detect HIGH on the pin, it will be floating. Connect a pull-up resistor to your input pins.
Or you can use pinMode(InPin, INPUT_PULLUP);
This will pull your input pin to high internally and then you can detect the swithces and implememnt the code.
What a great learning experience my first Arduino project is turning out to be.. I would now like to add a countdown until a sensor reading is taken and displayed, which will repeat infinitely. I've got the sensor and LCD display working fine but my loop is not quite right.. Should I be using a while() of some sort? How do I keep the timer ticking during the big delay between readings?
/*Code for self-watering plant with LCD readout*/
// value for LCD params
char ESC = 0xFE;
// analog input pin that the soil moisture sensor is attached to
const int analogInPin = A1;
// value read from the soil moisture sensor
int sensorValue = 0;
// if the readings from the soil sensor drop below this number, then turn on the pump
int dryValue;
// countdown timer until next soil reading
int timerValue = 9;
void setup() {
pinMode(12, OUTPUT);
// initialize serial communications at 9600 bps:
Serial.begin(9600);
// Set the "dry" value of soil on turning on the device
dryValue = analogRead(analogInPin);
// pause before intialize LCD
delay(2000);
// Initialize LCD module
Serial.write(ESC);
Serial.write(0x41);
Serial.write(ESC);
Serial.write(0x51);
// Set Contrast
Serial.write(ESC);
Serial.write(0x52);
Serial.write(40);
// Set Backlight
Serial.write(ESC);
Serial.write(0x53);
Serial.write(5);
//print the dry value to serial
Serial.print("Dry = " );
Serial.print(dryValue);
Serial.print(" ");
}
void loop(){
watering();
// wait some time (really should be delay(86400000))
delay(10000);
}
void printTimer(){
// Set cursor line 1, column 16
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x0F);
// print the timer value
Serial.print(timerValue);
timerValue = timerValue - 1;
if(timerValue == 0){
timerValue = 9;
}
}
void printVal(){
// set cursor line 2, column 1
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x40);
// print the sensor to the serial monitor:
Serial.print("Sensor = " );
Serial.print(sensorValue);
Serial.print(" ");
printTimer();
}
void watering(){
// read the analog in value:
sensorValue = analogRead(analogInPin);
//turn on the water pump for some time if the soil is too dry
if(sensorValue < dryValue){
digitalWrite(12, HIGH);
delay(2000);
digitalWrite(12, LOW);
}
else {
printVal();
}
}
It's actually really simple: Don't delay. Instead, initialize a timer to run a routine whenever it overflows or hits a certain value. Examine the datasheet for the microcontroller used in your Arduino for the specific bits to frob (note that the Arduino libraries use the timer 0 overflow vector for themselves), and the avr-libc documentation for how to denote the ISR(s) for the timer. Your loop() then becomes a big sleep while the timer runs the entire show for you.
I would use a timer library for Arduino like this http://playground.arduino.cc//Code/SimpleTimer
Just download the library, put it in the "libraries" folder in your sketchbook and restart your Arduino IDE to load the new library.
Then your code would look something like this. Basically what it does it updates the screen every loop and then once every 86400000 ms it checks the "watering" function. Just so you know this code would only check the soil once every 24 hours (86400000ms). I think a better solution would be to constantly check the soil and water anytime it is needed. But Im no gardener so maybe there is a reason for just checking once a day.
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
void setup() {
Serial.begin(9600);
timer.setInterval(86400000, watering); // how often you would call your watering function is set with the first variable
}
void loop() {
timer.run();
printTimer();
}
void printTimer(){
// Set cursor line 1, column 16
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x0F);
// print the timer value
Serial.print(timerValue);
timerValue = timerValue - 1;
if(timerValue == 0){
timerValue = 9;
}
}
void printVal(){
// set cursor line 2, column 1
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x40);
// print the sensor to the serial monitor:
Serial.print("Sensor = " );
Serial.print(sensorValue);
Serial.print(" ");
printTimer();
}
void watering(){
// read the analog in value:
sensorValue = analogRead(analogInPin);
// send it to the display
printVal();
//turn on the water pump for some time if the soil is too dry
if(sensorValue < dryValue){
digitalWrite(12, HIGH);
delay(2000);
digitalWrite(12, LOW);
}
}