Publicado el 13 de Octubre del 2019
1.134 visualizaciones desde el 13 de Octubre del 2019
818,8 KB
60 paginas
Creado hace 15a (24/02/2010)
LENGUAJE C
LENGUAJE C
PARA SISTEMAS DEDICADOS
PARA SISTEMAS DEDICADOS
FUNDAMENTOS
FUNDAMENTOS
Computadora
Se dispone de un S.O.
El S.O. inicia y configura los periféricos.
El S.O. brinda al usuario subrutinas para utilizar los
periféricos ( system calls ).
Microcontrolador
No posee un S.O.
El firmware debe iniciar los periféricos.
El usuario debe crear sus propias subrutinas para
utilizar los periféricos.
En lenguaje C para sistemas
dedicados no podemos hacer:
printf(“Hola Mundo”);
Llamada a la función main
A pesar que main es el punto de entrada
al programa, el firmware realiza tareas
previas a main. Entre ellas.
Cargar registros de configuración.
Limpiar zonas de RAM.
Cargar el puntero de pila SP.
Código en ensamblador
ORG
$EE00
…configuraci
configuracióónn de los
de los perif
perifééricos
ricos……
….
BRA
$
Código en C
ORG
$EE00
…código de inicialización…
CALL/JMP
main
main(void)
…código escrito por el usuario…
while(1)
{
}
void
{
}
Recursos
Recursos
Arquitecturas de memoria
Modelo tiny ( Freescale )
MOV PORTA,PORTB
Modelo small ( Freescale )
LDA PORTA
STA var1
Pasaje de parámetros
Al igual que en un computadora, la pila se
utiliza para el pasaje de parámetros:
int
funcion(char a, int b, float c,….)
Ejemplo de pasaje de parámetros
usando la pila
void main(void)
{
int
dunga, donga;
dunga = 3;
donga = 5;
dunga = suma(dunga, donga);
donga = resta(dunga, donga);
}
int sum(int s1, int s2)
{
return s1 + s2;
}
int
{
}
resta(int r1, int r2)
return r1 – r2;
Pasaje de parámetros usando la pila
Ventajas:
Al retornar de la
función se libera el
espacio de memoria.
Desventajas:
Llamados anidados
a funciones pueden
limitar la RAM libre.
Uso del heap
Se hace declarando variables estáticas
externas, mas conocidas como
VARIABLES GLOBALES.
Ejemplo de pasaje de parámetros
usando el heap
iInt dunga, donga;
void main(void)
{
dunga = 3;
donga = 5;
suma();
resta();
}
int suma(void)
{
dunga = dunga + donga;
resta(void)
dunga = dunga - donga;
}
int
{
}
Pasaje de parámetros usando el
heap
Ventajas:
Pueden anidarse los
llamados a funciones
sin que crezca la pila
enormemente.
Desventajas:
La memoria usada
en el heap no puede
liberarse.
Uso de las funciones recursivas
factorial(int n)
void
{
if(n == 1)
return 1;
return factorial(n-1) *
else
n;
}
factorial(8);
Variables
Variables
Tipos de datos básicos
En PC:
char: 1 byte
int: 2 ó 4 bytes
float: 4 bytes
En microcontroladores:
char: 1 byte
int: 2 bytes
float: 4 bytes
Variantes de los tipos básicos
Se admiten los modificadores signed y
unsigned.
También los modificadores short y long.
El float puede no estar contemplado en
versiones gratuitas de los compiladores.
Operaciones básicas
Aritméticas
Suma +
Resta –
Multiplicación *
División /
Resto %
Lógicas
AND &
OR |
XOR ^
No necesariamente existe en
ensamblador una instrucción
para realizar cierta operación
aritmética. Ej: Los PIC 16F no
cuentan con instrucciones de
multiplicación.
En ese caso el compilador debe
generar un algoritmo en assembler
que ejecute esa operación.
Alternativas al tipo float
En general queremos representar cifras
del tipo: 20,3 mV
Se trata de un número decimal de punto
fijo.
Tampoco se dispone de representación
en punto fijo.
Solución:
Trabajar las mangintudes
multiplicadas x10, x100, …
La cifra 20,3 se almacena como
203. Así puede contenerse en un
tipo int.
Manejo de bits como variables
Es válida aplicar una asignación a un bit.
Son válidas las operaciones lógicas
entre bits |, & y ^.
Ejemplos:
Freescale:
PTAD_PTAD4 = 1;
PIC:
PORTBbits.RB4 = 0;
Volatile
Código en C
void findecuenta(void)
{
…
if(time == 100)
{
time = 0;
…
}
}
Posible compilación en
ensamblador:
findecuenta:
LDA
…
CMP
BNE
CLR
…
time
#!100
…
time
Volatile
Si time no cambia antes del if, la
compilación anterior es válida.
Si time proviene del módulo timer puede
modificarse entre que es cargada y el if.
Solución
Código en C:
volatile
int time;
Compilación en
ensamblador:
void findecuenta(void)
{
findecuenta:
…
LDA
CMP
BNE
CLR
time
#!100
…
time
…
if(time == 100)
{
time = 0;
…
}
}
Reseña de punteros
Se declaran y usan de la forma
convencional:
*p;
int
char *p;
int
hola;
p= &hola;
*p = 3;
( hola = 3 )
Punteros a RAM
int
int
hola;
*p;
p = &hola;
*p = 3;
p apunta a una posición en RAM.
Punteros a ROM
char
char
*p;
texto[20] = “Hola mundo”;
p = texto;
p apunta a una posición en ROM (FLASH).
Arquitectura Von Neumann
( Freescale )
La RAM y ROM están en un
mismo mapa. Pueden accederse
por una única clase de punteros.
Arquitectura Harvard ( PIC )
La RAM y ROM están en mapas
diferentes. Se deben indicar a que
mapa apunta el puntero.
Punteros en micros Hardvard
Punteros a RAM:
char
char
p = &hola;
hola;
*p;
Punteros a ROM:
const char rom
char
rom *p;
p = texto;
texto[20] = “me duermo”;
Entrada y salida
Entrada y salida
En la computadora
Acceso al I/O de entrada:
a = getch();
Acceso al I/O de salida:
printf(“Hola mundo”);
Sistema dedicado
Crear bibliotecas de funciones:
LCD_printf(char *texto);
LCD_Dato(char caracter);
LCD_gotoxy(char x, char y);
sprintf resuelve todo
Genera textos.
Convierte datos int a
BCD.
Convierte datos float
a BCD.
Permite generar
salidas en formatos
muy complejos.
sprintf(texto,
“Chau”);
sprintf(texto, “%d”,
a);
sprintf(texto, “%f”, d);
sprintf(texto, “V =
%02.1f mV”, voltios);
Uso de los puertos de E/S
Acceso a pines individuales:
struct
{
byte PTAD0:1
byte PTAD1:1
byte PTAD2:1
byte PTAD3:1
byte PTAD4:1
byte PTAD5:1
byte PTAD6:1
byte PTAD7:1
}Bits;
Bits.PTAD0 = 1;
Mas sobre puertos
Acceso a todo el puerto:
union
Byte;
byte
byte
byte
byte
byte
byte
byte
byte
typedef
{
byte
struct
{
}Bits;
}PTADSTR;
PTAD0:1
PTAD1:1
PTAD2:1
PTAD3:1
PTAD4:1
PTAD5:1
PTAD6:1
PTAD7:1
PTADSTR.Byte = 0xff;
PTADSTR.Bits.PTAD0 = 1;
PTAD_PTAD0 = 1;
Manejo de periféricos
En PC usando system calls.
En microcontroladores:
Freescale:
Asistentes de configuración ( Processor Expert )
Funciones de biblioteca.
En PIC:
Bibliotecas.
Processor Expert
Permite configurar
cualquier módulo del
microcontrolador.
Processor Expert
Pueden configurarse
todos los parámetros
del módulo.
Processor Expert
Genera el código de
inicialización
Genera funciones
para el manejo de
módulo.
Genera vectores de
interrupción.
Bibliotecas para PIC
A/D
Comparador
EEPROM
I2C
PWM
…
Temporizacióónn
Temporizaci
Demoras cortas
Intercalando código en ensamblador:
unsigned char
contador_1;
asm
{
LDA #$32
STA contador_1
dem_100us_1:
NOP
NOP
NOP
Ttotal = 50 x 2µs = 100µs
Tint = 10 ciclos x 200ns = 2µs
DBNZ
}
contador_1,dem_100us_1
Demoras largas
Intercalando código en ensamblador:
unsigned char contador_1;
unsigned char contador_2;
unsigned char contador_3;
for(contador_3 = 0; contador_3 < 100;
contador_3++)
for(contador_2 = 0; contador_2 < 20;
contador_2++)
asm
{
LDA #$C8
STA contador_1
{
dem_1s_1:
NOP
NOP
NOP
DBNZ contador_1,dem_1s_1
}
}
Ttotal = 100 x 10ms = 1s
Text = 20 x 500µs = 10ms
Tint = 250 x 2µs = 500µs
Demoras largas
Módulo timer con interrupciones:
main(void)
void
{
TI1_SetPeriodSec(1);
}
ISR(TI1_Interrupt)
{
(void)TPM1C0SC;
TPM1C0SC = 0x80;
(código del usuario)
}
Código bloqueante
Durante el llamado a una función el programa
no continúa su ejecución hasta retornar de
ella.
Ej:
void main(void)
{
demora_seg(1);
}
Código no bloqueante
El programa puede continuar con otras tareas mientras una función no
entregue los resultados deseados.
main(void)
Ej:
void
{
…
}
ISR(TI1_Interrupt)
{
(void)TPM1C0SC;
TPM1C0SC = 0x80;
(código del usuario)
}
Timer tick de la PC
void __fastcall TForm1::Timer1Timer(TObject
*Sender)
{
}
( código del usuario )
Produce
interrupciones cada
1ms.
El usuario puede
generar eventos por
timer tick.
El usuario no debe
atender la
interrupción.
Eventos de timer con
microcontroladores
La velocidad del
timer tick es
determinada por el
firmware.
void TI1_OnInterrupt(void)
{
( código del usuario )
}
Pueden generarse
eventos por timer
tick.
El usuario no debe
atender la
interrupción.
Interrupciones
Interrupciones
Arquitectura PIC
Existen 1 ó 2 vectores
de interrupción.
El usuario debe
determinar con un if que
periférico disparó la
interrupción.
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm
GOTO low_isr
_endasm
}
#pragma code
#pragma interruptlow low_isr
void low_isr(void)
{
}
Arquitectura Freescale
El Processor Expert resuelve buena
parte del código.
Existen vectores independientes para
cada evento y periférico.
El usuario no debe atender una
interrupción. El Processor Expert genera
el código que lo hace.
Evento de conversión A/D
word AD1_OutV;
ISR(AD1_Interrupt)
{
((TWREG*)(&AD1_OutV))->b.high = ADC1RH;
((TWREG*)(&AD1_OutV))->b.low = ADC1RL;
Out
Comentarios de: Lenguaje C para sistemas dedicados (0)
No hay comentarios