Mikrobasic, Interrupts en multiplexen

Zo'n led kubus heeft me nooit erg kunnen boeien... ;)
Is moeilijk om er een te maken die er fraai uitziet en ook nog stevig is. En je bent er (ik wel) gauw op uitgekeken...

Vaak zijn het van die draadkubussen en nogal gammele bouwsels, die bij 1x blazen al instorten...

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Dat moeten we idd dus niet hebben.
Maar het meeste plezier is toch het realiseren, uitzoeken en ontdekken.

Ik vergelijk het een beetje met modelbouw van treinen. (Heb ik vroeger ook gedaan). Het maken, bouwen, wissels, de loop, huisjes bergen, etc.
Maar als het eenmaal klaar is, dan ga je niet uren met de treintjes rijden..
Je moet dus eigenlijk een hobby hebben die 'nooit af' is..

Lambiek

Special Member

Op 27 november 2019 09:44:17 schreef Bavelt:
Ik vergelijk het een beetje met modelbouw van treinen...... Maar als het eenmaal klaar is, dan ga je niet uren met de treintjes rijden.. Je moet dus eigenlijk een hobby hebben die 'nooit af' is..

Dat heb je met iedere hobby, maar als een project klaar is begin je gewoon met een nieuw project. :)

Ik ben bezig met een robot arm, als je die iets anders wil laten doen heb je een ander programma nodig. Dus programmeren maar weer. :)

Als je haar maar goed zit, GROETEN LAMBIEK.

De klok code werkt trouwens prima op een 16f887. Alleen vervangen:
LATA > PORTA
LATB > PORTB
ANSELA > ANSEL
ANSELB > ANSELH

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Op 27 november 2019 09:50:53 schreef Lambiek:
[...]
Dat heb je met iedere hobby, maar als een project klaar is begin je gewoon met een nieuw project. :)

Ik ben bezig met een robot arm, als je die iets anders wil laten doen heb je een ander programma nodig. Dus programmeren maar weer. :)

Kijk dat is natuurlijk ook gewoon leuk!

Op 27 november 2019 10:35:20 schreef Arco:
De klok code werkt trouwens prima op een 16f887. Alleen vervangen:
LATA > PORTA
LATB > PORTB
ANSELA > ANSEL
ANSELB > ANSELH

Ga ik zéker uitproberen. Ik ben alleen deze week niet op mijn plek (maar heb wel van alles meegenomen. Alleen zijn mijn 5e en 6e 7-Segment die ik hier heb Common Anode ipv Common Cathode. Dat is lastig door elkaar gebruiken.)

Typisch:ik heb de uren even niet aangesloten (ik heb maar 4 CK displays), maar de seconden in het programma zitten, loopt de klok na 10 uur ca 30 seconden uit de pas. terwijl met alleen minuten en seconden in het programma het ding perfect op tijd liep.
Er moet ergens iets een vertraging veroorzaken.

Oeps, foutje... :o
PR2 moet 249 zijn, geen 250...

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

(fOsc/4) / postscaler / prescaler / (PR2 value +1)

Ja, want je moet al 1 bij optellen voor de deelfactor, niet?
:)

Ja,... ;)
Komt doordat de timers bij '0' beginnen te tellen. '0' t/m '249' zijn 250 ticks...

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Dit keer geen vraag maar misschien wel leuk om te tonen:
(misschien elders posten?)

Een programmaatje mbv MikroBasic, dat gebruik maakt van twee I2C-modulen van de PIC16F1847.
Daarbij zijn 2 RTC klokjes aangesloten; een DS3231 en een DS1307.
Beide zijn bijna gelijk, zij het dat bij de 1307 een CH-bit ("Halt") bij de seconden zit. Deze moet je er bij het lezen dus afhalen met

pic basic code:

AND '0x7F' 

.
Er is een LCD diplay 16*2 aangesloten met een HD44780 chip, waarbij dus gebruik gemaakt wordt van een 4 data lijnen, een EN en RS.

Het programma toont van beide RTC-en de datum en de tijd, waarbij je dus kan zien hoe groot het verschil na verloop van tijd gaat worden.

pic basic code:

'==============================================================================
program Tijd1847
'------------------------------------------------------------------------------
dim LCD_RS as sbit at LATB6_bit
    LCD_EN as sbit at LATB7_bit
    LCD_D4 as sbit at LATA0_bit
    LCD_D5 as sbit at LATA1_bit
    LCD_D6 as sbit at LATA2_bit
    LCD_D7 as sbit at LATA3_bit

dim LCD_RS_Direction as sbit at TRISB6_bit
    LCD_EN_Direction as sbit at TRISB7_bit
    LCD_D4_Direction as sbit at TRISA0_bit
    LCD_D5_Direction as sbit at TRISA1_bit
    LCD_D6_Direction as sbit at TRISA2_bit
    LCD_D7_Direction as sbit at TRISA3_bit

dim Time  As Byte[7]
    Str   As String[3]

Dim Txt as string[2]

'==============================================================================
Sub procedure Write_ds3231_1()                    'Write RTCC registers RTC 1
'------------------------------------------------------------------------------
  i2c1_Start()
  i2c1_Wr(0xD0)
  i2c1_Wr(0x00)
  i2c1_Repeated_Start()
  i2c1_Wr(0xD0)
  i2c1_Wr(0x00)
  i2c1_Wr(0x01)                'Seconds
  i2c1_Wr(0x20)                'Minuts
  i2c1_Wr(0x23)                'Hours
  i2c1_Wr(0x01)
  i2c1_Wr(0x01)                'Day
  i2c1_Wr(0x12)                'Month
  i2c1_Wr(0x19)                'Year
  i2c1_Stop()
End Sub

'==============================================================================
Sub procedure Write_ds3231_2()                    'Write RTCC registers RTC 2
'------------------------------------------------------------------------------
  i2c2_Start()
  i2c2_Wr(0xD0)
  i2c2_Wr(0x00)
  i2c2_Repeated_Start()
  i2c2_Wr(0xD0)
  i2c2_Wr(0x00)
  i2c2_Wr(0x01)                'Seconds
  i2c2_Wr(0x20)                'Minuts
  i2c2_Wr(0x23)                'Hours
  i2c2_Wr(0x01)
  i2c2_Wr(0x01)                'Day
  i2c2_Wr(0x12)                'Month
  i2c2_Wr(0x19)                'Year
  i2c2_Stop()
End Sub

'==============================================================================
Sub procedure Read_DS3231_1()                     'Read RTCC registers RTC 1
'------------------------------------------------------------------------------
  i2c1_Start()
  i2c1_Wr(0xD0)
  i2c1_Wr(0x00)
  i2c1_Repeated_Start()
  i2c1_Wr(0xD1)
  Time[0] = Bcd2Dec(i2c1_Rd(1) And 0x7F)
  Time[1] = Bcd2Dec(i2c1_Rd(1))
  Time[2] = Bcd2Dec(i2c1_Rd(1) And 0x3F)
  Time[3] = Bcd2Dec(i2c1_Rd(1))
  Time[4] = Bcd2Dec(i2c1_Rd(1))
  Time[5] = Bcd2Dec(i2c1_Rd(1) And 0x7F)
  Time[6] = Bcd2Dec(i2c1_Rd(0))
  i2c1_Stop()
End Sub

'==============================================================================
Sub procedure Read_DS3231_2()                     'Read RTCC registers RTC 2
'------------------------------------------------------------------------------
  i2c2_Start()
  i2c2_Wr(0xD0)
  i2c2_Wr(0x00)
  i2c2_Repeated_Start()
  i2c2_Wr(0xD1)
  Time[0] = Bcd2Dec(i2c2_Rd(1) And 0x7F)
  Time[1] = Bcd2Dec(i2c2_Rd(1))
  Time[2] = Bcd2Dec(i2c2_Rd(1) And 0x3F)
  Time[3] = Bcd2Dec(i2c2_Rd(1))
  Time[4] = Bcd2Dec(i2c2_Rd(1))
  Time[5] = Bcd2Dec(i2c2_Rd(1) And 0x7F)
  Time[6] = Bcd2Dec(i2c2_Rd(0))
  i2c2_Stop()
End Sub

'==============================================================================
main:

'==============================================================================
  ANSELB = 0                                    'All output/digital
  ANSELA = 0                                    '
  TRISA  = 0                                    '
  TRISB  = 0                                    '
  OSCCON = %11101011                            '4MHz internal

  i2c1_init(100000)                             'Init i2c-1 port 100kHz
  i2c2_init(100000)                             'Init i2c-2 port 100kHz
  Lcd_Init()                                    'Init 1602 Display
  'Write_DS3231_1()                             'Write values to RTC-1
  'Write_DS3231_2()                             'Write values to RTC-2
  
  Lcd_Cmd(_LCD_CLEAR)
  Lcd_Cmd(_LCD_CURSOR_OFF)

While True                                      'Endless display loop
    Read_DS3231_1()                             'Read RTCC 1
    Delay_ms(5)
    ByteToStrWithZeros(Time[0], Txt)
    LCD_Out(1,14, txt)
    ByteToStrWithZeros(Time[1], Txt)
    LCD_Out(1,11, Txt + ":")
    ByteToStr(Time[2], Str)
    LCD_Out(1,8, Str + ":")
    ByteTostr (Time[4], Str)
    ltrim(str)
    LCD_Out(1,1, Str)
    ByteTostr (Time[5], Str)
    ltrim(str)
    LCD_Out(1,3, Str)
    ByteTostr (Time[6], Str)
    ltrim(str)
    LCD_Out(1,5, Str)
    delay_ms(5)

    '2nd RTC
    Read_DS3231_2()                             'Read RTCC 2
    Delay_ms(5)
    ByteToStrWithZeros(Time[0], Txt)
    LCD_Out(2,14, txt)
    ByteToStrWithZeros(Time[1], Txt)
    LCD_Out(2,11, Txt + ":")
    ByteToStr(Time[2], Str)
    LCD_Out(2,8, Str + ":")
    ByteTostr (Time[4], Str)
    ltrim(str)
    LCD_Out(2,1, Str)
    ByteTostr (Time[5], Str)
    ltrim(str)
    LCD_Out(2,3, Str)
    ByteTostr (Time[6], Str)
    ltrim(str)
    LCD_Out(2,5, Str)
    delay_ms(10)
  Wend
                                        '
end.  

Inmiddels heeft het geheel een aantal uren gelopen:
Na 12 uur lopen de klokjes 5 seconden uit elkaar. Dus per etmaal 10 seconden.
Over een jaar gemeten betekent dat 365 * 10 = 3650 seconden; meer dan een uur.
Vind ik vrij fors.

Waarbij het vermoeden is dat de DS1307 te snel loopt.

Ik denk dat een 'zelfgemaakte' klok (zoals bij de multiplex ledklok) een stuk nauwkeuriger loopt als die DS1307... ;)
(hier wijkt 'ie hooguit 1 seconde af per dag en dat is nog veel: komt doordat de externe 10MHz oscillator te langzaam loopt...)

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Dat denk ik ook, vandaar dat ik de 'zelfbouw' LED met interrupt nu ga testen met 6 displays en de PIC16F877.

De DS3231 loopt overigens een stuk nauwkeuriger. De DS1307 is inderdaad de 'boosdoener'die een toch wel forse afwijking vertoont, ondanks dat dit moduultje toch een kristaloscillator aan boord heeft.
Een uur per jaar vind ik best wel veel.

Daarom een mooie oefening om de eigen klok en de DS3231 op 1 board te plaatsen.

Zoals eerder gezegd:
Met een 12pF (ingang) en 22pF (uitgang) condensatortje (en zo kort mogelijke verbinding naar het kristal) liep de oscillator hier het nauwkeurigst.
(minder als 1 sec per week afwijking)

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

Die neem ik ook mee op het board.

Met dat DS1307 moduultje valt weinig te beginnen, denk ik. Volgens mij zit daar een 32.768Khz kristal op.

Als je alleen 22pF hebt kun je er 2 in serie zetten (11pF) werkt ook goed.
Ik vergelijk altijd met mijn DCF klok. (mijn PC klok loopt gruwelijk veel te langzaam...)

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

mijn PC klok loopt gruwelijk veel te langzaam...)

De PC klok wordt toch via internet regelmatig gesynchroniseerd op de echte tijd?

ZOu wel moeten (staat aan), maar regelmatig loopt 'ie tot een halve minuut of meer achter.
Schijnbaar gaat de verbinding dan mis met de time server.

Nu steekt het wat mij betreft ook niet op een minuut of wat bij die PC klok... ;)

[Bericht gewijzigd door Arco op 3 december 2019 17:04:58 (22%)]

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com

verwijderd

[Bericht gewijzigd door Bavelt op 4 december 2019 21:19:29 (99%)]

Zoals eerder gezegd:
Met een 12pF (ingang) en 22pF (uitgang) condensatortje (en zo kort mogelijke verbinding naar het kristal) liep de oscillator hier het nauwkeurigst.
(minder als 1 sec per week afwijking)

Ik heb de condensatortjes van 12 en 22pf aangebracht. En pal op de chip met korte draadjes (zie foto). Het verloop van de klok is hier met de PIC16F877 ca 2 sec per etmaal. Dat zou ca 12 minuten per jaar zijn.

Lambiek

Special Member

Nu staat het nog op een bread board met allemaal overgangsweerstand van je bedrading, als dat op een print staat wordt het waarschijnlijk beter.

Als je haar maar goed zit, GROETEN LAMBIEK.

Als je een scoop hebt, kun je de oscillatorfrequentie 'tweaken'.
Je kunt ook een offset toevoegen om de klok gelijk te laten lopen:
De 2 regels met clockoffset toevoegen, en Seccount veranderen in een integer.

Je kunt dan van -499(langzamer) tot +499(sneller) kiezen.
Ieder stapje corrigeert de uurlengte met 2mS, jaarlijks ongeveer 17.5 seconde.

Bij 2 seconden per dag verschil zou je ongeveer -42 (klok te snel) of +42 (klok te langzaam) in moeten vullen...

pic basic code:



Program Clock

Const Maxdigits      = 6         'Displayed digits
      Keytime        = 120       '0.6sec
      Keydebounce    = 10        '40mS
      Keyrpttime     = 2         '8mS
      ClockOffset    = -10       '+/-499 max. 

Const Segtab As Byte[10] = (0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f)
      Digtab As Byte[maxdigits]  = (0x1,0x2,0x4,0x8,0x10,0x20)

Dim DigCount   As Byte
    Digit      As Byte[maxdigits]
    Seccount   As Integer
    KeyCount   As Byte
    Flags      As Byte
      fMinute  As sBit At Flags.0
      fKeyRpt  As sBit At Flags.1
    Dp         As sBit At LATB.7
    Button     As sBit At PORTC.0

'----------------------------------------------------------------------------------------
sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'----------------------------------------------------------------------------------------
  If TMR2IF_bit Then                                                'See if timer2 irq
    Inc(Seccount)                                                   'If so, update coun-
    If Seccount = 500 Then                                          'ters.
      Seccount = 0                                                  'Set flag if minute
      fMinute = 1
    End If                                                          '
    '------------------------------------------------------------------------------------
    If Button = 0 Then                                              'Button pressed?
      Inc(KeyCount)                                                 'Yes, count + 1
      Select Case KeyCount                                          '
        Case KeyTime                                                'See if it's a nor-
          fKeyRpt  = 1                                              'mal or a repeated
          KeyCount = 0                                              'keypress.
        Case KeyDebounce                                            '
          fMinute = 1                                               '
          SecCount  = 0                                             '
          If fKeyRpt Then KeyCount = 0 End If                       '
        Case KeyRptTime                                             '
          If fKeyRpt Then                                           '
            fMinute  = 1                                            '
            SecCount  = 0                                             '
            KeyCount = 0                                            '
          End If                                                    '
      End Select                                                    '
    Else                                                            'No key, clear count
      fKeyRpt   = 0                                                 'and flag
      KeyCount  = 0                                                 '
    End If                                                          '
    '------------------------------------------------------------------------------------
    LATA = DigTab[DigCount]
    LATB = SegTab[Digit[DigCount]]
    If ((DigCount = 2) Or (DigCount = 4)) And (Seccount > 250) Then dp = 1 End If
    Inc(DigCount)
    If DigCount = MAXDIGITS THEN DigCount = 0 End If
    TMR2IF_bit = 0
  End If
end sub

'========================================================================================
Main:                                                               '
'----------------------------------------------------------------------------------------
  Dim lCnt As Byte

  T2CON      = %00100101                                            'Post:5 - Pre:16
  PR2        = 250                                                  'Timer load value
  TRISA      = %00000000                                            'Only RA4 input
  TRISB      = %00000000                                            '
  TRISC      = %00000001
  ANSELA     = %00000000                                            'All ports digital
  ANSELB     = %00000000
  GIE_bit    = 1                                                    'Enable timer2 irq
  PEIE_bit   = 1                                                    '
  TMR2IE_bit = 1                                                    '
  DigCount   = 0                                                    'Clear digits 
  For lCnt = 0 To Maxdigits-1                                       '
    Digit[lCnt]  = 0                                                '
  Next lCnt                                                         '
  Seccount   = 0                                                    '
'--------------------------------------------------------------------------------------
  While True                                                        '
    If (Digit[5] = 2) And (Digit[4] = 4) Then                       'If hour '24', reset
      For lCnt = 0 To Maxdigits-1                                   'to 00:00:00
        Digit[lCnt]  = 0                                            '
      Next lCnt                                                     '
    End If                                                          '
    While fMinute = 0     Wend                                      'Wait for time update
    Inc(Digit[0])                                                   '
    If Digit[0] = 10 Then                                           '
      Digit[0] = 0                                                  '
      Inc(Digit[1])                                                 '
      If Digit[1] = 6 Then                                          '
        Digit[1] = 0                                                '
        Inc(Digit[2])                                               '
        If Digit[2] = 10 Then                                       'Update all 4 Digit-
          Digit[2] = 0                                              'values
          Inc (Digit[3])                                            '
          If Digit[3] = 6 Then                                      '
            Digit[3] = 0                                            '
            Inc (Digit[4])                                          '
            Seccount = Seccount + ClockOffset                       '                 
            If Digit[4] = 10 Then                                   '
              Digit[4] = 0                                          '
              Inc(Digit[5])                                         '
            End If                                                  '
          End If                                                    '
        End If                                                      '
      End If                                                        '
    End If                                                          '
    fMinute = 0                                                     'Reset flag
  Wend                                                              '
                                                                    '
  End.                                                              '

Arco - "Simplicity is a prerequisite for reliability" - www.arcovox.com
RAAF12

Golden Member

Op 27 november 2019 00:02:48 schreef Arco:
Een klok die 15 minuten per dag voor of achter loopt vind ik niet erg nuttig... ;) (de interne oscillator is +/- 1% op zijn best...)
Met zo'n externe DIL oscillator zou 't wel net kunnen:

[afbeelding]

Ja, die dingen werken prima ik heb hier een liggen die al 35 jaar verouderd is! Die is akelig stabiel gebleken. Ik ben alleen de datasheet kwijt :-(
4 aansluitingen en bovenop staat in de hoek een dikke, zwarte dot als orientatie.
Die zit trouwens in hetzelfde kastje als de zelfbouw 15Hz-100kHz audio sweepgenerator gebaseerd op de Exar XR2206. Waarom kopen die boys hier zoveel kant en klaar spul. Ik vind zelfbouw leuker en goedkoper. Maar iedereen doet natuurlijk waar die zin in heeft....

Gepost donderdag 5 december 2019 12:25:43 |Quoten
Als je een scoop hebt, kun je de oscillatorfrequentie 'tweaken'.

Ik heb wel een scope, maar die gaat maar tot 15Mhz. Dan is de schaal niet toereikend om een signaal van 10Mhz mee af te stellen.

Ik heb ook wel een frequentiecountertje (met een PIC16F628A aan boord). Maar zodra ik de ingang hiervan verbind met ClockOut (Poort A6) dan werkt de oscillator niet meer. Blijkbaar is de belasting te groot.

Wellicht is daar nog iets tussen te flansen met een hoge impedantie? (Emittervolger o.i.d) zodat ik m.b.v de frequentiecounter het kan afstellen?