So, I want to write method than can provide blinking on LCD in special possition a specail value without using delay() method.
I wrote the next method:
void blink(int cursorIndex, int val) {
lcd.setCursor(cursorIndex, 0);
if (millis() - blinkTime > 1000) {
blinkTime = millis();
printValOnLCD(val);
} else {
lcd.print(" ");
lcd.print(" ");
}
}
But it work not in that case that I exectly need.
It blink only one time when millis() - blinkTime > 1000 in other cases it show __ .
How can I provide one blinking per one second??
This following code should let the LCD blink once per second. The blinking speed can be changed by changing the blinkSpeed_ms variable.
void blink(int cursorIndex, int val) {
lcd.setCursor(cursorIndex, 0);
blinkSpeed_ms = 1000; //This variable defines the blinking speed
if ((millis() - blinkTime > blinkSpeed_ms) && (millis() - blinkTime < blinkSpeed_ms * 2)) {
printValOnLCD(val);
} else if(millis() - blinkTime > (blinkSpeed_ms * 2)) {
blinkTime = millis()
}else {
lcd.print(" ");
lcd.print(" ");
}
}
Related
everyone, I am using, P10 Dot Matrix Display with Arduino Uno. I am using P10 Library from this link. P10_LED and I need to display the one-hour countdown on the display module. The given library uses TimerOne library. So for countdown i am using MsTimer2 library which usese timer2 of arduino.
When I individually run both of the libraries, my scrolling on the display is perfect and my timer library also generates a pure 1sec interrupt. Now what I did is the added both the library in my project and I am doing the countdown. But now suddenly my MsTimer2 doesn't generate pure 1sec.
Here is the code.
#include <MsTimer2.h>
#include <TimerOne.h>
#include"SPI.h"
#include <ledP10.h>
LedP10 myled;
uint8_t minute = 0, second = 0, hour = 1;
volatile bool xIsCountDone = false;
volatile bool xIsInterruptOcuured = false;
char time_buff[100];
void setup()
{
Serial.begin(9600);
myled.init(3,4,8,9 ,3);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
//myled.showmsg_single_scroll("this is single led test",2,8,0);
MsTimer2::set(1000, count);
MsTimer2::start();
}
void loop() {
if (xIsInterruptOcuured == true)
{
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
}
}
void count(){
second--;
if (second <= 0 || second > 59)
{
second = 59;
minute--;
if (minute <= 0 || minute > 59)
{
minute = 59;
hour--;
if (hour <= 0 || hour > 12)
{
xIsCountDone =true;
}
}
}
Serial.println(millis());
xIsInterruptOcuured = true;
}
In the interrupt routine, I am printing millis() to see at after how many ms the interrupt occurs. The results are something like this.
15:33:02.684 -> 1199
15:33:04.371 -> 2396
15:33:06.059 -> 3592
15:33:07.746 -> 4783
15:33:09.434 -> 5986
15:33:11.121 -> 7181
15:33:12.855 -> 8379
15:33:14.543 -> 9578
15:33:16.230 -> 10768
15:33:17.918 -> 11974
15:33:19.605 -> 13168
15:33:21.292 -> 14365
15:33:22.980 -> 15562
15:33:24.667 -> 16751
15:33:26.402 -> 17955
When I use only MsTimer2 library the results are something like this.
15:37:21.241 -> 998
15:37:22.226 -> 1998
15:37:23.257 -> 2998
15:37:24.241 -> 3998
15:37:25.226 -> 4998
15:37:26.257 -> 5998
15:37:27.241 -> 6998
15:37:28.225 -> 7998
15:37:29.257 -> 8998
15:37:30.241 -> 9998
15:37:31.225 -> 10998
15:37:32.256 -> 11998
15:37:33.241 -> 12998
15:37:34.225 -> 13998
15:37:35.256 -> 14998
My guess, it's happening because of the TimerOne library but I couldn't find the solution. In ledP10.cpp there is a callback method for timer1 and it contains loops and may line of code. But is timer1 interrupts priority is higher than timer2? But according to the ATmega328p datasheet, the vector no. for Timer2 is less than Timer1. Doesn't that mean Timer2 has a higher priority? My ultimate goal is to do the one-hour countdown. Any help with this problem or any additional information i am missing which will be useful or any other solution other than using timer2 interrupt will be appreciated.
Regards.
EDIT
Here is the code I used with millis() and gave me around 12min difference.
uint8_t new_buff[100];
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000; //the value is a number of milliseconds
uint8_t minute = 0, second = 0, hour = 1;
char time_buff[100];
void setup()
{
myled.init(3,4,8,9,3);
Serial.begin(9600);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
//Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = millis();
}
void loop() {
currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
Serial.println(millis());
second--;
startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = currentMillis;
}
}
This answer targets your example using millis(). You can avoid accumulating errors over time, by not setting the next update relative to the current time. Rather just increment it by one second each time. This way, it does not matter if your main loop gets blocked by an interrupt for some milliseconds.
Also note that you don't have to save hours, minutes and seconds separately, you can just calculate them:
unsigned long nextMillis = 1000;
unsigned long targetTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds
void setup(){
myled.init(3,4,8,9,3);
Serial.begin(9600);
updateMyLed(0);
}
void updateMyLed( unsigned long elapsedTime ){
char buffer[100];
unsigned long timeLeftInSeconds = (targetTime - elapsedTime) / 1000;
uint8_t hour = timeLeftInSeconds / 3600;
timeLeftInSeconds -= hour * 3600;
uint8_t minute = timeLeftInSeconds / 60;
uint8_t second = timeLeftInSeconds - (minute * 60);
sprintf((char*)buffer, " %d%d:%d%d:%d%d", (hour/10), (hour%10), (minute/10), (minute%10), (second/10), (second%10));
myled.showmsg_single_static((char*)buffer, 0);
}
void loop() {
if( millis() >= nextMillis ){
updateMyLed(nextMillis);
nextMillis += 1000;
}
}
In the Arduino world, some libraries are disabling the interrupts.
This happens with all WS2812 LEDS and also yours. Without disabling interrupts, there would be a timing problem with the external devices.
So, you should never use interrupts or library with interrupts, if you use another one who will disable the interrupts.
Do you want use the P10 library? You can, but do not use interrupts in your code. Do not add other libraries like IR_remote, since it will not work correctly.
Back to your problem, just update your timer in the loop. And do not wait until the a second is over to update your time by 1 second! This will always be more than 1second.
You can for example convert the millis to seconds seconds = millis() / 1000;.
Your loop could be so:
void loop() {
currentSeconds = millis() / 1000; //get the current "time" (actually the number of milliseconds since the program started)
if (currentSeconds != savedSeconds) //test whether the period has elapsed
{
savedSeconds = currentSeconds;
Serial.println(millis());
second--;
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
}
}
I have some time controlled segments inside my main loop that turning LEDs on/off and are storing values from a sensor into a linked list (Using this linked list library: https://github.com/ivanseidel/LinkedList). I have my baud rate set at 34800 because I want data to be transferred at a faster rate, and I have a a function that for loops the sensor data captured within the the timed loops and prints them.
The weird problem I'm facing is when I Serial.print() the data, it only works when I have a Serial.println()(just Serial.print() does not work) inside each of the if blocks. If I remove this Serial.println() the code does not work, and just gives out garbage in the Serial monitor.
What is causing this issue? How do I resolve it? Here is the code:
void setup( void )
{
Serial.begin( 38400 );
while(!Serial){
}
pinMode (ledPin670, OUTPUT);
pinMode (ledPin850, OUTPUT);
digitalWrite(ledPin670,HIGH);
digitalWrite(ledPin850,HIGH);
Start = millis();
timer = micros();
}
void loop( void )
{
if ( millis() - Start < 100 )
{
//Serial.read();
Serial.println(" ");
digitalWrite(ledPin670,LOW);
analogRead( A0 );
valList670.add(analogRead( A0 ));
time670.add(micros() - timer);
++Count;
}
else if ((millis() - Start >= 100) && (millis() - Start < 110)){
digitalWrite(ledPin670,HIGH);
}
else if ((millis() - Start >= 110) && (millis() - Start < 220))
{
// Serial.read();
Serial.println(" ");
digitalWrite(ledPin670,HIGH);
digitalWrite(ledPin850,LOW);
analogRead( A0 );
valList950.add(analogRead( A0 ));
time850.add(micros() - timer);
++Count2;
}
else if ((millis() - Start >= 220) && (millis() - Start < 230)){
digitalWrite(ledPin850,HIGH);
else
{
//Serial.println(millis() - Start);
Serial.println("count:");
Serial.println( Count );
Serial.println( Count2 );
Serial.println( Count3 );
arrayLoop(valList670, time670,10);
arrayLoop(valList850, time850,10);
valList670.clear();
valList850.clear();
time850.clear();
time670.clear();
timer = micros();
Count = 0;
Count2 = 0;
Start = millis();
}
void arrayLoop(LinkedList<int> &pinNum,LinkedList<unsigned long> &timer, int valDiff){
// Serial.println(pinNum);
int listSize = pinNum.size();
for (int h = 0; h < listSize; h+=valDiff) {
//Get value from list
if (h <= listSize){
int val = pinNum.get(h);
unsigned long tim = timer.get(h);
Serial.print(tim);
Serial.print("\t");
Serial.println(val);
}
}
}
Only call Serial.print() once.
If you define the circumstances under which you do, and do not, want to call Serial.print(), we can help you see that it happens that way.
Basically, though, you need to count how many times you have already printed. Only actually call print if the count is 0.
i am currently working in a ardunio alarm clock project without and rtc for school. I have a problem with my hour variable not increasing and my conditionals that checks it.
This code mostly works i can set time in hr and minutes but when the timer reaches 59 minutes the hour doesnt increase by 1. The second code that has been posted is the bit where the problem lies. Any tips/help would be appreciated.
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <EEPROM.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
const int numofMenus = 4;
int currentMenu = 0;
String menu[4][2] = {{"Set hour", "hr"}, {"Set minutes", "min"}, {"Set alarm", "o"}, {"Current Time", "ha"}};
int parameters[24];
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.noBlink();
}
void loop() {
inputAction();
if (currentMenu == 0)
{
printScreen();
}
if (currentMenu == 1)
{
printScreen();
}
if (currentMenu == 2)
{
printScreen();
}
if (currentMenu == 3)
{
int hr = parameters[0];
int mn = minute(parameters[1]);
int sec = second();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
if (parameters[1] >= 0 && parameters[1] <= 59 && sec < 59) {
parameters[0];
printtime(parameters[0]);
}
else if (parameters[1] == 59 && second() == 59) {
if (parameters[0]>=0 && parameters[0]<24){
parameters[0];
printtime(parameters[0]++);
//delay(1000);}
/*else if (parameters[0] == 24){
parameters[0]= 0;
printtime(parameters[0]);
}*/
}
}
lcd.print(":");
if (sec >= 0 && sec < 59) {
printtime(parameters[1]);
}
else if (sec == 59) {
parameters[1];
printtime(parameters[1]++);
delay(1000);
}
lcd.print(":");
printtime(sec);
/* if (sec == 60) {
mn+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}
if (mn == 60) {
hr+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}*/
delay (100);
}
}
void inputAction() {
uint8_t buttons = lcd.readButtons();
if (buttons & BUTTON_UP) {
if (currentMenu == 0) {
currentMenu = numofMenus - 1;
} else {
currentMenu--;
}
} else if (buttons & BUTTON_DOWN) {
if (currentMenu == numofMenus - 1) {
currentMenu = 0;
} else {
currentMenu++;
}
} else if (buttons & BUTTON_RIGHT) {
parameters[currentMenu]++;
} else if (buttons & BUTTON_LEFT) {
parameters[currentMenu]--;
}
}
void printScreen() {
lcd.clear();
lcd.print(menu[currentMenu][0]);
lcd.setCursor(0, 1);
lcd.print(parameters[currentMenu]);
lcd.print(" ");
lcd.print(menu[currentMenu][1]);
delay(100);
}
void printtime(int data) {
if (data >= 0 && data < 10) {
lcd.print('0');
}
lcd.print(data);
}
I don't think it is a good strategy to throw all those delays in the code. If you want to work with an RTC, you need to be mindful of those delays as they will affect the functionality of your program. If you don't account for delay properly, they will accumulate as errors. An error of 100 msecs will be seen as error in seconds easily within days.
I did not go through your code because it is hard to understand. I propose you have a look at this code which should be placed in your loop() function:
delay(100);
parameters = parameters + 100;
long rtcSeconds = parameters / 1000;
int seconds = (int) (rtcSeconds % 60); // Range 0 . 59 units: Secs
int minutes = (int)(((rtcSeconds - seconds) / 60) % 60); // Range 0 . 59 units: Mins
int hours = (int) (((rtcSeconds - minutes*60 - seconds) / (3600)) % 24); // Range 0 . 23 units: Hrs
I am using your parameters[0] field to keep track of the time in your syste, in milliseconds units. The field increases every 100 msecs as you see. You can recover the different time values using a combination of the modulus (%) and division operations. Now, I know you need to increase the time in your program. To do so, it is easy:
If you want to increase one second, do this: parameters[0] += 1000;
If you want to increase one minute, do this: parameters[0] += 1000 * 60;
If you want to increase one hour, do this: parameters[0] += 1000 * 3600;
Now, you might need to work with long variables as int have a limited range. You also need to watch for the time roll over when you change your time. If you are decreasing the time, you need to watch pramaters[0] doesn't become negative. In case it does, you need to add 3600 * 24 * 1000 msecs to force it jump one day ahead (3600 * 24 is one day in seconds). I hope you understand this is not a solution to your problem but an alternative approach using a little bit of a simpler code structure.
void loop() {
photoCell = analogRead(pin);
time = millis();
if (photoCell >= 400){
timeon = millis();
led = 1;
while (analogRead(pin) >= 400) {
timer = millis() - timeon;
//Serial.print("On");
//Serial.println(timer);
}
}
if (photoCell <= 400) {
timeoff = millis();
led = 0;
while (analogRead(pin) <= 400) {
timer2 = millis() - timeoff;
//Serial.print("Off");
//Serial.println(timer2);
}
}
if (timer >= 175 && timer <= 200 && led == 1) {
Serial.print("Char = ");
Serial.println(".");
codearray[i] = 8;
i++;
}
if (timer >= 580 && timer <= 600 && led == 1) {
Serial.print("Char = ");
Serial.println("-");
codearray[i] = 9;
i++;
}
This is my current code which works fine using a photocell plugged into A0 and an led wired into pin 9. The serial monitor displays whether or not I am flashing a dot or dash, morse corde, based on the timing.
However.. When I add this bit of code
if (codearray[0] == 8 && codearray[1] == 8 &&
codearray[2] == 8 && codearray[3] == 0) {
Serial.print("s");
}
The monitor prints nothing. This bit of code fills out an array I set up so I can print back into alphabetical the morse code that was deciphered. I'm pretty sure my logic is correct.
Looking to see if anyone understands why the 2nd bit of code would conflict with the first or what can be wrong with the analog input or serial monitor.
Your question is off topic here; probably belongs on stack overflow.
But it is obvious that you forgot to call Serial.Begin(9600); in setup(); n.b. 9600 is the arduino default baud rate.
The goal of this program is to write a string to the Arduino's LCD, and cycle between two different messages. The problem with my current version is that it cycles back and forth with no delay. How would I get these to write one at a time?
Here is the code, I left out some of the irrelevant parts:
#include <LiquidCrystal.h>
#include <string.h>
// These are the pins our LCD uses.
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// initalize the lcd, and button input at zero.
int lcd_key = 0;
int adc_key_in = 0;
//define values for each button
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // detects the value from the buttons
// The buttons give values close to which values we saet them between.
if (adc_key_in > 1000) return btnNONE; // When the input is greater than 1000 that means no buttons are being pressed,
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // if there is some issue with values, the programs will not break.
}
void setup()
{
Serial.begin(9600); //Set the serial monitor.
lcd.begin(16, 2); //Set the LCD
}
void loop()
{
timer = millis();
if (left == true) //Right alignment
{
lcd.clear() ; //Clear any existing text
lcd.setCursor(5, 0); //Set cursor to right side.
timer = millis();
if (millis() < (timer + 5000)) {
if (show1 == true) //See if first line should be displayed. If false, nothing is displayed.
{
lcd.print("Time");
}
//Second line
lcd.setCursor(4, 1);
if (show2 == true)//See if second line should be displayed
{
lcd.print("12:00 PM");
}
}
if ((timer + 5000) > millis() < (timer + 10000)) {
//Display Date
lcd.setCursor(5, 0);
if (show1 == true)//See if first line should be displayed.
{
lcd.print("Date");
}
//Second line
lcd.setCursor(1, 1);
if (show2 == true)//See if second second should be displayed.
{
lcd.print("Nov. 16, 2012");
}
}
}
}
This condition if ((timer + 5000) > millis() < (timer + 10000)) makes no sense in C - at least it don't do what you are expecting.
It is invoked like below:
first (timer + 5000) > millis() is invoked and its value is 0 or 1
next 0 or 1 (from first condition) is compared with (timer + 10000) which is always true (assuming that you have not overflow time value and you are not comparing with large negative number)
You should use something like if ((timer + 5000) > millis() && mills() < (timer + 10000)) or rather:
int hlp_time = millis();
if ((timer + 5000) > hlp_time && hlp_time < (timer + 10000))
since time returned by millis() will vary between each check in if condition.
Have you tried setting timer = millis(); to outside the loop?