\ 2006-07-31 SMBus.fs --- SMBus Basiscode
\ i2c Bus am R8C
\ P1.0 -- SCL
\ P1.1 -- SDA
\ Konstanten
0 Constant PinSCL
1 Constant PinSDA
port1 Constant PortI2C
$E3 Constant PddrI2C
\ SDA,SCL Pins auf 0 oder 1 setzen
: sda0 PinSDA PortI2C bclr ;
: sda1 PinSDA PortI2C bset ;
: scl0 PinSCL PortI2C bclr ;
: scl1 PinSCL PortI2C bset ;
\ 1 SCL Zyklus sind im Programm 4 ticks
: tick 1 us ;
: 2tick tick tick ;
\ sende 1 Bit
: bit>i2c ( bit -- )
IF sda1 ELSE sda0 ENDIF
tick scl1 2tick scl0 tick ;
\ erzeuge Bit Nr. i aus Byte x als 0 oder 1
: getBit ( x i -- b ) rshift $01 and ;
\ sende 1 Byte, (8 Bit) "most significant bit" zuerst
: >i2c ( x -- )
8 0 DO
dup 8 I 1+ - getBit
bit>i2c
LOOP
drop ;
\ sende START, STOP, REPEATED_START
: i2c_start ( -- ) tick sda0 2tick scl0 tick ;
: i2c_stop ( -- ) tick scl1 2tick sda1 tick ;
: i2c_rstart sda1 tick scl1 tick sda0 tick scl0 tick ;
\ setze SDA zum Lesen / Senden
: sdaInput ( -- ) PinSDA PddrI2C bclr ;
: sdaOutput ( -- ) PinSDA PddrI2C bset ;
\ lies SDA
: readSDA ( -- f )
PinSDA PortI2C btst IF 1 ELSE 0 ENDIF ;
\ lies 1 Byte (8 Bit), "most significant bit" zuerst
: <i2c ( -- x )
sdaInput
0
8 0 DO
1 lshift
tick scl1 tick readSDA tick scl0 tick
+
LOOP
sdaOutput ;
\ lies ACK (0) oder NACK (1) vom Partner
: ack<i2c ( -- f )
sdaInput
tick scl1 tick readSDA tick scl0 tick
sdaOutput ;
\ sende N Bytes nach Adresse addr
\ das "most significant Byte" liegt oben auf dem Stapel
: NB>i2c ( x1 .. xN.msB N addr -- )
i2c_start \ START
>i2c ack<i2c drop \ ADRESSE senden, ACK lesen
0 DO \ Schleife, nimmt N vom Stapel
>i2c ack<i2c drop \ DATA_BYTE verschicken
LOOP \ Ende Schleife
i2c_stop \ STOP
;
\ lies N Bytes von Adresse addr
\ das "least significant Byte" liegt oben auf dem Stapel
\ Adresse und ControlByte sind schon verschickt
: NB<i2c ( N addr -- xN.msB .. x1 )
i2c_rstart \ REPEATED_START
1+ >i2c ack<i2c drop \ ADRESSE | READ senden, ACK lesen
1- dup 0 > IF \ Schleife ueber N-1 Byte
0 DO \ Datenbyte = 0 (initialisieren)
<i2c 0 bit>i2c \ DATA_BYTE lesen, ACK schicken
LOOP \ Ende Schleife
ENDIF \
<i2c 1 bit>i2c \ letzes Byte lesen, NACK schicken
i2c_stop \ STOP
;
\ finis
\ Nach geladenem Gforth-R8C ueber die Tastatur in das
\ RAM des R8Cs eingeben. Danach per SAVESYSTEM
\ "festfrieren". Kann per EMPTY bis auf das eigentliche
\ Forth-System geloescht werden.
\ Ich verwende im gesamten Programm Grossschreibung.
\ Kleinschreibung reicht aber. Das System ist auf
\ egal voreingestellt.
HEX
\ Sudoku-Matrix, zeilenweise, pro Element ein Byte
CREATE M
0 C, 1 C, 2 C, 3 C, 4 C, 5 C, 6 C, 7 C, 8 C,
3 C, 4 C, 5 C, 6 C, 7 C, 8 C, 0 C, 1 C, 2 C,
6 C, 7 C, 8 C, 0 C, 1 C, 2 C, 3 C, 4 C, 5 C,
1 C, 2 C, 3 C, 4 C, 5 C, 6 C, 7 C, 8 C, 0 C,
4 C, 5 C, 6 C, 7 C, 8 C, 0 C, 1 C, 2 C, 3 C,
7 C, 8 C, 0 C, 1 C, 2 C, 3 C, 4 C, 5 C, 6 C,
2 C, 3 C, 4 C, 5 C, 6 C, 7 C, 8 C, 0 C, 1 C,
5 C, 6 C, 7 C, 8 C, 0 C, 1 C, 2 C, 3 C, 4 C,
8 C, 0 C, 1 C, 2 C, 3 C, 4 C, 5 C, 6 C, 7 C,
\ Hole Element in Zeile i und Spalte j von Matrix M
: IJ@ ( i j -- a[ij] ) SWAP 9 * + M + C@ ;
\ Speichere Element in Zeile i und Spalte j nach Matrix M
: IJ! ( a[ij] i j -- ) SWAP 9 * + M + C! ;
\ Addiere n modulo 9 zu saemtlichen Elementen von Matrix M
: ADDn ( n -- )
51 0 DO DUP M I + C@ + 9 MOD M I + C! LOOP DROP ;
\ INDEX
VARIABLE IX
\ Vertausche willkuerlich 2 Spalten einer Laengsdreierreihe in Matrix M
: XCHJ ( -- ) IX @ C@ 9 0
DO DUP 9 MOD DUP DUP 3 MOD 0> IF 1 - ELSE 1+ THEN
2DUP I SWAP IJ@ I ROT IJ@ ROT I SWAP IJ! I ROT IJ!
LOOP DROP ;
\ Vertausche Zeile 3 und 5 und Zeile 7 und 8 in Matrix M
: XCHI ( -- ) 9 0
DO 3 I IJ@ 5 I IJ@ 3 I IJ! 5 I IJ! 7 I IJ@ 8 I IJ@ 7 I IJ! 8 I IJ!
LOOP ;
\ ASCII --> Ziffernausgabe
: ZIFF ( n -- ) DUP 8 U> IF DROP SPACE SPACE ELSE 1+ . THEN ;
\ IX um 5 weitersetzen
: I5+! ( -- ) IX @ DUP 600 > IF 300 - THEN 5 + IX ! ;
\ Zufaellige Auslassungen
\ Etwa 27d Elemente bleiben als Vorgabe stehen. Breite Streuung!
: RAND ( n -- m ) IX @ C@ 3 MOD IF DROP 20 THEN I5+! ;
\ Bildschirmdarstellung von geaenderter Vorgabematrix
: V ( -- ) CR 9 0
DO 9 0 DO J I IJ@ ZIFF LOOP 5 SPACES
9 0 DO J I IJ@ RAND ZIFF LOOP CR
LOOP ;
\ Neue Sudoku-Matrix mit passender Vorgabematrix
: S ( -- ) IX @ C@ ADDN XCHI XCHJ I5+! V ;
\ Will man zu ein und derselben (Loesungs-)Matrix M verschiedene
\ Vorgabematrizen erzeugen, dann rufe man (beliebig oft) V auf.
\ Bei jedem erneuten Aufruf von V wird die bis dato erreichte
\ Sudoku-Matrix M beibehalten, waehrend die Vorgabematrix neu er-
\ zeugt wird.
\ Selbstverstaendlich kann man eine erreichte Vorgabematrix
\ auch per Hand ausbessern: Man uebernehme (und notiere auf
\ Papier) nur, sagen wir, 27d Elemente oder ergaenze (bei zu
\ wenigen Vorgabeelementen) Elemente durch Einfuegen von der
\ Sudoku-Matrix M her.
\ Man kann eine erreichte Sudoku-Matrix M auch per Hand aendern:
\ Dazu stehen die drei Forth-Worte x ADDN XCHI XCHJ (in
\ beliebiger Anwendungsreihenfolge) zur Verfuegung. x kann
\ eine beliebige Zahl sein.
\ Geaenderte Vorgabe-Matrizen bei gleichbleibender Sudoku-
\ Matrix werden durch V angezeigt. Geaenderte Sudoku-Matrizen
\ mit passender Vorgabe-Matrix werden durch S angezeigt.
\ Solche Tastatureingaben muessen natuerlich immer durch
\ [return] abgeschlossen werden, um Wirksamkeit zu erlangen.