I'm currently trying to put together a datalogger with an OLED screen and am having issues when adding the SD library to the script. I've seen that others have gotten error messages when combining Oled and SD cards that is related to RAM. Though in my case, the code runs, there is no error message, but the screen doesn't display anything. The code below shows the "OLED code" where the Oled display wouldn't show anything when I added the "#include <SD.h>". Also, since I quite new to this, some constructive criticism of the code itself is also welcome
Thanks!
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "Adafruit_MCP9808.h"
#include <Adafruit_BME280.h>
Adafruit_BME280 bme; // use I2C interface
Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
//oled definitions
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Create the MCP9808 temperature sensor object
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();
void setup() {
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // Address 0x3D for 128x64
// Clear the buffer
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.setTextColor(WHITE);
while (!Serial);
Serial.println("Loading");
if (!tempsensor.begin(0x18)) {
Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
while (1);
}
Serial.println(F("Found MCP9808!"));
tempsensor.setResolution(3); // sets the resolution mode of reading, the modes are defined in the table bellow:
// Mode Resolution SampleTime
// 0 0.5°C 30 ms
// 1 0.25°C 65 ms
// 2 0.125°C 130 ms
// 3 0.0625°C 250 ms
if (!bme.begin()) {
Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
while (1) delay(10);
}
bme_temp->printSensorDetails();
bme_pressure->printSensorDetails();
bme_humidity->printSensorDetails();
}
void loop() {
float temp = bme.readTemperature(); // get temperature in degree Celsius
float humi = bme.readHumidity(); // get humidity in rH%
float pres = bme.readPressure(); // get pressure in Pa
tempsensor.wake();
//Serial.println (tempsensor.getResolution());
float c = tempsensor.readTempC();
float f = tempsensor.readTempF();
//float sensor=analogRead(A4);
display.setCursor(0, 0);
display.print(F("Temp_1: "));
display.print(c,2);display.println(" \tC ");
display.println("");
display.print(F("Temp_2: "));
display.print(temp,2);display.println(" \tC ");
display.println("");
display.print(F("Humidity: "));
display.print(humi,2);display.println(" %RH ");
display.println("");
display.print(F("Pressure: "));
display.print(pres/100,2);display.println(" kPa ");
display.display();
delay(1000);
display.clearDisplay();
Its just memory problem. I fix it by decrease the resolution only for usage area.. Its not the best solution however good enough for me
This was apparently a memory issue.
I've now connected an Arduino Mega instead of a Nano, and the code ran nicely. I've also added the remaining piece of code that was necessary to log the sensor readings.
According to what I've read on other forums, the SD and SPI libraries take up quite a lot of memory.
Related
I am new to Arduino and Esp32 programming. I need to connect PCA9685 controller to ESP-32 cam to be able to control multiple servo motors but the SCL and SDA pins are occupied by the UART control board.
I searched for this and found something related to Wire.h library and wire.begin() and TwoWire but unable to implement it.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
// our servo # counter
uint8_t servonum = 0;
void setup() {
Wire.begin();
Wire.begin(2,15,100000); // this is to map new SCL and SDA pins to 2,15
Serial.begin(9600);
Serial.println("8 channel Servo test!");
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
delay(10);
}
// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {
double pulselength;
pulselength = 1000000; // 1,000,000 us per second
pulselength /= SERVO_FREQ; // Analog servos run at ~60 Hz updates
Serial.print(pulselength); Serial.println(" us per period");
pulselength /= 4096; // 12 bits of resolution
Serial.print(pulselength); Serial.println(" us per bit");
pulse *= 1000000; // convert input seconds to us
pulse /= pulselength;
Serial.println(pulse);
pwm.setPWM(n, 0, pulse);
}
void loop() {
pwm.setPWM(0, 0, 250);
}
Here is the test code that I am trying to run.
I got the implementation idea from https://randomnerdtutorials.com/esp32-i2c-communication-arduino-ide/
There are a few problems that I encounter along with no response from the code-
When PCA9685 is connected to esp32-cam and I try to upload the code, it doesn't work and gives fatal error.
When the reset button is pressed before upload the built-in flash blinks. This is presented as a problem because while trying to upload the code without PCA9685 attached, the code is uploaded without any fatal error and there is no 'flash blink'.
I tried a code from the same website mentioned above that looks for I2C devices and prints their address. It shows no devices even though the servo controller is connected to it.
PS- I am an absolute beginner in this field.
I'm having a strange problem that I hope someone can help with. My sketch works perfectly when uploaded to my UNO, but when I unplug it and plug it back in, it doesn't work correctly. If I re-upload it, it works again until power is cycled.
Once uploaded, the LCD reads:
Ferm:73.4 73/75
Room:75.1 75/75
After cycling power:
Ferm:73.45 73/18
Room:74.83 75/18
So after cycling power, I now get 2 decimal places and the "high" temp is stuck at "18".
/*
The circuit:
* 5V to Arduino 5V pin
* GND to Arduino GND pin
* CLK to Analog #5
* DAT to Analog #4
*/
// include the library code:
#include "Wire.h"
#include "Adafruit_LiquidCrystal.h"
#include <OneWire.h>
#include <DallasTemperature.h>
//variables for temp readings
float fermTemp;
float fermTempL=100;
float fermTempH=5;
float roomTemp;
float roomTempL=100;
float roomTempH=5;
// set OneWire bus to digital PIN 4 on the Arduino
#define ONE_WIRE_BUS 4
// Setup OneWire instance
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to Dallas Temp
DallasTemperature sensors(&oneWire);
// Connect via i2c, default address #0 (A0-A2 not jumpered)
Adafruit_LiquidCrystal lcd(0);
void setup()
{
// set up the LCD's number of rows and columns:
lcd.begin(16, 2);
// turn on backlight
lcd.setBacklight(HIGH);
}
void loop() {
readtemp();
LCDPrint();
}
void readtemp()
{
// get data from sensors
sensors.requestTemperatures();
fermTemp = (sensors.getTempFByIndex(0));
roomTemp = (sensors.getTempFByIndex(1));
// check/set High and Low temp
if (fermTemp<fermTempL) {
fermTempL=fermTemp;
}
if (fermTemp>fermTempH) {
fermTempH=fermTemp;
}
if (roomTemp<roomTempL) {
roomTempL=roomTemp;
}
if (roomTemp>roomTempH) {
roomTempH=roomTemp;
}
}
void LCDPrint()
{
lcd.setCursor(0,0);
lcd.print("Ferm:");
lcd.print(fermTemp,1);
lcd.setCursor(11,0);
lcd.print(fermTempL,0);
lcd.print("/");
lcd.print(fermTempH,0);
lcd.setCursor(0,1);
lcd.print("Room:");
lcd.print(roomTemp,1);
lcd.setCursor(11,1);
lcd.print(roomTempL,0);
lcd.print("/");
lcd.print(roomTempH,0);
}
I counted your characters, 16 per line. If you have a 16X2 display, there might be characters printed beyond the screen. I suspect it was not really 18, but something larger, say 180 or 1800. That could have been a result of failed first attempt to read temperature. This reading is stuck with you as temp High. In your code, you should define a reasonable high temperature, such as 125. Don't update temp High if it is above the reasonable temperature.
To confirm it, print temp High to serial port and inspect the value.
I have this RFID reader "Rosslare AY-X12", and it's working with Wiegand 26bit. I have an arduino mini Pro and connected together it's working fine but it only reads the card one time and then I have nothing.
When I put on the card arduino reads that card but only one time during the card is near by the reader and it again reads that card when I put off the card and then I put on. But I want to read that card continuously, I mean when the card is near by the Reader still reading the card, every 1ms reads that card.
Do you have any idea how to do that ? Is there any RFID arduino library which can do that? I had got the Mifare and its can do that. But this 125Khz reader which can communicate over Wiegand can't do that or I don't know how to do that.
I'm using this library : https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
My previous answer was deleted. I am going to make another attempt to answer the questions.
Do you have any idea how to do that ?
This cannot be done by Arduino because Arduino in your case is just reading the D0 and D1 pulses from your RFID reader. Since your RFID reader Rosslare AY-X12 does not send out continuous output of wiegand protocol, there is no way Arduino can read more than what was not sent to it.
The common RFID readers will not send continuous data of the same card because in the common use case (entry/exit/attendance), normally one tap is to check-in and another tap is to check-out. If the RFID reader sends continuous data of the same card, the main system receiving the multiple wiegand data will be confused and will not be able to determine if the user actually wish to check-in or check-out.
Is there any RFID arduino library which can do that?
No. There is no such RFID Arduino library. If the RFID reader is not sending out continuous data, there is no way the receiver (Arduino) can receive them.
Is there a way to achieve this?
Yes, there are some readers that has the option to turn on the continuous output of data, for example 714-52 Mifare® ID Reader with selectable outputs. In its specification :
Continuous output with tag in field or single transmission
With this reader configured to continuous output, you can then use Arduino and the monkeyboard wiegand library to read the data.
I wrote my own wiegand code. Its not that difficult. I attached interrupts to the data pins and when they change I log the zero or one. You then build up the binary string and once timed out because no bits coming in. Then you convert the binary to decimal.
#include <LiquidCrystal.h>
int data0 = 2; //set wiegand data 0 pin
int data1 = 3; //set wiegand data 1 pin
unsigned long bit_holder; //unsigned long (positive 32 bit number)
unsigned long oldbit = 0;
volatile int bit_count = 0;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
unsigned long badge;
unsigned int timeout;
unsigned int t = 800;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.print("Present Badge");
delay(2);
Serial.println("Present Badge");
pinMode(data0, INPUT);
digitalWrite(data0, HIGH);
pinMode(data1, INPUT);
digitalWrite(data1, HIGH);
attachInterrupt(0, zero, FALLING); //attach interrupts and assign functions
attachInterrupt(1, one, FALLING);
}
void zero(){
bit_count ++;
bit_holder = (bit_holder << 1) + 0; //shift left one and add a 0
timeout = t;
}
void one(){
bit_count ++;
bit_holder = (bit_holder << 1) + 1; //shift left one and add a 1
timeout = t;
}
void loop() {
timeout --;
if (timeout == 0 && bit_count > 0){
lcd.clear();
lcd.print("Dec:");
lcd.print(bit_holder);
lcd.setCursor(0,1);
lcd.print("Hex:");
lcd.print(String(bit_holder,HEX));
Serial.print("bit count= ");
Serial.println(bit_count);
Serial.print("bits= ");
Serial.println(bit_holder,BIN);
oldbit = bit_holder; //store previous this value as previous
bit_count = 0; //reset bit count
bit_holder = 0; //reset badge number
}
}
You may need to find a reader that offer a continuously reading, as I know almost of Wiegand Reader in the market can't perform a continuously reading because they have a "onboard" control that controls this...
Maybe you can try with Arduino Serial RFID Reader...
try a this timer libary Timer1 and mayby try this code it worked for me, my tags and cards now reads continuously.
Greetings from Denmark
Gregor
#include <Timer1.h>
//******************************************************************
// ATmega168, ATmega328:
// - Using Timer 1 disables PWM (analogWrite) on pins 9 and 10
// ATmega2560:
// - Using Timer 1 disables PWM (analogWrite) on pins 11 and 12
// - Using Timer 3 disables PWM (analogWrite) on pins 2, 3 and 5
// - Using Timer 4 disables PWM (analogWrite) on pins 6, 7 and 8
// - Using Timer 5 disables PWM (analogWrite) on pins 44, 45 and 46
//******************************************************************
unsigned int lastTime;
#include <SoftwareSerial.h>
SoftwareSerial RFID = SoftwareSerial(2,4);
char character;
String our_id;
void setup()
{
// Disable Arduino's default millisecond counter (from now on, millis(), micros(),
// delay() and delayMicroseconds() will not work)
disableMillis();
// Prepare Timer1 to count
// On 16 MHz Arduino boards, this function has a resolution of 4us
// On 8 MHz Arduino boards, this function has a resolution of 8us
startCountingTimer1();
lastTime = readTimer1();
Serial.begin(9600);
RFID.begin(9600);
}
void loop()
{
unsigned int now = readTimer1();
while (RFID.available()>0)
{
character = RFID.read();
our_id += character;
lastTime = now;
}
if (our_id.length() > 10) {
our_id = our_id.substring(1,13);
Serial.println(our_id);
our_id = "";
}
delay(1000);
}
I just purchased Seeed's TFT Touch Shield 2.0 for Arduino, but I cannot seem to figure out how to access the SD card while maintaining the ability to draw to the screen. The tutorials and documentation are quite insubstantial (for me), and most questions on the product site seem to be directed to the same wiki page, which doesn't explain anything about the SD interface, other than what example file draws bitmaps from the card.
I've used the SD interface with the Ethernet Shield before, but it's been a long time since then, so I can't quite remember the ins and outs. From my old code, it seems that, for normal usage of the SD library, you simply do:
#include <SD.h>
void setup()
{
pinMode(4, OUTPUT);
if (!SD.begin(4))
{
//Fail
}
... //Open file, read, etc.
}
To use the TFT screen normally (with the exception of drawing bitmaps), you do as such:
#include <SD.h>
#include <TFTv2.h>
#include <SPI.h>
void setup()
{
TFT_BL_ON; //Enable Backlight
Tft.TFTinit(); //Initialize TFT Screen
Tft.drawCircle(100, 100, 30,YELLOW); //Draw
}
In the provided example program on the wiki page for drawing bitmaps from the SD card, the setup code looks like this:
#include <SD.h>
#include <TFTv2.h>
#include <SPI.h>
#define chipSelect 4
Sd2Card card;
void setup()
{
pinMode(11,INPUT);
pinMode(12,INPUT);
pinMode(13,INPUT);
TFT_CS_HIGH;
pinMode(chipSelect,OUTPUT);
digitalWrite(chipSelect,HIGH);
Serial.begin(38400);
SPI.begin();
Tft.TFTinit();
//SPI.setClockDivider(SPI_CLOCK_DIV4);
//SDcard_info();
/**/
DDRB |= 0x04;
card.init(SPI_FULL_SPEED,chipSelect);
if(!SD.begin(chipSelect))//SPI_QUARTER_SPEED,
{ //53 is used as chip select pin
Serial.println("failed!");
while(1);
}
Serial.println("SD OK!");
Tft.setCol(0,239);
Tft.setPage(0,319);
Tft.sendCMD(0x2c);//start to write to display ram
TFT_BL_ON;
}
In loop() bitmaps are sequentially opened with SD.open(), drawn, and then closed with SD.close().
What I assume is happening is that pins 11 through 13 are set to input for some SPI-related reason, the TFT chip select 'enabled' mode is set to HIGH, and then the screen is subsequently enabled. Serial moniter is started, followed by SPI, and then the TFT. After those things happen, it does something unknown to me, starts the card, and then uses the standard card initialization method. It finishes up by preparing to draw the bitmaps and sends this 'command 0x2c', which is used frequently in the underlying libraries to "start to write to display ram".
The problem is that I have tried initializing the TFT and SD card using this code, and then attempted to draw graphics as shown in my second example, but this did not work. I need to be able to read bytes from the SD card, and then be able to draw simple graphics on-screen, and repeat.
So my question is: Is anyone who has used this shield before or has experience with this able to explain how one should go about writing the code to allow usage of both the SD card and screen or how the initialization and SPI processes work to make this possible?
Thanks for your answers in advance!
(Also, if this is not the correct SE site for this question, please feel free to migrate it accordingly.)
The solution to this problem is quite simple actually, and I must have been doing something wrong when I had combined the source files before.
The initialization code looks like this:
#include <SD.h>
#include <TFTv2.h>
#include <SPI.h>
Sd2Card card;
void setup()
{
pinMode(11, INPUT); //Pin mode changes; not sure what for
pinMode(12, INPUT);
pinMode(13, INPUT);
TFT_CS_HIGH; //Something with chipselect and the TFT
pinMode(4, OUTPUT); //Set chipselect pin to OUTPUT
digitalWrite(4, HIGH); //Set chipselect mode
SPI.begin(); //Start SPI
Tft.TFTinit(); //Initialize the TFT
TFT_BL_ON; //Turn on the TFT Backlight
Serial.begin(9600); //Start serial output
DDRB |= 0x04; //Some sort of processor IO port?
if(!SD.begin(4)) //Start the SD card
{
while(true) { } //Fail
}
}
It is basically the bitmap initialization code, with the extra TFT commands at the end left out. After this, both the screen and the SD card are usable, as was desired.
I'm trying to display a potentiometer's value on an Adafruit ST7565 GLCD. My serial monitor is giving me values between 1.62-1.67, while the GLCD ranges from -20,000 to +20,000. I'm not sure whether the arithmetic/data type is wrong or whether I am allocating memory improperly for the "sprintf" conversion.
#include "ST7565.h"
#include "stdlib.h"
char buffer[5];
int ledPin = 13; // LED connected to digital pin 13
char str[8];
// the LCD backlight is connected up to a pin so you can turn it on & off
#define BACKLIGHT_LED 10
// pin 9 - Serial data out (SID)
// pin 8 - Serial clock out (SCLK)
// pin 7 - Data/Command select (RS or A0)
// pin 6 - LCD reset (RST)
// pin 5 - LCD chip select (CS)
ST7565 glcd(9, 8, 7, 6, 5);
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16
void setup() {
Serial.begin(9600);
// turn on backlight
pinMode(BACKLIGHT_LED, OUTPUT);
digitalWrite(BACKLIGHT_LED, HIGH);
// initialize and set the contrast to 0x18
glcd.begin(0x18);
glcd.display(); // show splashscreen
delay(3000);
glcd.clear();
Serial.println(" ");
digitalWrite(BACKLIGHT_LED, HIGH);
glcd.drawstring(0,0," ");
glcd.display();
glcd.clear();
}
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
digitalWrite(BACKLIGHT_LED, HIGH);
Serial.println(voltage);
sprintf(str,"%d",voltage); // converts to decimal base.
glcd.drawstring(0,0,str);
glcd.display();
delay(500);
glcd.clear();
}
Any insight is appreciated. I don't have much formal programming experience, so linking a tutorial about data types won't be of any use. I need to see a specific example like this worked out to truly understand.
You used %d to print out a float; this is undefined behaviour (in your case, it probably dumped out the integer representation of some part of the float's bit sequence).
Instead of using sprintf (since sprintf(..., "%f", val) is reportedly broken on Arduino), use dtostrf:
dtostrf(voltage, 0, 2, buf);
Also, if you're interested, you can see how Arduino prints floats here.