Amigo homfly:
Un par de reflexiones sobre tu código sin haberlos probado sobre un 16F877 real
1º.- El #use fast_io(X) es mas peligroso que una piraña en un bidet
ya que deshabilita el automatismo del CCS C que coloca correctamente los set_tris_X delante de cada instrucción que implique una entrada o una salida por un pin determinado. Al usar fast_io(X) por el puerto X debes tú poner adecuadamente el set_tris_x() de ese puerto cuando desees leer o escribir en él. En tu código no hay ni un solo set_tris_X() por lo que sospecho que un problema viene de ahí precisamente. Quita el #use fast_io(A) y prueba, dejando que CCS C engorde el programa compilado pero te asegures que las direcciones de entrada/salida están bien colocadas.
2º.- El I2C en el PIC 16F877 usa de un hardware específico que tenemos disponible en los pines RC3 y RC4. Sin embargo en tu código usas A0 y A1, esto en si no debería ser fuente de problemas salvo que su funcionamiento real no va a hacer uso de las posibilidades del PIC sino que va a ser un I2C simulado por software que "incrusta" el CCS C al compilar. Yo siempre he sido partidario de que "si un pic tiene una funcion especifica para algo hay que usarla antes de probar cualquier otra combinacion posible".
3º.- En un programa "real" para un PIC "real" hay que adaptarse a la realidad. Quiero decir con esto que, por ejemplo, según leo en el Datasheet del PIC 16F877 resulta que tras un RESET, o al encenderlo, el PORTA del 16F877 se configura automáticamente como ENTRADA ANALÓGICA y no veo en tu código, al principo antes de empezar a hacer uso de tus funciones, ningún código encaminado a configurar cómo deseas que funcione tu puerto A en el PIC, qué funciones del mismo quieres habilitar y cuales deshabilitar .... Luego tu PIC al inicio empieza a funcionar como los señores de Microchip han decidido que debe funcionar, y eso puede coincidir o no con lo que tu necesitas. Un ejemplo claro es el que te he dado antes sobre el PORTA.
4º.- En los Fuses veo el NOWDT, o sea que deshabilitas el Watch Dog del PIC, pero despues usas los parámetros RESTART_WDT. Esto puede hacer que realmente habilites despues el Watch Dog de forma automática dentro de tus funciones, pero no veo en tu código una completa configuracion o uso del Watch Dog ... Esto puede hacer que el programa no funcione bien al estar el Whact Dog funcionando sin ser atendido correctamente. Si usas como fuse el NOWDT, elimina totalmente cualquier referencia posterior al WDT y asi te aseguras que no te va a molestar al poner en marcha tu programa.
Ea, mi último consejo es que te leas el Datasheet del 16F877 y veas qué estás usando y si de verdad está configurado como tu necesitas. Y tambien el manual del CCS C para ver qué influencia y que posibilidades tienen las distintas opciones de las funciones que estas usando.
Y si no lo tienes claro, pregunta que aqui estamos.