//////////////////////////////////////////////////////////////////////////////// // // CR_PWM2_3B.C // // // (RX) RECEPTOR PARA CONTROLE REMOTO PWM DE 2 CANAIS E 3 ON/OFF // AUTOR: CLÁUDIO LÁRIOS // INÍCIO: 13/11/2013 TÉRMINO: 15/11/2013 // LIBERADO USO PARA FINS DIDÁTICOS APENAS. // COM OPÇÃO PARA PIC12F675 OU 629 // PODE SER ESCOLHIDA O MODO DE SAIDA ON/OFF ENTRE PULSO /RETENÇÃO/INVERTIDO // TAMBÉM, EM CASO DE PERDA DO BYTE DE CALIBRAÇÃO, PODE SER USADO UM PROVISÓRIO // OBS.SUJEITO A BUGS AINDA NÃO OBSERVADOS EM USO. MONTAGEM REALIZADA E TESTADA // SOMENTE EM PLACA DE PROTOBOARD. //============================================================================== // DEFINIÇOES DO USUÁRIO //============================================================================== //ESCOLHA DO MICROCONTROLADOR: // Para usar o PIC12F675, descomente o abaixo e comente para usar o 12F629 #define F675 //============================================================================== // //============================================================================== // NOTA IMPORTANTE PARA OBTER O FUNCIONAMENTO DESTE SOFTWARE //============================================================================== // ATENÇÃO: CERTIFIQUE DE EXISTIR O BYTE DE CALIBRAÇÃO NO ENDEREÇO 3FFH DA FLASH // Caso tenha sido apagado acidentalmente, ao ligar, após a programação do pic, // NÃO funcionará. O programa irá fazer um 'call'para buscar o byte de calibra- // ção, mas não encontrará a instrução de retorno 'retlw xx'. Isto fará o progra- // se perder, resetando continuamente. // COMO SABER SE TENHO O BYTE DE CALIBRAÇÃO NO PIC? // LENDO A FLASH COM UM PROGRAMADOR, DEVERÁ SER ENCONTRADO NO ENDEREÇO 0X3FF, UM // VALOR COMEÇANDO COM 34 SEGUIDO DE 2 DIGITOS. EX. 3480. (34=RETLW 80= LITERAL // QUE SERÁ RETORNADO EM 'W' PARA CARGA DO REGISTRADOR '0SCCAL'. #define PERDI_BYTE_CALIBRACAO //Descomente o acima se você tem um pic que foi apagado o byte de calibração. //Será substituido por valor padrão que permita a operação do circuito. // //============================================================================== // MODO DE OPERAÇÃO DAS SAIDAS QUANDO SE ACIONA A RESPECTIVA TECLA NO TX // Poderá optar antes da compilação, se a saída será 'pulso' ou 'retençao' // Comente para 'modo pulso' e descomente para 'modo retenção'. #define B1_ret #define B2_ret #define B3_ret //============================================================================== // MODO DE OPERAÇÃO DAS SAIDAS INVERTIDAS OU MODO NORMAL // Poderá optar antes da compilação, se a saída será 'pulso' ou 'retençao' com // saídas invertidas ('1' já ao ligar o vcc e atua com '0' ao apertar botão do // TX) ou modo normal ('0' já ao ligar vcc e atua com '1' ao apertar botão do // tx). // Comente para 'modo normal' e descomente para 'modo invertido'. // #define B1_invertido // #define B2_invertido // #define B3_invertido //============================================================================== //////////////////////////////////////////////////////////////////////////////// // // FIM DAS DEFINIÇÕES DO USUÁRIO // // Obs. Não altere o programa a seguir, a menos que saiba o que está fazendo // //////////////////////////////////////////////////////////////////////////////// //============================================================================== // // DEFINIÇÕES GERAIS DO PROGRAMA // //============================================================================== #ifdef F675 #include <12F675.h> // includes #else #include <12F629.h> // includes #endif #ignore_warnings 203 //desconsidera mensagem de 'condition always true' #fuses INTRC_IO,NOWDT,NOPROTECT, NOMCLR ,BROWNOUT, PUT // palavra configuração #use delay(clock=4000000) // clock para 4 mhz #use fast_io(A) // sentido das portas feita pelo programador #ifdef PERDI_BYTE_CALIBRACAO // calibração do oscilador interno do pic #ROM 0X3FF = {0X3440}//máxima freq= 0x34fc ;média=0x3480; minima=0x3400 #endif #BYTE GPIO = 0X05 //============================================================================== //ALTERE ABAIXO, OS PINOS QUE DESEJAR COMO SAÍDAS (SOMENTE GPIO 0,1,2,4,5) // COM CUIDADO: #bit B1 = 0X05.1 // PINO 6 #bit B2 = 0X05.0 // PINO 7 #bit B3 = 0X05.5 // PINO 2 #bit CH1 = 0X05.2 // PINO 5 #bit CH2 = 0X05.4 // PINO 3 #DEFINE RFIN PIN_A3 // PINO 4 (IN) NÃO ALTERAR //------------------------------------------------------------------------------ // TRIS-STATE GPIO 543210 PINOS 2,3,4,5,6,7 -> '0' SAÍDA E '1' ENTRADA byte const TRIS_GPIO = 0b001000; //SENTIDO DAS PORTAS byte const serial_number =0x57 ; //serial number para este receptor // // tem que ser igual do TX byte const TMAX_SAIDAS_LIGADAS = 0x10;//tempo q/ saida fica ligada (modo pulso) //============================================================================== #byte TRISIO = 0X85 #byte timer0 = 0x01 // declara timer 0 #byte flags = 0x5e //registrador para flags gerais #byte flags1 = 0x5f //registrador para flags gerais #define flag_vez flags,0 #define flag_h flags,1 // flags usados na recepção do sinal pt2240b #define flag_tp flags,2 #define flag_aux flags,3 #define flag_rok flags,4 #define flag_acao flags,5 #define flag_tpr flags,6 #define flag_B1 flags1,0 //flags para modo retenção apenas #define flag_B2 flags1,1 #define flag_B3 flags1,2 #define flag_it1 flags1,3 byte const tmax= 30; //recepção -tempo em lc p/ indicar intervalo (sincronismo) int8 hc,lc,qb,tm1,tm2,tm3,tl1,tl2,vp1,vp2,botoes ; // variaveis globais #locate hc=0x49 #locate lc=0x4a #locate qb=0x4b int8 buffer[5]= {0,0,0,0,0}; #locate buffer=0x40 #priority timer1,timer0 //============================================================================== // DECLARAÇÃO DE PROTÓTIPOS DE SUBROTINAS E FUNÇÕES //============================================================================== void init_ram(); void acionar (); void reset_rx (); VOID MULTI_SAIDA(); //============================================================================== //////////////////////////////////////////////////////////////////////////////// // // SUBROTINAS E FUNÇÕES DO PROGRAMA // //////////////////////////////////////////////////////////////////////////////// //============================================================================== //============================================================================== // INICIALIZAÇÃO DE REGISTRADORES NA RAM //============================================================================== void init_ram(){ TRISIO= TRIS_GPIO;// ajusta trisio qb=40; // numero de bit a receber do tx lc=0; //zera registradores de recepção hc=0; tm1=0; //zera contadores de tempo auxiliares tm2=0; tm3=0; flags=0; //zera flags gerais flags1=0; ch1=0; //desliga saidas dos canais 1 e 2 ch2=0; //============================================================================== // SITUAÇÃO INICIAL DAS SAIDAS DOS BOTÕES CONFORME ESCOLHAS DE USUÁRIO //============================================================================== #ifdef B1_invertido B1=1; #else B1=0; #endif #ifdef B2_invertido B2=1; #else B2=0; #endif #ifdef B3_invertido B3=1; #else B3=0; #endif } //============================================================================== // ACIONAMENTOS DE SAÍDAS DOS BOTÕES E CARGA DOS VALORES DE PWM //============================================================================== void acionar (){ if((bit_test(botoes,0))||(bit_test(botoes,1))||(bit_test(botoes,3))){ tl1=0;// se algum botão estiver acionado no tx, então tl2=0;//reseta contadores de tempo de saidas ligadas } vp1=~buffer[3]; //carrega valor do pwm para canal 1 vp2=~buffer[2]; //carrega valor do pwm para canal 2 //============================================================================== // ACIONAMENTOS DE SAÍDAS DOS BOTÕES EM MODO PROGRAMADO PARA 'PULSO' //============================================================================== #ifndef B3_ret #ifdef B3_invertido if(bit_test(botoes,3)) B3=0; else B3=1;// #else if(bit_test(botoes,3)) B3=1; else B3=0;// #endif #endif #ifndef B2_ret #ifdef B2_invertido if(bit_test(botoes,0)) B2=0; else B2=1;// #else if(bit_test(botoes,0)) B2=1; else B2=0;// #endif #endif #ifndef B1_ret #ifdef B1_invertido if(bit_test(botoes,1)) B1=0; else B1=1;// #else if(bit_test(botoes,1)) B1=1; else B1=0;// #endif #endif //============================================================================== // ACIONAMENTOS DE SAÍDAS DOS BOTÕES EM MODO PROGRAMADO PARA 'RETENÇÃO' //============================================================================== #ifdef B3_ret if(!bit_test(flag_B3)){ if(bit_test(botoes,3)){ B3=!B3; bit_set(flag_B3);} } #endif #ifdef B2_ret if(!bit_test(flag_B2)){if(bit_test(botoes,0)){ B2=!B2; bit_set(flag_B2); } } #endif #ifdef B1_ret if(!bit_test(flag_B1)){if(bit_test(botoes,1)) { B1=!B1; bit_set(flag_B1); } } #endif bit_clear(flag_rok); //libera nova recepção } //============================================================================== // ZERA REGISTRADORES APÓS RECEPÇÃO DE UM BIT //============================================================================== void reset_rx (){ lc=0; hc=0; bit_clear(flag_h); } //============================================================================== //////////////////////////////////////////////////////////////////////////////// // ROTINA DE INTERRUPÇÃO DO TIMER 0 //////////////////////////////////////////////////////////////////////////////// //============================================================================== //============================================================================== // ROTINA DE INTERRUPÇÃO DO TIMER 1 //============================================================================== #int_timer1 void isr_tmr1(){ set_timer1(0xffff - 10000); // carga: timer 1 irá interromper a cada 10 ms bit_set(flag_it1); // impede esta interrupção de acionar a rotina do tmr0 bit_clear(flag_tpr); //libera flag para carga do pwm na int do tmr0 if(!bit_test(flag_vez)){ CH1=1; bit_set(flag_vez);}// alterna os canais else {CH2=1 ; bit_clear(flag_vez);} set_timer0(0xff-191); // gera o 1ms mínimo inicial enable_interrupts(int_timer0); //liga interrupção do timer 0 } //============================================================================== // FIM DA ROTINA DE INTERRUPÇÃO DO TIMER 1 //============================================================================== //============================================================================== // ROTINA DE INTERRUPÇÃO DO TIMER 0 //============================================================================== //============================================================================== // GERA AS SAÍDAS EM MODO PWM (PULSOS DE 1 A 2 MS) //============================================================================== #int_rtcc VOID isr_tmr0(){ if(!bit_test(flag_it1)){ //testa se ainda está na atuação da int. do timer1 if(bit_test(flag_tpr)) { ch1=0; //desliga saidas após 2ms ch2=0; disable_interrupts(int_timer0); //desliga interrupção do timer 0 } if(!bit_test(flag_tpr)) { bit_set(flag_tpr); //controla fluxo if(bit_test(flag_vez)) {set_timer0(vp1);}//gera de 1 até 2 ms canal1 else {set_timer0(vp2);} //gera de 1 até 2 ms canal2 } } bit_clear(flag_it1); //libera para atuação da int. do timer 0 } //============================================================================== // FIM DA ROTINA DE INTERRUPÇÃO DO TIMER 0 //============================================================================== //============================================================================== /////////////////////////////////////////////////////////////////////////////// // ROTINA PRINCIPAL //////////////////////////////////////////////////////////////////////////////// //============================================================================== //============================================================================== // INICIALIZAÇÃO DE PORTAS E REGISTRADORES //============================================================================== void main(){ #ifdef F675 setup_adc_ports(no_analogs); //somente pic12f675 SETUP_ADC(ADC_OFF); //DESLIGA ADC #endif setup_comparator(nc_nc_nc_nc); // desliga comparadores setup_counters (RTCC_INTERNAL,RTCC_DIV_4); //timer 0 interno /4 setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); //timer1 /1 ENABLE_INTERRUPTS(int_timer1); // liga interrupção por overflow do timer1 enable_interrupts(GLOBAL); // liga interrupção geral PORT_A_PULLUPS(TRUE); init_ram(); TRISIO= TRIS_GPIO;// ajusta sentido das portas de entrada e saídas vp1,vp2=0x3f; //============================================================================== // LOOP PRINCIPAL DE REPETIÇÃO //============================================================================== while (TRUE) { int aux; delay_us(50); //delay entre verificações da entrada rfin (pino 4). //============================================================================== //////////////////////////////////////////////////////////////////////////////// // // ROTINA DE RECEPÇÃO DOS 40 BITS DA TRANSMISSÃO DO TX // //////////////////////////////////////////////////////////////////////////////// //============================================================================== //buffer [4]=serial number/[3]=vp1/[2]=vp2/[1]=botoes/0=conferencia if(input(RFIN)&&(!bit_test(flag_rok))){ bit_set(flag_h); if(++hc==0) --hc; } else { if(!bit_test(flag_h)){if(++lc==0) --lc;} // incrementa lc e limita 0xff else { if(lc>tmax) { qb=40;} else { shift_right(&buffer[0],5,(lc>hc)) ; if (--qb==0){ qb=40; aux= buffer[1] + buffer[2] + buffer[3] + buffer[4] ; if((aux == buffer[0]) && (buffer[4]== serial_number)){ botoes=~buffer[1];//salva botões bit_set(flag_rok);} // há uma recepção no buffer } } reset_rx(); } } //============================================================================== // TESTA POR UMA RECEPÇÃO //============================================================================== if(bit_test(flag_rok) ){ acionar(); //temos uma recepção correta, acionar saídas bit_clear(flag_rok); } //============================================================================= // INCREMENTA CONTADORES DE TEMPO DO ESTADO DAS SAÍDAS //============================================================================= if(++tl1==0){ if(++tl2==TMAX_SAIDAS_LIGADAS) { tl2=0; tl1=0; //============================================================================== // DESLIGA AS SAÍDAS EM MODO PROGRAMADO PARA 'PULSO' //============================================================================== #ifndef B1_ret #ifdef B1_invertido B1=1; #else B1=0; //desliga s0 em modo pulso #endif #endif #ifndef B2_ret #ifdef B1_invertido B2=1; #else B2=0; //desliga s0 em modo pulso #endif #endif #ifndef B3_ret #ifdef B3_invertido B3=1; #else B3=0; //desliga s0 em modo pulso #endif #endif //============================================================================== // RESETA OS FLAGS DAS SAÍDAS EM MODO PROGRAMADO PARA 'RETENÇÃO' //============================================================================== #ifdef B1_ret bit_clear(flag_B1); //desliga flag_s0 em modo retenção #endif #ifdef B2_ret bit_clear(flag_B2);//desliga flag_s1 em modo retenção #endif #ifdef B3_ret bit_clear(flag_B3);//desliga flag_s2 em modo retenção #endif } } //============================================================================== // fim da rotina de recepção //============================================================================== }// while (TRUE) }//void main() //============================================================================== // FIM DO PROGRAMA //============================================================================== // Then, be happy! Enjoy with this assembly!