Engenharia Mobilis / Mbed 2 deprecated SATC_Painel_de_Controle

Dependencies:   MFRC522 mbed-STM32F103C8T6 mbed

Fork of C_005_EA_Painel_sem_bms by Engenharia Mobilis

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "main.h"
00002 /*
00003 192.168.0.59
00004 conta> pi
00005 senha> raspberry
00006     
00007 Feito para placa MCA versao PECI091BA
00008     
00009 Utiliza polling para afericao do estado dos botoes de acionamento frente/re
00010 utiliza polling para leitura do cartao
00011 
00012 Funcionalidades:
00013 
00014     Leitura de Cartao
00015     Botões: Frente/Re/Farol
00016     Acionamentos: KSI, Frente, Re, Farol    
00017     
00018 Codigo antecessor: C_005_DC
00019     Adicoes:
00020         Remocao da leitura de dados do bms
00021 
00022 TO DO:
00023 
00024 DONE:
00025 
00026         
00027 */
00028 
00029 
00030 // Arrays que armazenam os estados dos botoes
00031 uint16_t in_frente_states[n_amostras]= {0};
00032 uint16_t in_re_states[n_amostras]= {0};
00033 uint16_t in_farol_states[n_amostras]= {0};
00034 // contador utilizado para debounce, deixar os botoes impossivel de serem acionados
00035 uint8_t button_cooldown_counter = 0;
00036 
00037 DigitalIn in_frente(PB_5);
00038 DigitalIn in_re(PB_6);
00039 DigitalIn in_farol(PB_7);
00040 DigitalIn in_freio_de_estacionamento(PB_4);
00041 
00042 DigitalIn in_12v_charge_confirm(PB_10);
00043 
00044 // Indicadores para o usuario
00045 PwmOut     led_forward(PA_8);
00046 PwmOut     led_backward(PA_9);
00047 PwmOut     led_headlight(PA_11);
00048 PwmOut     buzzer(PB_1);
00049 
00050 DigitalOut embedded_led(PC_13);
00051 DigitalOut led_mobilis(PA_4);
00052 DigitalOut led_erro_3(PA_5);
00053 DigitalOut led_erro_2(PA_6);
00054 DigitalOut led_erro_1(PA_7);
00055 DigitalOut led_economia(PB_0);
00056 DigitalOut led_freio_est(PA_10);
00057 
00058 DigitalInOut io_seta_e(PB_3);
00059 DigitalInOut io_seta_d(PA_15);
00060 
00061 DigitalOut out_KSI(PA_1);
00062 DigitalOut out_frente(PA_2);
00063 DigitalOut out_re(PA_0);
00064 DigitalOut out_farol(PC_15);
00065 
00066 volatile static CanStatus can_status = {true,true};
00067 //struct que contem as falhas presentes no carro
00068 volatile static FalhasEAlarmes falhas_e_alarmes = {0,0,0,0,0};
00069 // Struct que contem informacoes sobre o estado do Painel, ver arquivo 'main.h'
00070 volatile static Painel painel = {BUTTON_none,FAROL_off};
00071 volatile uint16_t soc = 0;
00072 volatile uint16_t charge_current = 0;
00073 
00074 bool car_is_on = false;
00075 bool car_is_locked = false;
00076 bool battery_is_charging = false;
00077 bool battery_is_charged = false;
00078 
00079 // Timer utilizado para polling de botoes
00080 Ticker timer_botoes;
00081 CardReader    rf_chip   (PB_15, PB_14, PB_13, PB_12, PB_11);
00082 CAN can(PB_8,PB_9);
00083 
00084 char arr_id_usuario[4] = {0,0,0,0};
00085 
00086 
00087 
00088 int main(void)
00089 {    
00090     timer_botoes.attach(&checkButtons,button_polling_period);
00091     rf_chip.init(CRMODE_Polling);    
00092     can.frequency(250000);
00093     can.attach(&getMsg);
00094     initPWMs();
00095     turnOffSetup();
00096     out_KSI = 0;
00097     wait_ms(500);
00098     
00099     uint16_t T = 100;
00100     uint16_t k = 1;
00101     while(1){ 
00102         // dt: tempo decorrido
00103         uint16_t dt = T*k;
00104         // a cada 100 ms : le cartao, liga/desliga carro de acordo
00105         if (dt%100 == 0){
00106             if(!car_is_locked && rf_chip.readCard()){
00107                 if(rf_chip.cardIsValid()){
00108                     if(car_is_on){
00109                         tentaDesligarCarro();
00110                     }else{  
00111                         tentaLigarCarro();
00112                         if(car_is_on){
00113                             k=1;
00114                         }
00115                     }                
00116                 }else{
00117                     //Caso cartao nao seja valido
00118                     buzzWrongCard();
00119                 }
00120             }// nao faz nada caso nao haja cartao    
00121             //processa botao apertado, caso haja                     
00122             if(car_is_on){        
00123                 handlePressedButton();
00124             }
00125         }
00126         // a cada 500ms: envia mensagens no can bus sobre alarme, falhas e estado dos acionamentos
00127         if(dt % 500 == 0){
00128             if(car_is_on){
00129                 enviaEstadoDeAcionamentosFalhasEAlarmesViaCAN();
00130             }
00131         }
00132         
00133         // This routine is ran 
00134         if(dt % 1000 == 0){
00135             bool deve_travar_carro = in_12v_charge_confirm.read() == 1;
00136             if(deve_travar_carro){                
00137                 if(car_is_on){
00138                     turnOffSetup();
00139                     out_KSI = 0;
00140                 }
00141                 // acende certo led   
00142                 car_is_on = false;
00143                 car_is_locked = true;
00144             }
00145             bool deve_destravar_carro = car_is_locked && (in_12v_charge_confirm.read() == 0);
00146             if(deve_destravar_carro){
00147                 car_is_locked = false;
00148                 // apaga certo led
00149             }
00150             
00151             battery_is_charging = (in_12v_charge_confirm.read() == 1) && (charge_current > CHARGE_CURRENT_CHARGING);
00152             battery_is_charged = (in_12v_charge_confirm.read() == 1) && (charge_current < CHARGE_CURRENT_CHARGING);
00153             if(battery_is_charging){
00154                 led_mobilis = !led_mobilis;                    
00155             }else if(battery_is_charged){
00156                 led_mobilis = 1;
00157             }else if(!car_is_on){
00158                 led_mobilis = 0;
00159             }
00160             
00161             int mensagem_enviada_sucesso = sendCanCarState();
00162             afirmaFalha(!mensagem_enviada_sucesso, DTC_FALHA_CAN, &(falhas_e_alarmes.falha_mca));            
00163         }
00164         // a cada 5s: envia mensagem no can bus contendo id do usuario, 
00165         if(dt % 5000 == 0){  
00166             if(car_is_on){
00167                 
00168                 char can_data_uid [4] = {0,0,0,0};
00169                 std::copy(arr_id_usuario, arr_id_usuario+ID_SIZE, can_data_uid);
00170                 sendCanMsg(CAN_ID_id_usuario,can_data_uid,4);                
00171                                 
00172                 // Checa se inversor e BMS estao se comunicando atraves das flags can_inversor_ok e can_bms_ok
00173                 afirmaFalha(!can_status.can_inversor_ok, DTC_FALHA_INVERSOR_CAN, &falhas_e_alarmes.falha_mca);
00174                 afirmaFalha(!can_status.can_bms_ok, DTC_FALHA_BMS_CAN, &falhas_e_alarmes.falha_mca);
00175                 can_status.can_inversor_ok = false;
00176                 can_status.can_bms_ok = false;
00177                 
00178                 bool alarmes_existem = falhas_e_alarmes.alarme_mca ||  falhas_e_alarmes.alarme_weg;                                
00179                 bool falhas_existem = falhas_e_alarmes.falha_mca || falhas_e_alarmes.falha_weg || falhas_e_alarmes.falha_bms;                
00180 
00181                 led_erro_1 = falhas_existem;
00182                 led_erro_2 = alarmes_existem;
00183                 led_erro_3 = soc < SOC_BAIXA_CARGA;
00184 
00185             }                      
00186         }
00187         // a cada 10 s: reseta leitor de cartoes
00188         if(dt > 10000){
00189             int leitor_reset_sucesso = rf_chip.init(CRMODE_Polling);
00190             afirmaFalha(!leitor_reset_sucesso, DTC_FALHA_LEITOR, &falhas_e_alarmes.falha_mca);
00191             k=1;
00192         }
00193         k++;
00194         wait_ms(100);
00195     }    
00196 }
00197 
00198 /* Caso o flag acuse uma falha (com DTC 'DTC_da_falha'), registra ela no ponteiro *falha 
00199             caso nao acuse falha, limpa essa falha do ponteiro *falha
00200 */
00201 void afirmaFalha(int flag_not_ok, uint16_t DTC_da_falha, volatile uint16_t* falha){
00202     if(flag_not_ok){
00203         *falha = DTC_da_falha;
00204     }else if(*falha == DTC_da_falha){
00205         *falha = 0;
00206     }
00207 }
00208 
00209 // Executado ao passar o cartao quando carro esta' desligado
00210 void tentaLigarCarro(){
00211     turnOnSetup();
00212     car_is_on = true;     
00213     // copia o cartao lido para array 'arr_id_usuario', que sera enviado pelo barramento CAN
00214     std::copy(rf_chip.last_valid_card, rf_chip.last_valid_card+ID_SIZE, arr_id_usuario);
00215     sendCanMsg(CAN_ID_id_usuario,arr_id_usuario,4);
00216     painel.pressed_button=BUTTON_none; 
00217 }
00218 // Executado ao passar o cartao quando carro esta' ligado
00219 void tentaDesligarCarro(){
00220     // Verifica se cartao lido e' o mesmo que foi utilizado para ligar o carro
00221     bool card_matches_previous = memcmp(rf_chip.last_valid_card, arr_id_usuario, sizeof(rf_chip.last_valid_card)) == 0;
00222     if(card_matches_previous){
00223         turnOffSetup();
00224         car_is_on = false;        
00225         for(int i = 0; i < 15; i ++){
00226             sendCanCarState();
00227             wait_ms(1000);
00228         }        
00229         out_KSI = 0;
00230         //Limpa informacao sobre id do usuario
00231         memset(arr_id_usuario, 0, sizeof(arr_id_usuario));
00232     }else{
00233         buzzWrongCard();  
00234     }
00235 }
00236 // Executado pelo main
00237 void enviaEstadoDeAcionamentosFalhasEAlarmesViaCAN(){     
00238     // Prepara arrays para envio
00239     char arr_falhas_e_alarmes[8];
00240     populaArrayFalhasEAlarmes(arr_falhas_e_alarmes, 8);    
00241     const uint8_t ARR_SIZE = 4;
00242     char arr_acionamentos[ARR_SIZE] = {out_frente.read(), out_re.read(), out_farol.read(), in_freio_de_estacionamento.read()};
00243     // Envia as mensagens CAN
00244     sendCanMsg(CAN_ID_falhas_e_alarmes,arr_falhas_e_alarmes);
00245     sendCanMsg(CAN_ID_acionamentos,arr_acionamentos,ARR_SIZE);
00246 }
00247 
00248 void populaArrayFalhasEAlarmes(char* array, size_t n){
00249     // Arrays intermediarios para armazenar DTCs
00250     uint16_t can_falhas_array[2] = {0,0};
00251     uint16_t can_alarmes_array[2] = {0,0};     
00252     if(falhas_e_alarmes.falha_mca != 0){
00253         arrayPush(can_falhas_array, falhas_e_alarmes.falha_mca, 2);
00254     }
00255     if(falhas_e_alarmes.falha_bms != 0){
00256         arrayPush(can_falhas_array, falhas_e_alarmes.falha_bms, 2);
00257     }
00258     if(falhas_e_alarmes.falha_weg != 0){
00259         arrayPush(can_falhas_array, falhas_e_alarmes.falha_weg, 2);
00260     }
00261     if(falhas_e_alarmes.alarme_mca != 0){
00262         arrayPush(can_alarmes_array, falhas_e_alarmes.alarme_mca, 2);
00263     }
00264     if(falhas_e_alarmes.alarme_weg != 0){
00265         arrayPush(can_alarmes_array, falhas_e_alarmes.alarme_weg, 2);
00266     }
00267     char array_preparado[] = {can_falhas_array[0]&0xFF, can_falhas_array[0]>>8, can_falhas_array[1]&0xFF, can_falhas_array[1]>>8,
00268                             can_alarmes_array[0]&0xFF, can_alarmes_array[0]>>8, can_alarmes_array[1]&0xFF, can_alarmes_array[1]>>8};
00269     std::copy(array_preparado,array_preparado+8, array);
00270 }
00271 ////////////////////// BEGIN CAN /////////////////////////////////////////////
00272 /* Funcao chamada sempre que uma mensagem chega no barramento CAN
00273     obs: Roda concorrentemente com o main!!! 
00274 */
00275 
00276 int sendCanCarState(){
00277     
00278     char estados_do_carro[8] = {car_is_on, !car_is_on, in_12v_charge_confirm.read(), battery_is_charging, battery_is_charged, 0x00, 0x00, 0x00};
00279     return sendCanMsg(CAN_ID_ESTADO_DO_CARRO,estados_do_carro);    
00280 }
00281 
00282 void getMsg(){
00283     CANMessage msg;
00284     if(!can.read(msg)){
00285         return;
00286     }
00287     switch(msg.id){
00288         case CAN_ID_WEG_FALHAS_E_ALARMES:
00289             falhas_e_alarmes.falha_weg =  converteDTCWeg(msg.data[1]<<8 | msg.data[0]);
00290             falhas_e_alarmes.alarme_weg = converteDTCWeg(msg.data[3]<<8 | msg.data[2]);
00291             can_status.can_inversor_ok = true;
00292             break;
00293        case CAN_ID_BMS_FALHAS_E_ALARMES:
00294             falhas_e_alarmes.falha_bms = converteDTCBms(msg.data[5]<<8 | msg.data[4]);        
00295             can_status.can_bms_ok = true;
00296             break;
00297         case CAN_ID_BMS_SOC:
00298             { // Chaves utilizadas para que consigamos declarar variaveis dentro de um 'case'
00299             soc = msg.data[7]<<8 | msg.data[6];             
00300             charge_current = msg.data[3] << 8 | msg.data[2];
00301             bool falha_no_circ_de_carga = (soc < 50) && (charge_current < CHARGE_CURRENT_CHARGING) && (falhas_e_alarmes.falha_bms == 0) && (in_12v_charge_confirm.read() == 1);                
00302             afirmaFalha(falha_no_circ_de_carga, DTC_FALHA_CIRCUITO_DE_CARGA, &falhas_e_alarmes.falha_mca);
00303             }
00304             break;
00305         case CAN_ID_WEG_SENTIDO_DE_MOVIMENTO:
00306             {
00307             bool frente_inv = msg.data[0];
00308             bool re_inv = msg.data[2];
00309             bool divergencia = frente_inv != out_frente.read() || re_inv != out_re.read();
00310             afirmaFalha(divergencia, DTC_FALHA_DIVERGENCIA_ENTRE_ACIONAMENTOS, &falhas_e_alarmes.falha_mca);
00311             }
00312             break; 
00313         default:
00314             break;
00315     }
00316 }
00317 
00318 // funcao para envio de mensagem pelo barramento CAN
00319 int sendCanMsg(int id, const char *data, char len, CANType type, CANFormat format)
00320 {
00321     if(can.tderror() != 0 || can.rderror() != 0){
00322         can.frequency(250000);
00323         can.attach(&getMsg);
00324     }
00325     int msgSent = can.write(CANMessage(id,data,len,type,format));
00326     return msgSent;
00327 }
00328 /////////////////////////           END CAN                                ///////////////////////////
00329 
00330 /////////////////////////          BEGIN STANDARD IO                       //////////////////////////
00331 // Funcao que processa o botao apertado
00332 void handlePressedButton(){
00333     //ignora botao apertado caso tenha pouco tempo que um botao tenha sido apertado
00334     if(button_cooldown_counter > 0 ){
00335         painel.pressed_button= BUTTON_none;
00336         button_cooldown_counter --;
00337     }
00338     bool estado_mudou = setLedsAndRelays(painel.pressed_button);
00339     if(estado_mudou){
00340         beepBuzzer(100);
00341     }
00342     // inicializa contador caso botao tenha sido apertado
00343     if(painel.pressed_button != BUTTON_none){
00344         button_cooldown_counter = BUTTON_COOLDOWN_COUNTER_RESET;
00345     }     
00346      painel.pressed_button= BUTTON_none;
00347 }
00348 
00349 /* rotina executada sempre que o carro liga:
00350     Aciona KSI,
00351     Pisca todos os LEDS,
00352     Aciona buzzer por 100 ms
00353 */
00354 void turnOnSetup(){
00355     out_KSI = 1;
00356     out_frente = 0;
00357     out_re = 0;
00358     out_farol = 0;
00359     
00360     io_seta_e.output();
00361     io_seta_d.output();
00362 
00363     led_mobilis = 1;
00364     led_erro_3 = 1;
00365     led_erro_2=1;
00366     led_erro_1 =1;
00367     led_economia =1;
00368     led_freio_est=1;
00369     io_seta_e = 1;
00370     io_seta_d = 1;
00371     
00372     led_forward.write(led_max);
00373     led_backward.write(led_max);
00374     led_headlight.write(led_max);
00375     
00376     beepBuzzer(100);
00377     wait_ms(300);
00378     
00379     led_erro_3 = 0;
00380     led_erro_2=0;
00381     led_erro_1 =0;
00382     led_economia =0;
00383     led_freio_est=0;
00384     io_seta_e = 0;
00385     io_seta_d = 0;
00386     led_forward.write(led_weak);
00387     led_backward.write(led_weak);
00388     led_headlight.write(led_weak);          
00389     io_seta_e.input();
00390     io_seta_d.input();
00391     wait_ms(200);
00392 }
00393 
00394 
00395 /* rotina executada sempre que o carro desliga:
00396     Desaciona todos os acionamentos,
00397     Pisca todos os LEDS,
00398     Aciona buzzer por 100 ms
00399     espera 200 ms
00400     Aciona buzzer por 50 ms
00401 */
00402 void turnOffSetup(){
00403     io_seta_e.output();
00404     io_seta_d.output();
00405     out_frente = 0;
00406     out_re = 0;
00407     out_farol = 0;    
00408     led_mobilis = 1;
00409     led_erro_3 = 1;
00410     led_erro_2=1;
00411     led_erro_1 =1;
00412     led_economia =1;
00413     led_freio_est=1;
00414     io_seta_e = 1;
00415     io_seta_d = 1;
00416     led_forward.write(led_max);
00417     led_backward.write(led_max);
00418     led_headlight.write(led_max);    
00419     
00420     beepBuzzer(100);  
00421     wait_ms(300);                
00422     led_forward.write(0);
00423     led_backward.write(0);
00424     led_headlight.write(0);    
00425     led_mobilis = 0;
00426     led_erro_3 = 0;
00427     led_erro_2=0;
00428     led_erro_1 =0;
00429     led_economia =0;
00430     led_freio_est=0;
00431     io_seta_e = 0;
00432     io_seta_d = 0;
00433     io_seta_e.input();
00434     io_seta_d.input();
00435     wait_ms(200);    
00436     beepBuzzer(50);
00437     wait_ms(500);
00438 }
00439 
00440 // Acende leds e aciona reles de acordo com o botao apertado
00441 bool setLedsAndRelays(PainelButton button){
00442     bool buzz = true;
00443     switch (button){        
00444         case BUTTON_forward:
00445             led_forward.write(D_ON_LED_FRENTE_RE);
00446             led_backward.write(D_OFF_LED_FRENTE_RE);
00447             out_frente = 1;
00448             out_re = 0;           
00449             break;            
00450         case BUTTON_backward:
00451             led_forward.write(D_OFF_LED_FRENTE_RE);
00452             led_backward.write(D_ON_LED_FRENTE_RE);
00453             out_frente = 0;
00454             out_re = 1;           
00455             break;            
00456         case BUTTON_headlights:
00457             if(painel.farol == FAROL_on){
00458                 led_headlight.write(D_OFF_LED_HEADLIGHT);
00459                 painel.farol = FAROL_off;
00460                 io_seta_e = 1;
00461                 out_farol = 0;
00462             }else{
00463                 led_headlight.write(D_ON_LED_HEADLIGHT);
00464                 painel.farol = FAROL_on;
00465                 out_farol = 1;
00466             }            
00467             break;        
00468         case BUTTON_none:
00469         default:
00470             buzz = false;
00471             break;        
00472     }   
00473     return buzz;
00474 }
00475 
00476 // Configura o periodo das saidas PWM
00477 void initPWMs(){
00478     led_forward.period_ms(leds_pwm_period);
00479     led_backward.period_ms(leds_pwm_period);   
00480     led_headlight.period_ms(leds_pwm_period); 
00481     buzzer.period_us(buzzer_period_us);
00482 }
00483 
00484 // Acionamento do buzzer
00485 void beepBuzzer(int ms_duration){
00486     buzzer.write(D_BUZZER_STD);
00487     wait_ms(ms_duration);      
00488     buzzer.write(0);
00489 }
00490 
00491 void buzzWrongCard(){
00492     beepBuzzer(100);
00493     wait_ms(100);
00494     beepBuzzer(100);
00495     wait_ms(100);
00496     beepBuzzer(100); 
00497 }
00498 
00499 
00500 /* 
00501 Funcao acionada a cada 'button_polling_period' milissegundos em concorrencia com o main
00502         Se das ultimas 'n_amostras' de afericao de um botao, 
00503         pelo menos 'button_treshold' delas tiverem sido verdadeiras,
00504         Considera botao como apertado
00505     Algoritmo:
00506         Le o estado do botao
00507         Empurra esse estado num array
00508         Caso a soma dos elementos desse array for maior que 'button_treshold'
00509             e caso o acionamento nao esteja acionado (valido para frente/re):
00510             considera botao como apertado 
00511 */
00512 void checkButtons(){
00513     int frente_state = in_frente.read();
00514     arrayPush(in_frente_states, frente_state, n_amostras);
00515     bool frente_pressionado = arraySum(in_frente_states,n_amostras) > button_treshold;
00516     int re_state = in_re.read();
00517     arrayPush(in_re_states,re_state,n_amostras);
00518     bool re_pressionado = arraySum(in_re_states,n_amostras) > button_treshold;    
00519     if(re_pressionado && frente_pressionado)
00520     {
00521         painel.pressed_button = BUTTON_none;
00522     }else if(frente_pressionado && (out_frente.read() != 1))
00523     {
00524         painel.pressed_button = BUTTON_forward;
00525     }else if(re_pressionado && (out_re.read() != 1))
00526     {
00527         painel.pressed_button = BUTTON_backward;    
00528     }
00529     int farol_state = in_farol.read();
00530     arrayPush(in_farol_states,farol_state,n_amostras);
00531     if(arraySum(in_farol_states,n_amostras)> button_treshold){
00532         painel.pressed_button = BUTTON_headlights;
00533     }
00534 }
00535 
00536 /////////////////////// END STANDARD IO ////////////////////////////////////