Creo que quedaria algo asi:
#include <16f877.h>
#include string.h
#use delay (clock=4M)
#use RS232 (BAUD=9600, BITS=8, PARITY=N, XMIT=PIN_D4, RCV=PIN_D5)
void main (){
char input[4],i;
int codigo[4] = "123"; // Es un ASCII
while(true)
{
printf ( "Introduce el código para abrir la puerta: \r" ); //Mensaje pidiendo el código
//Tomo datos
// Tome todos los datos ahora compruebo
{
printf( "Código correcto\r" ); }
else
{
printf( "Código incorrecto, intente de nuevo. \r" ); }
}
}
Observa todos los cambios, lo que se transmite por la UART normalemtne es un caracter ASCII, asi que si recibis 3 caracteres '1','2','3' no es lo mismo que el numero 123(0x7B) , por ejemplo el 1 es 0x31 , asi que tendrias 3 valores 0x31,0x32 y 0x33
Basicamente es un string "123"
Podrias transformarlo en numero? por supuesto, pero para que complicarnos?

. Por eso en codigo lo escribi como "123"
Otros errores que tuviste:
char input[4];
data = input;
Si haces eso no estas copiando lo que tiene input a data... sino que estas copiando la direccion de donde se encuentra input[0] a data
En C Un string es una coleccion de caracteres con un caracter nulo al ultimo, son vectores. El caracter nulo es para indicarle a C que ahi termina.
Ej:
char codigo[4]= "123"
es lo mismo que
char codigo[4] = {'1','2','3','\0'}
Por otra parte tu programa no estaba en un bucle infinito asi que apenas fuera malo o bueno el resultado quedaria atrapado para siempre
el strcmp(input,codigo) lo que hace es verificar que sean iguales, observa que no le pongo[0] o lo que sea, ya que busco de pasarles las direcciones (punteros).. Una forma simple de eso seria algo asi:
(input[0] == codigo[0]) && (input[1] == codigo[1]) && (input[2] == codigo[2]) && (input[3] == codigo[3])
Es decir si todos son iguales da un 1, sino da un 0. ( obviamente la funcion es un poco mas compleja, ya que ambos tienen que tener el mismo largo, etc etc etc. Pero es para que le entiendas
Esa funcion se encuentra normalmente en string.h y pertenece a C.