Forum: Mikrocontroller und Digitale Elektronik STM32 und 11x74HC595.


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Daniel S. (sany)


Lesenswert?

Moin,

Ich bräuchte mal Hilfe mit einem Code für die Ansteuerung.

Ich habe 11 Stück 74HC595, die jeweils 84 LEDs ansteuern, 4 Ausgänge 
sind leer, die Ansteuerung erfolgt scheinbar mit LSB und nicht mit MSB.

Wenn mein Task startet, gehen die LEDs in umgekehrter Reinfolge an und 
wieder aus, also Beginnend bei Ausgang 88 bis Ausgang 73...

Wie drehe ich das um, so das Ausgang 1 - 16 angesteuert wird?

currentVal & (1 >> i)) brachte leider kein erfolg.


Mein Code:
1
uint64_t currentVal =  0b00000000000000000000000000000000000000000000000000000000000000000000000000000000;
2
void HC595write()
3
{
4
    for(int i=0; i<88; i++)
5
    {
6
        if(currentVal & (1<< i))
7
        {
8
            HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_SET);
9
        }
10
        else
11
        {
12
            HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_RESET);
13
        }
14
        HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_SET);
15
        HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_RESET);
16
    }
17
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_SET);
18
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_RESET);
19
}
20
21
void HC595writePin(uint8_t pin, uint8_t value)
22
{
23
      if (value == 0)
24
      {
25
          currentVal &= ~(1 << pin);
26
      }
27
      else
28
      {
29
          currentVal |= (1 << pin);
30
      }
31
      HC595write();
32
}
33
34
void StartDefaultTask(void *argument)
35
{
36
  /* init code for USB_DEVICE */
37
  MX_USB_DEVICE_Init();
38
  /* USER CODE BEGIN 5 */
39
40
  /* Infinite loop */
41
  for(;;)
42
  {
43
44
    for(int i=0; i < 16; i++)
45
    {
46
      HC595writePin(i, 0);
47
      osDelay(100);
48
    }
49
    osDelay(1000);
50
    for(int i=0; i < 16; i++)
51
        {
52
          HC595writePin(i, 1);
53
          osDelay(100);
54
        }
55
  }
56
  /* USER CODE END 5 */
57
}

vielen Dank für eure Hilfe :)

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Deine for Schleife bestimmt, in welcher Reihenfolge die Bits gezählt 
werden. Ich bezweifle allerdings, dass deine 64 Bit Variable 88 Bits 
enthalten kann.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

88 Bits in einer 64bit-Variable? Optimistisch!

von Christian M. (christian_m280)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Ich bezweifle allerdings, dass deine 64 Bit Variable 88 Bits enthalten
> kann.

Da musst Du Gregor fragen, der kann das:

Beitrag "Re: AT89C2051 und das UART Rätsel"

Gruss Chregu

von Falk B. (falk)


Lesenswert?

Daniel S. schrieb:
> Moin,
>
> Ich bräuchte mal Hilfe mit einem Code für die Ansteuerung.
>
> Ich habe 11 Stück 74HC595, die jeweils 84 LEDs ansteuern, 4 Ausgänge
> sind leer, die Ansteuerung erfolgt scheinbar mit LSB und nicht mit MSB.

> Wenn mein Task startet, gehen die LEDs in umgekehrter Reinfolge an und
> wieder aus, also Beginnend bei Ausgang 88 bis Ausgang 73...
>
> Wie drehe ich das um, so das Ausgang 1 - 16 angesteuert wird?
>
> currentVal & (1 >> i)) brachte leider kein erfolg.

Logisch, du hast den Code nicht verstanden. Siehe Bitmanipulation.

Naja. Solche Sachen packt man in ein Array mit uint8_t Datentyp, das ist 
verdaulicher, auch für fette 32 Bit CPUs. Und viel besser erweiterbar 
auf beliebige Schieberegisterlängen.
Im aktuellen Code und auch meiner Version unten, liegt das Ende der 
LED-Kette am Anfang der Daten, denn die werden zuerst ausgegeben. Kann 
man ggf. auch umdrehen.

1
uint8_t LEDdata[11];
2
 
3
void HC595write()
4
{
5
    int data;
6
7
    for(int i=0; i<11; i++)
8
    {
9
        data = LEDdata[i];
10
        for (int j=0; j < 8; j++)
11
        {
12
            if(data & (1<<j))
13
            {
14
                HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_SET);
15
            }
16
            else
17
            {
18
                HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_RESET);
19
            }
20
            HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_SET);
21
            HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_RESET);
22
        }
23
    } 
24
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_SET);
25
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_RESET);
26
}
27
28
void HC595writePin(uint8_t pin, uint8_t value)
29
{
30
    int bit, byte;
31
32
    byte = pin / 8;
33
    bit = pin % 8;
34
35
    if (value == 0)
36
    {
37
        LEDdata[byte] &= ~(1 << bit);
38
    }
39
    else
40
    {
41
        LEDdata[byte] |= (1 << bit);
42
    }
43
    HC595write();
44
}
45
46
void StartDefaultTask(void *argument)
47
{
48
    /* init code for USB_DEVICE */
49
    MX_USB_DEVICE_Init();
50
    /* USER CODE BEGIN 5 */
51
    /* Infinite loop */
52
    for(;;)
53
    {
54
        for(int i=87; i>=70; i--)
55
        {
56
            HC595writePin(i, 0);
57
            osDelay(100);
58
        }
59
        osDelay(1000);
60
        for(int i=70; i < 88; i++)
61
        {
62
            HC595writePin(i, 1);
63
            osDelay(100);
64
        }
65
    }
66
    /* USER CODE END 5 */
67
}

von Daniel S. (sany)


Lesenswert?

Hallo Falk,

vielen Dank, habe den Code mal getestet, funktioniert.

habe mal den Code abgeändert, nun funktionierts wie gewollt! :)
1
void HC595write()
2
{
3
  int data;
4
  for(int i=11; i >=  0; i--)
5
  {
6
    data = channelData[i];
7
8
    for(int j=7; j >= 0; j--)
9
    {
10
      if(data & (1<< j))
11
      {
12
        HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_SET);
13
      }
14
      else
15
      {
16
        HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_RESET);
17
      }
18
      HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_SET);
19
      HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_RESET);
20
    }
21
  }
22
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_SET);
23
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_RESET);
24
}

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Daniel S. schrieb:
> Hallo Falk,
>
> vielen Dank, habe den Code mal getestet, funktioniert.
> Jetzt müsste ich nur noch das ganze gedreht bekommen, denn wenn ich Pin
> 1 auf 1 stelle, geht die LED 88 an u.s.w.

Tja, sagte ich ja bereits.

> Über die Bitmanipulation müsste ich doch eigentlich das gedreht
> bekommen?

Jain, man muss die Adressierung der Bytes auch spiegeln.

> Wenn ich meine for-schleife nun aufif(data & (1>> j))
>
> funktionierts leider nicht,

Logisch.

> eigentlich muss ich doch die 1 in die andere
> Richtung schieben mit 1>>j... ?

Das allein reicht nicht.
1
#define LCD_CNT 88
2
#define BYTE_CNT ((LED_CNT+7)/8)
3
4
uint8_t LEDdata[BYTE_CNT];
5
 
6
void HC595write()
7
{
8
    int data;
9
10
    for(int i=BYTE_CNT; i>=0; i--)
11
    {
12
        data = LEDdata[i];
13
        for (int j=7; j >= 0; j--)
14
        {
15
            if(data & (1<<j))
16
            {
17
                HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_SET);
18
            }
19
            else
20
            {
21
                HAL_GPIO_WritePin(SER_GPIO_Port, SER_Pin, GPIO_PIN_RESET);
22
            }
23
            HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_SET);
24
            HAL_GPIO_WritePin(SRCLK_GPIO_Port, SRCLK_Pin, GPIO_PIN_RESET);
25
        }
26
    } 
27
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_SET);
28
    HAL_GPIO_WritePin(RCLK_GPIO_Port, RCLK_Pin, GPIO_PIN_RESET);
29
}
30
31
void HC595writePin(uint8_t pin, uint8_t value)
32
{
33
    int bit, byte;
34
35
    byte = pin / 8;
36
    bit = pin % 8;
37
38
    if (value == 0)
39
    {
40
        LEDdata[byte] &= ~(1 << bit);
41
    }
42
    else
43
    {
44
        LEDdata[byte] |= (1 << bit);
45
    }
46
    HC595write();
47
}
48
49
void StartDefaultTask(void *argument)
50
{
51
    /* init code for USB_DEVICE */
52
    MX_USB_DEVICE_Init();
53
    /* USER CODE BEGIN 5 */
54
    /* Infinite loop */
55
    for(;;)
56
    {
57
        for(int i=0; i<16; i++)
58
        {
59
            HC595writePin(i, 0);
60
            osDelay(100);
61
        }
62
        osDelay(1000);
63
        for(int i=16; i >= 0; i--)
64
        {
65
            HC595writePin(i, 1);
66
            osDelay(100);
67
        }
68
    }
69
    /* USER CODE END 5 */
70
}

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Daniel S. schrieb:
> Wenn ich meine for-schleife nun auf
> if(data & (1>> j))
> funktionierts leider nicht

Versuche morgen nochmal, die Frage neu zu formulieren, so dass sie 
verständlich ist. Bei der Gelegenheit kannst du dann auch eine Skizze 
von der Verschaltung der Schieberegister und deinen LEDs mit Nummern 
nachreichen.

Aber erst morgen!

: Bearbeitet durch User
von Daniel S. (sany)


Lesenswert?

Moin,

Scheinbar war das Forum nicht so schnell, oder ich zu langsam mit 
bearbeiten.

Habe es mir dass bereits so gedreht, wie ich das gebraucht habe, die 
Lösung hat sich eigentlich beim Beitrag schreiben automatisch ergeben 
:-)

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Daniel S. schrieb:
> vielen Dank für eure Hilfe :)

Für die 74HC595 kann man eine SPI-Schnittstelle nehmen, um bequem die 
Daten in die kaskadierten Chips hineinpumpen zu lassen, aber wenn man 
das Bitkippen schon selbst per Software macht oder üben will oder von 
mir aus auch machen muss und sowieso viele Kilobytes an SRAM noch übrig 
hat, kann man z.B. 100 Bytes für ein Bytearray opfern und jeweils nur 
ein Bit in einem Byte speichern, gerne auch an der LSB-Stelle, also im 
Bit 0. Dieser verschwenderische Umgang mit dem SRAM, der am Ende des 
Projekts sowieso ungenutzt im µController liegen würde, erleichtert 
unheimlich die Bitadressierung, also eigentlich dann schon die 
LED-Adressierung, da die LED-Adresse dann dem Index vom Array entspricht 
– demnach wird also auch das Codeschreiben sehr vereinfacht, obendrein 
wird im Hintergrund von der CPU vermutlich alles deutlich schneller 
ausgeführt, da grundsätzlich nur noch mit Bytes hantiert wird.

Man muss halt wissen, wann Sparen angesagt ist und wann aus Komfort- 
oder Geschwindigkeitsgründen das genaue Gegenteil angewandt werden darf 
– bei einem AT89C2051 oder AT89C51 kommt es auf jedes Byte an und dort 
muss man teilweise extrem sparen und oft auch zu Assembler greifen, weil 
auch der Flash relativ kurz ist, beim STM32 ist es Unsinn, krampfhaft 
irgendwelche Bitakrobatik mit Schiebe-, Modulooperationen oder gar 
Divisionen, die quasi mit jedem Schleifendurchlauf ausgeführt werden 
müssen, zu vollführen, wenn man sowieso sehr viel Speicher zur Verfügung 
hat und alles viel einfacher und vermutlich auch übersichtlicher oder 
leserlicher in C gestaltet werden kann. Wie ich bereits woanders mal 
sagte – eine kostbare Ressource, mit der schonend umgegangen werden 
muss, kann immer etwas anderes bedeuten, mal ist es der Speicher, mal 
die Zeit, ein anderes mal etwas ganz anderes oder eine Kombination aus 
allem, aber die wichtigste Ressource eines Homo sapiens ist die 
entsprechend gefaltete und vernetzte Hirnmasse, die es einem ermöglichen 
kann, über den Tellerrand hinauszuschauen und generell einen besseren 
Überblick zu bekommen; ja, zu bekommen, denn dieser wird nicht jedem von 
der geistigen, unsichtbaren Welt gewährt, geschenkt oder erlaubt, sich 
diesen selbst hart erarbeiten zu dürfen.

: Bearbeitet durch User
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.