Sorry, had niet gezien dat achter die Bcd2dec een I2C_RD instructie stond.
Sorry, had niet gezien dat achter die Bcd2dec een I2C_RD instructie stond.
Golden Member
Ok, dan de volgende uitdaging
Als dezelfde noten achter elkaar worden gespeeld, wil je er een pauze tussen zetten (anders klinkt het immers als 1 lange noot).
Ik dacht dat te doen door bij Sound_Play de waarde 0 op te geven. Dat werkt helaas niet, omdat er een minimum frequentie geldt.
Nu zegt de MikroBasic manual het volgende:
Note : Frequency range is limited by Delay_Cyc parameter. Maximum frequency that can be produced by this function is Freq_max = Fosc/(80*3). Minimum frequency is Freq_min = Fosc/(80*255). Generated frequency may differ from the freq_in_hz parameter due to integer arithmetics
De klok staat op 32Mhz. Volgens deze regel zou dan het minimum 32.000.000 / 80*255 = 1568 Hz zijn. Dat is in de praktijk niet zo.
De waarde 0 geeft een brom, de waarde 1 een ongedefiëerde hogere toon.
Daarom heb ik als oplossing gekozen na de noten een delay in te bouwen. Hiervoor is dan naast de noot en de duur ook de vertraging opgenomen in de 'tabel'.
'Lang zal ze leven
Const NOTE1 as WORD [10] = ( C5, C5, C5, C5, G4, E5, E5, E5, E5, C5)
Const DUR1 as Word [10] = (500, 200, 200, 500, 700, 500, 200, 200, 500,750)
Const DLY1 as Byte [10] = ( 15, 15, 15, 15, 0, 0, 15, 15, 15, 0)
En verderop:
Sub Procedure Verjaardag
For Toon = 0 to 9
Sound_Play(Note1[Toon], (Dur1[Toon] + Plus))
VDelay_MS(DLY1[Toon])
Next Toon
End sub
Dit werkt wel. Maar zelf vind ik het een beetje omslachtig.
Bovendien loop ik nu tegen de grens van het ROM geheugen aan. (evt op te lossen door de 'tabellen' in de EEprom te stoppen).
Wellicht kan het handiger.
Special Member
Tja,
De ingebakken functies zijn niet altijd even praktisch voor hele kleine processortjes met weinig geheugen.
De SOUND_PLAY gebruikt al 850 words geheugen. Komt doordat de functie universeel is qua pin instellingen e.d.
Als je alles zelf zou schrijven in Mikrobasic zou je minder als de helft aan geheugen nodig hebben...
De WORD tabellen bijv. gebruiken 2 flash words per word (dit omdat de flash maar 14 bits is, daar kan geen 'echt' word in)
Maar voor waardes < 16384 past dit prima in 1 flash geheugenplaats...
Golden Member
Als je alles zelf zou schrijven in Mikrobasic zou je minder als de helft aan geheugen nodig hebben...
Maar kan je dan zelf geluiden produceren met BASIC? Of kom je dan in .asm instructies terecht?
Special Member
Ja, natuurlijk kan dat.
'Geluid maken' is tenslotte niks anders als een pin hoog maken, tijdje wachten, pin weer laag maken, tijdje wachten,... (en dat in een loop)
Dat stelt niet veel voor. Alleen moet je dan zelf de 'wachttijden' berekenen die bij een bepaalde frequentie horen...
Golden Member
Dat is inderdaad heel grappig en simpel. Ik heb het net geprobeerd:
Een toon van 500Hz:
while true
delay_ms(1)
portb.3 = 1
delay_ms(1)
Portb.3 = 0
wend
Golden Member
En door te spelen met de 'duty cycle', kan je hiermee ook meteen het volume verkleinen:
while true
delay_us(1900)
portb.3 = 1
delay_us(100)
Portb.3 = 0
wend
Golden Member
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.
Special Member
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)
Golden Member
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
Golden Member
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.
Special Member
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))
Special Member
Zolang het century / 12/24 bit niet geset zijn geen problemen...
Golden Member
Ik had trouwens wat spulletjes besteld bij Farnell.
Supersnelle service moet ik zeggen!
Golden Member
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.
Special Member
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.
Golden Member
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.
Golden Member
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?
Special Member
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)
Golden Member
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.
Golden Member
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.
Special Member
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 vrijdag 1 november 2019 13:31:42 (43%)
Golden Member
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..).