PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ports nach Bitmaske setzen?



deko
14.09.2012, 19:57
Hallo,
ich habe 20 Bits jedes Bit soll einen Pin zugewiesen werden.

Bsp.
100
1=Bit 1 = PA7 auf high setzen
0=Bit 2 = PA6 auf low setzen
0=Bit 3 = PA5 auf low setzen

Ich suche also eine Funktion die genau das macht.

Wie schreibe ich das möglichst effektiv? Ich hab bisher gedacht jedes Einzelne Bit zu maskieren und in einer if schleife zu prüfen... das muss doch auch einfacher gehen?


Bit1 = PA7
Bit2 = PA6
Bit3 = PA5
Bit4 = PA4
Bit5 = PA3
Bit6 = PA2
Bit7 = PA1
Bit8 = PA0
Bit9 = PC6
Bit10 = PC5
Bit11 = PD7
Bit12 = PD6
Bit13 = PD5
Bit14 = PD4
Bit15 = PD3
Bit16 = PC4
Bit17 = PC3
Bit18 = PC2
Bit19 = PC1
Bit20 = PC0

gruß Daniel

markusj
14.09.2012, 20:54
Hi Daniel,

mal vorweg: Streiche "if-Schleife" aus deinem Wortschatz.

Zu deinem Problem: Wenn du die Belegung nicht ändern kannst, stellt sich nur die Frage, wie hässlich der Code wird. Eine schöne, schnelle und platzsparende Lösung gibt es dann nämlich nicht.

Zerlegen wir das ganze Mal systematisch: Die Bits 1-8 (eigentlich zählt man in der Informatik ab 0 ...) müssen umgedreht werden. Das kann eine kleine Schleife erledigen und ist noch nicht so dramatisch. Das Ergebnis kann dann direkt zugewiesen werden.
Die Bits 9 und 10 bilden zusammen mit den Bits 16-20 eine Sequenz von PC6-PC0, das kann man mit etwas Bitgeschubse auch wieder in ein Byte extrahieren, dann wieder Reihenfolge umdrehen und dem Port C zuweisen.
Bleiben noch die Bits 11 bis 15, die müssen "nur" umgedreht und an die richtige Stelle im Byte geschoben werden.

Bei Port C und Port D sind Bits unbelegt, die wirst du beim Zuweisen an den Port dann ausmaskieren wollen.

mfG
Markus

Ma|2TiNi
14.09.2012, 23:48
Hi Daniel,

sowas macht man am besten mit einer Lookup-Tabelle. Du übergibst der Tabelle die Nummer deines Bits (0..19) und sie liefert dir den PORT bzw. den PIN der angesteuert werden muss.
Dann brauchst du noch eine Methode die PORT, PIN und einen Wahrheitswert übergeben bekommt und den Pin entsprechend ein oder ausschaltet.
Für deinen konkreten Fall könnte es so aussehen:


//uint32_t_Auf_Ports_mappen.c
#include <avr/io.h>


#define ARRAY_LENGTH 20


uint8_t Port_Mask[ARRAY_LENGTH] = {
&PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA,
&PORTC, &PORTC,
&PORTD, &PORTD, &PORTD, &PORTD, &PORTD,
&PORTC, &PORTC, &PORTC, &PORTC, &PORTC
};


uint8_t Pin_Mask[ARRAY_LENGTH] = {
PA7, PA6, PA5, PA4, PA3, PA2, PA1, PA0,
PC6, PC5,
PD7, PD6, PD5, PD4, PD3,
PC4, PC3, PC2, PC1, PC0
};


uint32_t Potenz_Zahlen[ARRAY_LENGTH] = {
1,2,4,8,16,32,64,128,256,512,1024,
2048,4096,8192,16384,32768,65536,131072,262144,524 288
};




int main(void) {
DDRA = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;

uint32_t z = Potenz_Zahlen[2]| Potenz_Zahlen[7] | Potenz_Zahlen[11]; // schaltet bit 2,7 und 11 ein also PORTA.5 , PORTA.7 und PORTD.6

SET_PORTS(z);
}




void SET_PORTS(uint32_t x){
for(uint8_t i = 0; i< ARRAY_LENGTH; i++){
BIT_BOOL_SET(Port_Mask[i], Pin_Mask[i], x & Potenz_Zahlen[i]); // von x bleibt nur das i-te Bit unmaskiert,
// danach ist das int entweder 0 und das Bit muss gelöscht werden
// oder > 0 und dann wird es gesetzt
}
}


inline void BIT_BOOL_SET(volatile uint8_t *target, uint8_t bit, uint32_t b){
if (b>0){
BIT_SET(target, bit);
}else{
BIT_CLEAR(target, bit);
}
}




inline void BIT_SET(volatile uint8_t *target, uint8_t bit){
*target |= (1<<bit);
}




inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit){
*target &= ~(1<<bit);
}


Die wichtige Methode ist hier SET_PORTS der du einen 32-Bit int übergibst die setzt dann die Pins entsprechend in der Reihenfolge wie sie in Port_Mask und Pin_Mask aufgelistet sind.
Das Array Potenz_Zahlen ist nur eine Hilfe um ein bestimmtes Bit in einem Int zu maskieren.

Ich weiß zwar nicht welchen Chip du verwendest und welche Programmiersprache, aber vll hilft es dir trotzdem^^


Gruß Martin

markusj
15.09.2012, 10:22
Das hatte ich zuerst auch in Erwägung gezogen, ist aber deutlich ineffizienter als die direkte Lösung. Außerdem hast du einen kleinen aber fatalen Fehler in deinem Code:
Port_Mask ist nicht vom Typ (uint8_t) sondern vom Typ (volatile uint8_t *).

mfG
Markus

Ma|2TiNi
15.09.2012, 13:05
Ja stimmt, danke für den Hinweis, ich hatte es im Simulator getestet und da ist mit das nicht aufgefallen weil es schien trotzdem zu funktionieren.

Der Vorteil von der Methode ist das man sie immer wiederverwenden kann und nur die beiden Arrays anpassen muss. Aber die Bits da an die richtige Stelle zu schubsen ist natürlich effizienter, da hast du recht.

Gruß Martin

oberallgeier
15.09.2012, 13:37
... Bit zu maskieren und in einer if schleife zu prüfen ... das muss doch auch einfacher gehen? ...Ich nehme mal an, dass sich die Bitmuster immer wieder mal ändern. In einer Matrix von 10 x 12 LEDs (in einem LED-PingPong-Spiel) hatte ich verschiedene Muster mithilfe von Schleifen an- und ausgeknippst. Für Deine Aufgabe könnte das so aussehen:

// ........
#define SetBit(ADDR,BIT) ((ADDR) |= (1<<(BIT))) // Setzt Bit
#define ClrBit(ADDR,BIT) ((ADDR) &= ~(1<<(BIT))) // Löscht Bit
#define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
// ........
volatile int8_t Byte_A; //
volatile int8_t portpin; // Pinadressierung (im Port A)
// ........
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ........
// Mal beispielsweise (m)ein Musterbyte für die ersten acht Bits
Byte_A = 0b00110000; // Ist natürlich dasselbe wie Byte_A = 48,
// sieht für mich aber "deutlicher" aus
// ... dabei stehen hier
// das Bit 1 als LSB (gaaanz rechts) und Bit 8 als MSB (gaaanz links)
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ........
// Jetzt fragen wir mal acht bits ab und setzen die Portpins

for (uint8_t loopus = 0; loopus <= 7; loopus++)
{
portpin = 7 - loopus; // Brauchen wir zur Pinadressierung im Port A
ClrBit (PORTA, nmbrbit) // Pinn mal auf low setzen
if (IsBitSet (Byte_A, loopus)) // Abfrage des tatsächlichen Bits und
SetBit (PORTA, nmbrbit) // .. wenn das "1" ist - Pin auf high
} // Ende for (uint8_t loopus ,,,
// ........

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Die Bittabelle wie oben geschrieben:
Bit1 = PA7
Bit2 = PA6
Bit3 = PA5
Bit4 = PA4
Bit5 = PA3
Bit6 = PA2
Bit7 = PA1
Bit8 = PA0
....
Für die einzelnen/anderen Ports ist der Start- und Endwert der Laufvariablen und die Rechenvorschrift für die Pinnummer den Gegebenheiten anzupassen.

Natürlich ist das nix für Leute, die keine Schleifen mögen.