Forum: Compiler & IDEs Porterweiterung Atmega8 mit 74HC164


von Peter B. (shaphard)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin neu in der Welt der Mikrocontroller und habe eine Frage

ich habe das AVR MK2 Board mit einem Atmga8 ich benötige mehr Eingänge 
und habe mir hierfür zwei 74HC165 kaskadiert. Schaltplan siehe 
angehängtes Bild.

ich Programmiere in C leider habe ich ich nur eine Assembler Code finden 
können. Kann mir evtl. jemand den Code in C übersetzen? Wäre echt super.
Schon mal Danke im voraus.

Hier der Code:
1
; Porterweiterung für Eingänge mit Schieberegister 74xx165
2
; Ansteuerung per Software
3
 
4
.include "m8def.inc"
5
 
6
.def temp1 = r16
7
.def temp2 = r17
8
.def temp3 = r18
9
 
10
; Pins anpassen, frei wählbar
11
 
12
.equ SCHIEBE_DDR  = DDRB
13
.equ SCHIEBE_PORT = PORTB
14
.equ SCHIEBE_PIN  = PINB
15
.equ CLK          = PB3
16
.equ PL           = PB1
17
.equ DIN          = PB2
18
 
19
;-----------------------------------------------------------------------------
20
;
21
; Datensegment im RAM
22
;
23
;-----------------------------------------------------------------------------
24
 
25
.dseg
26
.org 0x60
27
Daten:      .byte 2             ; Speicherplatz für Eingangsdaten
28
 
29
;-----------------------------------------------------------------------------
30
;
31
; Programmsegment im FLASH
32
;
33
;-----------------------------------------------------------------------------
34
.cseg
35
    ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
36
    out     SPL, temp1
37
    ldi     temp1, HIGH(RAMEND)
38
    out     SPH, temp1
39
 
40
; CLK und PL als Ausgänge schalten
41
 
42
    ldi     temp1, (1<<clk) | (1<<pl)
43
    out     SCHIEBE_DDR, temp1
44
 
45
    sbi     schiebe_port, clk   ; Takt im Ruhezustand immer auf 1
46
                                ; komische Schaltung im 74xx165
47
 
48
; Zwei Bytes einlesen
49
 
50
    ldi     ZL,low(Daten)
51
    ldi     ZH,high(Daten)
52
    ldi     temp1,2
53
    rcall   schiebe_eingang
54
 
55
loop:
56
    rjmp    loop
57
 
58
;-----------------------------------------------------------------------------
59
;
60
; N Bytes seriell einlesen
61
;
62
; temp1 : N, Anzahl der Bytes
63
; Z     : Zeiger auf einen Datenbereich im SRAM
64
;-----------------------------------------------------------------------------
65
 
66
schiebe_eingang:
67
    push    temp2               ; Register sichern
68
    push    temp3
69
 
70
    cbi     schiebe_port, pl    ; Daten parallel laden
71
    sbi     schiebe_port, pl
72
 
73
schiebe_eingang_byte_schleife:
74
 
75
    ldi     temp3, 8            ; Bitzähler
76
schiebe_eingang_bit_schleife:
77
    lsl     temp2               ; Daten weiterschieben
78
 
79
; das IO Bit Din in das niederwerigste Bit von temp2 kopieren
80
 
81
    sbic    schiebe_pin, din    ; wenn Null, nächsten Befehl überspringen
82
    ori     temp2,1             ; nein, Bit setzen
83
 
84
    cbi     SCHIEBE_PORT, CLK   ; Taktausgang auf 0
85
    sbi     SCHIEBE_PORT, CLK   ; und wieder zurück auf 1, dabei Daten schieben 
86
 
87
    dec     temp3               ; Bitzähler um eins verringern
88
    brne    schiebe_eingang_bit_schleife ;wenn noch keine 8 Bits ausgegeben, nochmal
89
 
90
    st      z+,temp2            ; Datenbyte speichern
91
    dec     temp1               ; Anzahl Bytes um eins verringern
92
    brne    schiebe_eingang_byte_schleife   ; wenn noch mehr Bytes zu lesen sind
93
 
94
    pop     temp3
95
    pop     temp2
96
    ret

von Werner (Gast)


Lesenswert?

Peter Bauer schrieb:
> ich Programmiere in C leider habe ich ich nur eine Assembler Code finden
> können.

cbi - Clear Bit
sbi - Set Bit
ori - bitweises oder
u.s.w.

Wenn du C kannst sollte das kein Problem sein. Die Befehlsbeschreibungen 
stehen in Kurzform alle im Datenblatt im Anschnitt "Instruction Set 
Summary"

von Peter B. (shaphard)


Lesenswert?

so hab mal das C-Programm geschrieben, lässt sich auch ohne Fehler 
übersetzen, funktioniert aber leider nicht.
Jemand ne Idee??

nach dem Durchgang sollte das Eingansregister ja eingelesen sein und im 
Array eingang_mux stehen macht es aber nicht.
1
int main(void)
2
{
3
  DDRB |= ((1<<DDB0) | (1<<DDB1));  // Port B Pin 0 und 1 als Ausgang
4
  PORTB &= ~((1<<DDB0) | (1<<DDB1));  // auf 0 setzen
5
  DDRB &= ~((1<<DDB2));        // Port B Pin 2 als Eingang
6
  PORTB &= ~(1<<DDB2);        // Pullup aus
7
  
8
  int eingang_mux[16];
9
10
while(1) 
11
{
12
    
13
HC165_Lesen(eingang_mux);
14
15
16
} // End While 
17
} // End Main
18
19
void HC165_Lesen()
20
{
21
  int werte[16]={0};  // Array mit Eingangsdaten initalisiert mit 0
22
  int i;        // Zählvariable
23
  // PB0 = PL
24
  // PB1 = CLK
25
  // PB2 = Q7 (DIN)
26
  PORTB |= (1<<PB1);  // CLK auf 1 setzen
27
  
28
  PORTB &= ~(1<<PB0);  // PL = 0;
29
  PORTB |= (1<<PB0);  // PL = 1;
30
  
31
  for (i=0;i<16;i++)
32
  {
33
  if(PINB & (1<<PB2)) // Eingang Q7 ist 1
34
  {
35
      werte[i]=1;  // dann schreibe 1 ins Register
36
    
37
  }    
38
    else        // sonst
39
    {
40
     werte[i]=0;  // schreibe 0 ins register
41
    }
42
    
43
    // Eingansregister eins weiter takten
44
    
45
  PORTB &= ~(1<<PB1);  // CLK = 0;
46
  PORTB |= (1<<PB1);  // CLK = 1;
47
  }
48
  return werte[16]; // Eingangsregister an Hauptprogramm übergeben
49
}

von Dauergast (Gast)


Lesenswert?

Peter Bauer schrieb:
> nach dem Durchgang sollte das Eingansregister ja eingelesen sein und im
> Array eingang_mux stehen macht es aber nicht.

Warum sollte es denn in eingang_mux stehen?
Du möchtest das sicher gern, aber dazu muß es auch jemand reinschreiben.

HC165_Lesen schreibt die eingelesenen Werte in die lokale Variable 
"werte", und zwar index 0..15. Dann wird der Inhalt von werte[16] 
zurückgegeben, der gar nicht existiert. Ist aber egal, denn der 
Rückgabewert wird ja sowieso nicht benutzt.

von amateur (Gast)


Lesenswert?

Da ist was faul im Staate Dänemark!

void HC165_Lesen()
mit Aufruf: HC165_Lesen(eingang_mux);
und mit:    return werte[16];

von Peter B. (shaphard)


Lesenswert?

Dauergast schrieb:
> Warum sollte es denn in eingang_mux stehen?
> Du möchtest das sicher gern, aber dazu muß es auch jemand reinschreiben.

ich gebe mit Werte[16] das ganze Array zum Hauptprogramm zurück und 
schreibe es dort in das Array eingang_mux

ich kann auch einfach nur
1
return werte;
schreiben, ändert aber nichts


hier nochmal der Code habe noch einen Ausgang der mit eingang_mux 
gesetzt wird ergänzt

@Dauergast: wenn du eine Idee hast wies richtig geht wäre es schön wenn 
du meinen code an denn entsprechenden stellen korrigierst, dann kann ich 
auch verstehen was ich falsch mache.
1
int main(void)
2
{
3
  DDRB |= ((1<<DDB0) | (1<<DDB1) | (1<<DDB3) | (1<<DDB4));  // Port B 0, 1, 3 als Ausgang
4
  PORTB &= ~((1<<DDB0) | (1<<DDB1) | (1<<DDB3) | (1<<DDB4));  // auf 0 setzen
5
  DDRB &= ~((1<<DDB2));        // Port B 2 als Eingang
6
  PORTB &= ~(1<<DDB2);        // Pullup aus
7
  
8
  int eingang_mux[16];
9
while(1) 
10
{
11
    
12
HC165_Lesen(eingang_mux);
13
14
if(eingang_mux[0]=1) // wenn 1 dann
15
{
16
  PORTB |= (1<<DDB3); // Ausgang auf 1 setzen
17
}
18
else          // sonst
19
{
20
  //DDRB |= (1<<DDB3);
21
  PORTB &= ~(1<<DDB3); // Ausgang auf 0 setzen
22
}
23
} // End While 
24
} // End Main
25
26
int HC165_Lesen()
27
{
28
  int werte[16]={0};  // Array mit Eingangsdaten initalisiert mit 0
29
  int i;        // Zählvariable
30
  // PB0 = PL
31
  // PB1 = CLK
32
  // PB2 = Q7 (DIN)
33
  PORTB |= (1<<PB1);  // CLK auf 1 setzen
34
  
35
  PORTB &= ~(1<<PB0);  // PL = 0;
36
  PORTB |= (1<<PB0);  // PL = 1;
37
  
38
  for (i=0;i<16;i++)
39
  {
40
  if(PINB & (1<<PB2)) // Eingang Q7 ist 1
41
  {
42
      werte[i]=1;  // dann schreibe 1 ins Register
43
  }    
44
    else        // sonst
45
    {
46
     werte[i]=0;  // schreibe 0 ins register
47
    }
48
    
49
    // Eingansregister eins weiter takten
50
    
51
  PORTB &= ~(1<<PB1);  // CLK = 0;
52
  PORTB |= (1<<PB1);  // CLK = 1;
53
  }
54
  return werte; // Eingangsregister an Hauptprogramm übergeben
55
}

von Dauergast (Gast)


Lesenswert?

Du kannst kein Array zurückgeben, höchstens eine Pointer darauf. Ein 
Pointer auf Dein lokales "werte" ist allerdings nach Rückkehr aus der 
Funktion HC165_lesen ungültig, da "werte" nicht mehr existiert.

Du übergibst also eingang_mux als Parameter, und benutzt das für Deine 
Ergebnisse:
1
void HC165_Lesen(int *werte);
2
3
int main(void)
4
{
5
  int eingang_mux[16];
6
7
  DDRB |= ((1<<DDB0) | (1<<DDB1) | (1<<DDB3) | (1<<DDB4));  // Port B 0, 1, 3 als Ausgang
8
  PORTB &= ~((1<<DDB0) | (1<<DDB1) | (1<<DDB3) | (1<<DDB4));  // auf 0 setzen
9
  DDRB &= ~((1<<DDB2));        // Port B 2 als Eingang
10
  PORTB &= ~(1<<DDB2);        // Pullup aus
11
12
  while(1)
13
  {
14
    HC165_Lesen(eingang_mux);
15
    
16
    if(eingang_mux[0]=1) // wenn 1 dann
17
    {
18
      PORTB |= (1<<DDB3); // Ausgang auf 1 setzen
19
    }
20
    else          // sonst
21
    {
22
      //DDRB |= (1<<DDB3);
23
      PORTB &= ~(1<<DDB3); // Ausgang auf 0 setzen
24
    }
25
  } // End While
26
} // End Main
27
28
29
void HC165_Lesen(int *werte)
30
{
31
  int i;        // Zählvariable
32
  // PB0 = PL
33
  // PB1 = CLK
34
  // PB2 = Q7 (DIN)
35
  PORTB |= (1<<PB1);  // CLK auf 1 setzen
36
37
  PORTB &= ~(1<<PB0);  // PL = 0;
38
  PORTB |= (1<<PB0);  // PL = 1;
39
40
  for (i=0;i<16;i++)
41
  {
42
    if(PINB & (1<<PB2)) // Eingang Q7 ist 1
43
    {
44
      werte[i]=1;  // dann schreibe 1 ins Register
45
    }
46
    else        // sonst
47
    {
48
      werte[i]=0;  // schreibe 0 ins register
49
    }
50
51
    // Eingansregister eins weiter takten
52
    PORTB &= ~(1<<PB1);  // CLK = 0;
53
    PORTB |= (1<<PB1);  // CLK = 1;
54
  }
55
}

von EGS_TI (Gast)


Lesenswert?

Peter Bauer schrieb:
> Dauergast schrieb:
>> Warum sollte es denn in eingang_mux stehen?
>> Du möchtest das sicher gern, aber dazu muß es auch jemand reinschreiben.
>
> ich gebe mit Werte[16] das ganze Array zum Hauptprogramm zurück und
> schreibe es dort in das Array eingang_mux

Wie kommst du denn da drauf??????

von Karl H. (kbuchegg)


Lesenswert?

Dauergast schrieb:

nitpicking

>     if(eingang_mux[0]=1) // wenn 1 dann

     if(eingang_mux[0] == 1) // wenn 1 dann

Nicht dass der TO in seinem nicht vorhandenem C-Buch auch danach noch 
stundenlang sucht.

von Peter D. (peda)


Lesenswert?

Peter Bauer schrieb:
> leider habe ich ich nur eine Assembler Code finden
> können.

Dann hast Du aber sehr schlecht gesucht.
Es gibt haufenweise SPI-Code in C.

Peter Bauer schrieb:
> int werte[16]={0};  // Array mit Eingangsdaten initalisiert mit 0

Ja, man kann die Hose auch mit der Kneifzange anziehen. Warum diese 
16-fache Verschwendung von SRAM?
Ein 16 Bit Wert (unsigned int) reicht völlig. Es passen ganze 16 Bit 
hinein, wer hätte das gedacht.

von Peter B. (shaphard)


Lesenswert?

Danke für die Antworten, ich werde das heute ausprobieren sobald ich von 
der Arbeit Zuhause bin.


@Peter Dannegger
wollte das ohne SPI machen wie im AVR Tutorial beschrieben (unters 
drittel):
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister

Im Tutorial ist ja leider nur Assembler Code dabei was ich leider gar 
nicht kann.
Falls du aber noch irgendwo eine bessern C-Code gesehen hast kannst du 
Ihn gerne Posten, habe leider bisher nichts funktionierendes gefunden.

mit dem unsigned int hast du natürlich recht.

von Karl H. (kbuchegg)


Lesenswert?

Peter Bauer schrieb:
> Danke für die Antworten, ich werde das heute ausprobieren sobald ich von
> der Arbeit Zuhause bin.
>
>
> @Peter Dannegger
> wollte das ohne SPI machen wie im AVR Tutorial beschrieben (unters
> drittel):
> http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister
>
> Im Tutorial ist ja leider nur Assembler Code dabei was ich leider gar
> nicht kann.

Wichtig ist das Prinzip - und das geht aus dem ganzen beschriebenen 
Vorgeplänkel eindeutig hervor.

> Falls du aber noch irgendwo eine bessern C-Code gesehen hast kannst du
> Ihn gerne Posten, habe leider bisher nichts funktionierendes gefunden.

Du musst endlich einsehen, dass eine Programmiersprache nicht einfach 
nur irgendwie schmückendes Beiwerk ist, sondern dass man das LERNEN 
muss. Es hat keinen Sinn sich über die Feinheiten einer SPI 
Programmierung zu unterhalten, wenn du das dafür notwendige C nicht 
beherrscht.

Wer malen anfangen will, muss lernen Farben zu mischen und Pinsel 
auszuwaschen. Solange er das nicht kann, ist es sinnlos, sich über 
Farbkomposition und Bildaufbau mit ihm zu unterhalten. Wir können 
stundenlang die alten Meister studieren und wie sie ihre Bilder 
komponiert haben und wo sie welchen Trick eingesetzt haben, wenn der 
Lehrling dann an der ganz banalen Frage "wie mische ich meine Farbe, 
welchen Pinsel nehme ich und wie kriege ich ihn wieder sauber" 
scheitert. Mit dem einen Unterschied, dass man diese Malgrundlagen in 
einer Stunde lernen kann, eine Programmiersprache zu lernen aber Monate 
dauert. Ok, den Teil, den man hier braucht, hat man in ein paar 
Tagen/Wochen intus. Aber alleine die Formulierung "ein Array 
zurückgeben" zeigt schon, dass da etwas wesentliches im Grundverständnis 
fehlt. Und da geht es nicht um SPI bzw. wie man das geschickt anstellt. 
Denn bei SPI geht es im Grunde nur um zeitlich richtiges Wackeln mit 
µC-Pins und entsprechendes Setzen bzw. Abfragen von Werten. Und genau 
das ist hier NICHT dein eigentliches Problem. Dein eigentliches Problem, 
wie man es aus der ganzen Art der Fragestellung ablesen kann, besteht 
darin, dass dein C generell noch viel zu schwach ist. Die 
Schwierigkeiten mit SPI sind nur eine logische Folgeerscheinung davon.

Und ich möchte hinzufügen: Du bist damit nicht alleine, wie sich hier im 
Forum jeden Tag zeigt. Es tauchen immer wieder Leute auf, denen man im 
Grunde sagen muss: Sorry, aber deine ganze Ausdrucksweise, dein genazer 
Code zeigt, dass du mit deinen Kentnissen und mit deinem Wissen über die 
Programmiersprache noch nicht soweit bist, ein reales Projekt in Angriff 
zu nehmen. Wer einen Hammer nicht richtig rum in die Hand nehmen kann, 
sollte nicht (noch nicht) anfangen, ein Haus bauen zu wollen, sondern 
erst mal 20 Übrungsnägel in ein Stück Übungsholz einschlagen.

von Peter D. (peda)


Lesenswert?

1
#include <avr/io.h>
2
3
4
struct bits {
5
  uint8_t b0:1;
6
  uint8_t b1:1;
7
  uint8_t b2:1;
8
  uint8_t b3:1;
9
  uint8_t b4:1;
10
  uint8_t b5:1;
11
  uint8_t b6:1;
12
  uint8_t b7:1;
13
} __attribute__((__packed__));
14
15
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
16
17
18
#define SPI_CLK    SBIT( PORTB, 0 )  // clock
19
#define SPI_CLK_DDR  SBIT( DDRB,  0 )
20
#define SPI_MOSI  SBIT( PORTB, 1 )  // data out
21
#define SPI_MOSI_DDR  SBIT( DDRB,  1 )
22
#define  SPI_MISO_PIN  SBIT( PINB,  2 )  // data in
23
24
25
uint8_t shift_io( uint8_t b )  // send / receive byte
26
{
27
  uint8_t i;
28
29
  SPI_CLK_DDR = 1;    // set as output
30
  SPI_MOSI_DDR = 1;
31
32
  for( i = 8; i; i-- ){    // 8 bits
33
    SPI_MOSI = 0;
34
    if( b & 0x80 )    // high bit first
35
      SPI_MOSI = 1;
36
    b <<= 1;
37
    SPI_CLK = 1;
38
    if( SPI_MISO_PIN )
39
      b++;
40
    SPI_CLK = 0;
41
  }
42
  return b;
43
}

von Peter B. (shaphard)


Lesenswert?

Danke Peter für den Code
ich habe noch ein Frage dazu. Wie Frage ich jetzt das bit der Struktur 
ab?

normalerweise ja Strukturvariable.Struckturelement aber was ist hier 
dann die Strukturvariable?

z.B.
1
if(???.b7==1) // wenn 1 dann
2
{
3
  PORTB |= (1<<PB3); // Ausgang auf 1 setzen
4
}
5
else          // sonst
6
{
7
  PORTB &= ~(1<<PB3); // Ausgang auf 0 setzen
8
}

Danke für die Geduld mit mir...

von Peter D. (peda)


Lesenswert?

Du hast doch keine Struktur, sondern einen 16Bit-Wert.
Und da fragst Du eben ein Bit ab, indem Du alle anderen maskierst.
Genau, wie Du einen Portpin abfragst.

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.