Forum: Mikrocontroller und Digitale Elektronik AVR Project – Relay Timer with ATmega8 AVR MCU


von Sebastian M. (basti87)


Angehängte Dateien:

Lesenswert?

Guten Morgen liebe Forum Gemeinde,

ich habe mich an den vergangenen Tagen mal mit einem Projekt, welches 
ich im Internet gefunden habe auseinander gesetzt.

http://extremeelectronics.co.in/avr-projects/avr-project-relay-timer-with-atmega8-avr-mcu/

Dazu habe ich alle nötigen Daten heruntergeladen und im AVR Studio 
eingefügt, sowie die Schaltung auf meinen Steckbrettern 
zusammengesteckt. Siehe Foto.

Leider funktioniert es aber nicht. Ich habe aber darauf geachtet, die 
Fuses umzustellen.

Anschließend habe ich es versucht mit AVR Simulator IDE zu simulieren, 
auch ohne Erfolg. (Aber ohne die Fuses).

Kann mir jemand Tipps geben wie ich es zum laufen bekomme?

Hier der Code aus LCD_RELAY_TIMER.c:
1
/******************************************************
2
3
A Simple Device Timer project designed using ATmega8
4
AVR MVU. The Timer is usefull for keeping a device
5
"ON" for a specific period of time. After the set time
6
elapse the timer automatically turns the load off.
7
8
The Timer uses a standart 16x2 lcd module for user interface
9
UI. User can set the time using a 3 button keypad.
10
11
After that Timer is started. While count down is in 
12
progress, the time left is displayed on screen.
13
14
The program use our LCD driver library more details
15
of which can be found in Website.
16
17
Use avr-gcc + AVR Studio to compile.
18
19
Author: Avinash Gupta
20
E:Mail: me@avinashgupta.com
21
Web: www.eXtremeElectronics.co.in
22
23
*** THIS PROJECT IS PROVIDED FOR EDUCATION/HOBBY USE ONLY  ***
24
25
*** NO PROTION OF THIS WORK CAN BE USED IN COMMERIAL       ***
26
*** APPLICATION WITHOUT WRITTEN PERMISSION FROM THE AUTHOR ***
27
28
EVERYONE IS FREE TO POST/PUBLISH THIS ARTICLE IN
29
PRINTED OR ELECTRONIC FORM IN FREE/PAID WEBSITES/MAGAZINES/BOOKS
30
IF PROPER CREDIT TO ORIGINAL AUTHOR IS MENTIONED WITH LINKS TO
31
ORIGINAL ARTICLE 
32
33
34
35
36
Copyright (C) 2008-2009 eXtreme Electronics, India.
37
38
******************************************************/
39
40
#include <avr/io.h>
41
#include <avr/interrupt.h>
42
43
#include "lcd.h"
44
45
//Connection of Load
46
#define LOAD_DDR DDRC
47
#define LOAD_PORT PORTC
48
#define LOAD_POS PC0
49
50
//Global variable for the clock system
51
volatile unsigned int   clock_millisecond=0;
52
volatile char       clock_second=0;
53
volatile char       clock_minute=0;
54
volatile char       clock_hour=0;
55
56
57
void Wait(uint8_t n)
58
{
59
60
  uint8_t i,temp;
61
  temp=n*28;
62
63
  for(i=0;i<temp;i++)
64
    _delay_loop_2(0);
65
}
66
67
void LoadOn()
68
{
69
  LOAD_PORT|=(1<<LOAD_POS);
70
}
71
72
void LoadOff()
73
{
74
  LOAD_PORT&=(~(1<<LOAD_POS));
75
}
76
main()
77
{
78
79
  while(1)
80
  {
81
    LOAD_DDR|=(1<<LOAD_POS);
82
83
    LoadOff();
84
85
    //Enable Pullups on Keypad
86
    PORTB|=((1<<PB2)|(1<<PB1)|(1<<PB0));
87
88
    int8_t hr,min;  //Target Time
89
    hr=min=0;
90
91
    //Initialize the LCD Subsystem
92
    InitLCD(0);
93
    //Clear the display
94
    LCDClear();
95
96
    //Set up the timer1 as described in the
97
    //tutorial
98
    TCCR1B=(1<<WGM12)|(1<<CS11)|(1<<CS10);
99
    OCR1A=250;
100
101
    //Enable the Output Compare A interrupt
102
    TIMSK|=(1<<OCIE1A);
103
104
    //Enable interrupts globally
105
    sei();
106
107
    LCDClear();
108
    LCDWriteString("    Welcome     ");
109
    LCDWriteStringXY(0,1,"   Relay Timer  ");
110
111
    Wait(4);
112
113
    LCDClear();
114
    LCDWriteString("Set Time - 00:00");
115
    LCDWriteStringXY(0,1," Start     ^");
116
117
    uint8_t selection=1;
118
    uint8_t old_pinb=PINB;
119
120
    while(1)
121
    {
122
      while((PINB & 0b00000111) == (old_pinb & 0b00000111));
123
    
124
      //Input received
125
126
127
      if(!(PINB & (1<<PINB2)) && (old_pinb & (1<<PB2)))
128
      {
129
        //Selection key Pressed
130
        selection++;
131
        if(selection==3)
132
          selection =0;
133
      }
134
135
      if(!(PINB & (1<<PINB1)) && (old_pinb & (1<<PB1)))
136
      {
137
        //Up Key Pressed
138
        if(selection == 1)
139
        {
140
        
141
          //Hour is selected so increment it
142
          hr++;
143
144
          if(hr == 100)
145
            hr =0;
146
        }
147
148
        if(selection == 2)
149
        {
150
151
          //Min is selected so increment it
152
          min++;
153
154
          if(min == 60)
155
            min =0;
156
        }
157
158
        if(selection == 0)
159
        {
160
          //Start Selected
161
          break;
162
        }
163
164
165
      }
166
167
      if(!(PINB & (1<<PINB0)) && (old_pinb & (1<<PB0)))
168
      {
169
      //Down Key Pressed
170
        if(selection == 1)
171
        {
172
173
          //Hour is selected so decrement it
174
          hr--;
175
176
          if(hr == -1)
177
            hr =99;
178
        }
179
180
        if(selection == 2)
181
        {
182
183
          //Min is selected so decrement it
184
          min--;
185
186
          if(min == -1)
187
            min =59;
188
        }
189
190
        if(selection == 0)
191
        {
192
          //Start Selected
193
          break;
194
        }
195
196
      }
197
198
    
199
      old_pinb=PINB;
200
201
    
202
203
      //Update Display
204
      LCDClear();
205
      LCDWriteString("Set Time - 00:00");
206
      LCDWriteStringXY(0,1," Start    ");
207
208
      //Hour
209
      LCDWriteIntXY(11,0,hr,2);
210
211
      //Minute
212
      LCDWriteIntXY(14,0,min,2);
213
214
      if(selection == 0)
215
        LCDWriteStringXY(0,1,">");
216
    
217
      if(selection == 1)
218
        LCDWriteStringXY(11,1,"^");
219
220
      if(selection == 2)
221
        LCDWriteStringXY(14,1,"^");
222
223
      _delay_loop_2(0);
224
      _delay_loop_2(0);
225
      _delay_loop_2(0);
226
      _delay_loop_2(0);
227
228
      _delay_loop_2(0);
229
      _delay_loop_2(0);
230
      _delay_loop_2(0);
231
      _delay_loop_2(0);
232
    }
233
234
    //Start the Load
235
    LoadOn();
236
237
    //Now start the timer
238
    clock_hour = hr;
239
    clock_minute = min;
240
    clock_second =0;
241
242
    LCDClear();
243
    LCDWriteString("  Power Off In ");
244
245
    while(1)
246
    {
247
      LCDWriteIntXY(4,1,clock_hour,2);
248
      LCDWriteString(":");
249
      LCDWriteIntXY(7,1,clock_minute,2);
250
      LCDWriteString(":");
251
      LCDWriteIntXY(10,1,clock_second,2);
252
253
      if((clock_hour == 0) && (clock_minute == 0) && (clock_second == 0))
254
      {
255
        //Time Out
256
        LoadOff();
257
258
        LCDClear();
259
        LCDWriteString("Load Turned Off");
260
      
261
        while(1)
262
        {
263
          LCDWriteStringXY(0,1,"*Press Any Key*");
264
265
          Wait(1);
266
267
          LCDWriteStringXY(0,1,"                ");
268
269
          Wait(1);
270
271
          if((~PINB) & 0b00000111)
272
            break;
273
274
        }
275
276
        break;
277
278
      
279
280
      }
281
282
      _delay_loop_2(0);
283
      _delay_loop_2(0);
284
      _delay_loop_2(0);
285
      _delay_loop_2(0);
286
    }
287
  //Continue again
288
  }
289
290
291
}
292
293
//The output compate interrupt handler
294
//We set up the timer in such a way that
295
//this ISR is called exactly at 1ms interval
296
ISR(TIMER1_COMPA_vect)
297
{
298
  clock_millisecond++;
299
  if(clock_millisecond==1000)
300
  {
301
    clock_second--;
302
    clock_millisecond=0;
303
    if(clock_second==-1)
304
    {
305
      clock_minute--;
306
      clock_second=59;
307
308
      if(clock_minute==-1)
309
      {
310
        clock_hour--;
311
        clock_minute=59;
312
      }
313
    }
314
  }
315
}

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> Leider funktioniert es aber nicht.

Was heißt funktioniert nicht?

Fang mit was einfacherem an.
Steck mal eine LED an einen Port Pin und sieh nach, ob der µC überhaupt 
läuft, indem du die LED blinken lässt.
Im Moment sind da zu viele ungetestete Systeme im Spiel, so dass man 
nicht wirklich eine Aussage darüber treffen kann, was das Problem ist. 
Also muss man abspecken und mit einem möglichst einfachen Testprogramm 
System für System, Komponente für Komponente in Betrieb nehmen.

von Sebastian M. (basti87)


Lesenswert?

Hallo,

ja die LED blinkt. Mit funktioniert nicht meine ich, dass ich keine 
anzeige am LCD Display bekomme.

von Karl H. (kbuchegg)


Lesenswert?

Dann überprüf mal, wie du das LCD angeshclossen hast, und ob das mit der 
bei dir eingetragenen Konfiguration in lcd.h übereinstimmt.

von Sebastian M. (basti87)


Lesenswert?

Ja die Ports und Pins stimmen soweit, nur bei
1
#define LS_BLINK 0B00000001
2
#define LS_ULINE 0B00000010

bin ich mir unsicher.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Ja die Ports und Pins stimmen soweit


sagst du.
Photo?


>
1
> #define LS_BLINK 0B00000001
2
> #define LS_ULINE 0B00000010
3
>
>
> bin ich mir unsicher.

Braucht dich erst mal nicht zu interessieren.

von Karl H. (kbuchegg)


Lesenswert?

Autsch.
Der LCD Code ist furchtbar. So wie der geschrieben ist, trau ich dem 
nicht über den Weg.

Hol dir vom P.Fleury die LCD Library, konfigurier sie und mach damit mal 
ein Testprogramm.

PS: Auch der restliche Code ist furchtbar. Aber das ist ein anderes 
Thema.

von Sebastian M. (basti87)


Lesenswert?

wovon möchtest du ein Foto haben, von der Hardware?
1
/************************************************
2
  LCD CONNECTIONS
3
*************************************************/
4
5
#define LCD_DATA D  //Port PD0-PD3 are connected to D4-D7
6
7
#define LCD_E D //Enable OR strobe signal
8
#define LCD_E_POS PD4  //Position of enable in above port
9
10
#define LCD_RS D  
11
#define LCD_RS_POS PD6
12
13
#define LCD_RW D
14
#define LCD_RW_POS PD5
15
16
17
//************************************************
18
19
#define LS_BLINK 0B00000001
20
#define LS_ULINE 0B00000010

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> wovon möchtest du ein Foto haben, von der Hardware?
Nein, von deiner Schwester.

Natürlich von deiner Hardware!
Was denkst du wieviele hier schon nach Hilfe gefragt haben und Bein und 
Stein geschworen haben, ihre Anschlüsse wären korrekt und dann stellte 
sich nach Stunden heraus, dass sie sich zb bei den Pinnummern verzählt 
haben?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> #define LCD_RS D
> #define LCD_RS_POS PD6
>
> #define LCD_RW D
> #define LCD_RW_POS PD5

Das kann nicht stimmen.

Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann 
die RS Leitung nicht auf PD6 liegen

: Wiederhergestellt durch User
von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das kann nicht stimmen.
>
> Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann
> die RS Leitung nicht auf PD6 liegen

Die Ports am Controller sind PD0 - PD3 das sind die Anschlüsse am
LCD D4 - D7.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Karl Heinz Buchegger schrieb:
>> Das kann nicht stimmen.
>>
>> Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann
>> die RS Leitung nicht auf PD6 liegen
>
> Die Ports am Controller sind PD0 - PD3 das sind die Anschlüsse am
> LCD D4 - D7.

Ja, habs schon gemerkt.
In deinem Projekt ist eine etwas andere Version der LCD Routinen als 
die, die ich mir von der angegebenen Web-Site gezogen habe.

von Sebastian M. (basti87)


Angehängte Dateien:

Lesenswert?

Hier die Bilder...

von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> In deinem Projekt ist eine etwas andere Version der LCD Routinen als
> die, die ich mir von der angegebenen Web-Site gezogen habe.

Wie meinst du das? Habe diese runtergeladen und eingebunden und 
eigentlich nichts verändert.

von Sebastian M. (basti87)


Lesenswert?

Sebastian M. schrieb:
> Hier die Bilder...

Ach ja, der Aufbau ist nicht mehr komplett, hatte bereits angefangen mit 
dem Rückbau. LCD ist aber noch dran gewesen...

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Karl Heinz Buchegger schrieb:
>> In deinem Projekt ist eine etwas andere Version der LCD Routinen als
>> die, die ich mir von der angegebenen Web-Site gezogen habe.
>
> Wie meinst du das? Habe diese runtergeladen und eingebunden und
> eigentlich nichts verändert.

Die hier
http://extremeelectronics.co.in/avr-tutorials/using-lcd-module-with-avrs/

sind ein wenig anders gemacht.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> Ach ja, der Aufbau ist nicht mehr komplett, hatte bereits angefangen mit
> dem Rückbau. LCD ist aber noch dran gewesen...

Da ist aber nicht wirklich irgendwas nachvollziehbar zu erkennen.

von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Da ist aber nicht wirklich irgendwas nachvollziehbar zu erkennen.

Das habe ich mir schon fast gedacht. Ich hatte es bereits mehrmals 
kontrolliert und immer wieder neu zusammengesteckt.

Welche unterschiede hast du denn in den Routinen gefunden?

von Sebastian M. (basti87)


Lesenswert?

Soeben ist meine Bestellung gekommen. Ich werde mal ein anderes Quarz 
sowie andere Kondensatoren versuchen. Melde mich dann zurück.

von Sebastian M. (basti87)


Lesenswert?

Ich bekomme jetzt im AVR Studio folgende Warnung nach dem start von 
Build Solution.
1
Warning  1  
2
return type defaults to 'int' [enabled by default]  ...RELAY_TIMER_DOWNLOAD\LCD_RELAY_TIMER.c  76  1  RELAY_TIMER_DOWNLOAD

Das ist dieser Codeabschnitt in der LCD_RELAY_TIMER.c der Fehler soll in 
der Zeile main() sein.:
1
...
2
void LoadOff()
3
{
4
  LOAD_PORT&=(~(1<<LOAD_POS));
5
}
6
main()
7
{
8
9
  while(1)
10
  {
11
    LOAD_DDR|=(1<<LOAD_POS);
12
13
    LoadOff();
14
15
    //Enable Pullups on Keypad
16
    PORTB|=((1<<PB2)|(1<<PB1)|(1<<PB0));
17
18
    int8_t hr,min;  //Target Time
19
    hr=min=0;
20
...

von Sebastian M. (basti87)


Lesenswert?

Habe jetzt auch Unterschiede festgestellt zwischen dem Quellcode der auf 
der Homepage abgedruckt ist und der Datei die gedownloaded wird. Dabei 
ist meiner Meinung nach die Abgedruckte version die "fehlerhafte".

von Cyblord -. (cyblord)


Lesenswert?

main() hat keinen Rückgabetyp und deshalb wird der automatisch zu int.

Ist auch kein Fehler, sondern eine Warnung.

Sollte man troztdem beheben.

von Sebastian M. (basti87)


Lesenswert?

cyblord ---- schrieb:
> Ist auch kein Fehler, sondern eine Warnung.

das klingt so einfach. Spielt es keine rolle, wie ich main() deklariere? 
Was schlägst du vor?

von Cyblord -. (cyblord)


Lesenswert?

Sebastian M. schrieb:
> cyblord ---- schrieb:
>> Ist auch kein Fehler, sondern eine Warnung.
>
> das klingt so einfach. Spielt es keine rolle, wie ich main() deklariere?
> Was schlägst du vor?

int

Deshalb sollte auch ans Ende der main() ein return 0.
So macht man das sauber. Auch wenns im Controller keine Rolle spielt.


Und Rückgabetyp weglassen ist nie gut. Wieso fehlt der überhaupt?

von Sebastian M. (basti87)


Lesenswert?

cyblord ---- schrieb:
> Und Rückgabetyp weglassen ist nie gut. Wieso fehlt der überhaupt?

kann ich dir auch nicht sagen, dieses Projekt stammt von einer Homepage, 
ich versuche nur zur Übung das zum laufen zu bekommen.

http://extremeelectronics.co.in/avr-projects/avr-project-relay-timer-with-atmega8-avr-mcu/

von Sebastian M. (basti87)


Lesenswert?

cyblord ---- schrieb:
> nt
>
> Deshalb sollte auch ans Ende der main() ein return 0.

nur zum Verständnis, da ich den rückgabetyp nicht weiterverarbeite, ist 
es egal wie ich diesen Deklariere?

von Cyblord -. (cyblord)


Lesenswert?

Sebastian M. schrieb:
> cyblord ---- schrieb:
>> nt
>>
>> Deshalb sollte auch ans Ende der main() ein return 0.
>
> nur zum Verständnis, da ich den rückgabetyp nicht weiterverarbeite, ist
> es egal wie ich diesen Deklariere?

Nach irgendwelchen C Standards (die ich grade nicht genau benennen kann) 
sollte main() einen INT zurückgeben. Ich würde dabei bleiben. Auf einem 
Laufzeitsystem, ist das wichtig, damit ein programm einen errocode 
rückgeben kann. Darum auch return 0, da 0=kein fehler, <>0 = Fehler.
Du hast kein Laufzeitystem auf dem Controller, darum egal. Trotzdem 
würde ich mich bei C daran halten.

von Sebastian M. (basti87)


Lesenswert?

cyblord ---- schrieb:
> Nach irgendwelchen C Standards (die ich grade nicht genau benennen kann)
> sollte main() einen INT zurückgeben. Ich würde dabei bleiben. Auf einem
> Laufzeitsystem, ist das wichtig, damit ein programm einen errocode
> rückgeben kann. Darum auch return 0, da 0=kein fehler, <>0 = Fehler.
> Du hast kein Laufzeitystem auf dem Controller, darum egal. Trotzdem
> würde ich mich bei C daran halten.

Ok, danke für den Tipp.

Ich werde jetzt die Schaltung im Keller erneut aufbauen. Mal schauen ob 
es mit den neuen Komponenten klappt.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> kann ich dir auch nicht sagen, dieses Projekt stammt von einer Homepage,
> ich versuche nur zur Übung das zum laufen zu bekommen.

Konzentrier dich erst mal nur auf das LCD und lass den Timer-Code weg.

Ein einfaches
1
int main()
2
{
3
  InitLCD(0);
4
  LCDWriteString("    Welcome     ");
5
6
  while( 1 )
7
    ;
8
}
reicht, um das LCD in Betrieb zu nehmen und den Funktionsnachweis zu 
erbringen.
Alles andere sind erst mal nur zusätzliche Möglichkeiten, Fehler zu 
machen.
Und so prickelnd gut ist der Code von diesem Timer dann auch wieder 
nicht geschrieben.

von Sebastian M. (basti87)


Lesenswert?

So habe die Schaltung erneut zusammengesteckt, leider ohne Funktion. Als 
ich dann das Quarz gegen ein frisch geliefertes ausgetauscht habe, habe 
ich endlich eine Anzeige bekommen.

=> Quarz defekt <=

Nun gibt es aber ein neues Problem, welches dieses mal nicht an der 
Hardware liegen kann.

Nach dem Einschalten ist folgendes zu sehen:
("||||||||||||||||") = schwarze Rechtecke
("                ")

Nach dem Drücken von "Select" erscheint:
("    Welcome     ")
("   Relay Timer  ")

dann passiert nach 4 sek. nichts, erst durch drücken von
"select" oder "up" oder "down" für eine dauer von 3 sek. danach ist 
folgendes Bild:
("Set Time - 00:00")
(" Start     ^    ");

Jedes drücken einer Taste führt wieder zum Bild:
("    Welcome     ")
("   Relay Timer  ")



Karl Heinz Buchegger schrieb:
> Und so prickelnd gut ist der Code von diesem Timer dann auch wieder
> nicht geschrieben.

Leider bin ich aber nicht in der Lage, selbst einen Code zu schreiben. 
Somit bleibt mir nur noch die Möglichkeit, einen zu suchen, und diesen 
dann nach meinen Wünschen anzupassen.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> Leider bin ich aber nicht in der Lage, selbst einen Code zu schreiben.
> Somit bleibt mir nur noch die Möglichkeit, einen zu suchen, und diesen
> dann nach meinen Wünschen anzupassen.

Ich denke du willst üben?

Dann analysier den Anfang des Codes, sieh nach was passiert (die ganze 
Timer Sache lässt du erst mal weg), und analysiere wie die Sache mit den 
Tasten funktioniert.

Und dann schreibst du den ganzen Teil, der sich um LCD, Tasten und 
erhöhen/erniedrigen der einzelnen Zahlenwerte dreht neu und nach deinen 
Vorstellungen.

Eine bessere Übung gibt es nicht.

Wenn der Teil dann erst mal zufriedenstellend funktioniert, dann können 
wir uns über den Timer unterhalten, bzw. wie man dann die eingestellte 
Zeit tatsächlich ablaufen lässt. Aber erst mal hast du mit LCD, Tasten 
und deren Auswertung genug zu tun.

Sorry. Aber wer etwas selber bauen will, der muss auch selber ran. Das 
war schon immer die Maxime hier im Forum.

von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Eine bessere Übung gibt es nicht.

Hast du auch einen Vorschlag wie man dort am besten ran geht?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Karl Heinz Buchegger schrieb:
>> Eine bessere Übung gibt es nicht.
>
> Hast du auch einen Vorschlag wie man dort am besten ran geht?

Sicher.
Ignorier erst mal die komplette Timer Sache.

Du hast 2 Variablen, die Stunden und die Minuten.
Und du hast 3 Tasten.
Mit einer Taste wählst du aus, welchen Zahlenwert (Stunden oder Minuten) 
du verändern willst und mit den anderen beiden erhöhst bzw. erniedrigst 
du den Wert. Und dann werden die neuen Werte wieder am LCD angezeigt.

Analysier den Code. Genau diese Funktionalität ist da im Grunde schon 
programmiert, wenn auch etwas ... seltsam und langatmig. D.h. du hast 
schon Code, an dem du dir ansehen kannst, wie man zb den Wert einer 
Variablen ausgibt. Du hast schon Code der, ähm, Tastenabfragen 
realisiert. Nur bitte nimm nicht diese besch.... delay Funktionen des 
Autors, sondern wenigstens die im AVR-GCC bereits vorhandenen.

Fürs erste reicht es ja auch, wenn du nach dem Drücken einer Taste erst 
mal 2 unterschiedliche Texte anzeigst
1
int main()
2
{
3
  lcd_init( 0 );
4
5
  PORTB |= ( 1 << PB0 );
6
7
  while( 1 )
8
  {
9
    if( PINB & ( 1 << PB0 ) )
10
    {
11
      LCDGotoXY( 0, 0 );
12
      LCDWriteString("Oben ");
13
    }
14
    else {
15
      LCDGotoXY( 0, 0 );
16
      LCDWriteString("Unten");
17
    }
18
  }
19
}

Dann gehts eben weiter. Nicht etwas tun solange eine Taste gedrückt ist, 
sondern eine gedrückte Taste nur einmal auswerten. Um beim Original zu 
beliben, zb so
1
int main()
2
{
3
  uint8_t oldPin;
4
  uint8_t newPin;
5
6
  uitn8_t cnt = 0;
7
8
  lcd_init( 0 );
9
10
  PORTB |= ( 1 << PB0 );
11
12
  oldPin = PINB & ( 1 << PB0 );
13
14
  LCDWriteIntXY( 4, 1, cnt, 2 );
15
16
  while( 1 )
17
  {
18
    newPin = PINB & ( 1 << PB0 );
19
20
    if( newPin != oldPin )   // gibts einen Unterschied zu 'vorher'
21
                             // wenn ja, dann ist die Taste entweder
22
    {                        // gedrückt oder losgelassen worden
23
      cnt++;
24
      LCDWriteIntXY( 4, 1, cnt, 2 );
25
    }
26
    oldPin = newPin;
27
28
    _delay_ms( 10 );
29
  }
30
}

(@Alle: Ja ich weiß, die Entprellung ist nicht gut gelöst. Aber bei den 
Voraussetzungen ist alles andere noch zu schwer für ihn.)


Und so geht das eben weiter. Eines führt zum anderen.
Als nächstes brauchst du dann eine zweite Taste, so dass du den Wert 
nicht nur erhöhen, sondern auch verringern kannst.
Klappt das, dann kommt eine 2-te Variable ins Spiel, die verändert wird.
Und du musst irgendwie zwischen den beiden umschalten, so dass du beide 
voneinander unabhängig erhöhen/erniedrigen kannst.
Dazu brauchst du eine weitere (3-te) Taste, die die Umschaltung macht. 
Und du musst deinem Benutzer irgendwie anzeigen, welche der beiden 
Zahlen er gerade verändert.

Aber Grundvoraussetzung ist es nun mal, dass du Tasten auswerten und 
Aktionen daran knüpfen kannst. Perfekt um das zu üben.

von Sebastian M. (basti87)


Lesenswert?

Puh, ein ganz schönes Brett. Ich mach mich gleich dran...

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Puh, ein ganz schönes Brett. Ich mach mich gleich dran...

Tja. So ist das nun mal, wenn man etwas selber bauen will.
Man muss es lernen.
Aber dafür kriegt man dann auch exakt das, was man sich vorstellt :-)

von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> lcd_init( 0 );

das ist doch aber nicht der Aufruf der funktion in meinem Projekt oder? 
Hier lautet deiser Befehl InitLCD(0).

Wollen wir von vorne rein gleich die bessere LCD Routine nehmen?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Karl Heinz Buchegger schrieb:
>> lcd_init( 0 );
>
> das ist doch aber nicht der Aufruf der funktion in meinem Projekt oder?
> Hier lautet deiser Befehl InitLCD(0).

OK. Dann eben so.
Ich hab nicht bei jedem Aufruf der vorgefertigten Funktionen nachgesehen 
(*), ob sich die Funktion wirklich so schreibt. Dazu hast du ja die 
'Vorlage' mit dem Originalcode, in dem man schnell und einfach nachsehen 
kann.

(*) das ist von hier aus nämlich recht mühsam zu bewerkstelligen. Aber 
du hast ja den Code vor dir - sieh nach, wie die Funktion wirklich 
heißt. Aus dem Zusammenhang sollte klar sein, welche Funktion gemeint 
ist.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:

> Wollen wir von vorne rein gleich die bessere LCD Routine nehmen?

Wenn die hier jetzt funktionieren, dann nimm sie auch. Die sind momentan 
das kleinste Problem, so wie ich das sehe.

von Sebastian M. (basti87)


Lesenswert?

Ehrlich gesagt, verstehe ich jetzt nicht was dass oben für 
Codeausschnitte sind? Der erste ist ja nur ein Test, knopf drücken = 
Anzeige.

Aber sagt
1
PORTB |= ( 1 << PB0 );

nicht aus , dass der Ausgang auf logisch 1 gesetzt werden soll?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian M. schrieb:
> Ehrlich gesagt, verstehe ich jetzt nicht was dass oben für
> Codeausschnitte sind? Der erste ist ja nur ein Test, knopf drücken =
> Anzeige.
>
> Aber sagt
>
1
> PORTB |= ( 1 << PB0 );
2
>
>
> nicht aus , dass der Ausgang auf logisch 1 gesetzt werden soll?


Nein, nicht nicht in diesem Fall.
Denn der Pin PB0 am Port B wurde ja nicht mittels DDRB auf Ausgang 
programmiert. Daher ist er nach wie vor ein Eingang und daher schaltet 
diese Anweisung den Pullup Widerstand für diesen Pin ein.

AVR-GCC-Tutorial

> Der erste ist ja nur ein Test
Aber offenbar einer, den du in seiner Einfachheit nicht komplett 
verstehst.
Üben!
Solche Dinge, wie die Zusammenhänge der DDRx, PORTx und PINx Register 
dürfen kein Problem sein. Sowas musst du einwandfrei erkennen können, 
wenn du es siehst.
Denn sonst unterhalten wir uns über eine einfache Blinddarmoperation, 
dessen ausführender Arzt Schwierigkeiten beim Aufkleben eines Pflasters 
hat. Keine guten Voraussetzungen.

von Sebastian M. (basti87)


Lesenswert?

1
int main()
2
{
3
  uint8_t oldPin; // Variable deklarieren
4
  uint8_t newPin;// Variable deklarieren
5
6
  uitn8_t cnt = 0; //setzte cnt=00
7
8
  lcd_init( 0 ); // LCD initialisieren
9
10
  PORTB |= ( 1 << PB0 ); // Pin0 pull up ein
11
12
  oldPin = PINB & ( 1 << PB0 ); // oldPin ist =1 wenn pb0=1
13
14
  LCDWriteIntXY( 4, 1, cnt, 2 ); // schreibe an LCD zeile 1 spalte 4 
15
                                  //dem wert von cnt, zweistellig
16
17
  while( 1 )
18
  {
19
    newPin = PINB & ( 1 << PB0 );// newPin ist =1 wenn pb0=1
20
21
    if( newPin != oldPin )   // gibts einen Unterschied zu 'vorher'
22
                             // wenn ja, dann ist die Taste entweder
23
    {                        // gedrückt oder losgelassen worden
24
      cnt++;                 //erhöhe cnt um 1
25
      LCDWriteIntXY( 4, 1, cnt, 2 ); // schreibe an LCD zeile 1 spalte 4 
26
                                      //dem wert von cnt, zweistellig
27
28
    }
29
    oldPin = newPin;   // gleichsetzen
30
 
31
    _delay_ms( 10 );   // 10ms warten
32
  }
33
}

das ist ja alles schön und gut, aber weiterbringen tut mich das doch 
auch nicht. was bringt das? an welcher stelle ist das sinnvoll?

von Karl H. (kbuchegg)


Lesenswert?

Sagtest du nicht, du willst üben?

Dann übe! Und fang endlich an, nicht nur "malen nach Zahlen" zu 
betreiben, sondern deine Programme selbst zu entwickeln!
Den Grundstein hab ich dir gelegt um daraus das Programm zu entwickeln. 
Die weitere Entwicklung wirst du aber selber machen müssen. Denn letzten 
Endes willst DU ja dieses Projekt stemmen, nicht ich. Ich helfe dir 
nur, wenn du nicht mehr weiterkommst (und glaub mir, es wäre für mich 
wesentlich einfacher das Programm einfach zu schreiben als dich da durch 
die Entwicklung zu begleiten. Die 30 Minuten, die ich für das 
vollständige Programm brauchen würde, sind schon lange um)

von Sebastian M. (basti87)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die 30 Minuten, die ich für das
> vollständige Programm brauchen würde, sind schon lange um

Respekt... ich werde wahrscheinlich 3000 minuten brauchen... :-/, da ich 
das mit den schaltern nicht schnalle.

von Sebastian M. (basti87)


Lesenswert?

Guten Morgen,

ich habe mich mal um die taster gekümmert, bitte mal durchschauen.
Habs nochmal verbessert.

1
while(1)
2
    {
3
      // ### Zeit einstellen ###  
4
5
      
6
      
7
      
8
      // Select Key
9
      newPin = PINB & ( 1 << PB2 );    
10
      
11
      if (newPin != oldPin)
12
      {
13
        selection ++;
14
        
15
        if (selection ==3)
16
        {
17
          selection=0;
18
        }
19
          
20
      }
21
22
      // --- Up Key ---
23
      newPin = PINB & ( 1 << PB1 );
24
      
25
      if (newPin != oldPin)
26
      {
27
        
28
        if (selection ==1)      // Auswahl ist auf Stunden
29
        {
30
          hr++;
31
          if (hr==100)      // Wenn Stunde =100 setze wieder 0
32
          {
33
            hr=0;
34
          }
35
        }
36
        
37
        if (selection ==2)      // Auswahl ist auf Minuten
38
        {
39
          min++;
40
          if (min==60)      // Wenn Minute =60 setze wieder 0
41
          {
42
            min=0;
43
          }
44
        }
45
      
46
        
47
        if (selection ==0)
48
        {
49
          break;
50
        }
51
      }
52
        // --- --- ---
53
        
54
55
      // --- Down Key ---
56
      newPin = PINB & ( 1 << PB0 );
57
        
58
      if (newPin != oldPin)
59
      {
60
          
61
        if (selection ==1)      // Auswahl ist auf Stunden
62
        {
63
          hr--;
64
          if (hr==-1)      // Wenn Stunde =100 setze wieder 0
65
          {
66
              hr=99;
67
          }
68
        }
69
          
70
        if (selection ==2)      // Auswahl ist auf Minuten
71
        {
72
          min++;
73
          if (min==-1)      // Wenn Minute =60 setze wieder 0
74
          {
75
            min=59;
76
          }
77
        }
78
          
79
        if (selection ==0)
80
        {
81
          break;
82
        }
83
        // --- --- ---            
84
      }
85
        
86
        
87
    }

von Sebastian M. (basti87)


Lesenswert?

So, habe jetzt auch noch, wie ich glaube,die LCD Aktualisierung ergänzt. 
Das siht dann für dem DOWN KEY exemplarisch so aus:

1
// --- Down Key ---
2
      newPin = PINB & ( 1 << PB0 );
3
        
4
      if (newPin != oldPin)
5
      {
6
          
7
        if (selection ==1)      // Auswahl ist auf Stunden
8
        {
9
          hr--;
10
          if (hr==-1)      // Wenn Stunde =100 setze wieder 0
11
          {
12
            hr=99;
13
          }
14
        LCDWriteIntXY(11,0,hr,2);
15
        }
16
          
17
        if (selection ==2)      // Auswahl ist auf Minuten
18
        {
19
          min++;
20
          if (min==-1)      // Wenn Minute =60 setze wieder 0
21
          {
22
            min=59;
23
          }
24
        LCDWriteIntXY(11,0,min,2);
25
        }
26
          
27
        if (selection ==0)
28
        {
29
          break;
30
        }
31
        // --- --- ---

Jetzt fehlen noch die Curserpositionen und die eigentliche 
Timerfunktion.

von Sebastian M. (basti87)


Lesenswert?

Hey,

zur Info, ich habe jetzt zumindest den Ursprünglichen Code zum laufen 
bekommen. In der Schaltung von der Homepage fehlte die Verbindung von 
Pin 22 (AGND) zu GND und 21(AREF) zu +5V.

Wenn ich jetzt eine Zeit einstelle und starte:

2min eingestellt und gestartet:
1
Anzeige:
2
00:02:55
3
...
4
00:02:00
5
00:02:99
6
00:02:98
7
00:02:97
8
...
9
00:02:00
10
00:02:99
11
00:02:98
12
13
etc...

liegt das vielleicht an dem Timer dings?
1
ISR(TIMER1_COMPA_vect)
2
{
3
  clock_millisecond++;
4
  if(clock_millisecond==1000)
5
  {
6
    clock_second--;
7
    clock_millisecond=0;
8
    if(clock_second==-1) //-1
9
    {
10
      clock_minute--;
11
      clock_second=59;
12
13
      if(clock_minute==-1) //-1
14
      {
15
        clock_hour--;
16
        clock_minute=59;
17
      }
18
    }
19
  }
20
}

von Karl H. (kbuchegg)


Lesenswert?

Hier sitzt der Übeltäter
1
volatile char       clock_second=0;
2
volatile char       clock_minute=0;
3
volatile char       clock_hour=0;

hier ist nicht definiert ob ein char signed oder unsigned sein soll.
So wie die Vergleiche hier sind
1
...
2
    if(clock_second==-1) //-1
3
...

müssen das signed Werte sein.

Also
1
volatile signed char       clock_second=0;
2
volatile signed char       clock_minute=0;
3
volatile signed char       clock_hour=0;

von Ich (Gast)


Lesenswert?

Wahrscheinlich es liegt an die Timer Dinge, es ist die Timer
Funktionalität die Probleme gibt.

Es scheint dass das Problem ist das deine Sekunden Counter in eine
Variable ohne Vorzeichen gespeichert ist.

Also, im General jede Variable ist nur ein Sammlung von Bits die
irgendwo in den Arbeitsspeicher des Mikrocontroller liegen. Wie die Bits
interpretiert werden stellt man ein durch den Typ Deklaration.


Zum Beispiel:
1
char a = 0;  // 8 bit variable (mit oder ohne Vorzeichen abhängig von Kompilator/Plattform) und Anfangswert = 0 
2
unsigned char b = 0; // 8 bit variable ohne Vorzeichen und Anfangswert = 0 
3
signed char c = 0; // 8 bit variable mit Vorzeichen und Anfangswert = 0

was passiert wenn man eins subtrahiert:
1
a--;  // a hat jetzt ein Wert von -1 oder 255 (hängt von ob der Kompilator char als ein Typ mit oder ohne Vorzeichen nimnt  )  
2
b--; // b hat jetzt ein Wert von 255 ( Typ ohne Vorzeichen, 0 ist die Minimalwert)  
3
c--; // a hat jetzt ein Wert von -1 ( Typ mit Vorzeichen, -127 ist die Minimalvert. Analogisch zum der Fall mit Variable b, wenn b ein wert von -127 hätte und eins davon subtrahiert wird, dann würde c ein Wert von +127

Wieso sieht man 00:02:99 statt 00:02:255? Ich nehme an, dass wenn deine
Anzeige Funktion ein Wert mit Mehr Stellen als erwarten kriegt dann
Zeigt die die Maximale Wert die man mit die gewünschte Stellenmenge
anzeigen kann. Ich bin aber nicht sicher, ich hab fast kein Ehrfahrung
mit avr gcc und überall kein mit diese LCD Code.

Wenn du Englisch verstehen kannst (es ist sowieso extrem schwer
Programmieren zu Lernen ohne Englisch zu verstehen zu können) lies mal
den Artikel hier: https://en.wikipedia.org/wiki/C_data_types

Bisschen offtopic:

Ich weiss dass das ganze Ding an Anfang sehr verwirrend aussehen kann.
Man muss gleichzeitig auf Software und Hardware aufpassen: Dinge wie:
versorgt den Spannungsquelle eine gleiche Spannung? Auch under Last?
Sind die Kondensatoren für den Quarz die Richtige wert? Hab ich die
richtige Fuses am Kontroller programiert? Benutzt den Projektcode
irgendwelche nicht Standarte Erweiterungen und werden die von den
Kompilator die ich benutze Unterstützt? und viele viele mehr ähnliche
Fragen...

Wenn aber in die Ende man sein Projekt zu eine korrekt funktionierende
Zustand bringt alle diese Schwierigkeiten blenden in Vergangenheit aus.
Mindestens bis man genug zum Spielen mit seine neue Gadget hatte und ein
neues und mehr kompliziertes Projekt annimmt.

von Sebastian M. (basti87)


Lesenswert?

wunder bar, danke euch beiden.

Bin gerade am rumspielen, klappt auch ganz gut.

aber ein problem bekomm ich nicht weg, und zwar ist das der blinkende 
Cursor.

Ich habe folgende Änderungen versucht:

LCD.h
1
...
2
#define LS_BLINK 0B00000001 //geändert auf 0B00000000
3
#define LS_ULINE 0B00000010 //geändert auf 0B00000000
4
...
5
#define LCDClear() LCDCmd(0b00000001)    //geändert auf 0b00000000
6
#define LCDHome() LCDCmd(0b00000010);    //geändert aud 0b00000000

ohne Erfolg.

LCD.c
1
...
2
//Now the LCD is in 4-bit mode
3
4
  LCDCmd(0b00001100|style);    //geändert auf ohne |style
5
  LCDCmd(0b00101000);      //function set 4-bit,2 line 5x7 dot format
6
...

ohne erfolg.

Ich habe sowohl alles einzeln, als auch in Kombination probiert.
Habt ihr noch eine Idee?

PS: Die Anweisungen habe ich von hier
http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD

von Sebastian M. (basti87)


Lesenswert?

Sebastian M. schrieb:
> wunder bar

=wunderbar

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
Noch kein Account? Hier anmelden.