You are on page 1of 21

CARRERA: Ingenieria en Sistemas Computacionales V Semestre MATERIA: Arquitectura de Computadoras Unidad IV Microcontroladres

UNIDAD IV MICROCONTROLADORES

1.- QUE ES UN MICROCONTROLADOR? Es un circuito integrado programable, capaz de ejecutar las rdenes grabadas en su memoria. Est compuesto de varios bloques funcionales, los cuales cumplen una tarea especfica. Un microcontrolador incluye en su interior las tres unidades funcionales principales de una computadora: unidad central de procesamiento, memoria y perifricos de entrada y salida. EN ARQUITECTURA DE COMPUTADORAS: Bsicamente existen dos arquitecturas de computadoras, y por supuesto, estn presentes en el mundo de los microcontroladores: Von Neumann y Harvard. Ambas se diferencian en la forma de conexin de la memoria al procesador y en los buses que cada una necesita. La arquitectura Von Neumann es la que se utiliza en las computadoras personales, para ella existe una sola memoria, donde coexisten las instrucciones de programa y los datos, accedidos con un bus de direccin, uno de datos y uno de control. Debemos comprender que en una PC, cuando se carga un programa en memoria, a ste se le asigna un espacio de direcciones de la memoria que se divide en segmentos, de los cuales tpicamente tenderemos los siguientes: cdigo (programa), datos y pila. Es por ello que podemos hablar de la memoria como un todo, aunque existan distintos dispositivos fsicos en el sistema (HDD, RAM, CD, FLASH). En el caso de los microcontroladores, existen dos tipos de memoria bien definidas: memoria de datos (tpicamente algn tipo de SRAM) y memoria de programas (ROM, PROM, EEPROM, flash u de otro tipo no voltil). En este caso la organizacin es distinta a las de las PC, porque hay circuitos distintos para cada memoria y normalmente no se utilizan los registros de segmentos, sino que la memoria est segregada y el acceso a cada tipo de memoria depende de las instrucciones del procesador. A pesar de que en los sistemas integrados con arquitectura Von Neumann la memoria est segregada, y existan diferencias con respecto a la definicin tradicional de esta arquitectura; los buses para acceder a ambos tipos de memoria son los mismos, del procesador solamente salen el bus de datos, el de direcciones, y el de control. Como conclusin, la arquitectura no ha sido alterada, porque la forma en que se conecta la memoria al procesador sigue el mismo principio definido en la arquitectura bsica. Esta arquitectura es la variante adecuada para las PC, porque permite ahorrar una buena cantidad de lneas de E/S, que son bastante costosas, sobre todo para aquellos sistemas como las PC, donde el procesador se monta en algn tipo

de zcalo alojado en una placa madre. Tambin esta organizacin les ahorra a los diseadores de motherboards una buena cantidad de problemas y reduce el costo de este tipo de sistemas. Algunas familias de microcontroladores como la INTEL-51 y la Z80 implementan este tipo de arquitectura, fundamentalmente porque era la utilizada cuando aparecieron los primeros microcontroladores. La otra variante es la arquitectura Harvard, y por excelencia la utilizada en supercomputadoras, en los microcontroladores, y sistemas integrados en general. En este caso, adems de la memoria, el procesador tiene los buses segregados, de modo que cada tipo de memoria tiene un bus de datos, uno de direcciones y uno de control. La ventaja fundamental de esta arquitectura es que permite adecuar el tamao de los buses a las caractersticas de cada tipo de memoria; adems, el procesador puede acceder a cada una de ellas de forma simultnea, lo que se traduce en un aumento significativo de la velocidad de procesamiento, tpicamente los sistemas con esta arquitectura pueden ser dos veces ms rpidos que sistemas similares con arquitectura Von Neumann. La desventaja est en que consume muchas lneas de E/S del procesador; por lo que en sistemas donde el procesador est ubicado en su propio encapsulado, solo se utiliza en supercomputadoras. Sin embargo, en los microcontroladores y otros sistemas integrados, donde usualmente la memoria de datos y programas comparten el mismo encapsulado que el procesador, este inconveniente deja de ser un problema serio y es por ello que encontramos la arquitectura Harvard en la mayora de los microcontroladores. Por eso es importante recordar que un microcontrolador se puede configurar de diferentes maneras, siempre y cuando se respete el tamao de memoria que este requiera para su correcto funcionamiento.

2.- DIFERENCIA ENTRE UN MICROCONTROLADOR Y UN MICROPROCESADOR: La configuracin mnima bsica de un Microprocesador esta constituida por un Micro de 40 Pines, Una memoria RAM de 28 Pines, una memoria ROM de 28 Pines y un decodificador de direcciones de 18 Pines. Microcontrolador incluye todo estos elementos del Microprocesador en un solo Circuito Integrado por lo que implica una gran ventaja en varios factores: En el circuito impreso por su amplia simplificacin de circuitera. El costo para un sistema basado en Microcontrolador es mucho menor, mientras que para del Microprocesador, es muy alto en la actualidad. Los Microprocesadores tradicionales se basan en la arquitectura de Von Newmann, mientras que los microcontroladores trabajan con arquitectura de harvard. El tiempo de desarrollo de su proyecto electrnico es menor para los Microcontroladores.

Se puede observar en las grficas # 2 y 6, que la principal diferencia entre ambos radica en la ubicacin del registro de trabajo, que para los PICs se denomina W (Working Register), y para los tradicionales es el Acumulador (A). En los microcontroladores tradicionales todas las operaciones se realizan sobre el acumulador. La salida del acumulador esta conectada a una de las entradas de la Unidad Aritmtica y Lgica (ALU), y por lo tanto este es siempre uno de los dos operandos de cualquier instruccin, las instrucciones de simple operando (borrar, incrementar, decrementar, complementar), actan sobre el acumulador. En los microcontroladores PIC, la salida de la ALU va al registro W y tambin a la memoria de datos, por lo tanto el resultado puede guardarse en cualquiera de los dos destinos. La gran ventaja de esta arquitectura(Microcontroladores ) es que permite un gran ahorro de instrucciones ya que el resultado de cualquier instruccin que opere con la memoria, ya sea de simple o doble operando, puede dejarse en la misma posicin de memoria o en el registro W, segn se seleccione con un bit de la misma instruccin . Las operaciones con constantes provenientes de la memoria de programa (literales) se realizan solo sobre el registro W. PROYECTOS DE APLICACIN EN MICROCONTROLADOR PIC Y MICROCONTROLADOR ATMEL ESQUEMA

El sensor ms econmico y que adems no provoca falsas alarmas, es un simple interruptor magntico, el cual es un simple interruptor que es accionado por un imn. El ms usual es el de superficie, en donde queda el dispositivo visible, delatando que disponemos de algn sistema de seguridad.

Para los que deseen mantener la alarma completamente camuflada pueden disponer el sensor de empotrar, el cual incluso resulta muy cmoda su colocacin, ya que solo es necesario hacer un taladr para su instalacin. Para controlar varios accesos solo es necesario conectar varios de estos interruptores magnticos en serie, o incluso podemos realizar una proteccin mediante un fino hilo de cobre, el cual se rompa al forzar alguna puerta o ventana. Tambin podemos utilizar como sonda un simple termostato, para avisarnos de exceso de temperatura, o bien para indicarnos que haya algn problema en una cmara de refrigeracin.
Interruptor magnetico de superficie interruptor magnetico de empotar

Por si a alguien aun le queda alguna duda de la forma de conectar el circuito, en este diagrama se aprecia todo el conjunto.

Temporizador programable - interruptor cclico con rel


Este equipo produce una salida a rele ciclica y programable en 16 escalones mediante la actuacion de 4 microinterruptores. Las aplicaciones de este tipo de circuitos puede ser muy amplia: disparador automatico para realizar fotografias, actuador de electrovalvuilas de agua para el control de la humedad o refrescar el ambiente, control de circuitos de ozono para desconectarlos periodicamente, accionar bombas de agua durante un instante para evitar que estas se queden agarrotadas y terminen estropeandose, etc, etc. El circuito incorpora un led,el cual esta parpadeando cuando la salida esta inactiva, y prende fijo cuando la salida esta activada. Bajo demanda se pueden cambiar los tiempos de funcionamiento para que el circuito se adapte a cualquier aplicacion. Este circuito esta basado en un microcontrolador pic de tan solo 8 pines y bajo coste, el cual dispone de oscilador interno de 4Mhz, con el que podemos obtener tiempos muy precisos, con tan solo un error del 1%. Como se puede apreciar en el esquema el diseo queda muy reducido.

Prestar atencion al esquema ya que el rele es de 9v, ya que corresponde con la tension del transformador de 9v. Perfectamente se pueden sustituir el rele y transformador por 12v.

Disposicion de los componentes sobre la placa de circuito impreso.

En esta posicin estan todos en ON(cero)

En esta posicin todos en OFF (quince)

Hay que prestar atencion ala hora de realizar el PCB, ya que esta imagen esta vista desde la parte de los componentes.

MICROCONTROLADORES ATMEL INTRODUCCION


El AVR fue diseado para la ejecucin de programas escritos en cdigo C compilado. Por lo tanto, algunas instrucciones no estn; por ejemplo, no existe la instruccin 'suma inmediata' ('add immediate'), ya que la instruccin 'resta inmediata' ('substract immediate') con el complemento a dos puede ser usada como alternativa. La familia de microcontroladores AVR es bastante extensa y todas comparten el mismo ncleo AVR, pero tienen distintos perifricos y cantidades de RAM y ROM: desde el microcontrolador de la familia Tiny AVR ATtiny11 con 1kB de memoria flash y sin RAM (slo los 32 registros), con un encapsulado de 8 pines, hasta el microcontrolador de la familia Mega AVRATmega2560 con 256kB de memoria flash, 8kB de memoria RAM, 4kB de memoria EEPROM, conversor anlogo digital de 10 bits y 16 canales, temporizadores, comparador analgico, etc. Cada componente de la familia se ha diseado para que guarde cierta compatibilidad con el resto. Los microcontroladores AVR permiten la ejecucin de instrucciones mediante la metodologa 'pipeline' con dos etapas (cargar y ejecutar), que les permite ejecutar la mayora de las instrucciones en un ciclo de reloj, lo que los hace relativamente rpidos entre los microcontroladores de 8 bits. Como una primera sntesis, podemos decir que el set de instrucciones de los AVR es bastante regular, teniendo en cuenta las siguientes consideraciones: Los registros punteros X, Y y Z tienen capacidades de direccionamiento diferentes entre s. Los registros 0 al 15 tienen diferentes capacidades de direccionamiento que los registros 16 al 31. Las registros de I/O 0 al 31 tienen distintas caractersticas que las posiciones 32 al 63. La instruccin CLR afecta los 'flag', mientras que la instruccin SER no lo hace, a pesar de que parecen ser instrucciones complementarias (dejar todos los bits en 1, y dejar todos los bits en 0 respectivamente). Los cdigos de operacin 0x95C8 y 0x9004 hacen exactamente lo mismo (LPM).

Los Microcontroladores AVR


La empresa Atmel ha desarrollado una gran cantidad de microcontroladores en diferentes gamas, de forma similar a lo que ha hecho la empresa Microchip con nuestros viejos amigos: los PICs. Quiz, el ms popular es el ATMEL AT90S1200, que es algo as como el 16F84 de Microchip (en cuanto a popularidad se refiere). A continuacin se realiza algunos datos comparativos entre el AT90S1200 y el PIC16F84: N de instrucciones: AVR - 89, PIC - 35 Registros RAM: AVR - 32, PIC - 68 Velocidad: AVR - 12MHz, PIC: 20MHz Memoria de Programa: AVR - 1kByte FLASH (512 lneas de programa, 16bits por inst.), PIC:1kx14 (1024 lneas de programa de 14 bit cada una). Memoria EEPROM libre: AVR - 64Bytes, PIC - 64Bytes Salidas: AVR - 15, PIC - 13 TIMER: AVR - 1 de 8bit (con prescaler desde CK hasta CK/1024), PIC - 1 de 8 bit (con prescaler desde 1:2 hasta 1:256) Comparador Analgico (NO ADC): AVR - 1 PIC - NO POSEE Watchdog: Ambos poseen Oscilador interno: Ambos poseen, en el AVR slo habilitable con programacin paralela Niveles de pila (STACK): AVR - 3, PIC - 8 Interrupciones: AVR - reset, interna, externa, timer y por comparador analgico, PIC 5 interrupciones Bsicamente, los AVR tienen 3 registros para cada puerto de salida a saber: DDRB - Sirve para decir qu patas son de entrada o salida, 0 es entrada, 1 es salida (es inverso a los PIC). PINB - Registro que sirve para entradas solamente. PORTB - Registro que sirve para salidas solamente. Esto significa que para leer una entrada se debe usar el registro PINB mientras que para escribir datos en una salida se debe emplear el registro PORTB (obviamente si hacemos referencia a las patas del puerto B). En el ATMEL AT90S1200 el PortB tiene 8 bits de datos, a diferencia del PORTD que tiene slo 7. El bit 7 del PORTD no se emplea; PORTD tambin consta de 3 registros: DDRD, PORTD y PIND. CARACTERISTICAS: Alto desempeo, baja potencia. Arquitectura RISC avanzada: -120 instrucciones poderosas, la mayora con ejecucin de un solo ciclo de reloj. -32x8 registros de trabajo de propsito general. -operacin totalmente esttica.

Programa y Memoria de Datos no voltiles: -2/4/8 kbytes de Memoria Flash Programable en el sistema, con duracin: 10000 ciclos de escritura/borrado. -128/256/512 bytes de EEPROM programable en el sistema, con duracin: 100000 ciclos de escritura/borrado. -128/256/512 bytes de SRAM interna. -Cerrojo de programacin para autoprogramar la Memoria Flash y Seguridad de Datos de EEPROM.

CARACTERISTICAS PERIFERICAS
-Contador/Temporizador de 8 bits con Prescaler y dos canales PWM. -Contador/Temporizador de Alta Velocidad de 8 bits con Prescaler separado: Dos Salidas PWM de Alta Frecuencia con Registros de Comparacin de Salida separados. Generador Programable de Tiempo Muerto. -Interfaz Serie Universal con Detector de Condicin de Comienzo. -ADC de 10 bits: Cuatro Canales de Una Sola Salida. Dos Pares de Canales ADC Diferenciales con Ganancia Programable (1x, 20x). -Temporizador Programable de Vigilancia con Oscilador separado dentro del integrado. -Comparador Analgico dentro del integrado.

CARACTERISTICAS ESPECIALES DEL MICROCONTROLADOR -Sistema de Depuracin debugWIRE dentro del integrado. -Programable dentro del Sistema a travs del Puerto SPI. -Fuentes de Interrupcin Externas e Internas. -Modos de Descanso en Baja Potencia, de Reduccin de Ruido de ADC, y de Reduccin de Potencia. -Circuito Mejorado de Reinicializacin de Encendido. -Circuito Programable de Deteccin de Brown-out (estado en que la tensin es entre un 8 y un 12% inferior al valor tpico) . -Oscilador Calibrado interno.

PROGRAMADOR DE E2PROM AT28C64B El programador de memoria EEPROM At28c64B es un simple programador, basado en un diseo conocido, utiliza un microcontrolador At89c51 puede ser tambin el AT89C52 es indiferente, el Cristal debe ser si o realizar la comunicacin serial con la computadora.

DIAGRAMA DEL CIRCUITO El circuito que se ve a continuacin puede ser modificado para otras memorias Atmel como se la at28c16, at28c128, etc. Todas estas memorias tienen el mismo tipo de programacin pero distinta cantidad de memoria por lo que se debe solamente cambiar el bus de direcciones conectadndo 1 pin mas o retirando el mismo.

CODIGO FUENTE DEL PROGRAMA


;----------------------------------------------------------ban_rx BIT 0 RX EQU r3 tx EQU 22h ; aux EQU 23h n EQU 32h CE equ P3.7 OE equ P3.6 WE equ P3.5 datos equ P0 ;----------------------------------------------------------; VECTORES DE INTERRUPCION ;----------------------------------------------------------ORG 0000H ; encendido o reset jmp reset ORG 0003H ; external interrupt 0 reti ; ORG 000BH ; timer 0 overflow vector reti ; ORG 0013H ; external interrupt 1 vector reti ; ORG 001BH ; timer 1 overflow vector reti ; ORG 0023H ; serial I/O interrupt vector jb TI,no_chksum mov RX,SBUF setb ban_rx ; se ha resibido clr RI no_chksum: reti ; ;----------------------------------------------------------; PROGRAMA PRINCIPAL ;----------------------------------------------------------ORG 050h reset: call serial_9600 ;9600 baudios mov clr case: call call call conectar write read rx,#'n' ban_rx ; no hay RX 'n' ; no RX

jmp case ;----------------------------------------------------------------; configurar el puerto serial ;----------------------------------------------------------------serial_9600: ; inicia el puerto serie ; parauso con un oscilador de 11.0592Mhz ; para 9600 baudios

MOV SCON,#050H ;RX habilitada SETB ES ;interrupcion serial SETB EA ;interrupcion global SETB PS ;prioridad puerto serie alta MOV TMOD,#20H ;TIMER 1 MODO AUTORECARGA MOV TH1,#0fDH ;CARGA PARA 9600 BAUDIOS SETB TR1 ;INICIO DEL TIMER 1 clr ri clr ti ret ;----------------------------------------------------------------; Conectar a la pc configurara tiempo de tx ;----------------------------------------------------------------conectar: cjne Rx,#'c',fin_conectar mov tx,#'c' call tx_ mov rx,#'n' fin_conectar: ret ;----------------------------------------------------------------; Gravar en la memoria EEPROM ;----------------------------------------------------------------write: cjne RX,#'w',fin_write call iniciar falta_write: call sidale mov a,rx call write_at28c64b ; B,C <-- write(A) inc r0 inc dptr mov a,r0 cjne a,n,falta_write mov tx,rx call tx_ mov rx,#'n' fin_write: ret ;----------------------------------------------------------------; iniciar las direcciones ;----------------------------------------------------------------iniciar: call sidale ; n <-- sidale(rx) mov n,rx call sidale mov dph,r call sidale mov dpl,rx call sidale mov a,rx mov r0,a ret ;----------------------------------------------------------------; Read = lectura de la memoria EEPROM ;-----------------------------------------------------------------

read: cjne RX,#'r',fin_read call iniciar mov tx,rx call tx_ falta_read: call rx_ mov a,rx acall read_at28c64b mov tx,a acall tx inc r0 inc dptr mov a,r0 cjne a,n,falta_read fin_read: ret ;----------------------------------------------------------------; <-- sidale(rx= #'s') ; se responde a la computadora que ella puede enviar otro dato ;----------------------------------------------------------------sidale: mov tx,rx call tx_rx ret ;----------------------------------------------------------------; TX_rx programa que transmite el dato de TX ; espera un tiempo "delay" para recibir en RX seteando la bandera de recepcion ;----------------------------------------------------------------tx_rx: acall tx_ ; lo transmito acall rx_ ; espero recibir el mismo ret ;---------------------------------------------------------TX_: clr ri clr ti mov sbuf,tx falta_tx: jnb TI,falta_tx clr TI ret ;---------------------------------------------------------RX_: clr ban_rx clr ri no_rx: nop jnb ban_rx,no_rx clr ban_rx ; espero otro dato ret ;---------------------------------------------------read_at28c64b: ; clr We ; setb Ce ; setb Oe

mov p1,dpl mov p2,dph mov P0,#0ffh clr Ce nop clr Oe nop setb We nop ; 1 us mov a,p0 ret ;---------------------------------------------------write_at28c64b: mov p0,a mov p1,dpl mov p2,dph setb Oe clr Ce setb We nop clr We nop setb We nop ; clr Oe ; nop ret end

PLACAS DEL CIRCUITO


Circuito completo

Parte debajo de la placa (lado de la soldadura)

Parte de arriba de la placa(lado de los componentes y los puentes)

TERMOMETRO DIGITAL DS1620 CON ATMEL AT89Cxx Diagrama del circuito Este sensor de temperatura se lee serialmente a travs de su bus I2C.

Cdigo fuente del programa


; esta es la conexin de pines entre el ds1620 y el at89c52 displays equ p0 dq equ p3.2 clk equ p3.3 rst equ p3.4 t equ 3ah auxa equ 3bh n_hex equ 3ch nh equ 3dh signo equ 3eh ; ------------------- -------------------; reset ; vector de interrupcion del reset org 000h ; localidad de interrupcion reset ajmp start ; saltar a inicio ; ---------------------------------------; interrupciones (no usadas) ; ------------------- --------------------

org 03h ; interrupcion externa 0 reti org 0bh ; interrupcion del timer 0 reti org 13h ; interupcion externa 1 reti org 1bh ; interrupcion del timer 1 reti org 23h ; interrupcion del puerto serial reti org 25h ; localidad donde se inicia el resto del programa ; ---------------------------------------; inicio del programa principal ; ---------------------------------------org 30h start: setb clk ; pone a 1 el ck del ds1620 acall configure ; configura el ds1620 acall delay ; esperar 10 ms para configuracion de escritura loop: acall start_convert ; inicia el comando de convercion de temperatura acall delay ; esperar 1 segundo acall read_temperature ; inicia la lectura de temperatura mov a,r1 ; primer byte leydo call a_dec ; convercion a decimal call mostrar_display ; mostrando en el display ajmp loop ; ---------------------------------------; ESCRITURA EN EL DS1620 ; esta rutina escribe datos en el DS1620 ; ---------------------------------------write1620: mov r0, #08h ; contador de bits nextbitwrite: clr clk rrc a mov dq, c setb clk djnz r0, nextbitwrite ret ; ---------------------------------------; LECTURA DEL DS1620 ; ---------------------------------------read1620: mov r0, #09h ; contador de lectura de datos del DS1620 setb dq nextbitread: clr clk mov c, dq setb clk rrc a djnz r0, nextbitread clr dq ret ; ----------------------------------------

; CONFIGURACION DEL DS1620 ; ---------------------------------------configure: setb rst mov a, #0ch acall write1620 mov a, #00001010b ; cpu = 1, 1shot = 0, thf = 0, tlf = 0 acall write1620 clr rst ret ; ---------------------------------------; inicio de conversin ; ---------------------------------------start_convert: setb rst mov a, #0eeh acall write1620 clr rst ret ; ---------------------------------------; LECTURA DE TEMPERATURA ; ---------------------------------------read_temperature: setb rst mov a, #0aah ; transmitir comando lectura acall write1620 acall read1620 ; leer primer byte mov r1, a ; guarda primer byte acall read1620 ; leer segundo byte mov r2, a ; guardar el segundo byte clr rst ; final de la transferencia ret ; --------------------------------------; convercion de hexadecimal a decimal ; ----------------------------------; la convercion es de un numero hexadecimal de 1 byte en el acumulador a ; a un numero de datos decimales de 2 bytes en el mismo a = low y b = high ; --------------------------------------a_dec: mov signo,#0 jnb acc.7,es_posi es_nega: mov signo,#0ffh mov auxa,a ; guardo el negativo setb c clr a subb a,auxa addc a,#0 ; ahora a es positivo es_posi: mov n_hex,a mov a,#99h mov auxa,a mov b,#0ffh mov nh,#0ffh ; nl es el resultado high lazo:

mov add da jnc inc salto:

a,auxa a,#1 a salto nh

; incrementando el nhigh

inc b mov auxa,a mov a,b cjne a,n_hex,lazo mov b,nh ; detectando el signo mov a,signo cjne a,#0ffh,sin_signo con_signo: mov a,b ; agregando el signo negativo orl a,#040h mov b,a sin_signo: mov a,auxa ret ; ---------------------------------------; mostrar el display ; ---------------------------------------mostrar_display: mov auxa,a anl a,#0fh call buscar_numero ; encuentra el numero del display en aca mov displays,a clr p2.3 acall delay setb p2.3 mov a,auxa swap a anl a,#0fh call buscar_numero ; encuentra el numero del display en aca mov displays,a clr p2.2 acall delay setb p2.2 mov a,b ; la parte alta del decimal mov auxa,a anl a,#0fh call buscar_numero ; encuentra el numero del display en ac a mov displays,a clr p2.1 acall delay setb p2.1 mov a,b ; en la parte alta de b esta el signo anl a,#0f0h mov displays,a clr p2.0 acall delay setb p2.0 ret ; ------------------------------------------

; busca numero (retardo) ; -----------------------------------------buscar_numero: mov dptr,#tabla_display movc a,@a+dptr ret ; -----------------------------------------; d e l a y (retardo) ; -----------------------------------------delay: mov t,#0ffh buc: nop djnz t,buc ret ; -----------------------------------------; tabla del display ; ; esta es la secuencia de datos que genera los ; numeros para catodo comun ; -----------------------------------------tabla_display: ; 0 1 2 3 4 5 6 7 8 9 db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh end

You might also like