Posts mit dem Label ATtiny2313 werden angezeigt. Alle Posts anzeigen
Posts mit dem Label ATtiny2313 werden angezeigt. Alle Posts anzeigen

Freitag, 12. Februar 2010

LCD mit HD44780

Nachdem ich mehrere HD44780kompatibele LCDs bekommen habe war es an der Zeit sich mal eingehender damit zu beschäftigen.
Die Leude Mikrocontroller.net haben da ganze Arbeit geleistet und mich viel weitergebracht...
Wie auch immer, das erste "Projekt" auf dem LCD war -natürlich- eine Uhr. Und natürlich wieder mit meinem "Standart"-AVR ATtiny2313.



Das sieht doch schon mal nach was aus.
Uhrzeit war ein Klacks und auch das Datum war kaum herausfordernd. Was wirklich "schwer" war, war die implementierung der Bedienelemente: Taster wollen abgefragt werden und es soll erkannt werden od der Taster gedrüückt wurde, fetgehalten wurde oder losgelassen ist. Das ganze in verschiedenen "kontexten", schliesslich will man die Uhr ja auch stellen könnnen...

Und da war sie nun, ein paar zahlen auf nem LCD.
Ist aus einigem Abstand recht schwer zu lesen...

Das muss sich ändern:



Also einen neuen Zeichensatz gebastelt, und aus den maximal 8 eigenen Zeichen ein paar "richtig Große" Ziffern zusammengestellt.

Das ganze Programm füllt den 2313 mittlerweile zu 80% aus und das Listing ist irgendwie viel zu lang um es einfach hier zu posten...
( und dabei wollt ich noch einen Alarm-timer und ein Calibrierungs-byte (um sekunden/woche auszugleichen) mit einbauen...)

Also erslmal einen Ausschnitt, und zwar den für die grossen Ziffern:


lcd_big_ziffer:
; wandelt eine BCD ziffer in
; eine ziffer in großschrift
; es ist erforderlich das vorher der Zeichensatz_big geladen ist.
; die zahl wird in temp übergeben
; der offset auf dem LCD in temp2
; aufgerufene Unterprogramme
push temp
push temp2
push temp3
push ZL
push ZH

; Z-register initialisieren
ldi ZL, low(big_font*2)
ldi ZH, high(big_font*2)

;offset in der tabelle aus der ziffer berechnen (ziffer=ziffer*4)
lsl temp
lsl temp
clr temp3

add ZL, temp
adc ZH, temp3

;cursor in der ersten zeile positionieren
mov temp, temp2
rcall lcd_pos

;symbole für die erste Zeile ausgeben
lpm temp, Z+
rcall lcd_data
lpm temp, Z+
rcall lcd_data

;cursor in der 2. zeile positionieren
mov temp, temp2
ori temp, 0x40
rcall lcd_pos

;symbole für die 2. zeile ausgeben
lpm temp, Z+
rcall lcd_data
lpm temp, Z
rcall lcd_data

pop ZH
pop ZL
pop temp3
pop temp2
pop temp

ret

big_font:
; hier ist abgelegt welche symbole wie zu grossen ziffern zusammengesetzt werden
.db 0x07, 0x01, 0x06, 0x05 ;0
.db 0x20, 0x01, 0x20, 0x00 ;1
.db 0x04, 0x02, 0x06, 0x04 ;2
.db 0x02, 0x04, 0x04, 0x05 ;3
.db 0x06, 0x06, 0x03, 0x07 ;4
.db 0x00, 0x03, 0x04, 0x02 ;5
.db 0x06, 0x04, 0x06, 0x05 ;6
.db 0x03, 0x02, 0x20, 0x00 ;7
.db 0x05, 0x02, 0x06, 0x05 ;8
.db 0x07, 0x01, 0x03, 0x02 ;9


und dazu noch den Zeichensatz fürs LCD:


zeichensatz_big:
.db 0b00000011, 0b00011111 ;...xx xxxxx
.db 0b00000011, 0b00011111 ;...xx xxxxx
.db 0b00000011, 0b00000011 ;...xx ...xx
.db 0b00000011, 0b00000011 ;...xx ...xx
.db 0b00000011, 0b00000011 ;...xx ...xx
.db 0b00000011, 0b00000011 ;...xx ...xx
.db 0b00000011, 0b00000011 ;...xx ...xx
.db 0b00000011, 0b00000011 ;...xx ...xx

.db 0b00011111, 0b00011111 ;xxxxx xxxxx
.db 0b00011111, 0b00011111 ;xxxxx xxxxx
.db 0b00000011, 0b00000000 ;...xx .....
.db 0b00000011, 0b00000000 ;...xx .....
.db 0b00000011, 0b00000000 ;...xx .....
.db 0b00000011, 0b00000000 ;...xx .....
.db 0b00011111, 0b00000000 ;xxxxx .....
.db 0b00011111, 0b00000000 ;xxxxx .....

.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00000000, 0b00000011 ;..... ...xx
.db 0b00011111, 0b00011111 ;xxxxx xxxxx
.db 0b00011111, 0b00011111 ;xxxxx xxxxx

.db 0b00011000, 0b00011111 ;xx... xxxxx
.db 0b00011000, 0b00011111 ;xx... xxxxx
.db 0b00011000, 0b00011000 ;xx... xx...
.db 0b00011000, 0b00011000 ;xx... xx...
.db 0b00011000, 0b00011000 ;xx... xx...
.db 0b00011000, 0b00011000 ;xx... xx...
.db 0b00011111, 0b00011000 ;xxxxx xx...
.db 0b00011111, 0b00011000 ;xxxxx xx...

;tabellenende
.db 0xff, 0xff


Wenn ich mal eine schöne Möglichkeit gefunden habe Dateien zum download annzubieten gibt es den kompletten code.

Und ja, auch hiervon hab ich keine vorzeigbare schaltung. Aber vlt kann man sowas ja bald einfach mir "Fritzing" erstellen...

Montag, 31. August 2009

Meine erste selbsgebaute Uhr

So, nach mehreren (z.T.) erfolgreichen Vorversionen ist meine erste Uhr(enschaltung) nun fertig.
Ich, als Microkontroler-Anfänger bin über dieses Projekt gestolpert und habe wirklich viel davon gelernt. Z.B. wie man einen schönen BCD-7Segment-Decoder programmiert und wie man überhaupt ein Programm (in AVR-asm) struckturiert usw...

Also erstmal das Steckbrett:


Typisch Breadboard - mit Drahtverhau...

Man beachte die Anzeige:


Wie ich dieses klassische Rot und diese winzigen LEDs mag.
Einfach mal hier vorbeischauen.
(und JA die Siemens DL340M sind um Größenordnungen besser. aber für den Steckbrettaufbau irgendwie zu Schade)

Die Bediehnung der Uhr hab ich bei der aus "meinem" Auto abgeschaut: einfach aber nicht ausbaufähig. Mit einem Taster kann ein "reset" ausgelöst werden: dann zeigt die Uhr wieder 01:00 an. Mit einem weiteren werden die Stunden gestellt: jeder Tastendruck lässt dei Anteige eine Stunde weiterschalten. Und mit einem dritten Taster wird das gleiche mit der Minutenanzeige gemacht.

Die Schaltung werde ich nochmal schön mit Eagle aufhübschen, bis dahin muss der Code reichen.


; einfache Uhr mit 4stelliger LED Anzeige
; Anzeige ist DL340M - 7 Segement mit gem. Kathode
; by DH8SZ nach GPL

; Version 0.0.1 - Zählanzeige mit int.RC als Taktgeber und keiner Stellmöglichkeit
; Version 0.0.1a - statt Zeit werden Festwerte Angezeigt - Test
; Version 0.0.1b - Anzeige wieder normal - timer beschleunigt
; Version 0.0.1c - reti für interrupt-return geändert
; Version 0.0.2 - zählt nun bis 24:00 und der Dezimalpunkt der 2. Stundenstelle blinkt
; Version 0.0.3 - Tasten zum stellen: reset, PD2, PD3
; Version 0.0.3a - alte zählung + bugfixes in ledoff
; Version 0.0.3b - neue zählung (i.o.) + dezimalpunkt blinkt nun wirklich
; Version 0.0.4 - Sekunden 1:1 für Testaufbau
; Version 0.0.4a - LED-Multiplexfrequenz verdoppelt

; Display:
; -----
; I g I
; e I I f
; I I
; -----
; I d I
; b I I c
; I I
; -----
; a

; Ports (Display DL340M)
; PB0 - Pin4 - c
; PB1 - Pin9 - f
; PB2 - Pin3 - a
; PB3 - Pin6 - d
; PB4 - Pin13 - g
; PB5 - Pin2 - b
; PB6 - Pin11 - e
; PB7 - Pin5 - 5
;
; PD0 - Pin14 - kat.System1
; PD1 - Pin12 - kat.system2
; PD4 - Pin8 - kat.System3
; PD5 - Pin9 - kat.System4

.include "tn2313def.inc"

.def w1=R14
.def W2=R15
.def temp=R16
.def temp2=R17
.def std10=R18
.def std01=R19
.def min10=R20
.def min01=R21
.def sek10=R22
.def sek01=R23

;===========================================================================

.dseg
;alles leer

;===========================================================================

.cseg
.org 0x0000
rjmp reset ; Der Start des Programmes
.org 0x0001
rjmp stunden_stellen ;Interruptroutine zum Stunden erhöhen
.org 0x0002
rjmp minuten_stellen ;Interruptroutine zum Minuten erhöhen
.org 0x0004
rjmp takt ; Interruptroutine zum Sekunden zählen


charset:
; hier kommt die Tabelle für die BCD/7segment Umsetzung hin
.include "charset.asm"

;===========================================================================
; Initianisierung
;===========================================================================
reset:
;initialisieren des Stackpointers
ldi temp, RAMEND
out SPL, temp

;Analogkomparatoren abschalten
sbi ACSR,7

;Voreinstellungen für Uhrzeit
ldi std10, 0x00
ldi std01, 0x01
ldi min10, 0x00
ldi min01, 0x00

;Ausgabeports initianisieren PB7:0 = Ausgabe und 0
ldi temp, 0xff
out DDRB, temp
ldi temp, 0x00
out PORTB, temp

;Ports PD0, PB1, PB4, PB5 = Ausgabe und 1 / PB2, PB3 als Eingänge und pullup an
ldi temp, 0b00110011
out DDRD, temp
ldi temp, 0b00111111
out PORTD, temp

;INT0 und INT1 initialisieren
ldi temp, 0b00001010 ;fallende Flanke an INT0 und INT1 ist Auslöser
out mcucr, temp
ldi temp, 0b11000000 ;INT0 und INT1 freischalten
out gimsk, temp

;Timer/Counter1 (16Bit) initianisieren
;TCCR1B = 0 0 0 0 1 1 0 1 = no InputNoiseCanceler, InputCaptureEdgeSelect, Mode=CTC, Prescaler=1024
ldi temp, 0x0d
;ldi temp, 0x0c ;prescaler auf /256 statt /1024
out TCCR1B, temp
;OCR1A - Top für Counter setzen = 3200
ldi temp, 0x0c
ldi temp2, 0x80
out OCR1AH, temp
out OCR1AL, temp2
;TIMSK --> enabele OCIE1A output Compare Interrupt
ldi temp, 0x40
out TIMSK, temp
;TCNT1 auf 0 reseten
clr temp
out TCNT1H, temp
out TCNT1L, temp

;Interrupt erlauben
sei

;===========================================================================
; Hauptprogramm
;===========================================================================

main:
;Stunden darstellen - 10er Stelle
mov temp, std10
rcall convert
out PORTB, temp2
cbi PORTD, 5
rcall wait2ms
rcall ledoff

;Stunden darstellen - 1er Stelle - Dezimalpunkt blinkt im sekundentakt
mov temp, std01
rcall convert
sbrc sek01, 0
ori temp2, 0b10000000
out PORTB, temp2
cbi PORTD, 4
rcall wait2ms
rcall ledoff

;Minuten darstellen - 10er Stelle
mov temp, min10
rcall convert
out PORTB, temp2
cbi PORTD, 1
rcall wait2ms
rcall ledoff

;Minuten darstellen - 1er Stelle
mov temp, min01
rcall convert
out PORTB, temp2
cbi PORTD, 0
rcall wait2ms
rcall ledoff

;zurück zum Mainloop
rjmp main


;======================================================================
; Unterprogramme
;======================================================================

takt:
;dieses Unterprogramm wird ein mal pro Sekunde angesprungen
cli
inc sek01
cpi sek01, 0x0a
brlo takt_ende
clr sek01
inc sek10
cpi sek10, 0x06
brlo takt_ende
clr sek10
inc min01
cpi min01, 0x0a
brlo takt_ende
clr min01
inc min10
cpi min10, 0x06
brlo takt_ende
clr min10
inc std01
cpi std01, 0x04
brlo takt_ende
cpi std10, 0x02
brlo takt_01
clr std01
clr std10
rjmp takt_ende
takt_01:
cpi std01, 0x0a
brlo takt_ende
clr std01
inc std10
cpi std10, 0x0a
brlo takt_ende
clr std10
takt_ende:
sei
reti

;--------------------------------------------------------------------------

stunden_stellen: ;dieser Teil ist auch zum Stundn hochzählen
inc std01
cpi std01, 0x04
brlo stunden_ende
cpi std10, 0x02
brlo stunden_01
clr std01
clr std10
rjmp stunden_ende
stunden_01:
cpi std01, 0x0a
brlo stunden_ende
clr std01
inc std10
cpi std10, 0x0a
brlo stunden_ende
clr std10
stunden_ende:
reti


;---------------------------------------------------------------------------

minuten_stellen: ;minuten bei tastendruck hochzählen
inc min01
cpi min01, 0x0a
brlo minuten_ende
clr min01
inc min10
cpi min10, 0x06
brlo minuten_ende
clr min10
minuten_ende:
reti


;---------------------------------------------------------------------------

convert:
;convertiert BCD (temp) zu 7segment (temp2)
ldi ZL, LOW(charset<<1)
ldi ZH, HIGH(charset<<1)
add ZL, temp
lpm temp2, Z+
ret

;---------------------------------------------------------------------------

ledoff:
;Anzeige ausschalten
ldi temp, 0x00
out PORTB, temp
ldi temp, 0b00111111
out PORTD, temp
ret

;---------------------------------------------------------------------------

wait2ms:
;verzögrung für 1 ms at 3,2768MHz
ldi temp, 0x0d
mov w1, temp
clr w2
wait2ms_loop:
dec w2
brne wait2ms_loop
dec w1
brne wait2ms_loop
ret


Man, da hab ich mir ja ne Naht zusammengetippt: da wird tatsächlich jede Stelle der Anzeige in einem eigenen Register hochgezählt. Und bei einem Überlauf natürlich kompliziert verglichen und gesprungen...
mal sehn ob das noch einfacher zu lösen ist...

Nun hab ich keinen Pin mehr frei. Das Bedienkonzept ist auch eine Sackgasse und die Genauigkeit ist noch weiter zu prüfen.


Für meine nächse Uhr werde ich nen ATMega48 nehmen, der hat ein paar Beinchen mehr und es lässt sich dann auch noch eine Weckfunktion mit einbauen.

p.s. natürlich hab ich auch noch eine Zeichentabelle für den BCD-7Segment-Umsetzer:

; Carsetfile für BCD - zu - 7segment Umsetung
.db 0b01110111, 0b00000011 ;0 ,1
.db 0b00111110, 0b00011111 ;2, 3
.db 0b01001011, 0b01011101 ;4, 5
.db 0b01111101, 0b01010011 ;6, 7
.db 0b01111111, 0b01011111 ;8, 9
.db 0b01111110, 0b01101101 ;A, b
.db 0b00101100, 0b00101111 ;c, d
.db 0b01111100, 0b01111000 ;E, F

Freitag, 21. August 2009

80m Fuchsjagdsender nach DH1DA

Beim stöbern nach interessanten Projekten bin ich auf den Fuchsjagesender von DH1DA gestoßen.

( Für alle die eine Fuchsjagt für einen blutigen Sport halten. )

Hier ein Bild von meinem Aufbau (ohne Gehäuse):



Die Schaltung hab ich minimal abgewandelt: R1 und C2 weggelassen. Der Attiny2313 hat schon einen gute Power-On-Reset eingebaut so das ich eine externe R/C-Kombo für überflüssig halte.
Damit konnte das Layout der Platine vereinfacht werden, so das die (in meinen Augen) unsägliche Leiterbahnenkreuzung der Originalplatine wegfallen kann.

(ok, ich bin faul, desshalb hier erstmal nur ein Q&D Bild der Leiterseite):



Ein paar Freilufttests in leicht bebautem Gelände (also bei mir zu Hause) haben eine Reichweite von 200m ergeben.
Der (frische) 9V-Block hat über einen Tag ohne zu schwächeln durchgehalten und tut nun wo anders seinen Dienst.

Dieses Projet werde ich bei Gelegenheit mal "modernisieren": Platine erstellen, SMD, usw. ...