I made a simple lcd display example from this guide.
After it worked I'd like to play with it. I wrote a program to count fps of this screen. The big question is how slow is the Arduino.
Program code is here:
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int lastMillis = 0;
long fps = 0;
void setup() {
lcd.begin(16, 2);
lcd.print("seconds ");
lcd.setCursor(0, 1);
lcd.print("fps ");
}
void loop() {
if ((millis() - lastMillis) > 1000) {
lcd.setCursor(8, 0);
lcd.print(millis()/1000);
lcd.setCursor(4, 1);
lcd.print(fps);
fps = 0;
lastMillis = millis();
}
fps = fps + 1;
}
And it worked. I was happy to know that Arduino can do more than 300,000 fps on a small 16x2 lcd display.
But after number of seconds goes beyond 32 second (magic number) fps freezes at value 124,185 and never changes after that.
If someone know why is that happen, please explain it. I don't have a clue why fps ( that's set to 0 every second ) could freeze, while seconds are keep changing.
I got a video that shows what happens. Video
Then, as ahaltindis suggested, I changed the code to this:
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int lastMillis = 0;
long fps = 0;
void setup() {
lcd.begin(16, 2);
}
void loop() {
if ((millis() - lastMillis) > 1000) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("seconds ");
lcd.setCursor(0, 1);
lcd.print("fps ");
lcd.setCursor(8, 0);
lcd.print(millis()/1000);
lcd.setCursor(4, 1);
lcd.print(fps);
fps = 0;
lastMillis = millis();
}
fps = fps + 1;
}
And it get worse: video
I tried your code with my arduino uno. But I used Serial.print instead of lcd.print. It acted with same way. When sec hits the 32, serial monitor goes crazy.
Then I found that you defined lastMillis as an integer. In arduino(atmega) integer keeps 16bit value and that means it can store values in range of -32,768 to 32,767. When millis function hits 32,767(32sec), arduino sets your lastMillis's value as -32,768.
So your if block returns always true after 32 sec, because difference of millis() and lastMillis will always be greater than 1000. Thats why the only value you see is 1 and that is also why your lcd cannot respond well print requests after 32 sec.
The only change you should do is, change your lastMillis type as a long.
long lastMillis = 0;
Try changing
int lastMillis = 0;
To
unsigned int lastMillis = 0;
Let me know what happens
If you use an unsigned int you will overflow back to one so that your original code will work
Related
I'm using Tinkercad, and since it's my first time programming an LCD I just copied the procedure to connect the pins and make it work.
The thing is that it just lights up without displaying anything, I tried both wiring and unwiring the R/W pin but that doesn't work either, nothing will be displayed.
What did I miss? The other functions of the code works normally.
Image of the circuit:
This is the code:
#include <LiquidCrystal.h>
const int pin = 0; // analog pin
float celsius = 0, farhenheit =0; // temperature variables
float millivolts; //Millivolts from the sensor
int sensor;
const int G_LED = 13;
const int Y_LED = 12;
LiquidCrystal lcd(10, 9, 5, 4, 3, 2); // Building the LCD
void setup() {
lcd.begin(16,2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("C="); // "C=", "F=" and "mV" should be printed
lcd.setCursor(0, 1); // on the LCD in a column
lcd.print("F=");
lcd.setCursor(0, 2);
lcd.print("mV=");
pinMode(G_LED, OUTPUT);
pinMode(Y_LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
sensor = analogRead(pin); // Reading the value from the LM35 sensor using the A0 ingress
millivolts = (sensor / 1023.0) * 5000; // Converting the value in a number that indicates the millivolts
celsius = ((sensor * 0.00488) - 0.5) / 0.01; // Celsius value (10 mV for each degree, 0°=500mV)
farhenheit = celsius * 1.8 + 32; // Fahrenheit value
lcd.setCursor(4, 2); // Set the cursor at the right of "mV="
lcd.print(millivolts); // Print the mV value
lcd.setCursor(4, 0); // Same here for °C and °F
lcd.print(celsius);
lcd.setCursor(4, 1);
Serial.print(farhenheit);
if (millivolts < 700) { // Green LED is on when the temperature is under or equal to 20°
// if (celsius < 20) { // Alternative
analogWrite(G_LED, 255);
analogWrite(Y_LED, 0); }
else {
analogWrite(G_LED, 0);
analogWrite(Y_LED, 255); // Yellow LED is on when the temperature is above of 20°C
}
delay(1000);
}
Fix - I could not find the error, but I suspect it was due to the strange layout of the connections. You also tried to set the cursor to line 3, but the LCD you were using did not have 3 lines, it was a 16x2 LCD.
What I Did - So what I did was I re-did the entire project, I linked up a new LCD, this time with a digital contrast so that it could be dynamically changed. I also made sure to include the sensor you used in your last project. Over-all the project is an Arduino controlling an LCD and outputting the temperature in Fahrenheit and millivolts.
Here is the project link (Tinkercad).
Code:
#include <LiquidCrystal.h>
// Adds the liquid crystal lib
int contrast = 40; // Set the contrast of the LCD
LiquidCrystal lcd (12, 11, 5, 4, 3, 2); // Instantiate the LCD
float fahrenheit;
float millivolts;
void setup ()
{
analogWrite(6, contrast); // Wrjte the contrast to the LCD
lcd.begin(16, 2); // Init the LCD
}
void loop ()
{
int sensor = analogRead(0);
millivolts = (sensor/1023.0)*5000;
fahrenheit = (((sensor*0.00488)-0.5)/0.01)*1.8+32;
lcd.setCursor(0, 0);
lcd.print("Temp(F):");
lcd.setCursor(11, 0);
lcd.print(fahrenheit);
lcd.setCursor(0, 1);
lcd.print("Volts(mV):");
lcd.setCursor(12, 1);
lcd.print(millivolts);
}
Diagram
I have an issue trying to send some serial data through tx and rx to another arduino through a HC05 bluetooth module.
The overall project is developing a hybrid go kart and using the arduino as a simple ECU unit with a PID speed control over the PWM output controlling a DC motor. I have been working the project in steps and have go as far as setting up a footpedal with the arduino and controlling the electronic speed controller (ESC) directly. I have added a simple PID function to this along with a simple hall sensor to detect the speed and does require tuning but works great so far. Now the problem comes when I try to send data across over serial ports.
I have had the bluetooth modules connected with to separate arduinos and have successfully managed to send over data from one arduino with a pot input to another with a 3.5 inch TFT screen. When I try to integrate the master side of the project to the PID controlled DC motor the system freezes. I have since then removed the PID control and gone back to direct control and it still fails, i have tried commenting out the interrupt sequence for the encoder and put a static value for RPM and still freezes. the sending sequence works if I don't attempt to use any digital outputs. I am really confused. The code I have gone down to to try and debug this can be found below. This is not the full code and has been chopped to pieces to try and eliminate this fault. however in this code below, if I comment out the sendData function the system works and the motor spins with relative speed to the pedal input. as soon as I try to send the data the system runs for a seconds then freezes. the data is still being sent and the static readings are showing just the digital output seizes to work.
#include <TimerOne.h>
int previous = 0;
int Tavg = 0; // the average
int Tout = 0;
int throttle = A0;
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int ESCPin = 5;
unsigned int counter=0;
int RPM;
long Time = 0;
long ReadInt = 0;
void docount() // counts from the speed sensor
{
counter++; // increase +1 the counter value
}
void timerIsr()
{
Timer1.detachInterrupt(); //stop the timer
Serial.print("Motor Speed: ");
RPM = (counter*75 ); // RPM= counterx10*60/8 (x10 for second, 8 counts in encoder, 60 minutes === 75x counter)
Serial.print(RPM);
Serial.println(" Rotation per min"); Serial.print(Tout);Serial.print("= "); Serial.print(Tout*0.01961);Serial.println("V");
counter=0; // reset counter to zero
Timer1.attachInterrupt( timerIsr ); //enable the timer
}
void ReadEnc (){
Timer1.initialize(100000); // set timer for 0.1sec
attachInterrupt(0, docount, RISING); // increase counter when speed sensor pin goes High
Timer1.attachInterrupt( timerIsr ); // enable the timer
}
void sendData(){
if (Serial.available()>0) {
if (Serial.read() == 0){
//Serial.println(sendChars);
int RPMout = RPM;
Serial.write("<");
//delay(2);
//Serial.write(sendChars);
Serial.write("Data is,");
//delay(2);
Serial.write( itoa (RPMout, 4,10));
//delay(2);
Serial.write(", 30, 48.35");
//delay(2);
Serial.write(">");
//delay(10);
Serial.println("");
}
}
}
void setup()
{
Serial.begin(9600);
pinMode(2, INPUT_PULLUP); // internal pullup input pin 2
pinMode(ESCPin, OUTPUT);
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0; }
Time = millis();
ReadInt = -100;
}
void ReadSensor (){
// get the sensor value
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(throttle);
//Serial.println(readings[readIndex]);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
Tavg = total / numReadings;
}
void loop(){
ReadSensor();
ReadEnc();
RPM = 1800;
Tout = map(Tavg, 180, 860, 0, 200);
if (Tout>0){
analogWrite(ESCPin, Tout);
}
if (Time > ReadInt + 5000) {
sendData (); // when this is commented it works fine, tried moving it everywhere
ReadInt = Time;
}
Time = millis();
}
If anyone has any ideas please let me know, and I know I probably haven't explained my problem well so if their is any questions or more details needed please ask.
Second parameter of itoa should be a pointer to output bufffer. but you do not need itoa. use Serial.print(RPM);. For string the print and write functions are the same, but for number print has a version for int
I am trying to build a rev counter using a Hall effect sensor and an Arduino Uno. I'm using Arduino software and I have wrote the following code:
#include <LiquidCrystal.h>
int sensorPin = 2; // hall effect
float revs;
float rpm;
volatile byte rpmcount;
long previousmicros = 0;
long interval = 500000;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
void setup()
{
// setup serial - diagnostics - port
Serial.begin(115200);
// setup pins
pinMode(sensorPin, INPUT);
// setup interrupt
attachInterrupt(0, RPM, RISING);
}
void RPM()
{
rpmcount++;
}
void loop()
{
unsigned long currentmicros = micros();
int sensorValue = digitalRead(sensorPin); // sensor value is read
if (currentmicros - previousmicros > interval)
{
previousmicros = currentmicros;
detachInterrupt(0);
revs=10.0/rpmcount;
rpm =600.0/revs;
Serial.print("rpmcount : ");
Serial.print(rpmcount);
Serial.print(" rpm : ");
Serial.println(rpm);
lcd.clear();
lcd.begin(16, 2);
lcd.print("RPM = ");
lcd.setCursor(6,0);
lcd.print(rpm,0);
rpmcount=0;
attachInterrupt(0, RPM, RISING);
}
}
This works and measures the RPM correctly however the value is always a factor of 60. How can I change this so that it will measure the RPM more accurately, to say +-5 RPM? I tried playing about with my revs and rpm formulas but had little success.
Right now you have
rpm =60.0*rpmcount;
You will have to store the count over a longer time and calculate the value from that (or change how often loop is run)
In the ISR instead of increment a count, compute the amount of time elapsed since the last ISR fire.
unsigned long someArray[2] = {0,0};
unsigned char rpmindex = 0;
void RPM_isr()
{
rpmindex ^= 1;
someArray[rpmindex] = micros();
}
// And then in the main body
{
// Disable interrupts
// Copy someArray to a localArray
// reEnable interrupts
// Compute the interval between ISR fires
unsigned long interval = abs(localArray[0] - localArray[1]);
// Compute RPM
unsigned int rpm = (60*1000000)/interval;
}
Pseudo code interpreted at your own risk.
Edit: For bad math on RPM computation.
I'm writing some code for a homework assignment, and part of the assignment is to have a 16x2 LCD display a clock that shows how long the arduino has been on for. This clock needs to run off a timer interrupt. I have gotten that part working, but the second part of the assignment is to have another interrupt (an external button as the signal) that will reset the clock to all 0's. Currently the ISR doesn't seem to do anything. Any ideas?
#include <LiquidCrystal.h>
#include <TimerOne.h>
int buttonPin = 2;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
int secs, tens, minutes, tenminutes, hours, tenhours;
volatile long counter = 0;
void setup() {
Timer1.initialize(100000);
Timer1.attachInterrupt(timerISR);
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(0, buttonPressISR, CHANGE);
lcd.begin(16, 2);
lcd.setCursor(0,1);
lcd.print("0");
lcd.setCursor(1,1);
lcd.print("0");
lcd.setCursor(2, 1);
lcd.print(":");
lcd.setCursor(3,1);
lcd.print("0");
lcd.setCursor(4,1);
lcd.print("0");
lcd.setCursor(5, 1);
lcd.print(":");
lcd.setCursor(6,1);
lcd.print("0");
lcd.setCursor(7,1);
lcd.print("0");
}
void loop() {
secs = (counter/10) % 10;
tens = (counter/100) % 6;
minutes = (counter/600) %10;
tenminutes = (counter/6000) %6;
hours = (counter/36000) %10;
tenhours = (counter/360000) %10;
lcd.setCursor(7, 1);
lcd.print(secs);
lcd.setCursor(6,1);
lcd.print(tens);
lcd.setCursor(4, 1);
lcd.print(minutes);
lcd.setCursor(3, 1);
lcd.print(tenminutes);
lcd.setCursor(1, 1);
lcd.print(hours);
lcd.setCursor(0, 1);
lcd.print(tenhours);
}
void buttonPressISR() {
counter = 0;
}
void timerISR() {
counter++;
}
You know there is an Arduino Stack Exchange beta site for Arduino questions?
I can't see any obvious errors in the code. Are you aware that interrupt pin 0 on the code is actually the digital pin 2 on the Arduino?
This is my code and everything works fine except that i don't know how to get the melody i've created to loop? Another question is how do i get the LED to flash simultaneously as the melody plays?
#include "pitches.h"
int led = 9;
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4
};
int noteDurations[] = { 4, 8, 8, 4,4,4,4,4 };
void setup() {
pinMode(led, OUTPUT);
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}
}
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
simply put your code inside a standalone function, and call it from within loop:
#include "pitches.h"
int led = 9;
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4
};
int noteDurations[] = { 4, 8, 8, 4,4,4,4,4 };
void play_melody();
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
// keep the LED on while the melody's playing
play_melody();
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
// pause for one second between each melody iteration (you can remove this for continuous playing)
delay(1000);
}
void play_melody() {
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}
return;
}
If you don't know about function callings, I suggest you to open a C language book like the K&R, and read it, there's a lot to learn for you in it about the basics of C language programming.
在loop()內播放音樂,同時;在Timer中斷程式callback()內控制LED閃爍
例: Timer1.attachInterrupt(callback);
Playing the melody in the loop() function and blinking LED in the timer interrup function at the same time.
ex: Timer1.attachInterrupt(callback);