I have an Arduino Mega and would like to change the SDA&SCL pins from A4&A5 to A14&A15.
So that I can control an I2C LCD from there, I have the library but I don't see where the pins are set; however, I would imaging they have to be set somewhere...
I am new to c++ and libraries so my eyes may just be skipping over it
The standard i2c library uses dedicated hardware, which is tied to certain pins. To send a byte out in this way, your program writes a byte to a certain register (this will take just a few clock cycles), and the hardware takes care of shifting the bits out one by one on the SDA pin and toggling the SCL pin automatically.
What you probably looking for is software i2c, which implements the same protocol in software and should allow you to use arbitrary pins. It is likely that this library is considerably slower and uses more resources than the standard one: When your program wants to send a byte, the library has to extract a single bit, lookup which data pin you had defined, write the bit-value to that pin pin, lookup which pin you had defined for the clock, toggle that pin, wait a bit, toggle the clock again and so on, all in software. This will take a lot of time, but maybe you don't care in your application.
I2C pins are set in hardware in AVRs; there is no way to change them other than to use a completely different I2C bus, assuming the MCU even has any others in the first place.
If you want to use pins other than those available in hardware then you'll need to find a library that bit-bangs I2C over normal GPIOs, and then modify the LCD library to use that library instead of hardware I2C.
This question is quite old, but I would like to suggest this LiquidCrystal Software I2C library, because I didn't found many other working resources online and this library implements I2C protocol in software, so you can use any input/output pin of your Arduino.
Just need to specify SDA and SCL pins as 4th and 5th arguments when creating the LiquidCrystal_I2C object and then has the same functions of the standard LiquidCrystal_I2C library.
So, for example, you if you want to use pin 3 and 4, as SDA and SCL respective, your hello word will be:
// https://github.com/francesco-scar/LiquidCrystal_Software_I2C
// Based on https://github.com/johnrickman/LiquidCrystal_I2C project
#include <LiquidCrystal_Software_I2C.h> // Include library
LiquidCrystal_I2C lcd(0x3f, 16, 2, 3, 4); // Set the LCD address to 0x27 for a 16 chars and 2 line display
void setup() {
lcd.init(); // LCD initialization
lcd.backlight(); // Turn on backlight
lcd.print("Hello, world!"); // Print Hello, world!
}
void loop() {
}
Related
tl;dr can someone tell me if it is possible to set custom pins for an I2C slave (client, peripheral) within the Arduino environment?
Context
On an ESP32 (ESP32-WROVER from Freenove) I am trying to communicate with 2 devices that are I2C masters (Adafruit Monster M4sk)
On this particular ESP32-WROVER board the default SDA and SCL pins are used by a camera.
So I have to set up I2c on different pins. I'm using pin 2 as SDA and pin 15 as SDL.
I can easily set up I2C as a MASTER on those pins, works just fine using Wire.begin(2,15). I find lots of documentation about setting custom pins, multiple busses using Wire or TwoWire.
What I really want to do is something like this:
#include <Wire.h>
#define SDA1 2
#define SCL1 15
#define SDA2 21
#define SCL2 22
#define SLAVE_ADDRESS_ON_BUS_1 0x52
#define SLAVE_ADDRESS_ON_BUS_2 0x33
setup()
{
Wire.begin(SDA1,SCL1,SLAVE_ADDRESS_ON_BUS_1); // Join I2C bus 1 using pins 2 and 15
Wire1.begin(SDA2,SCL2,SLAVE_ADDRESS_ON_BUS_2);// Join I2C bus 2 using pins 21 and 22
Wire.onReceive(receiveI2CBus1Event); // register event for when master on i2c bus 1 writes
Wire.onRequest(WriteToI2CBus1Event); // register event for when master1 wants on i2c bus 2 wants to read
Wire1.onReceive(receiveI2CBus2Event); // register event for when master on i2c bus 2 writes
Wire1.onRequest(WriteToI2CBus2Event); // register event for when master on i2c bus 2 wants to read
}
As far as I can tell there is no way to use either Wire or TwoWire to create a peripheral on a custom set of pins...
Wire.begin(MY_ADDRESS);
I have tried re-defining SDA and SCL but that does not seem to work
Note I am running Expressif's ESP32 libraries v2.0.2 (ESP32 Libraries 1.0.6 and prior did not support ESP32 as a slave)
I have tried this (this being redefining SDA and SCL) using both Arduino IDE 1.8.19 and Arduino IDE 2.0.0.rc5
I can't be the first person trying to have an ESP32 act as an i2c slave using something other than the default pins...
Am I gonna have to resort to some sort of I2C bridge/switch/mux? if so, any recommendations? (preferably recommendations with arduino sample code showing how a master can assign an address to another master)
Thank you.
You're very close, you just have the order of the parameters flipped. The address comes first, followed by the pin numbers.
There are optional parameters to Wire.begin() that allow you to specify the pins used for the I2C controller in slave mode:
bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);
So you could call
Wire.begin(MY_ADDRESS, SDA1, SCL1);
and optionally specify the frequency as a final argument if you need to.
While this form of begin() looks like it's for a master, its code explicitly sets the is_slave flag:
is_slave = true;
and calls i2cSlaveInit().
I haven't actually used this so I can't promise it works, but this is the way the code is organized.
I want to program Stm32 bluepill with Arduino IDE but when I want to define pins like I write " pinMode(A10, OUTPUT)" it gives error. the error is "'A10' was not declared in this scope"
I want to know how should I declare Pins in Arduino IDE for STM32
Based on the error you're reporting, you're not building your code for the correct board. I suspect you're targeting the ArduinoUNO (default) which does not have an A10.
Also, as hcheung's answer mentions, the name on the blue pill is "PA10".
Follow the instructions here to install the board configuration for the STM "blue pill" then select it and build again.
https://maker.pro/arduino/tutorial/how-to-program-the-stm32-blue-pill-with-arduino-ide
Note, the board selection as of today is now "STM32F1 series" instead of "STM32F103C series" as specified at the link.
One reason could be there is not ADC pin of number 10 for the currently selected board (check the board on tool -> boards), there might be fewer number of ADC pins, e.g. try A0.
Or maybe you have selected wrong board. Bluepill isn't included in the Arduino IDE, by default. So you have to add it to your IDE first.
There is a nice instruction here on how to do this and a sample code.
https://maker.pro/arduino/tutorial/how-to-program-the-stm32-blue-pill-with-arduino-ide
Remember that this newly installed library could have small differences in syntax compared with standard Arduino code, Like this example that is taken from the mentioned site:
void setup() {
// change pin PC13
pinMode(PC13, OUTPUT);
}
//infinite loop
void loop() {
digitalWrite(PC13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(PC13, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
As you can see here the pin is selected using "PC13", and not just a number aka "13".
So in this case by installing the library used in the mentioned site you should write PA0 to PA7 for using ADC.
Here is a sample picture displaying the name of the pins and their features:
For STM32 Blue Pill with Arduino Core, digital pins are named based on its port and pin number, such as PB1, PA10.
There is no A10, I assumed that you mean PA10 (which was marked on the Blue Pill PCB as "A10" (for Port A Pin 10) due to limit space on the PCB.
To use it as a digital pin, simply use PA10 to address it, that is:
pinMode(PA10, OUTPUT);
or because PA10 internally happened to be referred as D10, you can also use:
pinMode(10, OUTPUT); //not recommended
For better understanding of all the pin assignments for STM32F103 Blue Pill, please take a look at the source code here and here.
I have started using the Arduino language instead of the pyFirmata version. I am using an Arduino UNO. I have run into the same problem, and that is that the OLED won't work. I've tried 2 different OLEDs, one from UCTRONICS and one from HiLetGo. They are both I2C 128x64 OLEDs, and the UCTRONICS one is yellow and blue while the HiLetGo one is all white. I've tried 2 different codes, one that I made and one example from the ssd1306 library. There are no errors, the OLEDs just don't light up. The board is alco connected to 4 touch sensors I am using for the same project but they have nothing wrong with them (yet). I have troubleshooted for a while now, and I have been able to pinpoint where the error is (probably) located. This is my code: (even though the ssd1306 I2C 128x64 example also doesn't work.) I also do not want suggestions that require extra hardware that I don't have, like an RTC (even though it is not related to this that was the only example I could come up with) This is my code: (even though the ssd1306 I2C 128x64 example also doesn't work.)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
#define sw 128
#define sh 64
Adafruit_SSD1306 display(sw, sh, &Wire, OLED_RESET);
void setup() {
Serial.begin(9600);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x78);
display.cp437(true);
pinMode(A4, OUTPUT);
}
void loop() {
digitalWrite(A4, HIGH);
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("test");
Serial.println("test");
digitalWrite(A4, LOW);
}
Like always, I only have 1 week to fix this so help would be greatly appreciated.
Your I2C address setting appears wrong. Arduino's Wire library (doc) uses 7 bit address. The last bit is read/write bit and Wire automatically takes care of it. So, you want to chop off the least significant bit and set the address to 0x3C instead of 0x78.
Adafruit_SSD1306 library actually uses 0x3C as a default address. See the declaration and notes for begin() in .h and .cpp files.
For more info, I suggest looking at SSD1306 data sheet. Here is the I2C data format. See how slave address is formatted.
Yes, these displays can be very annoying. I have experienced it myself.
First, go to the website of the supplier and see if they suggest any specific libraries to use. Some of the main issues I encountered are:
The supply voltage of the screen is not the standard 5V you expected but higher or lower. If it's lower or you supplied 5V to a 3.3V power in you might even have damaged or broke the display.
You switched the SDA/SDL wires up, forgot to connect some wires or have a faulty ground. Does the backlight work?
The library uses the wrong clockspeed
The I2C address the display is listening on differs from the one used in the library (this is the most common one for me)
It's not every time the fault of hardware, check the program as well. Load example test program and try again. https://iotforgeeks.com/i2c-oled-display-not-working/ helped me to resolve the same issue.
I try to communicate, read and write, from Arduino - slave - to RPi - master - with Android Things.
If i R/W, with a level converter, from RPi to Arduino 5v (16Mhz), everything works fine.
So i decide to eliminate the level converter, and use a 3v3 Arduino mini pro (8Mhz).
The write works fine, but when i try to read from the Arduino, the signal stops.
5v_16Mhz
After the Setup to 9, 0 address, and reads to 9, the signal still low and received the data. No problem.
3v3_8Mhz
After the Setup to 9, 0 address, and read to 9, the signal goes high and the data stop.
I used the same example for the Slave:
#include <Wire.h>
byte RFID[20] = {9,8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8,9,1,2};
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Wire.onReceive(receiveEvent); // register event
Serial.begin(115200); // start serial for output
pinMode(13, OUTPUT);
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Serial.println("Master ask");
digitalWrite(13, HIGH);
delay(250);
Wire.write(RFID, 20);
digitalWrite(13, LOW);
}
// function should be executes whenever data is received from master
// this function is registered as an event, but it's called every time the RPi
// call the Device.
void receiveEvent(int howMany) {
while (0 < Wire.available()) {
byte RTC_syn = Wire.read(); // receive byte
Serial.println(RTC_syn);
}
}
I really don't know how drives the signal high...
Someone can help me?
If i R/W, with a level converter, from RPi to Arduino 5v (16Mhz), everything works fine.
So i decide to eliminate the level converter, and use a 3v3 Arduino mini pro (8Mhz).
The write works fine, but when i try to read from the Arduino, the signal stops.
This is because level converter you had in the 5V/3.3V version does more than shift the voltage. It also acts as a nice high-impedance buffer between the two devices that helps keep the signal driven and avoids loading effects.
Without the buffer, your bus is likely experiencing a bit of loading. You can try to combat this by adding stronger pull-up resistors. The RPi3 has 1.8k pull-up resistors on the I2C lines, which generally works but can be marginal depending on the input impedance of the slave device. The Arduino Mini has pads to install I2C pull-ups but there are none by default.
The recommended pull-up resistance for a pure 3.3V I2C bus is closer to 1k, so you likely just need to add some stronger pull-ups between SCL/SDA and +3.3V. Anything you add will be in parallel to the RPi3 resistors so factor that into your calculation. For example, adding 4.7k resistors brings the effective resistance down to about 1.3k.
If you are unable to solve it with pull-ups, you can achieve the same buffer effect without level translation by using a line driver IC (random example).
If the level converter works, you should stick with it.
Communication protocols like I2C encode data into a series of logic HIGH and logic LOW signals. What does HIGH / LOW mean? It depends on the devices. For the majority of embedded devices, logic LOW will be ground, 0V.
For Arduinos and Raspberry Pis, the source voltage is different (3.3V versus 5V). This difference can lead to several potential issues.
The 5V signal is too high for the Arduino to handle, causing the Arduino to stop working or reboot
The 3.3V signal is not strong enough to be interpreted as logic HIGH. Embedded devices have circuits that round signals to HIGH/LOW, and the thresholds may not be entirely even. A 5V input may only accept 4.5V or higher, interpreting everything else as LOW or in an indeterminate state.
I am new to electronics, and trying to get my 1602 LCD to work with an I2C adapter.
I got my backlight to work, but I can't get text to show.
This is my current code:
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(5, 0);
lcd.print("HELLO");
}
void loop() {
lcd.backlight();
delay(2000);
lcd.noBacklight();
delay(2000);
}
I checked for the I2C address with the scanner and it is 0x27.
I Googled a bit and came past this post where someone posted this:
Simple test
Apply +5v / GND to LCD - display - and than apply background LED power ( sometime marked A/K) to the LCD module.
No other connections ( data etc.) are necessary for this power up test.
You should be able to discern ALL chatterers fields, but connecting contrast pot will make it easier.
It MAY not be totally visible but the module will initialize ( internally) on power up and ALL characters fields should show.
Of course by now you know you need basically three "power" connections to the LCD - LCD itself, contrast and backlight.
Sure looks as the main LCD power is missing - hence no intelligent data can be processed / displayed.
I did this test aswell and came to these results:
When providing 5V to the backlight, it shows up bright.
When providing 5V to both the backlight and the LCD itself the backlight gets darker but nothing else shows up.
I then accidentally put the I2C adapter upside down, but that did give me the text blocks.
How could I get the text to show? What am I currently doing wrong?
Minor point, have you tried trimming the pot? I suspect that this sets the contrast, and I forgot this and I had a blank display.
Yours Simon M.
Your I2C Adapter turns serial data into parallel output to the LCD pins.
Are you sure this is done to the pins you expect ?
Especially if you mix any I2C adapter to any 16 pin LCD module, you should check which signals you put where ...
If required, there are LiquidCrystal_I2C constructors where you can specify the LCD pins, if the default won't fit.