Tonen generen met PIC16F628A

Sorry, had niet gezien dat achter die Bcd2dec een I2C_RD instructie stond.

LDmicro user.
Bavelt

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'.

pic basic code:

 '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:

pic basic code:

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.

Fouten zijn het bewijs dat je het probeert..
Arco

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...

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

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?

Fouten zijn het bewijs dat je het probeert..
Arco

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...

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

Golden Member

Dat is inderdaad heel grappig en simpel. Ik heb het net geprobeerd:
Een toon van 500Hz:

pic basic code:


 while true
  delay_ms(1)
  portb.3 = 1
  delay_ms(1)
  Portb.3 = 0
 wend 
Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

En door te spelen met de 'duty cycle', kan je hiermee ook meteen het volume verkleinen:

pic basic code:

while true
  delay_us(1900)
  portb.3 = 1
  delay_us(100)
  Portb.3 = 0
 wend 
Fouten zijn het bewijs dat je het probeert..
Bavelt

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.

Fouten zijn het bewijs dat je het probeert..
Arco

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)

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

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

Fouten zijn het bewijs dat je het probeert..
Bavelt

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.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Ik zag trouwens nog een foutje in de Read_DS3231() (de AND's staan verkeerd)

pic basic code:


  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:

pic basic code:


  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 - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Grappig, want het werkt wel..

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Zolang het century / 12/24 bit niet geset zijn geen problemen...

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

Golden Member

Ik had trouwens wat spulletjes besteld bij Farnell.
Supersnelle service moet ik zeggen!

Fouten zijn het bewijs dat je het probeert..
Bavelt

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.

Fouten zijn het bewijs dat je het probeert..
Arco

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.

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

Golden Member

Dan laat ik hem lekker staan...

Fouten zijn het bewijs dat je het probeert..
Bavelt

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.

Fouten zijn het bewijs dat je het probeert..
Bavelt

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?

Fouten zijn het bewijs dat je het probeert..
Arco

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.

https://media.digikey.com/Photos/MikroElektronika/MFG_MIKROE-1205.JPG

Ik heb nog zo'n board liggen van de 18F serie (18F46xx/67xx/87xx serie)

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

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.

Fouten zijn het bewijs dat je het probeert..
Bavelt

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

pic basic code:

 '==============================================================================
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. 
Fouten zijn het bewijs dat je het probeert..
Arco

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%)

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

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..).

Fouten zijn het bewijs dat je het probeert..