News:

Let's find out together what makes a PIC Tick!

Main Menu

I2C Speed

Started by tolyan249, Feb 23, 2026, 03:50 AM

Previous topic - Next topic

tolyan249

---------------------------------------------------------   
   
Device =  16F628A 
Xtal = 20   
 
     
   
   
'-------------------------- --------------------------------
                                                                   
Declare  SHOW_SYSTEM_VARIABLES = OFF 
Declare  FSR_CONTEXT_SAVE = OFF 
Declare  Reminders = OFF   
Declare  Warnings = OFF   
Declare  Optimiser_Level 0   
Declare  Bootloader = OFF 
                                                                   
;--------------------------------------------------------------

Declare PortB_Pullups = OFF 
Declare  All_Digital = On   
                                                                   
'-------------------------- ------------------------
                                                                   
Declare  LCD_Type ALPHA   
Declare  LCD_DTPin  PORTB.0   
Declare  LCD_ENPin  PORTB.5   
Declare  LCD_RSPin  PORTB.4
Declare  LCD_Interface  4   
Declare  LCD_CommandUs  2000   
Declare  LCD_DataUs  50 
Declare  LCD_Lines   2 

   
   
Declare   Slow_Bus  OFF 
Declare   BUS_SCL   OFF   
Declare   BUS_SDA   OFF
Declare   bus_Bitrate 400    '100kHz, 400kHz, 1000kHz  I2C_SPEED_FAST  ;

Dim as n byte
dim v as bit

loop
    BStart
v=1
     I2COut SDA,SCL,n,[0]
    If   BusAck=0 Then  v=0 
    BStop
delayms 500
goto loop

I use I2cOut and I2CIN, the speed is always 100KHz, I can't change this speed, what could be the problem, where should I look?
Thank you.

Is there a description of the I2C library somewhere, or a library file that proton ide uses?

I measure it with an oscilloscope, and the pulse width is 10ms, which should be 2.5ms at 400kHz. Nothing changes when I change Hbus_Bitrate to 400.
BusAck doesn't work either, and there's no confirmation.

Dompie

The program shown above has several errors, so there's no result, and the Positron compiler didn't create a HEX. Therefore, a PIC cannot be programmed. Therefore, you couldn't have measured any results with this program. I think you were using a product other than Positron.

Johan

top204

Is this yet another chatGPT code listing?

Stephen Moss

Quote from: tolyan249 on Feb 23, 2026, 03:50 AMI measure it with an oscilloscope, and the pulse width is 10ms, which should be 2.5ms at 400kHz. Nothing changes when I change Hbus_Bitrate to 400.
BusAck doesn't work either, and there's no confirmation.
If you are using Positron then I suggest you read page 152-156 of the manual as some of your declares are not using the correct names or exist at all.

I2Cout & I2Cin are for using a software (bit-bashed) I2C bus, I could be wrong but don't think you can change the speed, it is fixed in the command to the most commonly use speed. If you want to have more flexibility over the transmission speed then you will probably need to use the PICs hardware communications module (typically called MSSP) and configure the relevant register values to get the input/output you want.

The H in HBus_Bitrate (and other peripheral/comms commands) refers to using Hardware (usually the PICs MSSP peripheral module) to transmit/receive data, therefore using it will have no affect on the transmission speed of the software based I2Cin & I2Cout commands. Again, read the manual and ensure you are not mixing up software and hardware based commands I2C commands.

Quote from: top204 on Feb 23, 2026, 12:21 PMIs this yet another chatGPT code listing?
Not sure, but I was thinking it looks like something AI would spit out.

tolyan249

#4
I have the PROTON IDE 3.5 compiler

I'm attaching the program along with Proteus, and I've implemented my own I2C, as I couldn't find any descriptions for I2CIN and I2COUT


sendTM_Config:
  If COM_ADDR=0 Then Return
 
;=================================
GoSub I2C_Start2 
    countBUFW=1 
    Command_Byte=2
    GoSub Write_PMBusParam 
    BUF_W
  • = 29
    Command_Byte=2
    GoSub Write_PMBusParam
    BUF_W
  • = 32
    GoSub Write_PMBusParam 
       
GoSub I2C_Stop2
;================================
 Return

The program scans the addresses, finds them, and displays the temperature. If I write to the sensor's registers, the sensor responds to the temperature I set, and the LED on the sensor lights up and goes out when the temperature is set in the registers. However, for some reason, the sensor's temperature is not displayed, and instead, the temperature I set is constantly read from the sensor. I cannot understand the issu.




Dompie

We're now living 14-15 years later, so a lot has changed. I recommend buying a new Positron compiler.
Proton no longer exists, and I'm guessing the Proton version you use, is 3.5.2.7. The Installation.txt file shows November 15, 2011!
The contents of this Installation.txt file:
Proton Development Suite 3.5.2.7
Download Link:
Compiler V3.5.2.7: http://www.compile-it.com/pdsbeta/PDS/Version%203_5_2_7/Proton%20Compiler%20Setup%203.5.2.7%20-%20Win7%20%2832-bit%29.exe
Patch : http://www.mediafire.com/file/6ovav13ndeg11v7/XP%203.5.2.7.zip

Installation
•Install the Compiler and replace ProtonIDE.exe and PrPlus.exe with cracked version.
•Now you have an up-to-date full working version
 
« Last Edit: November 15, 2011, 05:15:42 17:15 by Ahmad_k » 
 

I (and many other forum members) would be happy to help you if you have a recent Positron version.

Johan

top204

Creating a software (bit-bashed) I2C interface in Positron is relatively straightforward, as the code listing below illustrates. It is a library that implements all the elements of I2C, and can be slowed down or speeded up by changing values in the delays between pin toggles. :-)

$ifndef _I2C_SOFTWARE_INC_
$define _I2C_SOFTWARE_INC_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' I2C_Software.inc
' Software I2C writing and reading routines.
' Written for the Positron8 BASIC compiler by Les Johnson.
'
' Setup the default pins for SDA and SCL
'
$ifndef I2C_SDA_Pin
    $define I2C_SDA_Pin PORTC.4
    $SendWarning "$define I2C_SDA_Pin missing from main program, so using the default pin of PORTC.4"
$endif

$ifndef I2C_SCL_Pin
    $define I2C_SCL_Pin PORTC.3
    $SendWarning "$define I2C_SCL_Pin missing from main program, so using the default pin of PORTC.3"
$endif

'----------------------------------------------------------------------------------------------
' Delay a fixed number of microseconds and clock cycles
'
$define I2C_hDelayUs() DelayUS 3                        ' Delay a number of microseconds
$define I2C_hDelayCs() DelayCs 1                        ' Delay a number of clock cycles

'----------------------------------------------------------------------------------------------
' Send a single byte to the I2C bus
' Input     : pData holds the byte to write
' Output    : None
' Notes     : MSB first
'
Proc I2C_WriteByte(pData As Byte)
    Dim bIndex As Byte

    For bIndex = 7 Downto 0                             ' Create a loop for the 8-bits
        If pData.7 = 1 Then
            PinInput I2C_SDA_Pin                        ' Make the SDA pin an Input (High)
        Else
            PinOutput I2C_SDA_Pin                       ' Make the SDA pin an Output (Low)
        EndIf
        I2C_hDelayUs()
        PinInput I2C_SCL_Pin                            ' Make the SCL pin an Input (High)
        I2C_hDelayUs()
        PinOutput I2C_SCL_Pin                           ' Make the SCL pin an Output
        I2C_hDelayUs()
        pData = pData << 1
    Next
'
' Close up
'
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Read a single byte from the I2C bus
' Input     : None
' Output    : Returns the byte received
' Notes     : MSB first, sample before clock
'
Proc I2C_ReadByte(), Byte
    Dim bIndex   As Byte
    Dim wTimeOut As Word

    Result = 0
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    For bIndex = 7 Downto 0                             ' Create a loop for the 8-bits
        Result = Result << 1
        '
        ' Wait for any clock stretching
        '
        wTimeOut = $FFFF
        Repeat                                          ' Create a loop
            PinInput I2C_SCL_Pin                        ' Make the SCL pin an Input
            Dec wTimeOut                                ' \
            If wTimeOut = 0 Then Break                  ' / Exit the loop if the timeout reaches 0
        Until I2C_SCL_Pin = 1                           ' Until the SCL pin is high
        '
        ' Read the data
        '
        I2C_hDelayUs()
        Result.0 = I2C_SDA_Pin
        PinOutput I2C_SCL_Pin                           ' Make the SCL pin an Output (Low)
        I2C_hDelayUs()
    Next
EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus Start condition
' Input     : None
' Output    : None
' Notes     : A Start condition is high to low of SDA when SCL is high
'
Proc I2C_Start()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus restart condition
' Input     : None
' Output    : None
' Notes     : None
'
$define I2C_ReStart() I2C_Start()

'----------------------------------------------------------------------------------------------
' Send an I2C bus Stop condition
' Input     : None
' Output    : None
' Notes     : A Stop condition is low to high of SDA when SCL is high
'
Proc I2C_Stop()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Acknowledge
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_Ack()
    I2C_hDelayCs()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Not Acknowledge
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_NAck()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Setup the SDA and SCL pins for the software I2C interface
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_SetupPins()
    PinOutput I2C_SDA_Pin                               ' Make the I2C SDA pin an output
    PinOutput I2C_SCL_Pin                               ' Make the I2C SCL pin an output
EndProc

'----------------------------------------------------------------------------------------------
' Startup section
'
_I2C_Main_:
    I2C_SetupPins()                                     ' Setup the SDA and SCL pins for the software I2C interface

$endif      ' _I2C_SOFTWARE_INC_

A demo program that uses the above library is listed below:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Write and read an I2C EEPROM using the software I2C library routines
' Written for the Positron8 BASIC compiler by Les Johnson
'
    Device = 18F25K22                           ' Tell the compiler what device to compile for
    Declare Xtal = 64                           ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup the pins to use for the I2C interface
'
$define I2C_SDA_Pin PORTC.4                     ' Set the SDA pin for the I2C library
$define I2C_SCL_Pin PORTC.3                     ' Set the SCL pin for the I2C library

    Include "I2C_Software.inc"                  ' Load the software I2C library routines
'
' Create variables for the demo
'
    Dim bAddress As Byte
    Dim ByteIn   As Byte
    Dim ByteOut  As Byte

'---------------------------------------------------------------------------------------------
Main:
'
' Write bytes to the I2C EEPROM
'
    I2C_Start()                                 ' Send a Start condition
    I2C_WriteByte(%10100000)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(0)                            ' Send the High Byte of the address
    I2C_WriteByte(0)                            ' Send the Low Byte of the address
    For ByteIn = 0 To 9                         ' Create a loop
        I2C_WriteByte(ByteIn)                   ' Send the value of ByteIn to the EEPROM
    Next                                        ' Close the loop
    I2C_Stop()                                  ' Send a Stop condition
    DelayMS 5                                   ' Wait for the data to be entered into the EEPROM matrix
'
' Read bytes from the I2C EEPROM and display them on a serial terminal
'
    I2C_Start()                                 ' Send a Start condition
    I2C_WriteByte(%10100000)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(0)                            ' Send the High Byte of the address
    I2C_WriteByte(0)                            ' Send the Low Byte of the address
    I2C_ReStart()                               ' Send a Restart condition
    I2C_WriteByte(%10100001)                    ' Target an EEPROM, and send a Read command
    For bAddress = 0 To 9                       ' Create a loop
        ByteOut = I2C_ReadByte()                ' Load ByteOut with the byte received
        If bAddress = 9 Then                    ' Are we at the end of the reads?
            I2C_Stop()                          ' Yes. So send a Stop command
        Else                                    ' Otherwise...
            I2C_Ack()                           ' Send an Ack command
        EndIf
        HRSOutLn Dec ByteOut                    ' Display ByteOut on the serial terminal
    Next                                        ' Close the loop
    HRsout 13

'------------------------------------------------------------------------------
' Setup the config fuses for a PIC18F25K22 device to operate with an external crystal with the 4xPLL enabled
'
Config_Start
    FOSC     = HSHP                             ' HS oscillator (high power > 16 MHz)
    PLLCFG   = On                               ' Oscillator multiplied by 4
    PRICLKEN = On                               ' Primary clock enabled
    FCMEN    = Off                              ' Fail-Safe Clock Monitor disabled
    IESO     = Off                              ' Internal/External Oscillator Switchover mode disabled
    PWRTEN   = On                               ' Power up timer enabled
    BOREN    = SBORDIS                          ' Brown-out Reset enabled in hardware only (SBOREN is disabled)
    BORV     = 190                              ' Brown Out Reset Voltage set to 1.90 V nominal
    WDTEN    = Off                              ' Watch dog timer is always disabled. SWDTEN has no effect.
    WDTPS    = 128                              ' Watchdog Timer Postscale 1:128
    CCP2MX   = PORTC1                           ' CCP2 input/output is multiplexed with RC1
    PBADEN   = Off                              ' PORTB<5:0> pins are configured as digital I/O on Reset
    CCP3MX   = PORTB5                           ' P3A/CCP3 input/output is multiplexed with RB5
    HFOFST   = On                               ' HFINTOSC output and ready status are not delayed by the oscillator stable status
    T3CMX    = PORTC0                           ' Timer3 Clock Input (T3CKI) is on RC0
    P2BMX    = PORTB5                           ' ECCP2 B (P2B) is on RB5
    MCLRE    = EXTMCLR                          ' MCLR pin enabled, RE3 input pin disabled
    STVREN   = Off                              ' Stack full/underflow will not cause Reset
    LVP      = Off                              ' Single-Supply ICSP disabled
    XINST    = Off                              ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
    Debug    = Off                              ' Debug disabled
    Cp0      = Off                              ' Block 0 (000800-001FFF) not code-protected
    CP1      = Off                              ' Block 1 (002000-003FFF) not code-protected
    CP2      = Off                              ' Block 2 (004000-005FFF) not code-protected
    CP3      = Off                              ' Block 3 (006000-007FFF) not code-protected
    CPB      = Off                              ' Boot block (000000-0007FF) not code-protected
    CPD      = Off                              ' Data EEPROM not code-protected
    WRT0     = Off                              ' Block 0 (000800-001FFF) not write-protected
    WRT1     = Off                              ' Block 1 (002000-003FFF) not write-protected
    WRT2     = Off                              ' Block 2 (004000-005FFF) not write-protected
    WRT3     = Off                              ' Block 3 (006000-007FFF) not write-protected
    WRTC     = Off                              ' Configuration registers (300000-3000FF) not write-protected
    WRTB     = Off                              ' Boot Block (000000-0007FF) not write-protected
    WRTD     = Off                              ' Data EEPROM not write-protected
    EBTR0    = Off                              ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1    = Off                              ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTR2    = Off                              ' Block 2 (004000-005FFF) not protected from table reads executed in other blocks
    EBTR3    = Off                              ' Block 3 (006000-007FFF) not protected from table reads executed in other blocks
    EBTRB    = Off                              ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

tolyan249

#7
Thank you, but where can I download the program and which version should I use?
Found POCITRON STUDIO 2.0.2.9

I tried to connect the file to my project that you gave me above I2C, but it doesn't compile and there are a lot of errors. I downloaded POCITRON STUDIO 2.0.2.9

RGV250

Hi,
Positron studio is only the IDE, Positron 4.xx is the compiler.
I think you need to be here to purchase the latest version.
https://sites.google.com/view/rosetta-tech/home/how-to-purchase-the-positron-compilers

Regards,
Bob

tolyan249

#9
Declare Slow_Bus On - Off or 1 - 0
Slows the bus speed when using an oscillator higher than 4MHz.
The standard speed for the I2
C bus is 100KHz. Some devices use a higher bus speed of
400KHz. If you use an 8MHz or higher oscillator, the bus speed may exceed the devices specs,
which will result in intermittent transactions, or in some cases, no transactions at all. Therefore,
use this Declare if you are not sure of the device's spec. The datasheet for the device used will
inform you of its bus speed.


I2Cout supports the Speed Adventure.

Thanks for the help.

Pocitron studio compiler is also available
https://www.positronstudio.co.uk/

RGV250

Hi,
Positron studio is the IDE, the link I posted is for the compiler.

Bob

tolyan249

#11
I installed POSITRON 4. , applied the file given above I2C_Software.inc , applied the file given below , everything compiles , applied another pic , pic16f628a, gives an error in the file I2C_Software.inc , and there is another controller PIC18F25K20 , although I have PIC16F628A. What did I do wrong?
Thank you.



   Device = 16F628A                           ' Tell the compiler what device to compile for
    Declare Xtal = 20                           ' Tell the compiler what frequency the device is operating at (in MHz)

Config  CP_OFF, DEBUG_OFF, CPD_OFF, LVP_OFF, BODEN_OFF, PWRTE_OFF, WDT_OFF, XT_OSC

' Setup the pins to use for the I2C interface
'
$define I2C_SDA_Pin PORTA.0                     ' Set the SDA pin for the I2C library
$define I2C_SCL_Pin PORTA.1                     ' Set the SCL pin for the I2C library

    Include "I2C_Software.inc"                  ' Load the software I2C library routines
'
' Create variables for the demo
'
    Dim bAddress As Byte
    Dim ByteIn   As Byte
    Dim ByteOut  As Byte

'---------------------------------------------------------------------------------------------
Main:
'
' Write bytes to the I2C EEPROM
'
    I2C_Start()                                 ' Send a Start condition
    I2C_WriteByte(%10100000)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(0)                            ' Send the High Byte of the address
    I2C_WriteByte(0)                            ' Send the Low Byte of the address
    For ByteIn = 0 To 9                         ' Create a loop
        I2C_WriteByte(ByteIn)                   ' Send the value of ByteIn to the EEPROM
    Next                                        ' Close the loop
    I2C_Stop()                                  ' Send a Stop condition
    DelayMS 5                                   ' Wait for the data to be entered into the EEPROM matrix
'
' Read bytes from the I2C EEPROM and display them on a serial terminal
'
    I2C_Start()                                 ' Send a Start condition
    I2C_WriteByte(%10100000)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(0)                            ' Send the High Byte of the address
    I2C_WriteByte(0)                            ' Send the Low Byte of the address
    I2C_ReStart()                               ' Send a Restart condition
    I2C_WriteByte(%10100001)                    ' Target an EEPROM, and send a Read command
    For bAddress = 0 To 9                       ' Create a loop
        ByteOut = I2C_ReadByte()                ' Load ByteOut with the byte received
        If bAddress = 9 Then                    ' Are we at the end of the reads?
            I2C_Stop()                          ' Yes. So send a Stop command
        Else                                    ' Otherwise...
            I2C_Ack()                           ' Send an Ack command
        EndIf
        HRSOutLn Dec ByteOut                    ' Display ByteOut on the serial terminal
    Next                                        ' Close the loop
    HRSOut 13





For some reason, the I2C_software.inc file has a pic of 18f25k20, even though I have a pic16f628

tolyan249

#12
I changed I2C_hDelayCs() to I2C_hDelayUs(), and it compiles fine.
I don't understand how to change the I2C_DELAY() time from my program.


I Found It, Thanks.
$define I2C_hDelayCs() DelayCS 20




$define I2C_hDelayCs() DelayCS 2                        ' Delay a number of clock cycles


For some reason, the SCL at the end of the receive or transmit does not rise to +power


As I understand it, this makes a delay from the system frequency,
and the second is a delay specifically for I2C, or did I misunderstand something?

Proc I2C_hDelayUs()
    DelayUS 30                                          ' Delay a number of microseconds
EndProc




Made a test project reading temperature ,yes it works.
but I don't understand if the variable byte ,then it can take values up to 255 ,and here it shows 745 ,it is not clear ,it shows a temperature of 74.5 ,it is necessary to divide by 10. and the second question is how to know that came ACK or NACK when transmitting data to the device.










I2C_Start()                                ' Send a Start condition
    I2C_WriteByte(Address)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(2)
    I2C_WriteByte(5)
I2C_Stop()                                ' Send the High Byte of the address
 
I2C_Start()
    I2C_WriteByte(Address)
    I2C_WriteByte(3)                    ' Target an EEPROM, and send a Write command
    I2C_WriteByte(15) 
I2C_Stop()                                  ' Send a Stop condition





I got the same situation, if you write to the temperature sensor registers, the temperature is shown last when installing, and not the current temperature, what I wrote above. in the LM_75 project with my I2C

It is not clear what is wrong?






And I don't understand why the SCL signal is inverted.

                   
link to the LM75 above


And why are the SCL pulse widths different?

For some reason, the SCL pulses are different when sending an address and when receiving data. Is this normal?

tolyan249

#13
Help me, what am I doing wrong, I need to get the temperature and write to the LM75 sensor when the LED should light up at what temperature and when it should go out at what temperature, I'm trying but something doesn't work out, what am I doing wrong?




This procedure with i2c_software.inc, how can I use it in the main program to set the I2C speed?
Proc I2C_hDelayUs()
    DelayUS 1                                           ' Delay a number of microseconds
EndProc


 Thank you.

tolyan249

#14


'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' I2C_Software.inc
' Software I2C writing and reading routines
' Written for the Positron8 BASIC compiler by Les Johnson
'
' Setup the default pins for SDA and SCL
'

$ifndef _I2C_SOFTWARE_INC_
$define _I2C_SOFTWARE_INC_

$ifndef I2C_SDA_Pin
    $define I2C_SDA_Pin PORTC.0
    $SendWarning "$define I2C_SDA_Pin missing from main program, so using the default pin of PORTC.4"
$endif

$ifndef I2C_SCL_Pin
    $define I2C_SCL_Pin PORTC.1
    $SendWarning "$define I2C_SCL_Pin missing from main program, so using the default pin of PORTC.3"
$endif

'----------------------------------------------------------------------------------------------
' Delay a fixed number of microseconds and clock cycles.
' These can be changed to suite the speed required by the I2C interface.
'
$define I2C_hDelayCs() DelayCS 2                        ' Delay a number of clock cycles


Proc I2C_hDelayUs()
    DelayUS 1                                           ' Delay a number of microseconds
EndProc

'----------------------------------------------------------------------------------------------
' Send a single byte to the I2C bus.
' Input     : pData holds the byte to write
' Output    : None
' Notes     : MSB first
'

Proc I2C_WriteByte(pData As Byte), Byte
    Dim bIndex As Byte
    Dim ack As Byte

    For bIndex = 7 DownTo 0
        If pData.7 = 1 Then
            PinInput I2C_SDA_Pin
        Else
            PinOutput I2C_SDA_Pin
        EndIf
        I2C_hDelayUs()
        PinInput I2C_SCL_Pin
        I2C_hDelayUs()
        PinOutput I2C_SCL_Pin
        I2C_hDelayUs()
        pData = pData << 1
    Next

    ' Perform 9th clock cycle - ACK
    PinInput I2C_SDA_Pin       ' Release the SDA line so the slave can pull it low
    I2C_hDelayUs()
    PinInput I2C_SCL_Pin       ' Raise SCL line to high level
    I2C_hDelayUs()
    ack = I2C_SDA_Pin          ' Read SDA: 0 = ACK, 1 = NACK
    PinOutput I2C_SCL_Pin      ' Pull SCL line low
    I2C_hDelayUs()

    result= ack                 ' Return ACK (0 - acknowledged, 1 - not acknowledged)
EndProc
















'----------------------------------------------------------------------------------------------
' Read a single byte from the I2C bus.
' Input     : None
' Output    : Returns the byte received
' Notes     : MSB first, sample before clock
'
Proc I2C_ReadByte(), Byte
    Dim bIndex   As Byte
    Dim wTimeOut As Word

    Result = 0
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    For bIndex = 7 DownTo 0                             ' Create a loop for the 8-bits
        Result = Result << 1
        '
        ' Wait for any clock stretching
        '
        wTimeOut = $FFFF
        Repeat                                          ' Create a loop
            PinInput I2C_SCL_Pin                        ' Make the SCL pin an Input
            Dec wTimeOut                                ' \
            If wTimeOut = 0 Then Break                  ' / Exit the loop if the timeout reaches 0
        Until I2C_SCL_Pin = 1                           ' Until the SCL pin is high
        '
        ' Read the data
        '
        I2C_hDelayUs()                                  ' Delay between pin state changes
        Result.0 = I2C_SDA_Pin
        PinOutput I2C_SCL_Pin                           ' Make the SCL pin an Output (Low)
        I2C_hDelayUs()                                  ' Delay between pin state changes
    Next
EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus Start condition.
' Input     : None
' Output    : None
' Notes     : A Start condition is high to low of SDA when SCL is high
'
Proc I2C_Start()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus ReStart condition.
' Input     : None
' Output    : None
' Notes     : None
'
$define I2C_ReStart() I2C_Start()

'----------------------------------------------------------------------------------------------
' Send an I2C bus Stop condition.
' Input     : None
' Output    : None
' Notes     : A Stop condition is low to high of SDA when SCL is high
'
Proc I2C_Stop()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Acknowledge.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_Ack()
    I2C_hDelayUs()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Not Acknowledge.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_NAck()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Setup the SDA and SCL pins for the software I2C interface.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_SetupPins()
    PinLow I2C_SDA_Pin                                  ' Make the I2C SDA pin an output low
    PinLow I2C_SCL_Pin                                  ' Make the I2C SCL pin an output low
EndProc

'----------------------------------------------------------------------------------------------
' Startup section
'
_I2C_Main_:
    I2C_SetupPins()                                     ' Setup the SDA and SCL pins for the software I2C interface

$endif      ' _I2C_SOFTWARE_INC_



I have added support for ACK and NACK when sending data, so that I know that the slave has received the data and I can send the next data, if there is any.
to know that the slave responded And its application


Dim bAck As Byte
bAck = I2C_WriteByte(0xA0)      ' Send the byte

If bAck = 0 Then
    ' Device acknowledged, proceed further
Else
    ' Device did not acknowledge — error handling
End If

Verified it works.


tolyan249

#15
Main:

    Cls
    Print 1,1, "Scanning..."
    DelayMS 1000

    For Address = 1 To 127               ' I2C 7-bit addresses from 0x01 to 0x7F (general call 0x00 excluded)
       
        I2C_Start()
        bAck = I2C_WriteByte(Address << 1)   ' Write address with write bit (0)
        I2C_Stop()
       
        If bAck = 0 Then
        Cls
        Print 2,1, "Device:= " ,Dec Address
        DelayMS 2000
        Break
        EndIf
        Cls
        Print 1,1, "device <-> " ,Dec Address
        DelayMS 150
    Next
    Cls
    Print 2,1, "Scan complete   "
     DelayMS 2000

   
GoTo Main            ' or loop scan continuously






Here's the scanner searching for the device address, and it's working.



It's strange, and the SCL pulses match, but I don't understand why.
The i2c scanner works perfectly.