Sterrenhemel

Gebruik je soms pwm_init of zo? (die regelt alles natuurlijk ook al)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

Nee, geen Init. wel:

pic basic code:

PWM1_Remappable_START()

Wellicht dat die het regelt?

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Ik vroeg me nog iets anders af:

Ik gebruik de Software I2C.

Is het dan eigenlijk nog nodig op externe pull-ups weerstanden voor de SCL en SDA te gebruiken? Ik heb het wel gedaan, maar vroeg me af of dat wel moet. Omdat je immers geen hardware I2C bus gebruikt...

Man is still the most extraordinary computer of all. JF Kennedy

Zou kunnen dat die start wat doet met de settings. (kun je in de asm of lst file zien...)
Pull-ups moet altijd bij i2c. Hard of softwarematig maakt daarin geen verschil. Waarde hangt af van de bussnelheid, belasting, en kabellengte.

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

Op 4 maart 2021 21:43:53 schreef Arco:
Zou kunnen dat die start wat doet met de settings. (kun je in de asm of lst file zien...)
Pull-ups moet altijd bij i2c. Hard of softwarematig maakt daarin geen verschil. Waarde hangt af van de bussnelheid, belasting, en kabellengte.

Tja, ik heb maar 4K7 genomen, komt redelijk vaak voor in schema's.

Daarnaast, de PIC heeft 2 Poorten voor de ICSDAT en ICSCLK, waarmee je de PIC programmeert.
Nu gebruik ik deze poorten ook voor andere dingen, ervan uitgaande dat de ICS maar even nodig is voor het flashen.

Is dat zo? (m.a.w. er kleven geen bezwaren aan? Anders zou het je 2 poorten kosten)

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Voor de liefhebbers:

Dit is uiteindelijk het project sterrenhemel geworden.
Het is geschreven in MikroBasic, met als processor de PIC16F18857.

Het is een sterrenhemel, bestaande uit 8 panelen van 120 * 60 cm, dus in totaal een oppervlakte van 240 * 240 cm.
Ieder paneel heeft 64 leds.

Daarbij hebben 5 percelen een oranje led, die de planeet Mars voorstelt.
Die verschuift gedurende de nacht langs de hemel.
Één paneel is voorzien van gele ledjes, dis als maan fungeren. De schijngestaltes worden weergegeven.
Er zit een DS1307 RTC klokmodule in, waardoor de sterren de tijd kunnen weergeven.

Het programmma bevat 10 functies, met wat 'speeltjes' erbij in.

Dank aan iedereen, in het bijzonder aan Arco, voor de bijdrage die ik kreeg om dit te maken. :)

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Ik hwb voor de controle of de I2C bus vrij is het volgende:

pic basic code:

'====================================================================================================
 Sub Procedure Lcd_WrDat(Dim pDat As Byte)                       'Write data to display
'====================================================================================================
  [b]While (I2C1_Is_Idle) = 0 wend[/b]
  I2C1_Start()
  I2C1_Wr(0x78)
  I2C1_Wr(0x40)
  I2C1_Wr(pDat)
  Delay_ms(1)
  I2C1_Stop()
 End Sub

Er kleeft wel een nadeel aan deze constructie: Als er iets is dat veroorzaakt dat de I2C bus niet vrij is (bv slecht draadcontact naar display o.i.d.) dan betekent dat meteen dat alles 'hangt' en de processor wacht op iets dat niet gaat gebeuren.

Is er wellicht en betere methode, waarbij je bv een 'error' afvangt maar het programma wel doorloopt?

Ter illustratie: ik had dit met mijn e-deurbel. Het displaytje had een slecht Dupont contact (meteen vervangen natuurlijk), maar het resultaat was bonkende mensen op de deur omdat de bel het niet meer deed... ;(

Man is still the most extraordinary computer of all. JF Kennedy

Je kunt er een time-out inbouwen:

pic basic code:



Const TIME_OUT = 100
Dim   Cnt As Byte
 
'====================================================================================================
 Sub Procedure Lcd_WrDat(Dim pDat As Byte)                       'Write data to display
'====================================================================================================
  For Cnt = 1 To TIME_OUT
    If I2C1_Is_Idle Then Break End If  'Exit if idle
    Delay_ms(1)                        'Optional delay
  Next Cnt
  If Cnt < TIME_OUT Then
    I2C1_Start()
    I2C1_Wr(0x78)
    I2C1_Wr(0x40)
    I2C1_Wr(pDat)
    Delay_ms(1)
    I2C1_Stop()
  End If
 End Sub
Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Shiptronic

Golden Member

Op 21 maart 2021 13:45:12 schreef Bavelt:
Voor de liefhebbers:

Dit is uiteindelijk het project sterrenhemel geworden.
Het is geschreven in MikroBasic, met als processor de PIC16F18857.......
....Dank aan iedereen, in het bijzonder aan Arco, voor de bijdrage die ik kreeg om dit te maken. :)

Heb je er ook een filmpje van? dat zegt mij meer dan de ZIP-file ;)

Wie de vraag stelt, zal met het antwoord moeten leren leven.

Time-out moet je dan ook inbouwen in i2c_start/restart/stop/write/read, anders hangt de boel daar weer.

Ik zou ook eens naar het geheel kijken, want een time-out (hangen) op de i2c bus mag sowieso nooit voorkomen.

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

Op 7 april 2021 22:38:52 schreef Arco:
Time-out moet je dan ook inbouwen in i2c_start/restart/stop/write/read, anders hangt de boel daar weer.

Ik zou ook eens naar het geheel kijken, want een time-out (hangen) op de i2c bus mag sowieso nooit voorkomen.

Je krijgt het als bv de SDA of SCL verbinding naar een device weg is (slechte dupont verbinding)

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Op 7 april 2021 22:11:42 schreef Shiptronic:
[...]

Heb je er ook een filmpje van? dat zegt mij meer dan de ZIP-file ;)

Dit weekend is gepland om het defintief aan het plafond te monteren. Dan zal ik een filmpje maken.

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Time-out moet je dan ook inbouwen in i2c_start/restart/stop/write/read, anders hangt de boel daar weer.

Klopt, daar was ik idd ook achter gekomen.

Je kunt ook niet simpel

pic basic code:

If (I2C1_Is_Idle)= 1
  I2C1_Start()
  I2C1_Wr(0x78)
  I2C1_Wr(0x80)
  I2C1_Wr(pCmd)
  I2C1_Stop()
End IF
 End Sub

Doen

Met een juiste bedrading is het probleem niet echt actueel. Maar het is wel iets om rekening mee te houden.

Man is still the most extraordinary computer of all. JF Kennedy

Ik heb daar een eigen library voor gemaakt ('hangen' vind ik onacceptabel)

pic basic code:


module lib_i2c

Const I2CTimeOut = 200
Dim I2cStatus As Byte

'Statusbits:    00000001 - Start
'               00000010 - Restart
'               00000100 - Stop
'               00001000 - Write
'               00010000 - Read
'               00100000 - Idle
'               01000000 - Receive buffer
'               10000000 - Busy

Sub Procedure I2CInit()
Sub Procedure I2CStart()
Sub Procedure I2CRestart()
Sub Procedure I2CStop()
Sub Procedure I2CWrite(Dim pDat As Byte)
Sub Procedure I2CIdle()
Sub Function  I2CRead(Dim pAck As Byte) As Byte

implements

'==================================================================================================
Sub Procedure I2CIdle()                                             'Wait for bus idle
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  For lCnt = 0 To I2CTimeout                                        '
    If (I2C1CON And 0x1F) = 0  then break end if                    '
  Next lCnt                                                         '
  I2cStatus.5 = (I2C1CON And 0x1F)                                   '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2Cinit()                                             'Init I2C1 peripheral (400kHz)
'--------------------------------------------------------------------------------------------------
  I2C1BRG   = 0x0025                                                '(Fcy/scl)-(Fcy/10000000) -1
  I2CEN_Bit = 1                                                     'Enable I2C1
  Delay_ms(10)                                                      '
  I2C1STAT = 0                                                      '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStart()                                            'Start bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2cStatus = 0x80
  I2CIdle()                                                         'Wait for bus idle
  SEN_Bit = 1                                                       'Set start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (SEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus.0 = SEN_bit                                             'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CRestart()                                          'Restart bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  RSEN_Bit = 1                                                      'Set repeated start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (RSEN_Bit = 0) Then Break End If                             '
  Next lCnt                                                         '
  I2cStatus.1 = RSEN_bit                                            'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStop()                                             'Stop bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  PEN_Bit = 1                                                       'Set stop bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (PEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus.2 = PEN_Bit                                             'Errorstatus
  I2cStatus.7 = 0                                                   '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CWrite(Dim pDat As Byte)                            'Write byte pDat to bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  I2C1TRN = pDat                                                    'Data to send into buffer
  For lCnt = 0 To I2CTimeout                                        'Wait for interruptflag to
    If MI2C1IF_bit Then Break End If                                'get set
  Next lCnt                                                         '
  I2cStatus.3 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub

'==================================================================================================
Sub Function I2CRead(Dim pAck As Byte) As Byte                      'Read byte of bus(1=Nack/0=Ack)
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  RCEN_Bit = 1                                                      '
  For lCnt = 0 To I2cTimeout                                        'Wait for buffer
    If RBF_Bit Then Break End If                                    '
  Next lCnt                                                         '
  I2cStatus.6 = RBF_Bit Xor 1                                       'Errorstatus
  Result = I2C1RCV                                                  'Get received byte
  ACKDT_Bit = pAck                                                  'Send Ack/Nack
  ACKEN_Bit = 1                                                     '
  For lCnt = 0 To I2CTimeout                                        '
    If MI2C1IF_Bit Then Break End If                                '
  Next lCnt                                                         '
  I2cStatus.4 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub                                                             '
end.

'==================================================================================================
Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

Op 8 april 2021 22:40:29 schreef Arco:
Ik heb daar een eigen library voor gemaakt ('hangen' vind ik onacceptabel)

pic basic code:


module lib_i2c

Const I2CTimeOut = 200
Dim I2cStatus As Byte

'Statusbits:    00000001 - Start
'               00000010 - Restart
'               00000100 - Stop
'               00001000 - Write
'               00010000 - Read
'               00100000 - Idle
'               01000000 - Receive buffer
'               10000000 - Busy

Sub Procedure I2CInit()
Sub Procedure I2CStart()
Sub Procedure I2CRestart()
Sub Procedure I2CStop()
Sub Procedure I2CWrite(Dim pDat As Byte)
Sub Procedure I2CIdle()
Sub Function  I2CRead(Dim pAck As Byte) As Byte

implements

'==================================================================================================
Sub Procedure I2CIdle()                                             'Wait for bus idle
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  For lCnt = 0 To I2CTimeout                                        '
    If (I2C1CON And 0x1F) = 0  then break end if                    '
  Next lCnt                                                         '
  I2cStatus.5 = (I2C1CON And 0x1F)                                   '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2Cinit()                                             'Init I2C1 peripheral (400kHz)
'--------------------------------------------------------------------------------------------------
  I2C1BRG   = 0x0025                                                '(Fcy/scl)-(Fcy/10000000) -1
  I2CEN_Bit = 1                                                     'Enable I2C1
  Delay_ms(10)                                                      '
  I2C1STAT = 0                                                      '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStart()                                            'Start bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2cStatus = 0x80
  I2CIdle()                                                         'Wait for bus idle
  SEN_Bit = 1                                                       'Set start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (SEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus.0 = SEN_bit                                             'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CRestart()                                          'Restart bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  RSEN_Bit = 1                                                      'Set repeated start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (RSEN_Bit = 0) Then Break End If                             '
  Next lCnt                                                         '
  I2cStatus.1 = RSEN_bit                                            'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStop()                                             'Stop bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  PEN_Bit = 1                                                       'Set stop bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (PEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus.2 = PEN_Bit                                             'Errorstatus
  I2cStatus.7 = 0                                                   '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CWrite(Dim pDat As Byte)                            'Write byte pDat to bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  I2C1TRN = pDat                                                    'Data to send into buffer
  For lCnt = 0 To I2CTimeout                                        'Wait for interruptflag to
    If MI2C1IF_bit Then Break End If                                'get set
  Next lCnt                                                         '
  I2cStatus.3 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub

'==================================================================================================
Sub Function I2CRead(Dim pAck As Byte) As Byte                      'Read byte of bus(1=Nack/0=Ack)
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  RCEN_Bit = 1                                                      '
  For lCnt = 0 To I2cTimeout                                        'Wait for buffer
    If RBF_Bit Then Break End If                                    '
  Next lCnt                                                         '
  I2cStatus.6 = RBF_Bit Xor 1                                       'Errorstatus
  Result = I2C1RCV                                                  'Get received byte
  ACKDT_Bit = pAck                                                  'Send Ack/Nack
  ACKEN_Bit = 1                                                     '
  For lCnt = 0 To I2CTimeout                                        '
    If MI2C1IF_Bit Then Break End If                                '
  Next lCnt                                                         '
  I2cStatus.4 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub                                                             '
end.

'==================================================================================================

Dat ziet er inderdaad goed uit. Je gebruikt dus niet de standaard MikroBasic I2C library maar deze.
Je kunt dan dus bij elke uitvoering de status controleren en in je hoofdprogramma aangeven wat er dan moet gebeuren (bv foutmelding of verder gaan). Toch?

Ik zie hier het voor mij nieuwe Implements. Eerst som je de procedures op en vervolgens worden ze gespecificeerd.
Wat is nu het nut van deze implements?

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Terecht zeg je dat 'hangen' niet acceptabel is. Je verliest daardoor de controle over je programma wanneer een device om wat voor reden ook niet goed reageert.

Zou het eigenlijk niet zo moeten zijn dat MB in zijn eigen library een error-afhandeling had moeten maken in zijn procedures?

Man is still the most extraordinary computer of all. JF Kennedy

Heb ik al eens gevraagd.
Men zei dat ze expres voor deze oplossing hebben gekozen, omdat het voor minder gevorderde programmeurs anders misschien te ingewikkeld zou worden...

Implements is altijd noodzakelijk in een module. Er staat een stuk over modules in de helpfile...

Het 'hangen' gebeurt trouwens niet alleen bij fysieke busproblemen.
Sommige slaves hangen ook als je er teveel data naar toe stuurt zonder te wachten tot de bus weer vrij is...

[Bericht gewijzigd door Arco op 9 april 2021 11:53:02 (25%)]

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

De sterrenhemel zit aan het plafond, de print met processor (niet zichtbaar) tussen de panelen en plafond geprutst. Het werkt.
Maar heb toch nog wat problemen met stabiliteit (af en toe hangt het spul).

Wat ik zelf wat apart vind:
In de testopstelling op breadboard kan ik vanuit de laptop - USB de Pickit2 aansturen, die tevens de voeding verzorgt voor de schakeling, maar ook 8 LED matrixen met MAX7219 aangesloten. En een TSOP1836 IR-sensor ook aan boord. De ledjes branden keurig en de schakeling werkt.

Maar.., bij gebruik van de 'losse' leds i.p.v de matrix-LED's (1088AS), dan werkt de schakeling wel, echter de TSOP1836 IR sensor houdt het voor gezien
Die werkt alleen wanneer er een externe voeding van 5V is aangesloten.

Ik kan dat niet echt verklaren.

Zijn die Ledjes dan zo verschillend?

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Ik had daarnaast nog een twijfelpuntje:

De processor PIC16F18857 wordt nu maximaal gebruikt:
8 MAX7219's aangestuurd met dus 512 leds via SPI
Een RTC DS 3231 via I2C
Dan 7 PWM's voor 5 Marsleds en twee maanhelften.

Nu vroeg ik me af of dit niet teveel gevraagd is van het ding.

Ik kan natuurlijk de Marsleds en Maan aansturen met een eigen processortje, bv de PIC 12F1572, die ook nog eens een 16-bits PWM heeft.
En daar een apart printje van maken.

Is dat een rare gedachte?

Man is still the most extraordinary computer of all. JF Kennedy

Hij doet 't of hij doet het niet, 'teveel gevraagd' is er niet. (als alles qua timing erin past is het prima)
Enige wat ik controleer is meestal of er geen interrupts worden overgeslagen. (dat duidt er nl op dat er meer code is dan kan worden uitgevoerd)

Simpel te controleren door een outputpin iedere interrupt te togglen: er moet dan een nette 50/50 duty blokgolf uitkomen.
Als er soms blokken tussen zitten die langer zijn, dan is er een interrupt overgeslagen...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Bavelt

Special Member

Qua interrupt is de timer de enige die ik gebruik in het programma.
Daar zitten alle tellers aan gekoppeld.

En er wordt gekeken of binnen de tijd een (geldig) IR-signaal is ontvangen.

Het blijkt dat de processor gedurende de nacht stopt. De ledjes houden dan wel hun status quo (vanuit de MAX7219) en branden weliswaar, maar er 'loopt' niks meer. Geen maan, mars, en geen IR-controle meer.
Dat is natuurlijk niet de bedoeling.

In mijn testopstelling op breadboard loopt alles gewoon door.

Het enige echte verschil zijn de kabels naar de LED-panels. Die zijn doorgelust, de maximale lengte is 4.80 meter.

Geldt hier nu ook voor ze doen het of niet? Of kan zo'n kabel de processor op een gegeven moment ook laten stressen?

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Op 12 april 2021 12:02:47 schreef Arco:
Hij doet 't of hij doet het niet, 'teveel gevraagd' is er niet. (als alles qua timing erin past is het prima)
Enige wat ik controleer is meestal of er geen interrupts worden overgeslagen. (dat duidt er nl op dat er meer code is dan kan worden uitgevoerd)

Simpel te controleren door een outputpin iedere interrupt te togglen: er moet dan een nette 50/50 duty blokgolf uitkomen.
Als er soms blokken tussen zitten die langer zijn, dan is er een interrupt overgeslagen...

Dit is de summary. Qua RAM en ROM zit het wel goed lijkt me...

Man is still the most extraordinary computer of all. JF Kennedy
Shiptronic

Golden Member

Lange kabels kunnen antennes worden! En voor de gekste problemen zorgen :(

Welk type kabel gebruik je? soms helpt het om (getwiste) netwerk kabel( sheilded) te gebruiken.

[Bericht gewijzigd door Shiptronic op 12 april 2021 12:18:42 (40%)]

Wie de vraag stelt, zal met het antwoord moeten leren leven.
Bavelt

Special Member

Op 12 april 2021 12:16:35 schreef Shiptronic:
Lange kabels kunnen antennes worden! En voor de gekste problemen zorgen :(

Welk type kabel gebruik je? soms helpt het om (getwiste) netwerk kabel( sheilded) te gebruiken.

Ik heb UTP kabel CAT 5 gebruikt

Man is still the most extraordinary computer of all. JF Kennedy
Bavelt

Special Member

Op 12 april 2021 12:02:47 schreef Arco:
Hij doet 't of hij doet het niet, 'teveel gevraagd' is er niet. (als alles qua timing erin past is het prima)
Enige wat ik controleer is meestal of er geen interrupts worden overgeslagen. (dat duidt er nl op dat er meer code is dan kan worden uitgevoerd)

Simpel te controleren door een outputpin iedere interrupt te togglen: er moet dan een nette 50/50 duty blokgolf uitkomen.
Als er soms blokken tussen zitten die langer zijn, dan is er een interrupt overgeslagen...

Ik heb voor de zekerheid een 'Toggle' ingebouwd.

Het plaatje levert wel een goede 50/50 blok op.

Maar wat opvalt: op de 'bovenkant' van het signaal zit redelijk veel ruis / rommel.

Uitvergroot:

Man is still the most extraordinary computer of all. JF Kennedy