0% fanden dieses Dokument nützlich (0 Abstimmungen)
6 Ansichten42 Seiten

Chapter 5

Das Dokument beschreibt die Speicherorganisation des 8051/XC888 Mikrocontrollers, der eine Harvard-Architektur mit getrennten Programm- und Datenspeicheradressräumen verwendet. Der XC888 verfügt über 32 kB Flash-Speicher, 256 Byte internes RAM und 1,5 kB externes RAM sowie spezielle Funktionsregister. Zudem werden Konzepte wie Mapping und Paging zur Erweiterung des Adressraums und zur Verwaltung von I/O-Ports erläutert.

Hochgeladen von

wnabdulmustaqim
Copyright
© All Rights Reserved
Wir nehmen die Rechte an Inhalten ernst. Wenn Sie vermuten, dass dies Ihr Inhalt ist, beanspruchen Sie ihn hier.
Verfügbare Formate
Als PDF, TXT herunterladen oder online auf Scribd lesen
0% fanden dieses Dokument nützlich (0 Abstimmungen)
6 Ansichten42 Seiten

Chapter 5

Das Dokument beschreibt die Speicherorganisation des 8051/XC888 Mikrocontrollers, der eine Harvard-Architektur mit getrennten Programm- und Datenspeicheradressräumen verwendet. Der XC888 verfügt über 32 kB Flash-Speicher, 256 Byte internes RAM und 1,5 kB externes RAM sowie spezielle Funktionsregister. Zudem werden Konzepte wie Mapping und Paging zur Erweiterung des Adressraums und zur Verwaltung von I/O-Ports erläutert.

Hochgeladen von

wnabdulmustaqim
Copyright
© All Rights Reserved
Wir nehmen die Rechte an Inhalten ernst. Wenn Sie vermuten, dass dies Ihr Inhalt ist, beanspruchen Sie ihn hier.
Verfügbare Formate
Als PDF, TXT herunterladen oder online auf Scribd lesen

Speicherorganisation 8051/XC888

➢ 8051 Derivate besitzen getrennte Programm- und Daten-


speicheradressräume (→ Havard-Architektur)
➢ Programmcode wird nichtflüchtig im Flash oder ROM abgelegt
➢ Daten werden flüchtig im RAM gespeichert
➢ Bei einigen 8051 Derivaten kann externer Programm- bzw.
Datenspeicher von außen an den Chip angeschlossen werden
(XC888 unterstützt dies nicht)

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 3
Speicherorganisation XC888

Der XC888 besitzt folgende


Speicherbereiche:
• 32 kB Flash Programm Speicher
• 256 Byte internes RAM
• 1,5 kB (On-Chip) externes RAM (XRAM)
• 128 Byte für Special Function Register

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 4
Interner Datenspeicher 8051/XC888

0xFF
➢ Internes RAM hat eine Größe
Special von 256 Byte
RAM Function
Register ➢ Auf internes RAM wird über 8-
(SFR)
Bit-Adressen zugegriffen
0x80
0x7F ➢ Hauptunterteilung:

RAM ➢ 256 Byte RAM


➢ 128 Byte Special Function
0x30
0x2F Register (SFR)
RAM Bit-Adressraum
0x20
0x1F
Registerbänke
0x00

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 6
Interner Datenspeicher 8051/XC888

0xFF
➢4 Registerbänke
Special
RAM Function ➢ Jede Bank besteht aus 8
Register Registern (= 8 Byte).
(SFR)
➢ Bank 0: Bytes 0-7
0x80
0x7F ➢ Bank 1: Bytes 8-15
➢ Bank 2: Bytes 16-23
RAM
➢ Bank 3: Bytes 24-31
0x30
➢ Auswahl Bänke erfolgt über
0x2F
RAM Bit-Adressraum Flags RS0 und RS1 im
0x20
0x1F
Registerbänke
Statusregister
0x00
➢ Nach Reset ist Bank 0 aktiv

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 7
Interner Datenspeicher 8051/XC888

0xFF
➢ Dieser Bereich besteht aus 128
Special direkt adressierbaren Bits (16
RAM Function
Register Byte).
(SFR)
➢ Bits können mittels SETB-
0x80
0x7F
Befehl gesetzt bzw. mittels
CLR-Befehl gelöscht werden
RAM
➢ Die Bits werden über die Bit-
Adressen 0x00 bis 0x7F
0x30
0x2F angesprochen (z.B. setb 0Ah)
RAM Bit-Adressraum
0x20
0x1F
Registerbänke
0x00

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 8
Interner Datenspeicher 8051/XC888

0xFF
➢ Im Adressbereich von 0x30 bis
Special 0x7F liegt ein allgemein
RAM Function
Register nutzbarer Speicherbereich
(SFR)
➢ Der Speicher von Adresse 0x00
0x80
0x7F
bis 0x7F kann sowohl „direkt“
als auch „indirekt“ adressiert
RAM werden (siehe Folie 11)

0x30
0x2F
RAM Bit-Adressraum
0x20
0x1F
Registerbänke
0x00

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 9
Interner Datenspeicher 8051/XC888

0xFF
➢ Im Adressbereich von 0x80 bis
Special 0xFF liegt der obere RAM-
RAM Function
Register Bereich, welcher ebenfalls
(SFR) allgemein genutzt werden kann
0x80
➢ Die Adressierung dieser
0x7F
Speicherstellen erfolgt hier
RAM ausschließlich „indirekt“

0x30
0x2F
RAM Bit-Adressraum
0x20
0x1F
Registerbänke
0x00

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 10
Interner Datenspeicher 8051/XC888

0xFF
➢ Ebenfalls im Adressbereich
Special 0x80 bis 0xFF liegen die
RAM Function
Register sogenannten Special Function
(SFR) Register (SRF)
0x80
➢ Oberer RAM-Bereich und SFR
0x7F
besitzen selben Adressbereich
RAM
➢ Die Bereiche werden über
unterschiedliche Arten der
0x30
0x2F Adressierung angesprochen
RAM Bit-Adressraum
0x20
0x1F ➢ SFR werden „direkt“ adressiert
Registerbänke
0x00
➢ Einige SFR sind zusätzlich noch
bitadressierbar
➢ SFR dienen zur Konfiguration der On-Chip-Peripherie (z.B.
Start/Stop Timer)
20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 11
Interner Datenspeicher 8051/XC888

Beispiel zur indirekten Adressierung des oberen RAM-Bereichs


Aufgabe: Schreibe den Wert 0x55 in den oberen RAM-Bereich an die
Adresse 0x81.
mov r0,#81h ;Lade Register r0 mit dem Wert 0x81
mov @r0,#55h ;Schreibe Wert 0x55 in RAM an Adresse,
;die in r0 gespeichert ist (0x81)

Beispiel zur direkten Adressierung eines SFR


Aufgabe: Beschreibe das SFR mit der Adresse 0x81 (Stack Pointer) mit
dem Wert 0x55.
mov 81h,#55h ;Beschreibe das SFR mit der Adresse
;0x81 (Stack-Pointer) mit dem Wert 0x55
[81]= AA

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 12
Codesegment in Assembly

Variation 1
CSEG AT 0x00 ; Legt folgenden Code auf Codeadresse 0000h
jmp INIT ; Reset-Vektor Springe zum Programmstart
ORG 0x100 ; Platziere folgendes Codesegment 0x100 Bytes
; weiter hinten
INIT:
; Zugriffsbeispiele
mov a, P1_DATA ; P1_DATA in variable_a speichern

Variation 2
RSEG Relocatable Segment überlässt es dem Compiler/Linker

PROGRAMM SEGMENT CODE ; feststellt CodeSegment namens


PROGRAMM
RSEG PROGRAMM ; folgende Codezeilen stellen das Segment
; PROGRAMM dar, die IDE
; darf es "irgendwo" im Flash-ROM
platzieren

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 13
Codesegment in Assembly

CSEG AT 0h ; Legt folgenden Code auf Codeadresse 0000h


jmp INIT ; Reset-Vektor Sprung zum Programmstart
ORG 100h ; Platziere folgendes Codesegment 0x100 Bytes
; weiter hinten
KONST1: DB 0 ; Define constant Byte 0
KONST2: DB 0x55 ; Define constant Byte 55

CS

55

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 14
Datensegment in Assembly

Datensegment
(a)
VARS SEGMENT DATA; Datensegment mit Namen VARS
RSEG VARS ; IDE soll das Segment VARS "irgendwo" im RAM
; platzieren. Folgende Zeilen sind Segment VARS

(b)
DSEG AT 0x40 Legt folgenden Code auf Codeadresse 0x40
VAR_A: DS 1 ; Legt 1 Byte Speicher
VAR_B: DS 4 ; Legt 4 Byte Speicher
STACK: DS 20 ; Legt 20 Byte für Stack

INIT: MOV SP,#STACK ; SP = [STACK]

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 15
Mikrocomputertechnik

Thema:
Mapping & Paging, MMUs
Das Mapping-Konzept des XC888

➢ Aufgrund der Kompatibilität zum 8051 stehen lediglich 128 Byte-


Adressen für SFR zur Verfügung
➢ Adressraum SFR: Intervall [0x80, 0xFF] mit Größe (0xFF-
0x80)+1 = 0x80 = 128
➢ XC800-Derivate benötigen jedoch mehr als 128 SFR
➢ Mittels Mapping-Konzept kann der Adressbereich verdoppelt
werden
➢ Durch Verwendung des zusätzlichen Steuerbits RMAP kann auf
zwei physikalisch getrennte Speicher zugegriffen werden
➢ Bit RMAP ist nicht als Bit ansprechbar → Es muss über
Bitoperation auf zugehöriges SFR SYSCON zugegriffen werden
➢ Hierzu können die Makros SET_RMAP() und RESET_RMAP()
verwendet werden

Folie 17 02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Das Mapping-Konzept des XC888
SFR Data (to/from CPU)

[Link]

0xFF 0xFF
Module 1 SFRs Module (n+1) SFRs

Module 2 SFRs Module (n+2) SFRs


...

...
Module n SFRs Module m SFRs
0x80 0x80
Mapped Area (RMAP = 0) Mapped Area (RMAP = 1)

Folie 18 02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Das Paging-Konzept des XC888

➢ Mapping-Konzept erzielt 256 Bytes → Dies reicht noch nicht aus


➢ Mapping-Konzept: Erweiterung auf Systemebene
➢ Paging-Konzept: Erweiterung auf Modulebene
➢ Module sind z.B. Timer, ADC, Ports, … etc
➢ Modul steht festgelegtes Intervall an Adressen zu
➢ Reichen Adressen nicht aus, so muss Intervall wiederum
mehrfach verwendet werden
➢ Hinter einer Adresse können nochmals mehrere physikalische
Speicherbereiche existieren
➢ Dies bezeichnet man als Paging

Folie 19 02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Das Paging-Konzept des XC888

Folie 20 02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Mikrocomputertechnik

Thema:
Digitale Eingabe- und Ausgabeports
Begriffsabgrenzung I/O-Ports

➢ Pin

➢ Physikalisches „Füßchen“ eines µC


➢ Meist noch Info, welchem SFR das „Füßchen“ zugeordnet ist
➢ Parallel Ports
➢ Jeweils 8 Pins sind zu einem parallelen Port organisiert
➢8 Bits dienen zur Ein- und Ausgabe
➢ Ports

➢ Begriff Ports wird sehr allgemein eingesetzt


➢ Es kann sich um einen parallelen Port aber auch um einen
physikalischen Pin handeln

Folie 22 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
P0.1 Konfiguration: Beispiel

[Link]
[Link]?fileId=db3a304412b407950112b40c4a9e0afb XC888 Datasheet
20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 25
Konfiguration von I/O-Ports

➢ Port als Eingang- bzw. Ausgang: GPIO (GPI, GPO)


➢ GPIO: General Purpose Input/Output
➢ Theoretisch können von den 6 parallelen Ports 40 Port-Pins als
Ausgang oder alle 48 Pins als Eingang verwendet werden
➢ Konfiguration erfolgt über folgende Register
➢ Px_DIR (direction),
➢ Px_OD (open drain),
➢ Px_PUDEN (PullUp, -Down),
➢ Px_PDSEL (PullUp, -Down select)
(x = Port-Nummer)

Folie 26 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Ausgangsports
➢ Potential der Pins kann auf 0V (=log. 0) oder 5V (=log. 1) gelegt werden
➢ Potential am Port-Pin entspricht Wert in Register Px_DATA
➢ Ausgangsschaltungen: Totem-Schaltung oder Open-Drain-Mode
➢ Auswahl mittels Bits in Register Px_OD

Totem-Schaltung Open-Collector-Mode

Folie 27 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Ausgangsports

+ Betriebsspannung wählbar
- Bei „0“ auf Transistorbase, Ausgang
hochohmig

Open-Collector-Mode
Mit Pull-up

Folie 28 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Ausgangsports

- Betriebsspannung des
Microcontroller
+ Niederohmig nach Vcc und gnd

Totem-Schaltung

Folie 29 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Ausgangsports
➢ Mittels Pull-Einheit kann Pull-Up- bzw. Pull-Down-Widerstand hinzugefügt werden
(intern)
➢ Steuerung der Pull-Einheit erfolgt über die folgenden Register:
➢ Px_PUDEN: Pull Device Enable
➢ Px_PUDSEL: Pull-Up/-Down Selection

Px_PUDSEL

Folie 30 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Ausgangsports

02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 31
Eingangsports
➢ Anliegende Spannungen am Eingangsport [0V, 5V] werden auf logisch 0 oder
logisch 1 abgebildet
➢ Realisierung über Schmitt-Trigger:
➢ Wird obere Schaltschwelle überschritten: Eingangs-Bit in Px_DATA = 1
➢ Wird untere Schaltschwelle unterschritten: Eingangs-Bit in Px_DATA = 0
➢ Obere und untere Schaltschwelle sind unterschiedlich (z.B. 2V und 3V) ➔
Schalthysterese
➢ Ist Port als Eingang konfiguriert, ist Ausgangstreiber deaktiviert
➔ Register Px_OD hat daher keine Auswirkung auf Eingang
➢ Pull-Einheit kann auch für Eingänge verwendet werden

Folie 32 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Eingangsports
➢ Eingangswiderstand des Schmitt-Trigger ist hochohmig
➢ Einsatz des Pull-Device kann abhängig von Ausgangsbeschaltung sinnvoll sein

Px_PUDSEL

Folie 33 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Eingangsports
➢ Beispiel: Eingangsport mit Taster an 5V
➢ Schalter geöffnet: Über internen Pull-Down-Widerstand liegt Pegel auf 0V
(log. 0)
➢ Schalter geschlossen: Am Eingang liegen 5V (log. 1)

Px_PUDSEL

Folie 34 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Pull-up und Pull-down Wiederstände

02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 35
Beispiel

[Link]
condition-when-magnet-is-away-left-and_fig12_338100681

[Link]
Magnetic-Contact/dp/B07KP3TGXW

02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 36
Beispiel

Schreiben Sie eine void init() Funktion, die für Port 3 die unteren 4 Leitungen auf Eingang mit Pull-Up und die anderen 4
Leitungen auf Ausgang mit Open Drain Mode setzt.

Abbildung 1: Überblick der Port-Register

02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Prof. G. Raffius
Folie 37
Beispiel

Void init()
{
PORT_PAGE =1;
P3_PUDEN = 0x0F; // Pull up/down enable on für die unteren 4 Leitungen
P3_PUDSEL = 0x0F; // Pull up select für die unteren 4 Leitungen

PORT_PAGE = 3;
P3_OD = 0xF0; // P3 Open Drain für die 4 oberen Leitungen

PORT_PAGE = 0;
P3_DIR
= 0xF0 // unteren 4 Leitungen Eingänge, 4 oberen Leitungen Ausgänge
}

Folie 38 02.09.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Prof. G.
Raffius
Übung Ports

➢ Bitte P3.0 also Eingang mit Pull-up setzen


➢ Bitte P3.0…3 als Ausgang OD setzen
➢ Bitte P3.4…7 als Ausgang totempole setzen
➢ Bitte P2.0 als Eingang mit Pull-up setzen (nur P2.0)

Zu Hause: in Assembler

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 39
7-Segment_Anzeige
• Ziel 7-Segment-Anzeige: Darstellen von Zahlen und Buchstaben

• Anwendung: vielfältig, z.B. Stoppuhr, Wort-/Namensausgabe,…

• 7-Segment-Anzeige stellt Standardbauteil in der MCT dar

a
f b
g

e c
h
d

Folie 40 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
7-Segment_Anzeige
2-fach 7-Segmente Anzeige
mit D-Registern

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 41
7-Segment_Anzeige
• Anschluss der 7-Segment-Anzeige LED-Vorwiderstände

Latch (gesockelt) 7-Segment-Anzeige


Verdrahtung zu Ports

Folie 42 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
7-Segment_Anzeige
Zahlendarstellung auf der 7-Segment-Anzeige
• Mapping Portpin zu Segment in Schematics / Bild ersichtlich
• Wandlung in Hexzahlen sinnvoll in separater Funktion
• lookUp-Prinzip in ‘C‘:

Folie 43 20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Wandlung in Hexzahlen

Char ZifferZuSegment (char Zahl)


{ char anzeige = 0xFF; //alles aus
if (Zahl == 0)
anzeige = 0xC0;
if (Zahl == 1)
anzeige = 0xF9

if (Zahl == 15)
anzeige = 0x8E
return anzeige;
}

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 44
Wandlung in Hexzahlen
Char ZifferZuSegment (char Zahl)
{ switch(Zahl)
{
case 0:

·
{anzeige = 0xC0;
breack;}
case 1:
{anzeige = 0xF9;
breack;}

case 15:
{anzeige = 0x8E;
breack;}
default:
anzeige = 0xFF;
}
return anzeige;
}
20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 45
LookUp-Prinzip
In „C“
unsigned char ZifferZuSegment (unsigned char hexzahl)
{ ·

static const unsigned char AnzeigeArray[] =


{0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};
return anzeigeArray[hexzahl];
}

in Assembler:

Konstanten SEGMENT CODE;


RSEG Konstanten;

AnzeigeArray:
DB 0C0h, 0F9h, 0A4h, 0B0h, 099h, 092h, 082h,
0F8h, 080h, 090h, 088h, 083h, 0C6h, 0A1h, 086h, 08Eh; Amay
……
anzeige: ;// hex anzeige des wertes in R0

mov DPTR, #AnzeigeArray; IIin DPTR wird das erste Segmentgeladen


.
mov A,R0; Ro in ACC laden .

anl A,#0fh; An) AND


= 00000101
00001111
movc A, @A+DPTR; 00000101
….. ret;

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 46
Übung Ports

➢ Schreiben Sie ein Programm, dass mit einer Taste Start eine
Zählschleife startet und mit einer anderen Taste sie stoppt. Bitte
anzeige die 2 stelligen Hex-Wertes auf einer 7 Segment Anzeige

20.08.2014, Prof. J. Wietzke, übernommen und modifiziert aus Vorlagen von Dipl.-Ing.(FH) Ralf Hanke
Folie 47

Das könnte Ihnen auch gefallen