Home→Forums→MonoBrick EV3 Firmware→I2C communication PCF8574AP
- This topic has 21 replies, 5 voices, and was last updated 10 years, 2 months ago by Anders Søborg.
-
AuthorPosts
-
October 7, 2014 at 20:25 #4867
Bartłomiej DrozdParticipantHi, i have a problem with I2C communication. I need to control PCF8574AP with EV3, i used this, but i think, PCF8574AP doesn’t have register. How can i do it? If i use standard WriteRegister(byte register, byte data) it doesn’t work. Please, help me with this…
October 8, 2014 at 12:10 #4868
Tcm0ParticipantYou probably don’t need the resistors on the breadboard. Can you read registers?
October 8, 2014 at 16:25 #4869
Bartłomiej DrozdParticipantwhy i don’t need the resistors? In datasheet PCF8574AP doesn’t have any registers
October 8, 2014 at 21:11 #4870
Tcm0ParticipantThe PCF8574AP must have registers because otherwise no I2C device can work with it. But the registers are programmed in the software.
October 9, 2014 at 09:21 #4871
Helmut WunderParticipanthi,
you don’t need to address a register for R/W (it’s just register 0 then) –
maybe this helps:I2C Interface
I2C communication with this device is initiated by a master sending a start condition, a high-to-low transition on the SDA I/O while the SCL input is high.
After the start condition, the device address byte is sent, most-significant bit (MSB) first, including the data direction bit (R/W).
This device does not respond to the general call address.
After receiving the valid address byte, this device responds with an acknowledge, a low on the SDA I/O during the high of the acknowledge-related clock pulse.
The address inputs (A0–A2) of the slave device must not be changed between the start and the stop conditions.The data byte follows the address acknowledge. If the R/W bit is high, the data from this device are the values read from the P port. If the R/W bit is low, the data are from the master, to be output to the P port.
The data byte is followed by an acknowledge sent from this device. If other data bytes are sent from the master, following the acknowledge, they are ignored by this device. Data are output only if complete bytes are received and acknowledged.this is the (quite simple) NXC Code you might have a look at (it reads single muxed sensors, passed by it’s number “input”; nevertheless, you might also read and return the whole bitpattern by 1 reading instead of course for quicker readings :
int ReadPCF8574(char PCF8574Port, byte PCF8574ID, char input) { byte cnt = 0x02; byte I2CMsg[]; byte inbuf[]; byte Address = PCF8574ID; byte nByteReady = 0; int result = -1; int loop; ArrayBuild(I2CMsg, Address); Wait(8); while (loop == STAT_COMM_PENDING) { loop = I2CStatus(PCF8574Port, nByteReady); } if (I2CBytes(PCF8574Port, I2CMsg, cnt, inbuf)) { result = inbuf[1]; } if( result == (result | (1<<input-1)) ) { result = 0; } else { result = 1; } if(result==-1){ TextOut(0, LCD_LINE1, "Error: Check the"); TextOut(0, LCD_LINE2, " connection!"); Wait(500); ClearScreen(); } return result; }
- This reply was modified 10 years, 2 months ago by Helmut Wunder.
October 9, 2014 at 14:33 #4873
Bartłomiej DrozdParticipantsorry, i don’t know how to read a register… in NXC i did it that:
void writeReg(byte reg) { byte buff[] = {0x70, 0x00}; buff[1] = reg; int nbytes; I2CWrite(I2C, 0, buff); while(I2CStatus(I2C, nbytes) == STAT_COMM_PENDING); Wait(100); }
because i need only outputs and that is working fine, but i need it in C# on EV3. Maybe i’m doing something wrong? Here is my code…
Main.csusing System; using System.Threading; using MonoBrickFirmware; using MonoBrickFirmware.Display.Dialogs; using MonoBrickFirmware.Display; using MonoBrickFirmware.Sensors; using MonoBrickFirmware.UserInput; namespace test { class MainClass { public static void Main (string[] args) { EventWaitHandle stopped = new ManualResetEvent (false); ButtonEvents btn = new ButtonEvents (); byte address = 0x70; byte[] data1 = new byte[8] {1, 1, 1, 1, 1, 1, 1, 1}; byte[] data0 = new byte[8] {0, 0, 0, 0, 0, 0, 0, 0}; LcdConsole.WriteLine ("hello world!"); pcf pcf = new pcf (SensorPort.In1, address); btn.EscapePressed += () => { LcdConsole.WriteLine("stopped"); stopped.Set (); }; btn.LeftPressed += () => { pcf.WriteReg(0, data1); LcdConsole.WriteLine("write data1"); }; btn.RightPressed += () => { pcf.WriteReg(0, data0); LcdConsole.WriteLine("write data0"); }; stopped.WaitOne (); } } }
pcf.cs
using System; using MonoBrickFirmware; using MonoBrickFirmware.Sensors; namespace test { public class pcf : I2CSensor { public pcf (SensorPort Port, byte adress) : base (Port, adress, I2CMode.LowSpeed) { base.Initialise(); } public byte[] ReadReg(byte Register, byte Length) { return base.ReadRegister(Register, Length); } public void WriteReg(byte Register, byte[] Data) { base.WriteRegister(Register, Data); } public byte[] ReadAndWriteReg(byte Register, byte[] Data, int rxLength) { return base.WriteAndRead(Register, Data, rxLength); } public override string ReadAsString() { throw new NotImplementedException(); } public override void SelectNextMode() { throw new NotImplementedException (); } public override string GetSensorName() { return "PCF8574AP"; } public override void SelectPreviousMode() { throw new NotImplementedException (); } public override int NumberOfModes() { return 0; } public override string SelectedMode() { return "0"; } } }
October 9, 2014 at 17:42 #4874
Tcm0ParticipantYou can try to use “0x70” as the register.
October 9, 2014 at 17:59 #4875
Bartłomiej DrozdParticipantunfortunetly, it is not workking… i found source of sending function
/// <summary> /// Write and read an array of bytes to the sensor /// </summary> /// <returns>The bytes that was read</returns> /// <param name="register">Register to write to.</param> /// <param name="data">Byte array to write</param> /// <param name="rxLength">Length of the expected reply</param> protected byte[] WriteAndRead (byte register, byte[] data, int rxLength) { if (rxLength > BufferSize) throw new ArgumentOutOfRangeException("I2C Receive Buffer only holds " + BufferSize + " bytes"); if (data.Length > BufferSize) { throw new ArgumentOutOfRangeException("I2C Write Buffer only holds " + BufferSize + " bytes"); } bool dataReady = false; int replyIndex = 0; byte[] writeData = new byte[BufferSize];//30 Array.Copy (data, 0, writeData, 0, data.Length); ByteArrayCreator command = new ByteArrayCreator (); command.Append ((int)-1); command.Append ((byte)this.port); command.Append ((byte)1);//repeat command.Append ((short)0);//time command.Append ((byte)(data.Length + 2));//length of write data command.Append ((byte)((byte)I2CAddress >> 1)); command.Append (register); command.Append(writeData); command.Append ((byte)-rxLength); replyIndex = command.Data.Length; command.Append (new byte[BufferSize]);//make room for reply byte[] i2cData = command.Data; while (!dataReady) { unchecked { I2CDevice.IoCtl ((Int32)I2CIOSetup, i2cData); } int status = BitConverter.ToInt32 (i2cData, 0); if (status < 0) { throw new Exception ("I2C I/O error"); } if (status == 0) { byte[] reply = new byte[rxLength]; if (rxLength > 0) { Array.Copy(i2cData,replyIndex, reply,0, rxLength); } return reply; } } throw new TimeoutException("I2C timeout"); }
maybe this should help…
October 9, 2014 at 18:15 #4876
Helmut WunderParticipantI actually doubt that 0x70 is a valid register number.
It’s more supposed to be the device address, but there are several different PCF8574s out there with different device addresses like, e.g., 0x4E, 0x73 or something (CMIIW).
The registers are quite a different thing.
If you read a i2c byte the reading starts at 0x00 and then the read pointer is incremented automatically after each follow-up-reading. So if a i2c device has 10 registers starting at 0x00 you will reach the register number 0x05 by reading 5 bytes one after the other.For the PCF8574 simply start reading 2bytes starting at register 0x00;
the 1st byte contains the ack byte, the 2nd byte contains the bit I/O pattern.Anyway, f your code works by addr 0x70 using NXC it’s surely valid. Then it’s just a Mono source code issue.
- This reply was modified 10 years, 2 months ago by Helmut Wunder.
October 9, 2014 at 18:35 #4878
Bartłomiej DrozdParticipantin datasheet for PCF8574A address is
0 1 1 1 A2 A1 A0 0
and my A2, A1, A0 is 0, so b01110000 = 0x70. i should read bytes, but i need only write bits… i don’t understand too much…October 9, 2014 at 18:45 #4879
Helmut WunderParticipantyou first have to write bytes to initiate, and then read the values.
October 9, 2014 at 20:06 #4880
Bartłomiej DrozdParticipantok, i did that:
LcdConsole.WriteLine(BitConverter.ToString(pcf.ReadReg(2, 1)));
and i got “03” on lcd when i connect P0 to + and “02” when i connect P0 to -. So, register is just a number of port to read/write?October 10, 2014 at 07:26 #4881
Helmut WunderParticipantabout the technical details of i2c I don’t know more than I already told you, and the Mono code is far too complicated for me to understand, so what you are actually doing in your C# source is far beyond me.
My skills just fit to use NXC and Sketch C.
In Sketch C I just have to use wire.write() and wire.read(),
and for display output I just use Serial.write() or TextOut() –
that’s it, and that’s why I can use both NXC and Sketch (and no Mono at all).
So for Mono you would need professional Mono helpers 😉October 10, 2014 at 12:18 #4882
Tcm0ParticipantI’m not sure that “LcdConsole.WriteLine(BitConverter.ToString(pcf.ReadReg(2, 1)));” works.
Try it with “LcdConsole.WriteLine(Convert.ToString(pcf.ReadReg(2, 1)));October 10, 2014 at 19:38 #4883
Bartłomiej DrozdParticipantunfortunetly, that is not working… it display only “System.Byte[]”. When i use my version, it dislpay hex byte. When i change to pcf.ReadReg(16, 1) it is reading all 8 bits
-
AuthorPosts
You must be logged in to reply to this topic.
Follow