Finalmente no me aguante y lo revise a fondo

Era simple, solo habia que hacerle una negacion a todo eso envez de lo que proponias. Es decir, hacer lo siguiente:
output_bit(dato, !(datob & 0x1));
Y listo. En proteus y en la vida misma funciona correctamente.
Gracias Cryn, va perfecto.
Porcierto, en la funcion load_letra(...) pude reducir el codigo, cosa que hiciste en una parte pero no entiendo porque no en las demas. Me explico mejor mostrando como deje el codigo:
void load_letra(int caracter){
int i,j;
if(isalnum(caracter)){
if(isalpha(caracter)){
if(isupper(caracter))
{
for(j=0;j<8;j++){
//matriz[5][j]=letrasM[i][j];
matriz[5][j]=letrasM[caracter - 'A'][j];
}
}
else{
for(j=0;j<8;j++){
//matriz[5][j]=letras_m[i][j];
matriz[5][j]=letras_m[caracter - 'a'][j];
}
}
}
else{
for(j=0;j<8;j++){
matriz[5][j]=numeros[caracter-'0'][j];
}
}
}
else{
switch(caracter){
case ' ': i=0; break;
case '!': i=1; break;
case '"': i=2; break;
case '#': i=3; break;
case '$': i=4; break;
case '%': i=5; break;
case '&': i=6; break;
case '´': i=7; break; //este es el acento
case '(': i=8; break;
case ')': i=9; break;
case '*': i=10; break;
case '+': i=11; break;
case ',': i=12; break;
case '-': i=13; break;
case '.': i=14; break;
case '/': i=15; break;
case ':': i=16; break;
case ';': i=17; break;
case '>': i=18; break;
case '=': i=19; break;
case '<': i=20; break;
case '?': i=21; break;
case '[': i=22; break;
case ']': i=23; break;
case '^': i=24; break;
case '_': i=25; break;
case '{': i=26; break;
case '|': i=27; break;
case '}': i=28; break;
case '@': i=29; break;
case 'ñ': i=30; break; // esta es la enie
case '\f': i=31; break;
}
for(j=0;j<8;j++){
matriz[5][j]=chars[i][j];
}
}
}
Aunq se podria ahorrar mas ROM haciendo todo en una sola matriz no se podria para micros como los 16f o menores, asiq para compatibilizacion esta bien pero para ahorrar se podria hacer y esta funcion podria eliminarse.
Salu2.