Shift Register reacting to shiftout function incorrectly - c++

I am new to this shift register. So i created a online simulation of the shift register that hook up to 8 LEDs, the ol' 8bit translate to 8 LED experiment. My design is that when i entered a character like "a" into the serial monitor, it will show in the result in code like 100000, and it should shown in the LEDs too(the sixth LED should light up).
char character;
byte input = 0b01;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
byte input = 0b01;
if (Serial.available() > 0) {
character = Serial.read();
if (character == 'a') {
Serial.print("character received: ");
Serial.println(character);
for (int i = 0; i < 5; i++) {
updateShiftRegister(input);
input = input << 1;
delay(100);
}
Serial.print("Input: ");
Serial.print(input, BIN);
Serial.println();
} else {
Serial.print("Please retry.\n");
}
}
}
void updateShiftRegister(byte input) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, input);
digitalWrite(latchPin, HIGH);
}
Problem is when i run the thing, the result is alright but the shift register in the simulation is wack. Every LEDs turn on,
I found the shiftout function is main cause of this, any idea why it is causing every LED to light up?

Related

Arduino communication via COM Port isnt working

I want my Arduino to light up the LED if he reads "on" in the Serial Port.
At Serial.print(serialData); it prints out what he reads but at if (serialData == "on") it wont work.
int led1 = 9;
int led2 = 6;
String serialData;
void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(10);
}
void loop() {
if (Serial.available() > 0){
serialData = Serial.readString();
Serial.print(serialData);
if (serialData == "on"){
analogWrite(led1, 255);
}
if (serialData == "off"){
analogWrite(led1, 0);
}
}
}
Anybody know, what I'm doing wrong?
There are two issues in your code:
The timeout is set to 10ms. In 10ms, you can at best enter a single character. readString() will return after a single character and the read string will likely be "o", "n", "f".
When you hit the RETURN key, a carriage return and a line feed character are also transmitted ("\r\n").
The solution is to increase the timeout considerably and to use readStringUntil() to read until the newline character is discovered. This is the indication that a full word (or command) has been entered.
Additionally, the carriage return and line feed need to be trimmed off.
#include <Arduino.h>
int led1 = 9;
int led2 = 6;
String serialData;
void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(2000);
}
void loop() {
if (Serial.available() > 0){
serialData = Serial.readStringUntil('\n');
serialData.trim();
Serial.println(serialData);
if (serialData == "on"){
analogWrite(led1, 255);
}
if (serialData == "off"){
analogWrite(led1, 0);
}
}
}

How do I call a functions from serial input in Arduino?

I'm super new to programming so apologies if this is a badly phrased question or just confusing code! I have some Arduino code that automates things inside my campervan. The arduino reads data from temperature and battery sensors, and also controls the heating system. I had everything working, but the code was really inefficient and buggy, and I'd frequently get gibberish back when reading from the sensors. The internet suggested I use start and end markers to identify the useful information and discard the rest. Some copy and pasting and editing, I've ended up with the code below. However while the start and end markers are filtering out the information, I can't seem to make it call functions which actually do the controlling of things (e.g., move a servo, switch the heater on etc.).
// Van control system.
// Heater and sensor control code
// 20.03.2021
// This code controls the heater and reads from temp and power sensors.
#include <Servo.h> //Controls the heater air flow
#include <DHT.h> //temp sensor
#define DHT_SENSOR_TYPE DHT_TYPE_11
#include <Adafruit_INA260.h> //this breakout board monitors battery level and power consumption
Adafruit_INA260 ina260 = Adafruit_INA260();
Servo myservo; // servo to turn on heater
int pos = 90;// variable to store the servo position
#define DHTPIN 3 // temp sensor pin
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
// Set up pins, the controller uses a common ground, so only one
// ground connection is needed. Pin A and B are used as pairs to
// generate a quadrature signal that mimics a rotary encoder (which controllers the heater)
int pinA = 9; //Pin A of encoder output
int pinB = 10; // Pin B of encoder output
int offPin = 11; // Acts as momentary on button
int onPin = 12; // Act as momentary off button
const byte numChars = 32; //serial input buffer
char receivedChars[numChars];
boolean newData = false;
void setup() {
Serial.begin(9600);
dht.begin(); //initalise temp sensor
myservo.attach(5); //attaches servo to pin.
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(onPin, OUTPUT);
pinMode(offPin, OUTPUT);
digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(onPin, LOW);
digitalWrite(offPin, LOW);
ina260.begin(); //initalise power sensor
Serial.println("<ATMega is ready>"); //confirms that microcontroller is ready
}
//End of set up process.
void loop() {
recvWithStartEndMarkers(); //for maximum efficiency, loop should be as short as possible.
showNewData();
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; //terminate string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.println(receivedChars); //this works and I get the character back in the serial monitor.
if (receivedChars == "H") {
upHeat(); //this doesn't work, if the character is H I want to call this function
}
else if (receivedChars == "C") {
downHeat();
}
else if (receivedChars == "O") {
heatOn();
}
else if (receivedChars == "F") {
heatOff();
}
else if (receivedChars == "a") {
servoPosOne();
}
else if (receivedChars == "s") {
servoPosTwo();
}
else if (receivedChars == "d") {
servoPosThree();
}
newData = false;
}
}
void upHeat() { //this generates a quadrature to simulate a rotary encoder.
digitalWrite(pinB, HIGH);
delay(200);
digitalWrite(pinA, HIGH);
delay(200);
digitalWrite(pinB, LOW);
delay(200);
digitalWrite(pinA, LOW);
delay(200);
digitalWrite(pinB, HIGH);
delay(200);
digitalWrite(pinA, HIGH);
delay(200);
digitalWrite(pinB, LOW);
delay(200);
digitalWrite(pinA, LOW);
}
//I haven't included the rest of the functions because, if one works, the rest will.
Any help would be amazing. I feel like it could be something really simple that I'm missing. Equally it could all be completely terrible!

Coding arduino traffic ligth with timer and button

I need make a traffic light that works on countdown:
when number on timer == 0 or if button pressed green led should turn on
otherwise red led
There is my loop,
I tried without for loop and button worked but if I add for loop (for timer) button not responding
thank you
crosswalk_button = digitalRead(2); //That will read the state of the button, if it's pressed or not
for (int i = numberfor7digit; i >= 0; i--) { //numberfor7digit is = 9
numbers(i); //numbers is a function i wrote which shows int it takes currently i
delay(1000);
if (crosswalk_button == 0) { //If you press the button for the crosswalk on with the green one for the crosswalk
numbers(0);
greenhigh(); // green high is a function too, which turns on green light
}
// when number in 7 segment is 0 it will turn on green
else if (i == 0) {
numbers(0);
greenhigh();
}
// for any other number it turns on red
else {
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
}
}
}
Few things which will help you to design this system effectively are:
Use Interrupts to read the value of the button
This will make the turning on Green Light irrespective of what's been executed by the Arduino when the button is pressed.
Example: Illustration to show how to configure a button for interrupt
int interruptPin = 2; //button attached to this pin
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), greenhigh, LOW);
}
void loop() {
//Your code inside this loop
}
void greenhigh() {
//Your code for turning green light high
numbers(0);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW);
}
Seven Segment Display
Now, since the button is fixed writing code for seven segment display will be simpler.
Example: Illustration to show SSD working
digitalWrite(RED_LED, HIGH);
for (int i = numberfor7digit; i >= 0; i--) {
numbers(i);
delay(1000);
}
greenhigh();
delay(5000);
Conclusion
Complete code can be written as:
int interruptPin = 2; //button attached to this pin
int numberfor7digit = 9;
int GREEN_LED = 10; //TODO: Input here your actual green led
int RED_LED = 11; //TODO: Input here your actual red led
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), greenhigh, LOW);
}
void greenhigh() {
//TODO: Your code for turning green light high
numbers(0);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW);
}
void numbers(int n) {
//Your implementaion of numbers()
}
void loop() {
digitalWrite(RED_LED, HIGH);
for (int i = numberfor7digit; i >= 0; i--) {
numbers(i);
delay(1000);
}
greenhigh();
delay(5000);
}
You have to read the status of your button every time the loop runs i.e. the for loop that you are using.
And I have also removed the delay and replaced it with an if statement similar to blink without delay example.
One more thing, there is no need to create a crosswalk_button variable
You can directly replace it with digitalRead(2)
Use this code, it should work.
void loop() {
for(int i = numberfor7digit; ; i >= 0; i--) {
static long previousMillis = 0;
if(millis() - previousMillis >= 1000) {
numbers(i);
previousMillis = millis();
}
crosswalk_button = digitalRead(2);
if(crosswalk_button == false || i == 0) {
i = 0;
numbers(i);
greenhigh();
} else {
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW):
}
}
}

How to use both water flow rate sensor and GSM(SIM900) in arduino uno?

#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);
String outMessage1 = "Hello Arduino";
String outMessage2 = "Arduino2";
volatile int NbTopsFan; //measuring the rising edges of the signal
int Calc;
int hallsensor = 2; //The pin location of the sensor
int condition_1 = LOW;
int condition_2 = LOW;
int gsm_condition_1 = HIGH;
int gsm_condition_2 = HIGH;
String destinationNumber = "+6014681xxxx";
void rpm () //This is the function that the interupt calls
{
NbTopsFan++; //This function measures the rising and falling edge of the hall effect sensors signal
}
// The setup() method runs once, when the sketch starts
void setup() //
{
Serial.begin(9600); //This is the setup function where the serial port is initialised,
SIM900.begin(19200);
SIM900power();
delay(20000);
pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input
pinMode(13, OUTPUT);
attachInterrupt(0, rpm, RISING); //and the interrupt is attached
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void SIM900power()
{
digitalWrite(9,HIGH);
delay(1000);
digitalWrite(9,LOW);
delay(5000);
}
void sendSMS1()
{
gsm_condition_2 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\""); //recipient's mobile number, in international format
delay(100);
SIM900.println(outMessage1); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
}
void sendSMS2()
{
gsm_condition_1 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\""); //recipient's mobile number, in international format
delay(100);
SIM900.println(outMessage2); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
}
void gsm_check()
{
if (condition_1 == HIGH && gsm_condition_1 == HIGH) {
condition_1 = LOW;
gsm_condition_1 = LOW;
sendSMS1();
}
else if ( condition_2 == HIGH && gsm_condition_2 == HIGH) {
condition_2 = LOW;
gsm_condition_2 = LOW;
sendSMS2();
}
}
void water_rate()
{
NbTopsFan = 0; //Set NbTops to 0 ready for calculations
sei(); //Enables interrupts
delay (1000); //Wait 1 second
cli(); //Disable interrupts
Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate in L/hour
Serial.print (Calc, DEC); //Prints the number calculated above
Serial.print (" L/hour\r\n"); //Prints "L/hour" and returns a new line
}
void loop ()
{
water_rate();
if ( Calc > 100 ) {
digitalWrite(13, HIGH);
condition_1 = HIGH;
}
else {
digitalWrite(13, LOW);
condition_2 = HIGH;
}
gsm_check();
}
I cannot use water flow rate sensor and GSM(SIM900) together. Once I use both then GSM will not work at all. I have tried a lot of methods to solve it but still not succeeded. Hope you guys can give me some help.
I was having the same problem. The solution is to stop the time 2 interrupt from running to send the message.
The edit of your code:
void sendSMS2()
{
cli();
gsm_condition_1 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\"");
delay(100);
SIM900.println(outMessage2); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
sei();
}
The problem is that the sensor can only read using the interrupt, but your sim900 will not function when the interrupt is active. So you'll have to temporarily disable the interrupt and then carry on. Also, SIM900.print("AT+CMGF=1\r"); should be in void loop.
The last problem is that your sim 900 will not send integer. So you'll have to send it as a string. Please follow this example for that: http://microembarcado.blogspot.com.au/p/wr-bridge-send-sms-with-temperature.html
I sat for about 4 hours to figure it out.
Hope this makes things a little simplier for you.

Arduino clear buffer

#include <stdio.h>
#define LED 13
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available() == 4) {
char command[5];
for (int i = 0; i < 4; i++) command[i] = Serial.read();
command[4] = '\0';
Serial.println(command);
if (strcmp(command, "AAAA") == 0) {
digitalWrite(LED, HIGH);
Serial.println("LED13 is ON");
} else if (strcmp(command, "BBBB") == 0) {
digitalWrite(LED, LOW);
Serial.println("LED13 is OFF");
}
}
}
I have that code, that reads 4 characters long strings. However, I need it to ignore any string that is not 4 characters long.
So, imagine this input:
AAAA
BBBB
BBB
AAAA
Right now, it reads {"AAAA", "BBBB", "BBBA"}.
I need it to read {"AAAA", "BBBB", "AAAA"}.
Any idea? Thank you.
You can check the duration time of inter-character delay. Set a timeout, such as 100ms. When there is no more data received after the specified timeout, that means the whole string is transferred completely. Then you can check the length of the string and execute your application logic.