#include <16f876a.h> // Definiciones del PIC 16F877A.
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de siempre.
#use delay(clock=20000000) // Oscilador a 20 Mhz.
#use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7) // Configuración del RS232.
#use I2C(slave,SDA=PIN_C4,SCL=PIN_C3,slow,address=0x20)
#use fast_io (B) // Puerto B para BCD
// CONSTANTES /////////////////////////////////////////////////////////////////
int const lenbuff=40; // Longitud de buffer RS232.
// VARIABLES EN RAM ///////////////////////////////////////////////////////////
int xbuff=0x00; // Índice: siguiente char en cbuff.
char cbuff[lenbuff]; // Buffer.
char rcvchar=0x00; // Ultimo caracter recibido.
int1 flagcommand=0; // Flag para indicar comando disponible.
int16 frecuencia; // Valor de la frecuencia.
int timeout; // Valor para temporizar los envios RS232.
int intentos; // Variable de intentos de comunicacion RS232
int mode=1; // Valor del modo de obtencion frecuencia.
int32 BAND=0x00; // Variable banda para ICOM y BCD.
byte instruccion[10];
int16 Frec[lenbuff]; // Argumento de comando.
#byte SSPSTAT = 0xFC7
#bit BFBIT=SSPSTAT.0
#bit STARTBIT=SSPSTAT.3
#bit STOPBIT=SSPSTAT.4
#byte SSPCON1=0xFC6
// Declaración de Funciones ///////////////////////////////////////////////////
void inicbuff(void); // Borra buffer.
int addcbuff(char c); // añade caracter recibido al buffer.
void procesa_comando(void); // Procesa comando.
void envia_IF(void); // Envia comando IF;.
void procesa_i2c(void);
// INTERRUPCIONES /////////////////////////////////////////////////////////////
#int_rda
void serial_isr() { // Interrupción recepción serie USART.
rcvchar=0x00; // Inicializo caracter recibido.
if(kbhit()){ // Si hay algo pendiente de recibir ...
rcvchar=getc(); // lo descargo y ...
addcbuff(rcvchar); // lo añado al buffer y ...
}
}
#int_ssp
void i2c_isr() {
int state=0;
state=i2c_isr_state();
if(state < 0x80) //Maestro está enviando datos
{
//Para SSPCON1 = 0x3E;//0b00111110;//Si no se pone esta registro así no entra aquí para el bit de start y de stop
if (state == 0) //O bien es el bit de start o es el Address
{
if (!BFBIT) //Si no hay datos, el BFBIT=0 y por tanto es el START, el STARTBIT está a 1 en toda la trama menos cuando se eleva el STOPBIT
{
//Si ponemos antes el i2c_read(); vaciaremos el buffer y por BFBIT se pondrá a cero y no sabremos si es el address o el BITSTART
}
else
{
}
}
else if (state > 0) //Más bytes recividos, es data
{
if(!STOPBIT)
{
instruccion[state-1] = i2c_read();
if (instruccion[state-1]==0x3b) procesa_i2c();
}
else
{
//Entra aqui si es el bit de stop, fin de trama de datos
SSPSTAT=0x00; //Reseteamos el registro...no me digais...el compilador no lo hace solo con SSPCON1=0b00111110
}
}
}
if(state == 0x80) //Master esta requiriendo datos
{
// received a START + ( I2C_ADR | 1)
// i2c_write(data) must be used to write a byte
i2c_write(0x05);
}
if(state > 0x80) //Master esta requiriendo datos
{
// master has read the byte sent by the slave.
// i2c_write(data) must be used to write a byte
}
}
// Desarrollo de Funciones ////////////////////////////////////////////////////
void inicbuff(void){ // Inicia a \0 cbuff.
int i;
for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los
cbuff[i]=0x00; // caracteres en el buffer.
}
xbuff=0x00; // Inicializo el indice de siguiente
// caracter.
}
int addcbuff(char c){ // Añade a cbuff.
if (xbuff==38) C=0x3B; // Si el buffer esta lleno procesarlo.
switch(c){
case 0x3B: // ";" -> Habilita Flag para procesar
flagcommand=1; // Comando en Main.
break;
default:
cbuff[xbuff++]=c; // Añade caracter recibido al Buffer.
}
}
// Programa Principal /////////////////////////////////////////////////////////
void main() { // Funciòn principal.
int band1;
inicbuff(); // Borra buffer al inicio.
SSPCON1 = 0x3E;//0b00111110;
enable_interrupts(global); // Habilito interrupciones globales.
enable_interrupts(int_ssp); // Habilita la interrupcion I2C.
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); // Configura timer para temporizar.
port_b_pullups(TRUE); // Activo pull-up internas.
do{
while (mode==1){ // Modo manual.
}
while (mode==2){
band1=band; // Capturo la banda para compararla con la siguiente lectura
BAND=(input_B()& 0x1F); // Leo valor BDC en puerto B
// ENVIAR VALOR DE LA BANDA si band1!=BAND
}
while (mode==4){ // modo serie
enable_interrupts(int_rda); // Habilita Interrupción RS232.
if (get_timer1()>=65500)timeout++; // Si desborda el timer incrementamos contador.
if (timeout>=30){ // Miramos si el contador externo del timer desborda
if (intentos >= 5){
// NO HAY COMUNICACION SERIE
}
envia_IF();
} // timer desborda y enviamos comando.
if(flagcommand) procesa_comando(); // Si hay comando pendiente
} // de procesar ... lo procesa.
}while(true);
}
// Procesador de Comandos /////////////////////////////////////////////////////
void procesa_comando(void){ // Función de procesado de comando.
int i;
int16 frecuencia1;
flagcommand=0; // Desactivo flag de comando pendiente.
for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los
Frec[i]=0x00; // caracteres en el argumento.
}
if(cbuff[0]=='I'&&cbuff[1]=='F'){ // Comparo inicio del buffer con comando "IF".
i=5;
do{ // Extraemos argumento del buffer
Frec[i-5]=(cbuff[i]-48); // a partir del 6º byte y hasta ";".
}while(cbuff[++i]!=0x3B);
frecuencia1=frecuencia; // Guardo temporalmente la frecuencia anterior
frecuencia=(Frec[0]*10000)+(Frec[1]*1000)+(Frec[2]*100)+(Frec[3]*10)+(Frec[4]);
// ENVIAR VALOR DE LA FRECUENCIA si frecuencia1!=frecuencia
intentos=0; // Reinicio intentos de comunicacion RS232
timeout=0; // Reinicio el contador del timer.
set_timer1(0); // Reinicio el timer1.
}
inicbuff(); // Borro buffer.
}
void envia_IF(){ // Funcion de envio de comando.
printf ("I"); // Envio instruccion ...
delay_ms(120); // para que el TS850SAT ...
printf ("F"); // envie la informacion ...
delay_ms(120); // de la frecuencia ...
printf (";"); // Fin de trasmision.
timeout=0; // Reinicio el contador del timer.
set_timer1(0); // Reinicion el timer1.
intentos=++intentos;
}
void procesa_i2c(){ // Funcion de procesado de instruccion I2C
int mode1; // Variable temporal para guardar el modo actual
if (instruccion[0]==0x6d){ // Modo en que debe adquirir la frecuencia
mode1=mode; // Guardo temporalmente el modo anterior
mode=instruccion[1]; // Actualizo el modo con el actual
if (mode!=4 && mode1==4)output_low(pin_C5); // Si paso a modo NO rs232 bloqueo recepcion.
if (mode==4) output_high(pin_C5); // Si el modo actual es rs232 activo recepcion
break;
}
}