/** ****************************************************************************** * @file main.c * @author Ira Lukas * @version BMS_30_cells * @date 19_5_2019 * @brief Main program ****************************************************************************** * * BMS_30_cells_CAN * ****************************************************************************** */ /* vtazeni souboru ------------------------------------------------------------------*/ #include "stm32f4xx.h" #include // dekralace promenych // flagy static uint8_t data; static uint8_t stav = 0; static uint32_t cas_vysilani = 0; static uint8_t flagConfig = 1; static uint8_t flagNewData = 0; static uint8_t flagReadData = 0; static uint16_t flagVysilaniCAN = 0; static uint16_t flagTimeCan = 0; static uint8_t canSwitch = 0; static uint8_t flagUKO = 0; // flagy pro BMS OK static uint8_t BPConI = 0; // BPcon = Batterz Pack Connected static uint8_t BPConT = 0; static uint8_t BPConOV = 0; static uint8_t BPConUV = 0; static uint8_t flagOC = 0; // nadproud static uint8_t flagOT = 0; // vysoka teplota static uint8_t flagUV = 0; //podpeti static uint8_t flagOV = 0; //prepeti // data static uint8_t poleUdata[57]; static uint16_t poleU[30]; static uint8_t poleUdataCan[57]; static uint8_t poleTdata[16]; static uint32_t celkoveUCan = 0; // balancery static uint16_t balanceryB = 0; static uint16_t balanceryM = 0; static uint16_t balanceryU = 0; static uint32_t balancery = 0; static uint32_t indexBal = 0; static uint8_t balanceryB1 = 0; static uint8_t balanceryB2 = 0; static uint8_t balanceryM1 = 0; static uint8_t balanceryM2 = 0; static uint8_t balanceryU1 = 0; static uint8_t balanceryU2 = 0; static uint8_t balanceryB1Can = 0; static uint8_t balanceryB2Can = 0; static uint8_t balanceryM1Can = 0; static uint8_t balanceryM2Can = 0; static uint8_t balanceryU1Can = 0; static uint8_t balanceryU2Can = 0; // teploty static float tExt1 = 0; static float tExt2 = 0; static float t1 = 0; static float t2 = 0; static uint8_t t1Byte = 0; static uint8_t t2Byte = 0; static float Rt1 = 0; static float Rt2 = 0; static float tExt3 = 0; static float tExt4 = 0; static float t3 = 0; static float t4 = 0; static uint8_t t3Byte = 0; static uint8_t t4Byte = 0; static float Rt3 = 0; static float Rt4 = 0; static float tExt5 = 0; static float tExt6 = 0; static float t5 = 0; static float t6 = 0; static uint8_t t5Byte = 0; static uint8_t t6Byte = 0; static float Rt5 = 0; static float Rt6 = 0; static uint8_t poleT[6]; // mereny proud static int32_t Vout=0; // Vout in A0 static int32_t Vref=0; // Rout in A0 static float Ip = 0; static int16_t IpCan = 0; static int16_t Ipn = 400; // indexy static uint8_t indexPole = 0; static uint8_t intPeriod = 10; static uint32_t celkoveU = 0; static uint8_t indexU = 0; static uint8_t indexT = 0; //Logic static uint32_t indexNap = 0; static uint32_t indexTep = 0; static uint32_t prepeti = 0; static uint32_t podpeti = 0; static uint8_t teplota = 0; // CAN struktury CanTxMsg TxMessage; CanRxMsg RxMessage; static uint32_t dataCAN; static uint32_t idCAN; static uint32_t lengthCAN; static uint8_t CAN1_out; // funkce void Init_GPIO(void); void Init_TIM3(void); void Init_SPI1(void); void Init_CAN(void); void Init_ADC(void); __IO uint32_t i=0; #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /* NASTAVENI FREKVENCE OSCILATORU - reference manual schema str. 216 */ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 8 /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ #define PLL_Q 5 #define PLL_N 240 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2 #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.*/ void SystemInit(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Enable HSE Bypass - external source */ RCC->CR |= ((uint32_t)RCC_CR_HSEON); RCC->CR |= ((uint32_t)RCC_CR_HSEBYP); /* Select regulator voltage output Scale 1 mode */ RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; /* HCLK = SYSCLK / 1 */ RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK / 2 */ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; /* PCLK1 = HCLK / 4 */ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; /* Configure the main PLL */ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); /* Enable the main PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till the main PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /* Select the main PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); { } } /** * @brief Main program * @param None * @retval None */ int main(void) { // prototypy funkci Init_GPIO(); Init_TIM3(); Init_SPI1(); Init_CAN(); Init_ADC(); SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); NVIC_EnableIRQ(TIM3_IRQn); NVIC_EnableIRQ(ADC_IRQn); while (1) { if(flagVysilaniCAN >= 500) // aby byl flag delitelny periodou vypisovani hodnot v terminalu { // kontrola odeslání dat - pouze vybraná data !!! if(CAN_TransmitStatus(CAN1, CAN1_out) == CAN_TxStatus_Ok){ // tenhle if musi být pred odesláním GPIOC->ODR ^= GPIO_Pin_1; } switch(canSwitch){ case 0: { TxMessage.DLC = 8; // delka zpravy, pocet bajtu TxMessage.IDE = CAN_ID_STD; //11 bitovy ID TxMessage.RTR = CAN_RTR_Data; TxMessage.StdId = 0; TxMessage.Data[0] = flagTimeCan; // pomocna promenna pro cas TxMessage.Data[1] = flagTimeCan >> 8; TxMessage.Data[2] = Vref; // referencni napeti proudove cidla TxMessage.Data[3] = Vref >> 8; TxMessage.Data[4] = Vout; // vystupni napeti proudoveho cidla TxMessage.Data[5] = Vout >> 8; TxMessage.Data[6] = IpCan; // vypocteny proud TxMessage.Data[7] = IpCan >> 8; CAN1_out = CAN_Transmit(CAN1, &TxMessage); // odeslani zpravy canSwitch = 1; } break; case 1:{ // vysilani dat po CANu TxMessage.DLC = 8; // delka zpravy, pocet bajtu TxMessage.IDE = CAN_ID_STD; //11 bitovy ID TxMessage.RTR = CAN_RTR_Data; TxMessage.StdId = 1; TxMessage.Data[0] = poleUdataCan[9]; // 7. clanek BOTTOM TxMessage.Data[1] = poleUdataCan[10] & 0x0F; TxMessage.Data[2] = poleUdataCan[24]; // 5. clanek MIDDLE TxMessage.Data[3] = poleUdataCan[25] & 0x0F; TxMessage.Data[4] = poleUdataCan[42]; // 5. clanek TOP TxMessage.Data[5] = poleUdataCan[43] & 0x0F; TxMessage.Data[6] = (celkoveUCan/10) & 0x00FF; TxMessage.Data[7] = (celkoveUCan/10) >> 8; CAN1_out = CAN_Transmit(CAN1, &TxMessage); // odeslani zpravy canSwitch = 2; } break; case 2:{ TxMessage.DLC = 6; // delka zpravy, pocet bajtu TxMessage.IDE = CAN_ID_STD; //11 bitovy ID TxMessage.RTR = CAN_RTR_Data; TxMessage.StdId = 2; TxMessage.Data[0] = balanceryB1Can >> 6; //balanceryB1 TxMessage.Data[1] = 0; TxMessage.Data[2] = balanceryM1Can >> 4; //balanceryM1 TxMessage.Data[3] = 0; TxMessage.Data[4] = balanceryU1Can >> 4; //balanceryU1 TxMessage.Data[5] = 0; CAN1_out = CAN_Transmit(CAN1, &TxMessage); // odeslani zpravy canSwitch = 3; } break; case 3: { TxMessage.DLC = 4; // delka zpravy, pocet bajtu TxMessage.IDE = CAN_ID_STD; //11 bitovy ID TxMessage.RTR = CAN_RTR_Data; TxMessage.StdId = 3; TxMessage.Data[0] = t1Byte; //teplota t1 - hodnota v 1 bajtu TxMessage.Data[1] = 0; TxMessage.Data[2] = t2Byte; //teplota t2 - hodnota v 1 bajtu TxMessage.Data[3] = 0; CAN1_out = CAN_Transmit(CAN1, &TxMessage); // odeslani zpravy canSwitch = 0; } break; } flagVysilaniCAN = 0; } } } /** * @brief Inicializace GPIO * @param None * @retval None */ // inicializace ADC void Init_ADC(){ ADC_InitTypeDef ADC_InitStruct; // ADC Init structure definition, nova struktura typu ADC_InitTypeDef ADC_CommonInitTypeDef ADC_Com_InitStruct; //ADC Common Init structure definition RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2 , ENABLE); ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_ScanConvMode = DISABLE; ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //ADC_InitStruct.ADC_ExternalTrigConv = ; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_NbrOfConversion = 1; ADC_Com_InitStruct.ADC_Mode = ADC_Mode_Independent; ADC_Com_InitStruct.ADC_Prescaler = ADC_Prescaler_Div2; ADC_Com_InitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_Init(ADC1,&ADC_InitStruct); ADC_Init(ADC2,&ADC_InitStruct); ADC_CommonInit(&ADC_Com_InitStruct); ADC_Cmd(ADC1,ENABLE); ADC_Cmd(ADC2,ENABLE); ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //end of conversion ADC_ITConfig(ADC2,ADC_IT_EOC,ENABLE); //end of conversion } // inicializace GPIO void Init_GPIO(void) { GPIO_InitTypeDef GPIO_InitStruct; /* povoleni hodin GPIOA, GPIOB */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC , ENABLE); /* LED */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOC, &GPIO_InitStruct); GPIOC->ODR ^= GPIO_Pin_0; //led /* ENABLE pin */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIOA->BSRRL = GPIO_Pin_3; // pin PA3 high - zacne se napájet digitální isolátor - jinak nefunguje komunikace !!! /* CAN1 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1); /* CAN2 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_CAN2); GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_CAN2); /* BMS OK */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOC, &GPIO_InitStruct); //GPIOC->BSRRL = GPIO_Pin_2; // pin PC2 high - BMS OK /* CHARGER */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOC, &GPIO_InitStruct); //GPIOC->BSRRL = GPIO_Pin_3; // pin PC3 high - CHARGER /* CURRENT SENZOR */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; //Uout - PA1, Uref - PA2 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; GPIO_Init(GPIOA, &GPIO_InitStruct); } // inicializace TIM3 void Init_TIM3(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_InternalClockConfig(TIM3); /* core 120 MHz */ TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //nahoru TIM_TimeBaseStructure.TIM_Period = 60000; // TIM_TimeBaseStructure.TIM_Prescaler = 0; //delicka 1 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* TIM1 enable counter */ TIM_Cmd(TIM3, ENABLE); /* interrupt source config */ TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); } // inicializace SPI1 void Init_SPI1(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // funkce která pusti clk pro danou periferii RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2); /* WS */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); /* CK */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); /* DIN */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); /* DOUT */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; /* Soft ChipSelect */ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; // softwarove ovládany, stejný jako u LED GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIOA->BSRRL = GPIO_Pin_4; /* Chipselect High */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStruct.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); } // inicializace CAN1 void Init_CAN(){ CAN_InitTypeDef CAN_InitStruct; // vztvoreni promenne can_initTypeDef CAN_FilterInitTypeDef CAN_FilterInitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE); //konfigurace CANu, 120 MHz / predelicka 4 pro APB1 -> f CANu je 30 MHz CAN_InitStruct.CAN_ABOM = DISABLE; CAN_InitStruct.CAN_AWUM = DISABLE; CAN_InitStruct.CAN_BS1 = CAN_BS1_7tq; //6 CAN_InitStruct.CAN_BS2 = CAN_BS2_4tq; //3 CAN_InitStruct.CAN_Mode = CAN_Mode_Normal; // zatim LoopBack na test, pak normal mode CAN_InitStruct.CAN_NART = DISABLE; CAN_InitStruct.CAN_Prescaler = 5; // 5, posunuto o 1, deleno 6x CAN_InitStruct.CAN_RFLM = DISABLE; CAN_InitStruct.CAN_SJW = CAN_SJW_2tq; // 2, doporuceno CAN_InitStruct.CAN_TTCM = DISABLE; CAN_InitStruct.CAN_TXFP = DISABLE; CAN_Init(CAN1,&CAN_InitStruct); CAN_FilterInitStruct.CAN_FilterActivation = ENABLE; CAN_FilterInitStruct.CAN_FilterFIFOAssignment = 0; CAN_FilterInitStruct.CAN_FilterIdHigh = 0; CAN_FilterInitStruct.CAN_FilterIdLow = 0; CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0; CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0; CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStruct.CAN_FilterNumber = 0; CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit; CAN_FilterInit(&CAN_FilterInitStruct); CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); } // TIM3 ISR void TIM3_IRQHandler (void) { TIM3->SR = (uint16_t) ~TIM_IT_Update; //GPIOC->ODR ^= GPIO_Pin_1; //led if(cas_vysilani >= intPeriod) // nasobek casu flagStartADC { /* SPI */ data = SPI1->DR; //uloz data z SPI registru do promenne if(flagConfig){ // konfigurace měřících členů switch(stav) { case 0: //zacatek zpravy { GPIOA->BSRRH = GPIO_Pin_4; //CS low GPIOC->BSRRH = GPIO_Pin_0; //led modra intPeriod = 5; // zmena periody pro vstup do case } break; case 1: //CMD { SPI1->DR = 1; // WCRFG } break; // UPPER case 2: //CFGR0 { SPI1->DR = 228; // 1 = UV/OV comparator period -> Comparator OFF } break; case 3: //CFGR1 balancery { SPI1->DR = balanceryU1; //63 } break; case 4: //CFGR2 - balancery + maskovani { SPI1->DR = 240; //240 pro maskovani } break; case 5: //CFGR3 - maskovani { SPI1->DR = 252; // 1111 1100 } break; case 6: //CFGR4 - UV { SPI1->DR = 104; } break; case 7: //CFGR5 - OV { SPI1->DR = 175; } break; // MIDDLE case 8: //CFGR0 { SPI1->DR = 228; // 1 = UV/OV comparator period -> Comparator OFF } break; case 9: //CFGR1 balancery { SPI1->DR = balanceryM1; //255 } break; case 10: //CFGR2 - balancery + maskovani { SPI1->DR = balanceryM2; //15 } break; case 11: //CFGR3 - maskovani { SPI1->DR = 0; } break; case 12: //CFGR4 - UV { SPI1->DR = 104; } break; case 13: //CFGR5 - OV { SPI1->DR = 175; } break; // BOTTOM case 14: //CFGR0 { SPI1->DR = 228; // 1 = UV/OV comparator period -> Comparator OFF } break; case 15: //CFGR1 balancery { SPI1->DR = balanceryB1; //255 } break; case 16: //CFGR2 - balancery + maskovani { SPI1->DR = balanceryB2; // 15 } break; case 17: //CFGR3 - maskovani { SPI1->DR = 0; } break; case 18: //CFGR4 { SPI1->DR = 104; } break; case 19: //CFGR5 { SPI1->DR = 175; } break; case 20: //konec zpravy { GPIOA->BSRRL = GPIO_Pin_4; //CS high GPIOC->BSRRL = GPIO_Pin_0; //led modra intPeriod = 10; // zmena periody pro vstup do case flagConfig = 0; flagReadData = 1; } break; } stav = (stav + 1)%21; } if(flagReadData){ // vycteni dat napeti a teplot switch(stav) { case 0: //zacatek zpravy { GPIOA->BSRRH = GPIO_Pin_4; //CS low GPIOC->BSRRH = GPIO_Pin_0; //led modra } break; case 1: //CMD { SPI1->DR = 0x10; // stard ADC } break; case 2: //CS high { GPIOA->BSRRL = GPIO_Pin_4; //CS high GPIOC->BSRRL = GPIO_Pin_0; //led modra } break; case 3: { // volno } break; case 4: //zacatek zpravy { GPIOA->BSRRH = GPIO_Pin_4; //CS low GPIOC->BSRRH = GPIO_Pin_0; //led modra intPeriod = 1; // zmena periody pro vstup do case - rychle } break; case 5: //CMD - read voltage { SPI1->DR = 0x04; //0x04 } break; case 6: // chci az dalsi byte { SPI1->DR = 0x00; } break; // BOTTOM case 7: //CVR00 { poleUdata[0] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 8: //CVR01 { poleUdata[1] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 9: //CVR02 { poleUdata[2] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 10: //CVR03 { poleUdata[3] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 11: //CVR04 { poleUdata[4] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 12: //CVR05 { poleUdata[5] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 13: //CVR06 { poleUdata[6] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 14: //CVR07 { poleUdata[7] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 15: //CVR08 { poleUdata[8] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 16: //CVR09 { poleUdata[9] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 17: //CVR10 { poleUdata[10] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 18: //CVR11 { poleUdata[11] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 19: //CVR12 { poleUdata[12] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 20: //CVR13 { poleUdata[13] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 21: //CVR14 { poleUdata[14] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 22: //CVR15 { poleUdata[15] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 23: //CVR16 { poleUdata[16] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 24: //CVR17 { poleUdata[17] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 25: //PEC { poleUdata[18] = data; //uloz data z SPI registru SPI1->DR = 0; } break; // MIDDLE case 26: //CVR00 { poleUdata[18] = data; //uloz data z SPI registru, 18 je spravne !!! prepisuju PEC SPI1->DR = 0x00; } break; case 27: //CVR01 { poleUdata[19] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 28: //CVR02 { poleUdata[20] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 29: //CVR03 { poleUdata[21] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 30: //CVR04 { poleUdata[22] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 31: //CVR05 { poleUdata[23] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 32: //CVR06 { poleUdata[24] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 33: //CVR07 { poleUdata[25] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 34: //CVR08 { poleUdata[26] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 35: //CVR09 { poleUdata[27] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 36: //CVR10 { poleUdata[28] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 37: //CVR11 { poleUdata[29] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 38: //CVR12 { poleUdata[30] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 39: //CVR13 { poleUdata[31] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 40: //CVR14 { poleUdata[32] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 41: //CVR15 { poleUdata[33] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 42: //CVR16 { poleUdata[34] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 43: //CVR17 { poleUdata[35] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 44: //PEC - nazpracovavam { poleUdata[36] = data; SPI1->DR = 0; } break; // TOP case 45: //CVR00 { poleUdata[36] = data; //uloz data z SPI registru, 36 je správne, prepisuju PEC SPI1->DR = 0x00; } break; case 46: //CVR01 { poleUdata[37] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 47: //CVR02 { poleUdata[38] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 48: //CVR03 { poleUdata[39] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 49: //CVR04 { poleUdata[40] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 50: //CVR05 { poleUdata[41] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 51: //CVR06 { poleUdata[42] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 52: //CVR07 { poleUdata[43] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 53: //CVR08 { poleUdata[44] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 54: //CVR09 { poleUdata[45] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 55: //CVR10 { poleUdata[46] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 56: //CVR11 { poleUdata[47] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 57: //CVR12 { poleUdata[48] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 58: //CVR13 { poleUdata[49] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 59: //CVR14 { poleUdata[50] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 60: //CVR15 { poleUdata[51] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 61: //CVR16 { poleUdata[52] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 62: //CVR17 { poleUdata[53] = data; //uloz data z SPI registru SPI1->DR = 0; } break; case 63: //PEC - nazpracovavam { poleUdata[54] = data; SPI1->DR = 0; intPeriod = 10; } break; case 64: //CS high - konec zpravy { GPIOA->BSRRL = GPIO_Pin_4; //CS high GPIOC->BSRRL = GPIO_Pin_0; } break; case 65: { //volno } break; // TEPLOTA case 66: //zacatek zpravy { GPIOA->BSRRH = GPIO_Pin_4; //CS low GPIOC->BSRRH = GPIO_Pin_0; //led modra } break; case 67: //CMD { SPI1->DR = 0x30; // stard ADC tamperature } break; case 68: //CS high { GPIOA->BSRRL = GPIO_Pin_4; //CS high GPIOC->BSRRL = GPIO_Pin_0; //led modra } break; case 69: { //volno } break; case 70: { GPIOA->BSRRH = GPIO_Pin_4; //CS low GPIOC->BSRRH = GPIO_Pin_0; //led modra } break; case 71: { SPI1->DR = 0x08; // cti RDTMP intPeriod = 5; // zmena periody pro vstup do case } break; case 72: // chci az dalsi byte { SPI1->DR = 0x00; } break; //BOTTOM case 73: //TMPR0 { poleTdata[0] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 74: //TMPR1 { poleTdata[1] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 75: //TMPR2 { poleTdata[2] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 76: //TMPR3 { poleTdata[3] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 77: //TMPR4 { poleTdata[4] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 78: //PEC { poleTdata[5] = data;//uloz data z SPI registru SPI1->DR = 0x00; } break; // MIDDLE case 79: //TMPR0 { poleTdata[5] = data; //prepsani PECu SPI1->DR = 0x00; } break; case 80: //TMPR1 { poleTdata[6] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 81: //TMPR2 { poleTdata[7] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 82: //TMPR3 { poleTdata[8] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 83: //TMPR4 { poleTdata[9] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 84: //PEC { poleTdata[10] = data;//uloz data z SPI registru SPI1->DR = 0x00; } break; // UPPER case 85: //TMPR0 { poleTdata[10] = data; //prepsani PECu SPI1->DR = 0x00; } break; case 86: //TMPR1 { poleTdata[11] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 87: //TMPR2 { poleTdata[12] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 88: //TMPR3 { poleTdata[13] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 89: //TMPR4 { poleTdata[14] = data; //uloz data z SPI registru SPI1->DR = 0x00; } break; case 90: //PEC { poleTdata[15] = data;//uloz data z SPI registru SPI1->DR = 0x00; } break; case 91: { GPIOA->BSRRL = GPIO_Pin_4; //CS high GPIOC->BSRRL = GPIO_Pin_0; //led modra intPeriod = 10; // zmena periody pro vstup do case flagReadData = 0; flagNewData = 1; } break; } stav = (stav + 1)%92; } if(flagNewData){ // preskladani dat napeti do poleU - 16 bitova cisla indexU = 0; for(indexPole = 0; indexPole <= 29; indexPole++){ poleU[indexPole] = ((((poleUdata[indexU] & 0x00FF) | ((poleUdata[indexU + 1] & 0x000F) << 8)))*15)/10; indexPole++; poleU[indexPole] = ((((poleUdata[indexU + 1] & 0xF0) >> 4) | ((poleUdata[indexU + 2] & 0xFF) << 4))*15)/10; indexU = indexU + 3; } // preulozeni dat napeti do novych promennych - kdyby preruseni prislo behem vysilani, zmenili by se data - toto to omezi for(indexPole = 0; indexPole <= 57; indexPole++){ poleUdataCan[indexPole] = poleUdata[indexPole]; //poleUdataCAn se vysílá po CANu - obsahuje 8 bitove cisla, tak jak byly vycteny po SPI -> tzn. zarizeni, ktere je prijme je musi prepocitat } // BALANCERY celkoveU = 0; // potreba vynulovat !!!!!!! jinak pretéka a hodnota je nesmysl - porad by se pricitalo for(indexU = 0; indexU < 30; indexU++){ indexBal = 1 << indexU; celkoveU = celkoveU + poleU[indexU]; if(poleU[indexU] >= 4200){ balancery = balancery | indexBal; // pokud je napeti vetsi nez 4200 mV bude 1 na prislusno pozici - sepne balancer } if(poleU[indexU]<4170){ balancery = balancery & (~indexBal); // vypnuti balanceru kdyz napeti bdue mensi nez 4170 mV } } //balancery = 0xFFFFFFFF; // pro sepnutí vsech balanceru //preskupeni balanceru do jednotlivych promených - nutné pro konfiguraci LTC6802 (konfigurace se aktualizuje ve switch) balanceryB1 = ((uint8_t)(balancery & 0x000000FF)); balanceryB2 = (uint8_t)((balancery & 0x00000F00) >> 8); balanceryM1 = (uint8_t)((balancery & 0x000FF000) >> 12); balanceryM2 = (uint8_t)((balancery & 0x00F00000) >> 20); balanceryU1 = (uint8_t)((balancery & 0x3F000000) >> 24); // pro CAN - stejne jako napeti balanceryB1Can = balanceryB1; balanceryB2Can = balanceryB2; balanceryM1Can = balanceryM1; balanceryM2Can = balanceryM2; balanceryU1Can = balanceryU1; celkoveUCan = celkoveU; // napeti uloziste // prepocet teploty - neni idealni ale funkcni // preskupeni dat podle tabulku z datasheetu LTC 6802-1 tExt1 = (float)(((poleTdata[0] & 0xFF) | ((poleTdata[1] & 0x0F) << 8))); tExt1 = tExt1*1.5/1000; Rt1 = (tExt1*100500)/(3.075-tExt1); tExt2 = (float)(((poleTdata[1] & 0xF0) >> 4) | ((poleTdata[2] & 0xFF) << 4)); tExt2 = tExt2*1.5/1000; Rt2 = (tExt2*101400)/(3.075-tExt2); t1 = 0.000000001*Rt1*Rt1 - 0.0005*Rt1 + 64.4; // predpis z prolozeni bodu závislsoti odporu cidla na teplote t2 = 0.000000001*Rt2*Rt2 - 0.0005*Rt2 + 64.4; // predpis z prolozeni bodu závislsoti odporu cidla na teplote tExt3 = (float)(((poleTdata[5] & 0xFF) | ((poleTdata[6] & 0x0F) << 8))); tExt3 = tExt3*1.5/1000; Rt3 = (tExt3*100500)/(3.075-tExt3); tExt4 = (float)(((poleTdata[6] & 0xF0) >> 4) | ((poleTdata[7] & 0xFF) << 4)); tExt4 = tExt4*1.5/1000; Rt4 = (tExt4*101400)/(3.075-tExt4); t3 = 0.000000001*Rt3*Rt3 - 0.0005*Rt3 + 64.4; // predpis z prolozeni bodu závislsoti odporu cidla na teplote t4 = 0.000000001*Rt4*Rt4 - 0.0005*Rt4 + 64.4; tExt5 = (float)(((poleTdata[10] & 0xFF) | ((poleTdata[11] & 0x0F) << 8))); tExt5 = tExt5*1.5/1000; Rt5 = (tExt5*100500)/(3.075-tExt5); tExt6 = (float)(((poleTdata[11] & 0xF0) >> 4) | ((poleTdata[12] & 0xFF) << 4)); tExt6 = tExt6*1.5/1000; Rt6 = (tExt6*101400)/(3.075-tExt6); t5 = 0.000000001*Rt5*Rt5 - 0.0005*Rt5 + 64.4; // predpis z prolozeni bodu závislsoti odporu cidla na teplote t6 = 0.000000001*Rt6*Rt6 - 0.0005*Rt6 + 64.4; // preulozeni pro can t1Byte = (uint8_t)(t1); t2Byte = (uint8_t)(t2); t3Byte = (uint8_t)(t3); t4Byte = (uint8_t)(t4); t5Byte = (uint8_t)(t5); t6Byte = (uint8_t)(t6); // ulozeni do pole poleT[0] = t1Byte; poleT[1] = t2Byte; poleT[2] = t3Byte; poleT[3] = t4Byte; poleT[4] = t5Byte; poleT[5] = t6Byte; flagNewData = 0; // nulování flagu pro zpracovani dat flagConfig = 1; // priste pujde ve switch do konfigurace // vyhodnoceni pro optoclen CHARGER if(balancery == 0x3FFFFFFF){ //0x3FFFFFFF znamená sepnutí vsech balancéru -> nabito -> vypnuti nabijecky - na dobíjení se musí podle pravidel dohlízet -> nasleduje rucni odpojeni GPIOC->BSRRH = GPIO_Pin_3; // low - optoclen CHARGER rozepnut } else{ GPIOC->BSRRL = GPIO_Pin_3; // high - optoclen CHARGER sepnut } // vyhodncoeni pro BMS OK //proud - vyhodnocovani s hysterezi if(Ip > 600){ // vypnutí pri nadproudu 600A, BMS OK vypne pomocí flagOC flagOC = 1; } if(Ip < 400){ // pokud proud klesne pod 400 A, BMS OK sepne pomocí flagOC flagOC = 0; } // prepeti - vyhodnocovani s hysterezi for(indexU = 0; indexU < 30; indexU++){ indexNap = 1 << indexU; if(poleU[indexU] >= 4300){ // nastaveni priznaku pro vypnuti BMS OK pokud nejaky clanek prekroci 4300 mV prepeti = prepeti | indexNap; } if(poleU[indexU]<4250){ // hranice 4250 mV prepeti = prepeti & (~indexNap); // nastaveni priznaku pro opetovne sepnuti BMS OK } } if(prepeti)flagOV = 1; // jakakoliv hodnota krom 0, pak se nastavi priznak pro vypnuti BMS OK else flagOV = 0; // prepeti = 0 //podpeti - vyhodnocovani s hysterezi for(indexU = 0; indexU < 30; indexU++){ indexNap = 1 << indexU; if(poleU[indexU] <= 3000){ //nastaveni priznaku pro vypnuti BMS OK pokud nejaky clanek klesne pod 3000 mV podpeti = podpeti | indexNap; // } if(poleU[indexU]>3200){ podpeti = podpeti & (~indexNap); // nastaveni priznaku pro opetovne sepnuti BMS OK } } if(podpeti)flagUV = 1; // jakakoliv hodnota krom 0, BMS OK vypne else flagUV = 0; // podpeti = 0, tzn. clanky splnuji napeti // teploty - vyhodnocovani s hysterezi for(indexT = 0; indexT < 6; indexT++){ indexTep = 1 << indexT; if(poleT[indexT] > 80){ // 80 stupnu Celsia teplota = teplota | indexTep; // nastaveni priznaku pro vpynuti BMSK OK pri vysoke teplote } if(poleT[indexT] < 75){ teplota = teplota & (~indexTep); // nastaveni priznaku pro opetovne sepnuti BMS OK } } if(teplota)flagOT = 1; // BMS OK vypne else flagOT = 0; // clanky splnuji horni teplotni mez if(flagOC || flagOV || flagUV || flagOT){ // vypnuti podle hodnoty flagu - staci jeden flag v logicke jendicce GPIOC->BSRRH = GPIO_Pin_2; // low - BMS OK vypnuto } else{ GPIOC->BSRRL = GPIO_Pin_2; // high - pokud jsou flagy nulove, tak BMS Ok bude sepnuto } } cas_vysilani = 0; // nulovaní flag vstupu do switche } flagVysilaniCAN++; // flag pro vysílání CAN flagTimeCan++; // pro vypis dat v terminalu po 1 s cas_vysilani++; // flag vstupu do switche // start ADC ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_144Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_144Cycles); ADC_SoftwareStartConv(ADC1); ADC_SoftwareStartConv(ADC2); } // ADC ISR void ADC_IRQHandler(void){ ADC1->SR = (uint16_t) ~ADC_IT_EOC; // nulováni interrupt flagu ADC2->SR = (uint16_t) ~ADC_IT_EOC; // ulozeni dat z registru ADC Vout = ADC1->DR; Vref = ADC2->DR; // prepocet hodnot podle presnosti ADC - 12 bitu Vout = ((3300000/4095)*Vout)/1000; Vref = ((3300000/4095)*Vref)/1000; // vypocet proudu if(Vout >= Vref){ Ip = -(((Vout - Vref-24)*1000*Ipn)/1250)/35; // hodnota 24 je zjistený rozdil mezi Vout a Vref } if(Vout < Vref){ Ip = +(((Vref-Vout-24)*1000*Ipn)/1250)/35; } IpCan = (int16_t)(Ip); } /* END OF FILE */