Hallöchen.. Auf Basis eines kleinen STM32 Board mit einem STM32F103C8T6 entwickel ich zur Zeit ein kleines MiniScope für mein EuroRack. Wellenform und Frequenz werden auf dem kleinen 0.89" OLED Display bereits angezeig. Was noch fehlt ist ein kleiner Spektrumanalyse. Mal schaun wie ich das programmieren kann. Den Code gibts später.. Youtube: https://www.youtube.com/watch?v=3xvXjU5WA7M
Schaltplan und Code sind in Arbeit. Vlt wird es auch ein DIY Bausatz mit Platine und Frontblende geben. Mal schaun.. Folgende Funktionen sind geplant bzw schon fertig: 1 Kanal Audio-In und Out. Menüsteuerung mit Encoder. Welleformdarstellung, Frequenzmessung, Spektrumanalyse falls der Prozessor (STM32F103C8T6) dafür schnell genug ist, Ausgabe eines Testton für 440Hz Abgleich, Trigger- und Pegelanpassung. Die Breite des Moduls wird ca. 31mm betragen und Standarthöhe haben. Meine größtes Projekt:http://cczwei-forum.de/cc2/thread.php?threadid=5878&page=34&sid=ebda167b65cda8a49cf9b28a4719d6fa Gruß Rolf
Hallöchen und guten Morgen.. Wie kann ich während der Laufzeit die Sample Rate im ADC ändern. Meine das hier: sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
Beitrag #6001768 wurde von einem Moderator gelöscht.
Hallöchen.. Ich hab für mich eine praktische Lösung gefunden. Ich rufe in der main.c für die Änderung der Samplerate eine eigene Initialisierung für den ADC1 auf in der die SampleRate einfach überschrieben wird. Die eigentliche Initialisierung für den ADC1 erfolgt vorher. Nach der erneuten Initialisierung in der Tastenabfrage muss der ADC1 wieder neu gestartet werden. Ist zwar nicht elegant programmiert aber es funktioniert. Tastenabfrage in der main.c
1 | switch(TBase_sw){ |
2 | case 0: TIM3->ARR = 320; // Scope TimeBase |
3 | MX_ADC1_Init1(); // Sample rate 1.5 cycles |
4 | HAL_ADC_Start (&hadc1); |
5 | ssd1306_SetCursor(0,0); |
6 | ssd1306_WriteString("100us", Font_7x10, White); |
7 | ssd1306_UpdateScreen(); |
8 | break; |
9 | case 1: TIM3->ARR = 800; // Scope TimeBase |
10 | MX_ADC1_Init2(); // Sample rate 7.5 cycles |
11 | HAL_ADC_Start (&hadc1); |
12 | ssd1306_SetCursor(0,0); |
13 | ssd1306_WriteString("250us", Font_7x10, White); |
14 | ssd1306_UpdateScreen(); |
15 | break; |
16 | case 2: TIM3->ARR = 1600; // Scope TimeBase |
17 | MX_ADC1_Init3(); // Sample rate 13.5 cycles |
18 | HAL_ADC_Start (&hadc1); |
19 | ssd1306_SetCursor(0,0); |
20 | ssd1306_WriteString("500us", Font_7x10, White); |
21 | ssd1306_UpdateScreen(); |
22 | break; |
23 | case 3: TIM3->ARR = 3200; // Scope TimeBase |
24 | MX_ADC1_Init4(); // Sample rate 28.5 cycles |
25 | HAL_ADC_Start (&hadc1); |
26 | ssd1306_SetCursor(0,0); |
27 | ssd1306_WriteString("1.0ms", Font_7x10, White); |
28 | ssd1306_UpdateScreen(); |
29 | break; |
30 | case 4: TIM3->ARR = 8000; // Scope TimeBase 3: |
31 | MX_ADC1_Init5(); // Sample rate 41.5 cycles |
32 | HAL_ADC_Start (&hadc1); |
33 | ssd1306_SetCursor(0,0); |
34 | ssd1306_WriteString("2.5ms", Font_7x10, White); |
35 | ssd1306_UpdateScreen(); |
36 | break; |
37 | case 5: TIM3->ARR = 16000; // Scope TimeBase |
38 | MX_ADC1_Init6(); // Sample rate 55.5 cycles |
39 | HAL_ADC_Start (&hadc1); |
40 | ssd1306_SetCursor(0,0); |
41 | ssd1306_WriteString("5.0ms", Font_7x10, White); |
42 | ssd1306_UpdateScreen(); |
43 | break; |
44 | case 6: TIM3->ARR = 32000; // Scope TimeBase |
45 | MX_ADC1_Init7(); // Sample rate 71.5 cycles |
46 | HAL_ADC_Start (&hadc1); |
47 | ssd1306_SetCursor(0,0); |
48 | ssd1306_WriteString("10ms", Font_7x10, White); |
49 | ssd1306_UpdateScreen(); |
50 | break; |
51 | case 7: TIM3->ARR = 64000; // Scope TimeBase |
52 | MX_ADC1_Init8(); // Sample rate 239.5 cycles |
53 | HAL_ADC_Start (&hadc1); |
54 | ssd1306_SetCursor(0,0); |
55 | ssd1306_WriteString("20ms", Font_7x10, White); |
56 | ssd1306_UpdateScreen(); |
57 | break; |
58 | }
|
Initialisierung in adc.c
1 | /* ADC1 init function */
|
2 | void MX_ADC1_Init(void) |
3 | {
|
4 | ADC_ChannelConfTypeDef sConfig = {0}; |
5 | |
6 | /** Common config
|
7 | */
|
8 | hadc1.Instance = ADC1; |
9 | hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; |
10 | hadc1.Init.ContinuousConvMode = ENABLE; |
11 | hadc1.Init.DiscontinuousConvMode = DISABLE; |
12 | hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; |
13 | hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; |
14 | hadc1.Init.NbrOfConversion = 1; |
15 | if (HAL_ADC_Init(&hadc1) != HAL_OK) |
16 | {
|
17 | Error_Handler(); |
18 | }
|
19 | /** Configure Regular Channel
|
20 | */
|
21 | sConfig.Channel = ADC_CHANNEL_1; |
22 | sConfig.Rank = ADC_REGULAR_RANK_1; |
23 | sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; |
24 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
25 | {
|
26 | Error_Handler(); |
27 | }
|
28 | |
29 | }
|
30 | |
31 | void MX_ADC1_Init1(void) |
32 | {
|
33 | ADC_ChannelConfTypeDef sConfig = {0}; |
34 | |
35 | sConfig.Channel = ADC_CHANNEL_1; |
36 | sConfig.Rank = ADC_REGULAR_RANK_1; |
37 | sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; |
38 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
39 | {
|
40 | Error_Handler(); |
41 | }
|
42 | }
|
43 | |
44 | void MX_ADC1_Init2(void) |
45 | {
|
46 | ADC_ChannelConfTypeDef sConfig = {0}; |
47 | |
48 | sConfig.Channel = ADC_CHANNEL_1; |
49 | sConfig.Rank = ADC_REGULAR_RANK_1; |
50 | sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5; |
51 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
52 | {
|
53 | Error_Handler(); |
54 | }
|
55 | }
|
56 | |
57 | |
58 | void MX_ADC1_Init3(void) |
59 | {
|
60 | ADC_ChannelConfTypeDef sConfig = {0}; |
61 | |
62 | sConfig.Channel = ADC_CHANNEL_1; |
63 | sConfig.Rank = ADC_REGULAR_RANK_1; |
64 | sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5; |
65 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
66 | {
|
67 | Error_Handler(); |
68 | }
|
69 | }
|
70 | |
71 | void MX_ADC1_Init4(void) |
72 | {
|
73 | ADC_ChannelConfTypeDef sConfig = {0}; |
74 | |
75 | sConfig.Channel = ADC_CHANNEL_1; |
76 | sConfig.Rank = ADC_REGULAR_RANK_1; |
77 | sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; |
78 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
79 | {
|
80 | Error_Handler(); |
81 | }
|
82 | }
|
83 | |
84 | void MX_ADC1_Init5(void) |
85 | {
|
86 | ADC_ChannelConfTypeDef sConfig = {0}; |
87 | |
88 | sConfig.Channel = ADC_CHANNEL_1; |
89 | sConfig.Rank = ADC_REGULAR_RANK_1; |
90 | sConfig.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; |
91 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
92 | {
|
93 | Error_Handler(); |
94 | }
|
95 | }
|
96 | |
97 | void MX_ADC1_Init6(void) |
98 | {
|
99 | ADC_ChannelConfTypeDef sConfig = {0}; |
100 | |
101 | sConfig.Channel = ADC_CHANNEL_1; |
102 | sConfig.Rank = ADC_REGULAR_RANK_1; |
103 | sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; |
104 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
105 | {
|
106 | Error_Handler(); |
107 | }
|
108 | }
|
109 | |
110 | void MX_ADC1_Init7(void) |
111 | {
|
112 | ADC_ChannelConfTypeDef sConfig = {0}; |
113 | |
114 | sConfig.Channel = ADC_CHANNEL_1; |
115 | sConfig.Rank = ADC_REGULAR_RANK_1; |
116 | sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5; |
117 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
118 | {
|
119 | Error_Handler(); |
120 | }
|
121 | }
|
122 | void MX_ADC1_Init8(void) |
123 | {
|
124 | ADC_ChannelConfTypeDef sConfig = {0}; |
125 | |
126 | sConfig.Channel = ADC_CHANNEL_1; |
127 | sConfig.Rank = ADC_REGULAR_RANK_1; |
128 | sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; |
129 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) |
130 | {
|
131 | Error_Handler(); |
132 | }
|
133 | }
|
Gruß Rolf
:
Bearbeitet durch User
Rolf D. schrieb: > Den Code gibts später.. Funktioniert bei deinem blue pill clone, auch wenn du parallel zum 10k R10 noch 1k8 lötest, der USB Anschluss über generic_boot20_pc13.bin ? So daß der STM32 über den maple driver anprechbar wird ? https://circuitdigest.com/microcontroller-projects/programming-stm32f103c8-board-using-usb-port Bei mir gibt es nach dem flashen des generic_boot20_pc13.bin nicht mal ein USB 'erkannt' Systemsound, geschweige denn ein Maple COM Port. Und bekommst du die möglichen 2.3Msps (7.5Msps interleaved) mit dem ADC über dein HAL hin ?
Ich programmiere mein STM32F103C8T6 Board über einen STLINK V2 Adapter vom Nucleo-Board. USB hab ich noch nicht ausprobiert. Zum ADC: Laut Datenblatt schaft der STM32F103C8 1MHz Samplerate (12Bit) bei 14MHz Clock Frequenz.
Hallöchen.. Kleine Katastrophe! CubeMX hat in der main.c meinen ganzen User Code gelöscht. Habe leider das Häckchen bei "Keep User Code when re-generating" im Code generator rausgenommen und neuen Code generiert. Die alte mein.o ist noch vorhanden. Kann man da was machen ?!
Schonmal versucht aus einem Burger wieder eine Kuh zu machen? Das wird leider nix wenn der Editor da kein Backup gespeichert hat.
Mein Beileid! Dafür/dagegen gibt es svn & co ;) Wenn man aufpaßt klappt das mit CubeMX und nachträglich rumfummeln erstaunlich gut, ich bin begeistert. Ersetzt aber kein Repository! Bzgl. BluePill und USB kann ich sagen das mein LinuxPC den auch mit 10K erkennt und als /dev/ttyACM0 einrichtet, Senden/Empfangen klappt.
Rolf D. schrieb: > Kleine Katastrophe! CubeMX hat in der main.c meinen ganzen User Code > gelöscht. NichtWichtig schrieb: > Mein Beileid! Meines auch. Denn Backups sind nur etwas für höchstprivilegierte Leute mit entsprechend viel Geld in der Portokasse. Wir armen Schlucker dagegen müssen das Zeugs immer neu eintippen.
Mmm. Schade.. kann man nix machen. Gut das ich Teile vom Quellcode im Forum und in anderen Projekten stehen habe. Dann werde ich mir das wieder mühselig zusammensetzen. Frage: Warum werden die User Codes in anderen C-Files wzB adc.c immer wieder gelöscht, obwohl ich das Häckchen bei "Keep User Code when re-generating" gesetzt habe und den Code unter /* USER CODE BEGIN 1 */ stehen habe ?
:
Bearbeitet durch User
1. ist "Keep User Code when re-generating" die default-Einstellung, und wenn du da den Haken ohne Not heraus nimmst, bist du selber Schuld. 2. hat mir CubeMX noch nie den Code versemmelt - das funktioniert genau wie es soll, so lange man eigenen Code in die entsprechend markierten Bereiche schreibt und die bereichs-Markierungen nicht beschädigt. 3. erkennst du jetzt hoffentlich, daß es sinnvoll ist, eigenen Code auch in eigene c-Files zu schreiben. 4.: daß man ab und an auch mal ein Backup anfertigen sollte wurde bereits gesagt.
Ich verstehs trotzdem nicht. Haken ist drin und mein Code stand im User Bereich. Nachdem ich jetzt wieder in CubeMX Code generiert habe ist wieder alles weg. Ist doch Mist :(
Vor lauter "Angst" mache ich das so: Zwischen die Marker in main.c setze ich ein include Statement das auf meine eigene Datei verweist. Dann verliere ich schlimmstensfalls nur diese eine Zeile. Subversion kann ich nur empfehlen. Für Einzelkämpfer ist dieses Tool einfacher anzuwenden, als alle anderen Source repositories. Man muss nicht einmal einen Subersion-Server installieren. Dazu empfehle ich das TortoiseSVN Paket, es enthält meiner Meinung nach die beste GUI für SVN. Was macht ein Source Repository?: Es speichert ein Backup deiner Quelltexte ab, sobald du das Kommando dazu absetzt. Bei Änderungen speichert es nur die Teile ab, die verändert wurden (commit). Deswegen kannst du das so oft nutzen, wie du willst - Speicherplatz wird kein Problem sein. Du kannst funktionsfähige Versionen kennzeichnen und mehrere Varianten (branches) deines Programms anlegen, um unterschiedliche Versionen parallel weiter zu pflegen. Wenn du dann in der aktuellen Version einen Fehler korrigierst, kannst du diese Änderung (mit etwas Glück vollautomatisch) in die älteren Programmversionen übertragen. Du kannst jeder Zeit auf ältere Versionen deines Quelltextes zugreifen. Die Hauptaufgabe dieses Tools ist allerdings, die Änderungen mehrerer Entwickler zusammen zu führen (merge). Den Teil wirst du alleine wohl selten nutzen.
Hallo.. Die grundsätzliche Schaltung für das meSCOPE ist jetzt fertig. Muss das ganze jetzt auf eine Platine löten (siehe Bild). Schaltplan: Das Scope hat einen 16Bit DA-Wandler mit zwei Ausgangskanälen. Den hab ich für die Schaltungsentwicklung auf eine SOP-8 Platine gelötet. Ausgang A ist für die Ausgabe einer Gleichspannung. Ausgang B gibt einen 440Hz Ton aus. Beiden DAC-Ausgänge besitzen eine Tristate-Funktion und werden abwechselnd geschaltet. Dadurch benötige ich keinen zweiten OP für die Ausgabe einer Messspannung. Über Poti R8 kann die Eingangsspannung für das Scope geregelt werden. IC4a begrenzt die Eingangsspannung am AD-Wandler. IC4b ist als Komperator geschaltet und für das Triggern der Wellenform zuständig. Die Stromversorgung (+3.3V) für das STM32 Prozessor-Board liefert die +12V Spannung über K1. Hab noch einen Butterwoth-Filter 2.Ordnung für den DA-Wandler integriert. Die berechnete Filterfrequenz liegt bei 10KHz. Das STM32 Board entspricht von den Abmessungen der Anschlusspins genau einer 40pol IC-Fassung. Gruß Rolf
Hallo zusammen.. Im Schaltplan gibts noch ein paar kleine Änderungen. Die Stromversorgung für das Scope kann über Jumper K2 auf +5V oder +12V festgelegt werden. An den Steuerleitungen SCL und SDA für das Display fehlten noch die 4.7K Pullup- Widerstände. Alle Bauteile sind jetzt bestückt. Auf der Rückseite befindet sich das STM32 BluePill Prozessor Board. Nächste Schritte sind das Verlöten der restlichen Bauteile und die Zusammenführung der einzelnen Software Module im Programm. Gruß Rolf
Find ich klasse :-) ich lese mit btw kennst du das: http://www.gabotronics.com/development-boards/xmega-xprotolab.htm ?
Hallöchen.. Hab mal ein wenig mit dem neuen Frontplatten Designer von Schaefer AG gearbeitet. Hier die Frontplatte für den Prototyp. Ich denke, das ich noch eine Scala für das Poti einfügen werde. Die aktuellen Kosten für eine Frontplatte (Bild) betragen ca. 30 Euro (Schaefer AG). Die Abmessungen für die Frontplatte betragen 40x128,4mm und 2mm dick. Gruß Rolf
:
Bearbeitet durch User
Hallöchen.. Die Frontplatte des Scops ist jetzt fertig designed. Etwas Schwierigkeiten hatte ich mit dem Frontplatten Designer von Schaefer AG und der Grafik für die Poti Scala. Die Scala habe ich mit dem FrontDesigner3.0 erzeugt und dann in Gimp als PNG-File exportiert. Danach konnte ich die Scala im Frontplatten Designer importieren. Gruß Rolf
:
Bearbeitet durch User
Hallöchen.. Mittlerweile habe ich meine Frontplatte von der Firma Schaefer AG erhalten. Leider ist der Text über den Reglern etwas zu klein geraten und die Bohrlöcher für die Audiobuchsen sind nicht an der richtigen Position. Also habe ich jetzt die Dinge korrigiert und die Frontplatte nochmal einmal bestellt, mit der Hoffnung das es dieses mal stimmt. Hab mal aus Lust und Frust ein "Synthmännchen" Logo für meine zukünftigen Eurorack Module entwickelt (siehe Bild 2)
Das sieht lustig aus, so ein mini Display in den großen Gehäuse. Den Rest würde mit ganz vielen funktionslosen Schaltern und geheimnisvollen Beschriftungen voll machen, dann sieht es noch witziger aus.
ja, du must noch jung sein und sehr gute Augen haben :) Ich hätte das eher in ein Handgehäuse mit einer Prüfspitze vorne eingebaut.
Harry L. schrieb: > 4.: daß man ab und an auch mal ein Backup anfertigen sollte wurde > bereits gesagt. Und dass man seinen Code in einem Versionierungstool (typischerweise heute svn oder git) verwaltet! Das ist für mich Grundvoraussetzung bei der Software-Entwicklung. Würd ich nie mehr ohne machen. Das Backup wird dann vom Repository gemacht. Stefan F. schrieb: > Subversion kann ich nur empfehlen. Für Einzelkämpfer ist dieses Tool > einfacher anzuwenden, als alle anderen Source repositories. Man muss > nicht einmal einen Subersion-Server installieren. Bei git gibt es nicht mal den Server im klassischen Sinn. Per Default ist das Repository erstmal lokal. Allerdings ist git tatsächlich deutlich komplizierter in der Anwendung als svn, wobei der Hauptteil der Komplexität erst zum Tragen kommt, wenn man mit mehreren Entwicklern verteilt arbeitet. Es ist allerdings mit git einfacher als mit svn, wenn man mehrere Rechner hat und die Repos dort immer miteinander synchronisieren will.
Beim Logo Designe hat mich das hier inspiriert: https://www.youtube.com/watch?v=J73VdiesIW0 Geiles Video und es passt zur kommenden Weihnachtszeit :)
>Bei git gibt es nicht mal den Server im klassischen Sinn. Per Default >ist das Repository erstmal lokal. Allerdings ist git tatsächlich >deutlich komplizierter in der Anwendung Ja da gilt wie so oft, übung macht den Meister. Aber wenn man man dann aus dem ff ein git init, git add . und git commit "init repo" macht und jedes Projekt in 5 sekunden in eine Versionsverwaltung überführt ist schon toll. dann macht das spaß. git push und git fetch brauchst du ja nur beim hochladen (wie du ja auch erwähnt hast). Unbedingt vorher mal ausprobieren, wie man einen Stand aus einem Commit wieder herstellt (gibt es ein paar Fallen). git rocks!
Normalerweise sollte ein Programm, welches am Code rumfummelt, vorher ein backup selbiger Datei machen. Kenne ich eig. nur so, selbst WinMerge macht das. Immer. CubeMX nicht?!
>Normalerweise sollte ein Programm, welches am Code rumfummelt, vorher >ein backup selbiger Datei machen. Kenne ich eig. nur so, selbst WinMerge >macht das. Immer. CubeMX nicht?! Nö, auch bei git muss man tatsächlich wissen, was man tut. solange es nur ums "hinzufügen" von Code geht, bleibt das recht einfach und save. Allerdings kann beim Herstellen einiges Schiefgehen. Deswegen sollte man den Fall durchspielen, wenn gerade nicht die Hütte brennt
Random .. schrieb: > vorher ein backup selbiger Datei machen Wobei das Repsository drei Vorteile bietet: 1) Nachvollziehbarkeit sämtlicher Änderungen von Anfang bis Ende 2) Änderungen mehrerer Benutzer zusammen führen 3) Einzelne Änderungen (nicht komplette Dateien) rückgängig machen Für einen Einzelkämpfer ist Punkt 2 natürlich irrelevant.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.