Mikrocontroller: ATtiny13
IDE: Atmel Studio
Ich versuche, eine Hello World-Anwendung zu schreiben, indem ich High auf Port PB4 schreibe.
Das funktioniert gut:
int main(void)
{
DDRB = 0x10;
PORTB = 0x10;
while(1)
{
}
}
Betrachtet man die Definition von DDRB und PORTB, zeigen sie wie erwartet auf 0x17 und 0x18.
Das funktioniert aber nicht:
int main(void)
{
char *dir = (void *)0x17;
char *port = (void *)0x18;
*dir = (unsigned int)0x10;
*port = (unsigned int)0x10;
while(1)
{
}
}
Ist mein Code falsch oder muss ich etwas anderes tun, um Zeiger zu verwenden?
Zeiger sind Zeiger. Das sind sie. Sie werden überhaupt nicht anders behandelt (wie könnte man sie anders behandeln?)
Die Hauptunterschiede zwischen X86 und AVR sind:
Außerdem macht Ihr Code keinen Sinn:
char *dir = (void *)0x17;
Einem Zeichen * eine Leere * zuweisen?
error: invalid conversion from ‘void*’ to ‘char*’
Ich bin im Moment nicht zum Kompilieren des ATTiny13 eingerichtet, also sind diese Nummern alle für den ATMega328p:
Der Zugriff auf DDRB und PORTB führt zu dieser Assembly:
12c: 80 e1 ldi r24, 0x10 ; 16
12e: 84 b9 out 0x04, r24 ; 4
130: 85 b9 out 0x05, r24 ; 5
Der Zugriff auf einen Zeiger auf einen Speicherplatz führt zu dieser Assembly:
12c: 80 e1 ldi r24, 0x10 ; 16
12e: 80 93 17 00 sts 0x0017, r24
132: 80 93 18 00 sts 0x0018, r24
Wie Sie sehen können, sind DDRB und PORTB keine normalen Variablen. DDRB ist definiert als:
#define DDRB _SFR_IO8(0x04)
und PORTB als:
#define PORTB _SFR_IO8(0x05)
_SFR_IO8() ist ein Makro:
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
und _MMIO_BYTE ist:
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
__SFR_OFFSET kann je nach Chip entweder 0 oder 0x20 sein (normalerweise 0x20).
Das muss also bedeuten, dass die Adressen von DDRB und PORTB größer als 0x20 sein müssen.
Beim 328P-Chip ist DDRB 0x04 und PORTB 0x05. Also, Zugriff als 0x24 und 0x25, mit den richtigen Datentypen also:
volatile uint8_t *dir = (volatile uint8_t *)0x24;
volatile uint8_t *port = (volatile uint8_t *)0x25;
*dir = 0x10;
*port = 0x10;
ergibt diese Baugruppe:
12c: 80 e1 ldi r24, 0x10 ; 16
12e: 84 b9 out 0x04, r24 ; 4
130: 85 b9 out 0x05, r24 ; 5
Ähnlich aussehend? Der Compiler hat den 0x20-Offset erkannt, erkannt, dass es sich um SFRs handelt, und die richtigen out
Anweisungen ohne den 0x20-Offset kompiliert.
Der Zugriff auf Ihre Portadressen + 0x20 funktioniert also möglicherweise für ATTiny13.
Wenn man sich nur den ATTiny25 ansieht, DDRB = 0x10
ergibt sich Folgendes:
out 0x17, r24
und der Zugriff auf einen Zeiger an der Adresse 0x37 führt zu:
out 0x17, r24
Das sieht also so aus, als wäre es wahrscheinlich (fügen Sie 0x20 zu Ihrer Zeigeradresse hinzu).
0x0
auf 0x9F
die Register, E / A und SRAM zugegriffen wird. Was sind die anderen Adressräume?volatile
in diesem Fall Qualifizierer erfordern. Warum sollten sie sonst optimiert werden, wenn Sie eindeutig einen expliziten Schreibvorgang durchführen und dies nicht einer extern ausgelösten Funktionalität überlassen haben (die daher dem Compiler so erscheint, als würde sie nie verwendet), wie eine ISR?0x17
und 0x18
stammten aus dem Datenblatt und der Eingabe für das Makro in VS. Ich hätte mir genauer ansehen sollen, was das Makro macht. Was ich nicht verstehe, ist, wie der Compiler erkennen kann, dass es sich um SFRs handelt (was ist ein SFR?) Und den Offset loswerden kann?outportb(0x378, 0x34);
.in
und out
Opcodes für den Zugriff auf einen separaten IO-Bus (es gibt 2 Signale, /MREQ und /IORQ, um die verschiedenen Adressräume auszuwählen).error: invalid conversion from ‘void’ to ‘char*’
" Hier geht es um ein void
, nicht um ein void *
.
Matt Jung
tgun926
Matt Jung
sherrelbc
unsigned int
Besetzungen ergeben keinen Sinn; Die Datenrichtungs- und Portregister sind nur 8 Bit breit. Es ist ziemlich unwahrscheinlich, dass das Ihr Problem ist, aber versuchen Sie es mit dem Castinguint8_t
.tgun926
0x10
ist 8 Bit breit, oder?sherrelbc
uint16_t* dir = DDRB
und dann*dir = (uint8_t) 0x10
.