Zou toch moeten kloppen. Hoe test je dat?
Dit topic is gesloten
Special Member
Zou toch moeten kloppen. Hoe test je dat?
Golden Member
In de interrupt:
pic basic code:
IF TMR2IF_bit Then ' See if timer2 irq
PORTA.0 = NOT PORTA.0 'Test on Scope
-
-
Scope: 0,2 ms periode. Plus een frequentieteller er op: 5.000 Khz
Special Member
Dat klopt. 10000 toggles van een pin geeft 5000Hz...
Golden Member
Op 10 november 2020 16:00:10 schreef Arco:
Dat klopt. 10000 toggles van een pin geeft 5000Hz...
Ach ja, natuurlijk. Het is aan-uit...
Golden Member
Ik heb hier het volledige programma dat ik er van heb gemaakt vanmiddag.
De IR-string (trein) begint met een blik van 9ms, gevolgd door een pauze van 4,5ms. M.a.w het duurt ca 13ms voordat de 'echte' informatie komt.
Daarom heb ik een teller (treinteller) gedefinieerd, die in de interrrupt pas dingen laat doen als de 13ms voorbij zijn.
Omdat de signalen zijn omgedraaid t.o.v. de tekening, inverteer ik PortB.1 (waar de sensor op zit) naar Port A.0.
Het resultaat per karakter ("0" of""1) komt in een string die ik op de LCD wil tonen.
Het geheel werkt echter nog niet, omdat er ergens toch een denkfout in zit..
pic basic code:
'==============================================================================
Program IR_HD44780
'==============================================================================
Const HMIN = 4 'Min value pulse high
HMAX = 8 'Max value pulse high
LMIN = 4 'Min value pulse low
L1 = 8 'Max value for '1' in pulse low
LMAX = 14 'Max value pulse low
TIMEOUT = 25 'Max count value
dim LCD_RS as sbit at LATB3_bit
LCD_EN as sbit at LATB2_bit
LCD_D4 as sbit at LATB7_bit
LCD_D5 as sbit at LATB6_bit
LCD_D6 as sbit at LATB5_bit
LCD_D7 as sbit at LATB4_bit
LCD_RS_Direction as sbit at TRISB3_bit
LCD_EN_Direction as sbit at TRISB2_bit
LCD_D4_Direction as sbit at TRISB7_bit
LCD_D5_Direction as sbit at TRISB6_bit
LCD_D6_Direction as sbit at TRISB5_bit
LCD_D7_Direction as sbit at TRISB4_bit
OldState As Byte
HiCnt As Byte
LoCnt As Byte
i1 As Byte
FInterrupt As Byte
Nieuwe_Trein As Byte
Charx As Char
Resultaat As String[24]
Treinteller As Byte
Str as String[16]
'================================================================================
Sub Procedure Toon(Dim pAantal as byte) 'Test tool
'================================================================================
Dim i1 as Byte
For i1 = 1 to pAantal
LATB.1 = 1
Delay_ms(1000)
lATB.1 = 0
Delay_ms(1000)
Next i1
End Sub
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
IF TMR2IF_bit Then ' See if timer2 irq
PORTA.0 = NOT PORTB.0
If PORTA.0 = 1 Then
If Nieuwe_Trein = 0 then
Treinteller = Treinteller + 1 ' Skip first Burst of 13 ms
if Treinteller > 130 then
If OldState <> PORTA.0 Then
OldState = PORTA.0
If (HiCnt > HMIN) And (HiCnt < HMAX) And
(LoCnt > LMIN) And (LoCnt < LMAX) Then
If LoCnt < L1 Then
'valid pulse '1' found...
CharX = "1"
Else
'valid pulse '0' found
CharX = "0"
End If
HiCnt = 0
LoCnt = 0
End If
End If
If HiCnt < HMAX Then Inc(HiCnt) End If
End If
End if
Else
OldState = PORTA.0
If LoCnt < LMAX Then Inc(LoCnt) End If
End if
TMR2IF_bit = 0
End If
End Sub
'==============================================================================
main:
'==============================================================================
ANSELA = 0 'All output/digital
ANSELB = 0
TRISA = %11110000
TRISB = %00000001
OSCCON = %11110000 '32MHz internal, 4x PLL On
T2CON = %00000110 'Pre: 16 - Post:1
PR2 = 49 'Timer load value
GIE_bit = 1 'Enable timer irq
PEIE_bit = 1
TMR2IE_bit = 1 'Enable Timer2 overflow interrupt
TMR2IF_bit = 0 'Clear Timer1 overflow interrupt flag bit
Lcd_Init() '
Lcd_Cmd(_LCD_CLEAR)
Lcd_Cmd(_LCD_CURSOR_OFF)
Lcd_Out(1, 1, "Start")
Delay_Ms(1000)
i1 = 0
PORTB.1 = 0
Nieuwe_Trein = 0
Treinteller = 0
While true
if Charx <> " " then
Resultaat[i1] = charX
i1 = i1 + 1
if i1 > 15 then
i1 = 0
Lcd_Out(1, 1, Resultaat)
Nieuwe_Trein = 0
Treinteller = 0
Delay_ms(100)
End if
end if
Charx = " "
Wend
'
end.
Mocht je iets raars zien..hou ik me graag aanbevolen!
Golden Member
Je hoeft dan alleen bij iedere interrupt te kijken of de pin hoog of laag is, en dat kan vrij ruim.
Tussen de 4 en 8 keer hoog? (400...800uS). Dan is het een 'hoog' puls.
Tussen de 8 en 14 keer laag? (0.8...1.4mS). Dan is het een 'laag' puls.
Ik zit hier nog naar te turen, maar zie het verband nog niet, waar je die 4, 8 en 14 (* 100uS) vandaan haalt in relatie tot het een hoog of laag is...
Special Member
De interrupt komt iedere 100uS. Dus 576uS is 5 a 6 interrupts. (4 tot 8 is dus ruim genomen)
De 'laag' periode is 576uS ("1") of 1125uS ("0"). (4...8...14 weer ruim genomen)
Golden Member
Die tijden snap ik nu..
Toch zit er nog iets niet goed in de interrupt routine.
De start van een pulstrein bestaat uit 9 plus 4,5 = 13,5 ms = 135
'tikken'van de timer.
Die moet ik dus eerst doen. Daarna kan het gaan lopen.
De interrupt werkt, alsmede ook de sensor. Dat kan ik testen nmet een ledje.
De routine komt echter nooit in een 'valid pulse' terecht.
(Voor het gemak heb ik de literals er even in gezet):
pic basic code:
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
IF TMR2IF_bit Then ' See if timer2 irq
PORTA.0 = NOT PORTB.0
If PORTA.0 = 1 Then
If StartBytes < 135 then ' Skip first Burst of 13,5 ms
Inc(StartBytes)
goto Einde
End if
If OldState <> PORTA.0 Then
OldState = PORTA.0
If (HiCnt > 4) And (HiCnt < 8) And
(LoCnt > 4) And (LoCnt < 14) Then
If LoCnt < 8 Then
'valid pulse '1' found...
CharX = "1"
Else
'valid pulse '0' found
CharX = "0"
End If
HiCnt = 0
LoCnt = 0
End If
End If
If HiCnt < 8 Then Inc(HiCnt) End If
Else
OldState = PORTA.0
If LoCnt < LMAX Then Inc(LoCnt) End If
End if
Einde:
TMR2IF_bit = 0
End If
End Sub]
Ik zoek me een ongeluk, maar kan het niet vinden...
Special Member
Ik zal er eens naar kijken...
Golden Member
Op 11 november 2020 01:29:55 schreef Arco:
Ik zal er eens naar kijken...
Ik ben er zelf ook al wat mee aan het spelen geweest en heb een poging gewaagd.
Ik krijg nu wel wat op het schermpje na indrukken, (is al heel wat.. ) maar het resultaat is 'random'. je moet daarnaast ca 6 keer drukken op de AB voor er wat komt. En iedere keer wordt er wat anders getoond.
Ik had er een timercounter bij ingestopt, omdat je weet dat vanaf het startpunt de de data (dus na de burst van 13,5ms) het resultaat na 32*562,5 = 18000uS klaar moet zijn.
Maar daar lag het net aan en het gaat dus nog niet goed:
pic basic code:
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
IF TMR2IF_bit Then ' See if timer2 irq
PORTA.0 = NOT PORTB.0
If PORTA.0 = 1 Then
If StartBytes < 135 then ' Skip first Burst of 13,5 ms
Inc(StartBytes)
goto Einde
else
inc(TimerCount) ' Start Timer Counter at receive
End if
if Oldstate <> PORTA.0 then ' PORTA.0 Changed from 0 to 1
Oldstate = PORTA.0
if (LoCnt > 4) And LoCnt < 8 then
HiCnt = 1
LoCnt = 0
Charx = "0"
Goto Einde
End if
if (LoCnt > 8) And LoCnt < 14 then
HiCnt = 1
LoCnt = 0
Charx = "1"
Goto Einde
End if
Else ' PORTA.0 was already High
Inc(HiCnt)
End if
Else
Inc(LoCnt) 'Increase Low Counter
End If
Einde:
TMR2IF_bit = 0
End If
End Sub
[Bericht gewijzigd door Bavelt op woensdag 11 november 2020 13:29:49 (50%)
Golden Member
Ik had er een timercounter bij ingestopt, omdat je weet dat vanaf het startpunt de de data (dus na de burst van 13,5ms) het resultaat na 32*562,5 = 18000uS klaar moet zijn.
Ik moet mezelf tegenspreken, dat is natuurlijk niet waar.
Wanneer de string uit 32 keer een '1' bestaat is de tijd veel langer dan bv 32 keer een '0'.
Het is dus geen vaste lengte qua tijd.
Het enige dat je weet is dat het totaal 32 bits mogen zijn. (2 keer adres, 1 keer data en 1 keer inverted data. De laatste heb ik inderdaad niet nodig)
Lastige materie, hoor...
Golden Member
Op 11 november 2020 01:29:55 schreef Arco:
Ik zal er eens naar kijken...
Dit is wat ik tot nu toe heb. Ik krijg nu wel een string te zien per druk op de AB knop. Echter bij dezelfde knop krijg ik steeds andere kakrakters.
Zou je er nog eens een vlotte blik op willen werpen of je iets ziet wat dat kan veroorzaken?
pic basic code:
'==============================================================================
Program IR_HD44780
'==============================================================================
Const HMIN = 4 'Min value pulse high
HMAX = 8 'Max value pulse high
LMIN = 4 'Min value pulse low
L1 = 8 'Max value for '1' in pulse low
LMAX = 14 'Max value pulse low
TIMEOUT = 25 'Max count value
dim LCD_RS as sbit at LATB3_bit
LCD_EN as sbit at LATB2_bit
LCD_D4 as sbit at LATB7_bit
LCD_D5 as sbit at LATB6_bit
LCD_D6 as sbit at LATB5_bit
LCD_D7 as sbit at LATB4_bit
LCD_RS_Direction as sbit at TRISB3_bit
LCD_EN_Direction as sbit at TRISB2_bit
LCD_D4_Direction as sbit at TRISB7_bit
LCD_D5_Direction as sbit at TRISB6_bit
LCD_D6_Direction as sbit at TRISB5_bit
LCD_D7_Direction as sbit at TRISB4_bit
OldState As Byte
HiCnt As Byte
LoCnt As Byte
i1 As Byte
j1 As Byte
x1 As Byte
Charx As Char
Result As String[32]
StartBytes As Byte
Str As String[16]
'================================================================================
Sub Procedure Toon(Dim pAantal as byte) 'Test tool
'================================================================================
Dim i1 as Byte
For i1 = 1 to pAantal
LATB.1 = 1
Delay_ms(1000)
lATB.1 = 0
Delay_ms(1000)
Next i1
End Sub
'================================================================================
Sub Procedure Show_Result() 'Show Output on LCD
'================================================================================
Str = " "
Lcd_Out(1, 1, Str)
Lcd_Out(2, 1, Str)
For x1 = 0 to 15
Str[x1] = Result[x1] 'First 16 bytes on Row 1
Next x1
Lcd_Out(1, 1, Str)
'Second 16 bytes on Row 2
For j1 = 16 to 31
Str[j1-16] = Result[j1]
Next j1
Lcd_Out(2, 1, Str)
For j1 = 0 to 31 'Clear Resultaat after show
Result[j1] = " "
Next j1
End Sub
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
IF TMR2IF_bit Then ' See if timer2 irq
PORTA.0 = NOT PORTB.0
If PORTA.0 = 1 Then
If StartBytes < 135 then ' Skip first Burst of 13,5 ms
Inc(StartBytes)
goto Einde
End if
if Oldstate <> PORTA.0 then ' PORTA.0 Changed from 0 to 1
Oldstate = PORTA.0
if (LoCnt > 4) And LoCnt < 8 then
HiCnt = 1
LoCnt = 0
Charx = "0"
Goto Einde
End if
if (LoCnt > 8) then
HiCnt = 1
LoCnt = 0
Charx = "1"
Goto Einde
End if
Else ' PORTA.0 was already High
Inc(HiCnt) ' Increaee High Counter
End if
Else
Inc(LoCnt) 'Increase Low Counter
End If
Einde:
TMR2IF_bit = 0
End If
End Sub
'==============================================================================
main:
'==============================================================================
ANSELA = 0 'All output/digital
ANSELB = 0
TRISA = %11110000
TRISB = %00000001
OSCCON = %11110000 '32MHz internal, 4x PLL On
T2CON = %00000110 'Pre: 16 - Post:1
PR2 = 49 'Timer load value
GIE_bit = 1 'Enable timer irq
PEIE_bit = 1
TMR2IE_bit = 1 'Enable Timer2 overflow interrupt
TMR2IF_bit = 0 'Clear Timer1 overflow interrupt flag bit
Lcd_Init() '
Lcd_Cmd(_LCD_CLEAR)
Lcd_Cmd(_LCD_CURSOR_OFF)
Lcd_Out(1, 1, " ")
Lcd_Out(2, 1, " ")
Delay_Ms(100)
i1 = 0
j1 = 0
PORTB.1 = 0
StartBytes = 0
Result = " "
While true
if Charx <> " " then
Result[i1] = charX
Inc(i1)
if (i1 > 31) then
Show_Result()
i1 = 0
j1 = 0
StartBytes = 0
End If
Charx = " "
End if
Wend
'
end.
Special Member
Volgens mij moet zoiets werken:
De interrupt wacht op de start van een trein en slaat die vervolgens op (32 bits) in IRCode[]
Als alles compleet is wordt flag fIRFound op '1' gezet.
In main() kun je die testen en de data verwerken. Data blijft aanwezig tot je de fIRFound flag in main() reset.
pic basic code:
'======================================================================================
Program Test
Const MINHI = 4 'Min value pulse high
MAXHI = 8 'Max value pulse high
MINLO = 4 'Min value pulse low
MEDLO = 8 'Max value for '1' in pulse low
MAXLO = 14 'Max value pulse low
TIMEOUT = 50 'Max count value
Dim HiCnt As Byte
LoCnt As Byte
Cnt As Byte
IRCode As String[32]
Flags As Byte
fPrev As sBit At Flags.0
fIRFound As sBit At Flags.1
Dim IRIn As sBit At PORTB.0
'========================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'========================================================================================
IF TMR2IF_bit Then 'Timer interrupt?
If fIRFound = 0 Then
If IrIn Then 'Input high?
If fPrev = 0 Then 'Low to high?
If (HiCnt = TIMEOUT) And (LoCnt = TIMEOUT) Then 'If timeouts, then
Cnt = 0 'start of new code
HiCnt = 0 '
LoCnt = 0 '
End If '
If (HiCnt > MINHI) And 'Pulse within specs?
(HiCnt < MAXHI) And '
(LoCnt > MINLO) And '
(LoCnt < MAXLO) Then '
If (LoCnt < MEDLO) Then 'Yes, add it to
IRCode[Cnt] = "0" 'string
Else '
IRCode[Cnt] = "1" '
End If '
LoCnt = 0 '
HiCnt = 0 '
Inc(Cnt) '
If Cnt = 32 then fIRFound = 1 End If '32 pulses found
End If '
If HiCnt < TIMEOUT Then Inc(HiCnt) End If '
Else '
If LoCnt < TIMEOUT Then Inc(LoCnt) End If '
End If '
fPrev = IrIn 'Save new state
End If '
End If
TMR2IF_bit = 0
End If
End Sub
'=====================================================================================
main:
End.
Golden Member
Hey Arco, dank je!
Er komt evenwel nog geen resultaat. De interrupt komt nooit in een geldige waarde terecht, dus IRCode blijft leeg.
Nu start de IR-String met een 'blok' van 9ms hoog, gevolgd door een laag van 4,5 ms.
Het duurt dus 13,5 ms voordat de 'echte' informatie komt. Zo te zien houdt de routine daar geen rekening mee. Is dat juist?
Special Member
Als er een blok langer als een puls binnenkomt wordt Cnt gereset en begint alles opnieuw.
Ik zie wel dat TIMEOUT te lang is, maak er eens 30 van (=3mS)
Golden Member
Op 11 november 2020 21:52:53 schreef Arco:
Als er een blok langer als een puls binnenkomt wordt Cnt gereset en begint alles opnieuw.
Ik zie wel dat TIMEOUT te lang is, maak er eens 30 van (=3mS)
Dat helpt niet...
Ik vroeg me even af of bij de wisseling van de IR-Poort van Laag naar Hoog
pic basic code:
HiCnt = 0
niet moet zijn:
pic basic code:
HiCnt = 1
Anders zou je de eerste "1" niet meetellen, dacht ik.
Even geprobeerd, maar dat helpt ook niet. Hij vindt geen geldige waarde.
Ik heb het even op papier nagetekend, maar een logische "1" krijg je pas na een laag-niveau van minimaal 1687,5 ms, ofwel minimaal 16 tikken.
Ik liep daarop vast.
Er moet nog iets zijn in de logica (afvraging) waarom er nooit een conditie komt die voldoet aan een "0" of "1".
Zoals ik de IR-String bekijk (maar heb het waarschijnlijk mis), is in principe alleen de laag-tijd bepalend.
Wordt die gevolgd door een tijd van 562,5 (zeg 4 - 7 tikken) dan is het een "0".
Wordt die gevolgd door een tijd van 1687,5 (zeg 8- 18 tikken), dan is het een "1".
Wat gaat hier nu fout?
Special Member
De regel:
pic basic code:
If (HiCnt = TIMEOUT) And (LoCnt = TIMEOUT) Then
wacht op een puls die langer is als een gewone '1' of '0'
Als die gevonden is worden alle counters op 0 gezet. Het ophogen van Hi/Lo counters wordt verderop in de routine gedaan:
pic basic code:
...
If HiCnt < TIMEOUT Then Inc(HiCnt) End If '
Else '
If LoCnt < TIMEOUT Then Inc(LoCnt) End If '
End If '
Ik ga er wel vanuit dat de pin in rust laag is en de pulsjes positief. Is dat niet zo, dan moet je dat even omdraaien in de code.
[Bericht gewijzigd door Arco op woensdag 11 november 2020 22:43:20 (11%)
Golden Member
Ik ga er wel vanuit dat de pin in rust laag is en de pulsjes positief. Is dat niet zo, dan moet je dat even omdraaien in de code.
Dat heb ik gedaan. De Sensor zit nl op PortB.0.
Die is hoog in rust. Die moet dus worden omgedraaid.
Ik doe dat met
pic basic code:
PORTA.0 = NOT PORTB.0
in de Interrupt, waarbij
pic basic code:
IRIn As sBit At PORTA.0
is gedefinieerd.
Ik heb getest (met een ledje) dat de time-out ook nooit wordt bereikt.
Dat zou toch tenminste één keer moeten gebeuren: bij de start van de string. (9ms hoog + 4,5ms laag).
Ik zou die string eigenlijk wel eens willen zien, hoe die er nu precies uit ziet.
Maar ja, die komt maar één keer voorbij na een druk op de AB.
Nu heb ik destijds een Logic Analyzer gekocht (nooit mee getest).
Kan ik daar wat mee? Of werkt die alleen op 'lopende patronen'?
Special Member
Logic Analyzer is hier prima voor te gebruiken.
pic basic code:
PORTA.0 = Not PORTB.0
is trouwens wat vreemd. (portxx zijn inputs, daar valt niks aan hoog of laag te maken. Kan soms werken maar is niet betrouwbaar, LATxx gebruiken)
Golden Member
is trouwens wat vreemd. (portxx zijn inputs, daar valt niks aan hoog of laag te maken. Kan soms werken maar is niet betrouwbaar, LATxx gebruiken)
Ok, Maar PortB.0 is input (daar zit de IR-sensor op)
Dat zou dan worden
pic basic code:
LATA.0 = PORTB.0
?
Logic Analyzer is hier prima voor te gebruiken
Dus die kan een eenmalige string 'capturen', die ik later kan 'ergens' kan bekijken?
Daar zal ik dan dus software voor nodig hebben..
Golden Member
Daarnaast bedacht ik me, ik zou natuurlijk ook de input, zonder afvragingen, per tik van 100us via UART op de PC kunnen tonen. Dan weet ik ook precies wat er binnenkomt, toch?
Special Member
Wat er met een UART gebeurt heb ik geen idee. (die verwacht niet echt een 1736 baud pulstrein van wisselende lengte en met varierende pulslentes.)
Waarschijnlijk komt daar troep uit...
Bij die logic analyzer zal je toch wel software hebben gehad? (de mijne was 8 euro en daar zat een softwarepakket bij...)
Je kunt de analizer starten voor bijv 1, 2, 5, of 10 seconden en dan neemt die alles op. Kun je terugkijken wat er gebeurd is in die periode.
Golden Member
Wat er met een UART gebeurt heb ik geen idee. (die verwacht niet echt een 1736 baud pulstrein van wisselende lengte en met varierende pulslentes.)
Waarschijnlijk komt daar troep uit...
Ik bedoelde het eigenlijk anders: Ik benoem een grote string in mijn programma en in de interrupt kijk ik vanaf het moment dat de Poort hoog wordt, iedere 100uS wat de poort is. Een 0 of een 1. Dat zet ik in de string. En dan na bv 300 tekens stop ik, en laat de inhoud van de string op de PC zien zien (in een rustig tempo .
(als het goed is dan zou dat 90 keer een "1" moeten zijn, 45 keer een "0" en dan afhankelijk van adress+command de waardes)...
Maar, het werken met de analyzer op zich is al een oefening. Ik heb het ding een hele tijd geleden gekocht, maar nooit gebruikt.
Dit zat er in het doosje:
Dus geen software. Ik heb al wat 'gegoogled', en zag dat daar wat open source toepassingen voor zijn.
Special Member
Ik heb dezelfde van Sparkfun, kreeg daar een link bij voor de open source software.
(Er is trouwens ook een simpele hack om hem met Saleae software te gebruiken)
[Bericht gewijzigd door Arco op donderdag 12 november 2020 11:55:04 (18%)
Golden Member
En welke is nu het makkelijks in gebruik?
Voor dit moment hoef ik geen 8 kanalen, twee zou voldoende zijn.
Om de string en de timer te zien...
Dit topic is gesloten