Een puzzelstukje is nog even om een 'timer' in te stellen, dwz hoe lang een procedure moet worden uitgevoerd.
Daarbij vraagt de Delay instructie een integer. Maar als je de frequentie naar tijd gaat omrekenen, kom je met afrondingsverschillen.
Bijvoorbeeld freq = 523 Hz. Tijd = 1000 / 523 = 1,9 en zal hij 1 van maken.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Ja,,
Ingebakken delay functies zijn alleen voor het groffe werk, voor precieze timing zul je zelf een (meestal interrupt gestuurde) timer moeten maken...
Als je veel interrupts gebruikt, zijn de ingebouwde delays vreselijk onnauwkeurig, delay_mS(100) kan dan wel 150mS of meer duren.
(dit omdat de delay steeds onderbroken wordt door een interrupt)
Voor de timerfunctie had ik inmiddels al een truc bedacht: je weet de frequentie, en daardoor de tijdsinterval. Door het tellen van alle pulsen kan je vaststellen wanneer de limiet (duur) is bereikt.
Dan kan met for -- next
Inmiddels heb ik het programaatje wat uitgebreid en heb nu een PIC16F1827.
Deze MC werkt inderdaad wat lekkerder dan de 1826, vanwege zijn grotere capaciteit.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Ik zag trouwens nog een foutje in de Read_DS3231() (de AND's staan verkeerd)
Time[0] = Bcd2Dec(i2c1_Rd(1))
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))
moet zijn:
Time[0] = Bcd2Dec(i2c1_Rd(1))
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))
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Op 26 oktober 2019 18:12:21 schreef Arco:
Is bij de 1826/27/47 al gedeclareerd in de include file (P16F1826.MBAS)[bijlage]
Is deze include wellicht uit te schakelen? Het is nl af en toe wat lastig met noten.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Je kunt hem editen (staat in de DEFS directory van de compiler.)
Weghalen zou ik niet doen; alle registernamen en config settings (o.a. PORTx, LATx, TRISx, ANSELx...) zitten daar ook in, die ben je dan ook kwijt.
Het werken met MikroBasic begint steeds beter te lopen.
Ook de samenwerking met PICKit3 is fijn. Compileren en PicKit pakt hem vanzelf op en programeert de uC.
Ik heb diverse settings van de Editor uitgeprobeerd.
Ik ben alleen nog veel aan het schuiven binnen de code vind ik. Zo mis ik wat in VB.NET zo mooi werkt, dat is dat hij de code mooi formateert. Bijvoorbeeld inspringen na een if en het netjes uitlijnen zodat je precies weet bij welke if de end hoort (handig als je veel geneste statements hebt).
Maar wellicht kan dat in MB ook.
Op 25 oktober 2019 19:41:55 schreef Arco:
[...]
Ik gebruik de PIC24FJ256GA106/108/110 vaak...
https://nl.farnell.com/search?st=pic24fj256ga1
Dit zijn wel grote dingen. Maar hoe gebruik je die in een testomgeving?
Dat kan dan vast niet op een breadboard neem ik aan. En zijn daar dan voetjes voor te krijgen?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Ik laat meteen een print maken als ik een ontwerp heb (kost tegenwoordig toch geen drol meer)
Maar er zijn ook boarden als de EasyPicFusion V7 waar je een losse module met de gewenste processor op kunt steken.
Ik heb nog zo'n board liggen van de 18F serie (18F46xx/67xx/87xx serie)
Goh, wéér wat geleerd...
Dat krijg je als je zolang uit een hobby bent geweest.
Het gaat nu ineens heel snel, eerst met wat TTL spelen, PIC's programmeren, andere type uC, andere programmeer-omgeving...
Wel heel grappig (en tijdrovend).
En ook best spannend.
Ter leering ende vermaeck..
Hier is mijn programmaatje.
Een deurbel, die verschillende melodietjes speelt afhankelijk van de datum.
Met de PiC16F1827 als Micro Controller
'==============================================================================
Program Deurbel
'------------------------------------------------------------------------------
'Notes Frequency (Hz)
Const E4 = 329
Const G4 = 392
Const A4 = 440
Const A4h = 466
Const B4a = 499
Const C5 = 523
Const C5h = 554
Const D5 = 587
Const D5h = 622
Const E5 = 659
Const F5 = 698
Const G5 = 784
Const A5 = 880
Const A5a = 932
Const B5a = 987
Const C6 = 1047
Const D6 = 1175
'Midsomer Murders
Const NOTE as WORD [13] = (D5h, D5, D5h,D5, C5,A4h, D5, C5,D5h, G5, C6,B5a, G5)
Const DUR as Word [13] = (250,250,250,250,375,125,250,1000,250,750,500,250,1500)
'Lang zal ze leven
Const NOTE1 as WORD [13] = ( C5, C5, C5, C5, G4, E5, E5, E5, E5, C5)
Const DUR1 as Word [13] = (500, 200, 200, 500, 700, 500, 200, 200, 500, 750)
Const DLY1 as Byte [13] = ( 15, 15, 15, 15, 0, 0, 15, 15, 15, 0)
'Jingle Bells
Const NOTE2 as WORD [11] = (E5, E5, E5, E5, E5, E5, E5, G5, C5, D5, E5)
Const DUR2 as Word [11] = (250, 250, 500, 250, 250, 500, 250, 250, 250, 250, 750)
Const DLY2 as Byte [11] = ( 15, 15, 100, 15, 15, 150, 0, 0, 0, 0, 0)
'Hoor wie klopt daar kinderen
Const NOTE3 as WORD [22] = (G4, G4, E5, C5, C5, C5, G4, G4, E5, C5, C5, C5, G4, G4, D5, C5H, D5, C5H, D5, E5, C5)
Const DUR3 as Word [22] = (220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 250, 250, 250, 250, 250, 250, 250, 250, 700)
Const DLY3 as Byte [22] = ( 15, 0, 0, 15, 15, 15, 15, 0, 0, 15, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0)
'Stille Nacht
Const NOTE4 as WORD [23] = ( G5, A5, G5, E5, G5, A5, G5, E5, D6, D6, B5a, C6, C6, G5, A5, A5, C6, B5a, A5, G5, A5, G5, E5)
Const DUR4 as Word [23] = (420, 420, 420, 620, 420, 420, 420, 620, 420, 320, 520, 420, 320, 520, 320, 220, 320, 220, 320, 320, 320, 320, 620)
Const DLY4 as Byte [23] = ( 0, 0, 0, 200, 0, 0, 0, 200, 15, 0, 200, 15, 0, 200, 15, 0, 0, 0, 0, 0, 0, 0, 0)
'O Denneboom
Const NOTE5 as WORD [16] = ( G4, C5, C5, C5, D5, E5, E5, E5, E5, D5, E5, F5, B4a, D5, C5, C5)
Const DUR5 as Word [16] = (420, 220, 220, 520, 420, 220, 220, 520, 420, 420, 420, 320, 320, 420, 220, 420)
Const DLY5 as Byte [16] = ( 0, 15, 15, 200, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 15, 0)
'We wish you a mary Christmas
Const NOTE6 as WORD [30]= ( C5, F5, F5, G5, F5 , E5, D5, D5, D5, G5, G5, A5, G5, F5, E5, C5, C5, A5, A5, A5a, A5, G5, F5, D5, C5, C5, D5, G5, E5, F5)
Const DUR6 as Word [30] = (420, 220, 220, 220, 220, 220, 220, 420, 420, 220, 220, 220, 220, 220, 220, 420, 420, 220, 220, 220, 220, 220, 220, 420, 420, 420, 420, 420, 420, 720)
Const DLY6 as Byte [30] = ( 0, 15, 0, 0, 0, 0, 15, 15, 0, 15, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0)
Const PLUS as byte = 100 'Extra delay for speed melodie)
Dim Time As Byte[7]
Dim Toon As Byte
Dim Xmas as byte
Dim Switch1 as sbit at PORTA.0
''==============================================================================
Sub procedure Write_DS3231() 'Write Date in RTC registers
''------------------------------------------------------------------------------
i2c1_Start()
i2c1_Wr(0xD0)
i2c1_Wr(0x00)
i2c1_Repeated_Start()
i2c1_Wr(0xD0)
i2c1_Wr(0x01) 'Seconds
i2c1_Wr(0x31) 'Minutes
i2c1_Wr(0x12) 'Hour
i2c1_Wr(0x3) 'Daynr
i2c1_Wr(0x01) 'Day
i2c1_Wr(0x11) 'Month
i2c1_Wr(0x19) 'Year
i2c1_Stop()
End Sub
'==============================================================================
Sub procedure Read_DS3231() 'Read Date in RTC registers
'------------------------------------------------------------------------------
i2c1_Start()
i2c1_Wr(0xD0)
i2c1_Wr(0x00)
i2c1_Repeated_Start()
i2c1_Wr(0xD1)
Time[0] = Bcd2Dec(i2c1_Rd(1))
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 Midsomer
For Toon = 0 to 12
Sound_Play(Note[Toon], (Dur[Toon] + Plus))
Next Toon
End Sub
Sub Procedure Verjaardag
For Toon = 0 to 9
Sound_Play(Note1[Toon], (Dur1[Toon] + Plus))
VDelay_MS(DLY1[Toon])
Next Toon
End sub
Sub Procedure JingleBells
For Toon = 0 to 10
Sound_Play(Note2[Toon], (Dur2[Toon] + Plus))
VDelay_MS(DLY2[Toon])
Next Toon
End sub
Sub Procedure HoorWieKlopt
For Toon = 0 to 21
Sound_Play(Note3[Toon], (Dur3[Toon] + Plus))
VDelay_MS(DLY3[Toon])
Next Toon
End sub
Sub Procedure StilleNacht
For Toon = 0 to 22
Sound_Play(Note4[Toon], (Dur4[Toon] + Plus))
VDelay_MS(DLY4[Toon])
Next Toon
End sub
Sub Procedure Denneboom
For Toon = 0 to 15
Sound_Play(Note5[Toon], (Dur5[Toon] + Plus))
VDelay_MS(DLY5[Toon])
Next Toon
End sub
Sub Procedure Merry_Xmas
For Toon = 0 to 29
Sound_Play(Note6[Toon], (Dur6[Toon] + Plus))
VDelay_MS(DLY6[Toon])
Next Toon
End sub
'==============================================================================
main:
'==============================================================================
ANSELB = 0 'All output/digital
ANSELA = 0 '
TRISA = 0 '
TRISB = 0
PORTA = %11111111 'Port A to high
OSCCON = %11110000 '32MHz internal
i2c1_init(100000) 'Init i2c port 100kHz
Sound_Init(PORTB, 3) 'Init Sound Port (B.3)
Xmas = 0
'Write_DS3231() 'Time can be reset by uncommend
While True 'Endless loop waiting for S1
if Switch1 = 0 then
delay_ms(20) 'Delay for depressing disturb
if Switch1 = 0 then
Read_DS3231() 'Read RTCC
Delay_ms(100)
if ((Time[4] > 15) and (Time[5] = 11) Or ((Time[4] < 6) And (Time[5] = 12))) then
HoorWieKlopt()
else
if ((Time[4] = 13) AND (Time[5] = 06) or ((Time[4] = 15) AND (Time[5] = 12))) then
Verjaardag()
else
if (Time[4] = 24)AND (Time[5] = 12) then
StilleNacht()
else
if (Time[4] > 5) AND (Time[4] < 27) AND (Time[5] = 12) then
Xmas = Xmas + 1
If Xmas > 3 then 'Around Xmas time there will be played 3 different melodies
Xmas = 1
end if
select case Xmas
case 1
JingleBells()
case 2
Denneboom()
case 3
Merry_Xmas()
end select
else
Midsomer()
end if
end if
end if
end if
end if
end if
Delay_ms(100)
Wend
end. Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Mooi...
Voor het puntje op de i: PORTA en PORTB moeten eigenlijk LATA en LATB zijn... (werkt betrouwbaarder)
Zo mis ik wat in VB.NET zo mooi werkt, dat is dat hij de code mooi formateert.
Nooit naar gekeken, ik vind dat vreselijk...
(doe het liever zelf)
[Bericht gewijzigd door Arco op (43%)]
Op 1 november 2019 13:09:27 schreef Arco:
Mooi...Voor het puntje op de i: PORTA en PORTB moeten eigenlijk LATA en LATB zijn... (werkt betrouwbaarder)
Ik had ergens gelezen dat je voor Input altijd PORT moet gebruiken en voor output altijd LAT.
Dat is dus niet zo?
Voor de sound (PORT B.3) moet het idd sowieso LAT zijn.
Voor de constanten had ik zelf liever een tabel gehad met één naam, waarbij je met indexen de juiste waarden selecteert.
Want nu heb ik voor ieder melodietje een eigen tabel én een eigen procedure.
Waarbij de lengte van de 'tabel' (aantal constanten) ook nog eens nogmaals moet worden opgegeven in de procedure.
Het is weliswaar recht-toe-recht-aan en heel zelfverklarend, maar het lijkt me zelf wat overdone en niet efficiënt.
Het zou hierbij mooi zijn als je een instructie had in de geest van LEN(NOTE..).
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Je hebt gelijk; er staat TRISA = 0.
Ik gebruik PORTA voor het afvragen van de schakelaar, dus input.
Maar het werkt wel.
Dan zal de status vermoedelijk automatisch op input worden gezet?
Wellicht hierdoor:
PORTA = %11111111 [Bericht gewijzigd door Bavelt op (16%)]
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Je leest gewoon de pin status uit. Als die als output staat, zul je die (met de schakelaar) met geweld naar beneden trekken.
Dat vinden de output drivers niet fijn (die proberen de pin hoog te houden), maar ze overleven het meestal wel...
Ik heb de schakeling even getest zonder de RTC- DS3231 module erin. Dan blijft de processor wachten tot hij iets krijgt. Eeuwig dus.
Is er wellicht iets te bedenken dat je een afvraging kunt doen of de I2C Lees of schrijfopdracht wel is gelukt? Of een vorm van Time-out (waarbij je dan bv een LEDje kan laten branden bij een mislukte I/O).
Want stel je voor dat zo'n moduultje stuk is, dan hangt de boel dus ook.
In de Arduino is er een programmaatje dan alle adressen afspeurt of er een I2c Device is gevonden. (I2C-scanner).
Die zal ook wel iets in de geest doen of een I/O is gelukt, ACKnowledge, o.i.d.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Da's gebruikelijk met de meeste libraries dat i2c dan hangt... 
Daarom heb ik zelf een vervangende versie gemaakt...
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.
'==================================================================================================