Die Suche ergab 233 Treffer

von bbock
26.02.2023, 17:00
Forum: Hardware
Thema: PCW WiFi Modem
Antworten: 35
Zugriffe: 18462

Re: PCW WiFi Modem

Hallo Jungsi,

die zweite Diskette ist im 720 kB Format. Was für ein Gotek-Laufwerk hast du denn? Musst du evtl. von 40 Tracks auf 80 Tracks umschalten?

Welche Schritte genau hast du denn durchgeführt? Für eine Fehleranalyse werden wir wohl deutlich detailliertere Informationen brauchen. So, wie du es beschreibst, also kein OK nach einem AT-Befehl, lässt mich ein Hardware-Problem vermuten. Ich hatte das auch anfangs, und Kurt hat das Modem für mich nachgelötet und dann funktionierte alles. Das Flashen war bei dir erfolgreich?
von bbock
25.02.2023, 14:22
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 35150

Re: Fragen und Antworten zum C-Kurs

kurt hat geschrieben: 25.02.2023, 12:33 ...Versuch einmal soetwas, müßte gehen: *(&a + 4) = 42;. '&a' greift auf den Inhalt von a zu, addiert 4 hinzu und benutzt das Ergebnis dann, um 42 auf die Stelle zu schreiben, auf die *a zeigt. ...
Nein, a ist ja schon ein Pointer; &a ist die Adresse der Pointer-Variablen, das ist ein Schritt zu weit zurück. *(a + 4) = 42; wäre richtig, wenn a ein char-Pointer wäre. Weil's aber ein int-Pointer ist, müssen wir dem C-Compiler sagen, dass er a wie einen char-Pointer behandeln soll - via type cast:
*( (char *)a + 4) = 42;
  1. (char *)a wandelt den int-Pointer in einen char-Pointer um.
  2. + 4 addiert 4 zur Speicheradresse dazu (jetzt wirklich 4 Bytes und nicht 4 int-Werte respektive 8 Bytes)
  3. *(...) dereferenziert den Pointer, d.h. wir kommen von der Adresse zum darunter gespeicherten Wert. Das ist ein einzelnes Byte, weil wir ja einen char-Pointer dereferenzieren.
  4. = 42 speichert den Wert 42 als einzelnes Byte an der neu berechneten Speicheradresse
von bbock
25.02.2023, 14:09
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 35150

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 25.02.2023, 12:51 Davon abgesehen, darf ich mir etwas wünschen?
Ich möchte in einem der nächsten Beispiele gerne
aus Basic

Code: Alles auswählen

10 PRINT AT(10,14);"O"; 
wissen wie es in C aussieht
Schönes Wochenende
Das würde man in C ähnlich wie in TurboPascal mit gotoxy(10, 14); machen - normalerweise...

In der Theorie muss man dazu conio.h einbinden:

Code: Alles auswählen

#include <stdio.h>
#include <conio.h>

int main(void) {
    gotoxy(10, 14);
    putchar('O'); // oder printf("%s", "O");
}
In der Praxis funktioniert das aber nicht, weil das z88dk das leider bei der Plattform Amstrad PCW nicht unterstützt. Ich habe das so gelöst, dass ich meine eigene Funktion gotoXY geschrieben habe (mit XY in Großbuchstaben, damit es keine Namenskonflikte mit gotoxy aus conio.h gibt):

Code: Alles auswählen

#include <stdio.h>

void gotoXY(unsigned int x, unsigned int y) {
    putchar(27);        // ESC
    putchar('Y');       // cursor to position
    putchar(y + 32);    // row + 32
    putchar(x + 32);    // column + 32
}

int main(void) {
    gotoXY(10, 14);
    putchar('O'); // oder printf("%s", "O");
}
von bbock
25.02.2023, 13:58
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 35150

Re: Fragen und Antworten zum C-Kurs

Zur Pointerarithmetik:
Wenn du auf ein einzelnes Byte zugreifen möchtest, dann solltest du einen char Pointer verwenden. Sagen wir mal, du hast schon einen int Pointer bzw. einen int Array a, wie im Beispiel in 10.2. Dann könntest du folgendes machen:

char *cp;
cp = (char *) a;
*(cp + 4) = 42;

Oder - ohne separate Pointer-Variable:

*( (char *) a + 4) = 42;

Man nennt das type casting; das hatten wir noch nicht...
Sagen wir, a liegt an der Speicheradresse 3000 und der Array ist mit Nullen initialisiert. Dann sieht das im Speicher so aus:
a[0] - 3000: 0 0
a[1] - 3002: 0 0
a[2] - 3004: 0 0
a[3] - 3006: 0 0
a[4] - 3008: 0 0

( (char *) a + 4) ist dann 3004, durch *( (char *) a + 4) = 42; änderst du das erste Byte des dritten int-Werts, also des int-Werts mit dem Index 2. Das ist das LSB (least significant byte), weil der Z80 int-Werte im little endian Format verarbeitet. Ein printf("%d", a[2]); liefert dann 42, denn das MSB (most significant Byte) ist 0.
a[0] - 3000: 0 0
a[1] - 3002: 0 0
a[2] - 3004: 42 0
a[3] - 3006: 0 0
a[4] - 3008: 0 0
von bbock
24.02.2023, 17:24
Forum: Hardware
Thema: PCW WiFi Modem
Antworten: 35
Zugriffe: 18462

Re: PCW WiFi Modem

Hier ist CP/M 1.8 mit qterm und vdu. Es sind zwei Disketten (A und B), jeweils im HFE- und im DSK-Format.

CPM18_qterm_vdu.zip
(903.39 KiB) 193-mal heruntergeladen
von bbock
24.02.2023, 16:59
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 9838

10. Pointer, Array, String

10.1 Pointer

Alle Daten, die ein Computer verarbeitet, werden in Speicherzellen abgelegt, auf die der Mikroprozessor über deren Adressen zugreifen kann. Man kann sich das wie eine lange Straße vorstellen, bei der die aneinandergereihten Häuser die Speicherzellen darstellen; die Adressen entsprechen dann den Hausnummern. Bei Byte-Maschinen - und zu denen zählt die Joyce - besteht eine Speicherzelle aus acht Bit oder einem Byte. Der Z80-Prozessor kann 64 kByte, also 65.535 einzelne Adressen verwalten. Das sind 2 hoch 16 Adressen; daraus folgt, dass eine Adresse 16 Bit lang ist.

char ist ein Datentyp, der aus einem einzelnen Byte besteht. Eine Variable, die als char ch deklariert wurde, kann also ein Byte speichern. Greift man im Programmcode auf ch zu, dann ist der Inhalt dieses Bytes gemeint, von dem der C-Compiler weiß, wo im Speicher es sich befindet. Wenn wir wissen müssen, wo im Speicher sich ch befindet, z.B. um ch mit der C-Funktion scanf zu füllen, dann müssen wir die Adresse von ch ermitteln. Wir haben das bereits bei der Verwendung von scanf erfahren: der &-Operator ermittelt die Adresse einer Variablen, d.h. &ch liefert die 16-Bit-Adresse der Variablen ch.

Speichert man diese Adresse wiederum in einer Variablen ab, dann nennt man diese Variable einen Zeiger oder englisch Pointer. Pointer-Variablen werden mit einem Stern und dem Typ der Ziel-Variablen gekennzeichnet. Um einen Pointer für ch zu deklarieren, schreiben wir z.B. char *p;. Damit p auf ch zeigt, weisen wir p die Adresse von ch zu: p = &ch;. Um nun auf das Zeichen in ch über den Pointer zuzugreifen, müssen wir den Pointer "dereferenzieren". Das geschieht über den *-Operator, z.B. putchar(*p);.

Ein kleines Beispielprogramm soll das veranschaulichen:

Code: Alles auswählen

#include <stdio.h>

int main(void) {
    char ch;
    char *p;
    
    ch = 'X';    // ch enthaelt jetzt das Zeichen 'X'
    putchar(ch); // gibt X auf der Konsole aus
    p = &ch;     // p erhaelt die Adresse von ch, d.h. p zeigt auf ch
    *p = 'Y';    // das Zeichen, auf das p zeigt, also ch, wird auf 'Y' gesetzt
    putchar(*p); // gibt Y auf der Konsole aus
    putchar(ch); // gibt ebenfalls Y auf der Konsole aus, da ch ueber p veraendert wurde
    
    return 0;
}
10.2 Array

Arrays sind Speicherstrukturen mit mehreren Elementen gleichen Typs; auf die Elemente kann man über einen Index zugreifen. Es gibt eindimensionale Arrays, die auch als Vektoren bezeichnet werden, und mehrdimensionale Arrays. Die Anzahl der Dimensionen bestimmt, wieviele Indizes man benötigt, um auf ein einzelnes Element zuzugreifen.

Einen Array mit fünf int-Elementen deklariert man etwa so: int a[5];. Damit erhält man eine Array-Variable a, deren Elemente man über die Indizes 0 bis 4 erreicht: a[0], a[1], ..., a[4]. Der kleinste Index ist in C-Arrays immer 0, der größte ist die Anzahl der Elemente minus eins. Da die Indizes auch über Variablen bereitgestellt werden können, hat man damit eine sehr bequeme Speicherstruktur für den Zugriff auf gleichartige Elemente.

Code: Alles auswählen

#include <stdio.h>

int main(void) {
    int a[5];
    int i;
    
    // Array mit Vielfachen von 3 belegen
    for (i = 0; i < 5; i++) {
        a[i] = i * 3;
    }
    
    // Array ausgeben
    for (i = 0; i < 5; i++) {
        printf("Zahl an Index %d: %d\n", i, a[i]);
    }

    return 0;
}
Das Programm gibt folgendes aus:

Zahl an Index 0: 0
Zahl an Index 1: 3
Zahl an Index 2: 6
Zahl an Index 3: 9
Zahl an Index 4: 12

In C sind Arrays gleichzeitig Pointer-Strukturen. a ist also in unserem Beispiel ein int-Pointer. Um das erste Element, also das Element mit dem Index 0, auf den Wert 17 zu setzen, schreiben wir normalerweise a[0] = 17;. Genausogut können wir aber auch *a = 17; schreiben, da a eben auch ein Pointer ist. Um das vierte Element auf 21 zu setzen, schreiben wir a[3] = 21; oder *(a + 3) = 21;.

Die Pointer-Schreibweise ist noch erklärungsbedürftig. a ist ein Pointer; die Variable enthält also die Adresse des Arrays bzw. die Adresse des Elements mit dem Index 0. (a + 3) ist die Adresse des Elements mit dem Index 3, wobei aber nicht 3, sondern 6 zur Adresse des Arrays addiert wird, denn a ist vom Typ int und ein int beansprucht 2 Bytes Speicherplatz. Die Multiplikation mit der Typgröße macht der Compiler automatisch. Bei Zeigerarithmetik muss man immer beachten, von welchem Typ die Pointer sind. Die Pointer-Variablen selbst belegen dagegen immer 2 Bytes, weil jede Adresse 16 Bits = 2 Bytes lang ist, egal, ob der Pointer auf einen char, einen int oder sonst etwas zeigt.
von bbock
24.02.2023, 11:49
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 35150

Re: Fragen und Antworten zum C-Kurs

Danke für den Hinweis, Kurt, ich hab's korrigiert.

Tatsächlich findet man die for-Endlosschleife am häufigsten vor. Das mag daran liegen, dass manche Compiler dann keinen unnötigen Bedingungs-Code einfügen, aber das wäre ein Thema für die Compiler-Optimierung. Die beiden Compiler des z88dk erzeugen allerdings denselben Code, egal welchen Schleifentyp man verwendet. Aus folgendem Code

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
    for (;;) {
        printf(".");
    }
    
    return 0;
}

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
    while (1) {
        printf(".");
    }
    
    return 0;
}

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
    do {
        printf(".");
    } while (1);
    
    return 0;
}
wird jeweils folgender Assembler-Code:

sccz80:

Code: Alles auswählen

; Function main flags 0x00000000 __stdc 
; int main()
	C_LINE	4,"endlos1.c::main::0::1"
._main
.i_2
	ld	hl,i_1+0
	push	hl
	ld	a,1
	call	printf
	pop	bc
	jp	i_2	;EOS
.i_3
	ld	hl,0	;const
	ret
zsdcc:

Code: Alles auswählen

;	---------------------------------
; Function main
; ---------------------------------
_main:
l_main_00102:
	ld	hl,___str_0
	push	hl
	call	_printf
	pop	af
	jr	l_main_00102
	SECTION rodata_compiler
___str_0:
	DEFM "."
	DEFB 0x00
	SECTION IGNORE
von bbock
21.02.2023, 21:26
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 9838

9 Operatoren

9.1 Arithmetische Operatoren

Im Programm prim wurden Operatoren verwendet, die noch erläutert werden müssen. Die Grundrechenarten sind + (plus), - (minus), * (mal) und / (geteilt durch). Es gibt sie sowohl für Gleitkommazahlen wie auch für Ganzzahlen. Bei der Ganzzahldivision werden die Nachkommastellen abgeschnitten; es wird dabei nicht gerundet. Den Rest einer Ganzzahldivision kann man mit dem Modulo-Operator % ermitteln. In C gilt "Punkt- vor Strichrechnung", d.h. *, / und % haben Vorrang vor + und -. So ist 3 + 2 * 5 nicht 25, sondern 13, weil 2 * 5 zuerst berechnet wird. Möchte man eine andere Berechnungsreihenfolge haben, dann muss man Klammern setzen. (3 + 2) * 5 ergibt folglich 25.

9.2 Vergleiche und logische Verknüpfungen

Die Vergleichsoperatoren sind > (größer als), >= (größer oder gleich), < (kleiner als), <= (kleiner oder gleich) und == (gleich). Vorsicht: ein häufiger Programmierfehler ist das Verwechseln des Zuweisungsoperators = mit dem Vergleichsoperator ==.

Für logische Verknüpfungen werden die Operatoren && (und) und || (oder) verwendet. Dies sind die logischen Operatoren, die man nicht mit den bitweise Verknüpfungen & und | verwechseln sollte.

Beispiel: if (a > 5 && b <= 7) printf("passt!");

9.3 Bit-Manipulationen

In C kann man ganzzahlige Variablen bitweise manipulieren. Folgende Operatoren stehen zur Verfügung:

& - und-Verknüpfung von Bits
| - oder-Verknüpfung von Bits
^ - exklusive oder-Verknüpfung von Bits (XOR)
<< - Bit-Verschiebung nach links
>> - Bit-Verschiebung nach rechts
~ - Bit-Komplement (Einer-Komplement)

Beispiele:
  • c = n & 0177; löscht alle Bits in n bis auf die letzten sieben (0177 ist eine oktale Zahlkonstante und entspricht der Bitfolge 01111111)
  • x = x | MASK; setzt in x genau die Bits, die in MASK auf 1 gesetzt sind
9.4 Inkrement und Dekrement

Ganzzahl- und char-Variablen können inkrementiert und dekrementiert, d.h. um eins erhöht oder erniedrigt werden. Außerdem gibt es in C abkürzende Schreibweisen für bestimmte Operationen:

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
    int i;

    puts("i ist zu Beginn immer gleich 5");
    
    i = 5;
    ++i;
    printf("++i -> %d\n", i); // ergibt 6

    i = 5;
    --i;
    printf("--i -> %d\n", i); // ergibt 4

    i = 5;
    i += 2; // entspricht i = i + 2;
    printf("i += 2 -> %d\n", i); // ergibt 7

    i = 5;
    i -= 2; // entspricht i = i - 2;
    printf("i -= 2 -> %d\n", i); // ergibt 3

    i = 5;
    i *= 2; // entspricht i = i * 2;
    printf("i *= 2 -> %d\n", i); // ergibt 10

    i = 5;
    i /= 2; // entspricht i = i / 2;
    printf("i /= 2 -> %d\n", i); // ergibt 2 (eigentlich 2.5, aber bei Ganzzahlen werden die Nachkommastellen abgeschnitten)

    i = 5;
    i %= 2; // entspricht i = i % 2;
    printf("i %%= 2 -> %d\n", i); // ergibt 1
    
    return 0;
}
von bbock
21.02.2023, 21:00
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 9838

8.5 Schleifen (Fortsetzung)

Wir schreiben ein Programm zur Berechnung einer Primzahlenliste:

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
    int z, d;
    char prim;
    int grenze;
    int count;

    printf("Bis zu welcher Zahl sollen die Primzahlen ermittelt werden? ");
    scanf("%d", &grenze);
    printf("\nPrimzahlen bis %d:\n", grenze);
    count = 0;
    
    printf("  2 ");
    
    for (z = 3; z < grenze; z += 2) {
        prim = 'Y';
        
        for (d = 3; d < z / 2; d += 2) {
            if (z % d == 0) {
                prim = 'N';
                break;
            }
        }
        
        if (prim == 'Y') {
            printf("%4d ", z);
        }
    }
    
    return 0;
}
Wir kompilieren und binden mit:

Code: Alles auswählen

zcc +cpm -subtype=pcw80 prim.c -o prim.com
In der Funktion main werden zunächst die benötigten Variablen deklariert. Dann erfolgt die Eingabe der Obergrenze, bis zu der Primzahlen ausgegeben werden sollen. Das geschieht wieder mit der C-Funktion scanf; zur Erinnerung: wir müssen hier die Adresse der Variablen grenze übergeben, also &grenze.

Die erste Primzahl - die 2 - geben wir immer aus (was zu einer kleinen Unstimmigkeit führt, wenn wir als Obergrenze 0 oder 1 eingeben). Dann durchlaufen wir mit der Variablen z alle Zahlen bis zur Obergrenze in Zweierschritten. Wir prüfen bis z / 2, ob die Zahl durch d teilbar ist. d beginnt mit 3 und wird ebenfalls in Zweierschritten hochgezählt. Dann prüfen wir, ob die Division von z durch d einen Rest ergibt (Modulo-Division); falls nein, dann ist die Zahl z keine Primzahl und wir beenden die innere Schleife mit break.

Wurde die innere for-Schleife durchlaufen, ohne dass wir einen Teiler gefunden haben, dann ist die Zahl eine Primzahl und wir geben sie aus.

Die for-Schleifen haben drei Ausdrücke innerhalb der Klammern, die den Ablauf bestimmen. Wir sehen uns das am Beispiel der z-Schleife an:

for (z = 3; z < grenze; z += 2) {

Der erste Ausdruck ist die Initialisierung. Sie wird einmalig zu Beginn der Schleife durchgeführt. Hier wird die Variable z mit 3 initialisiert. Im ersten Schleifendurchlauf hat z also den Wert 3.

Der zweite Ausdruck ist die Schleifenfortsetzungsbedingung, also das Gegenteil der Abbruchbedingung. Solange die Bedingung erfüllt ist, läuft die Schleife.

Der dritte Ausdruck wird am Ende jedes Schleifendurchlaufs ausgeführt. Oft wird hier die Schleifenvariable hoch- oder heruntergezählt.

Jeder der drei Ausdrücke ist optional. Es können auch alle drei Ausdrücke weggelassen werden; in dem Fall erhält man eine Endlosschleife (die natürlich innerhalb des Schleifenkörpers mit break oder return verlassen werden kann). Die Semikoli müssen aber bleiben.

Da wir drei Varianten für die Formulierung von Schleifen in C kennen, gibt es auch drei Möglichkeiten eine Endlosschleife zu schreiben:

1. for (;;) {...}
2. while (true) {...
3. do {...} while (true);
von bbock
21.02.2023, 20:57
Forum: Hardware
Thema: PCW WiFi Modem
Antworten: 35
Zugriffe: 18462

PCW WiFi Modem - Artikel der Klubzeitung

Mein Artikel für die Klubzeitung der JOYCE-User-AG e.V.:

PCWWiFiModem.pdf
Artikel Klubzeitung
(424.49 KiB) 168-mal heruntergeladen
Edit: aktuelle Version des Artikels hochgeladen