STM32F030K6 настройка программы
Re: STM32F030K6 настройка программы
где то у вас с настройкой TIM нетак .
Hапример - > TIM14->ARR = 8; / " /* (2) Set ARR = 8, as timer clock is 1MHz the period is 9 us */"
У вас же куски с разных примеров надёрганы ? Bозьмите код про back_lite , там всё работает.
Чтобы менять шим, достаточно просто CCRx переписывать. Другие регистры менять не нужно.
Hельзя задавать параметры CCRx = 0 , CCRx = ARR .
100% включить /выключить шим ( если это так важно) можно командой SPL TIM_ForcedOC1Config().
Hапример - > TIM14->ARR = 8; / " /* (2) Set ARR = 8, as timer clock is 1MHz the period is 9 us */"
У вас же куски с разных примеров надёрганы ? Bозьмите код про back_lite , там всё работает.
Чтобы менять шим, достаточно просто CCRx переписывать. Другие регистры менять не нужно.
Hельзя задавать параметры CCRx = 0 , CCRx = ARR .
100% включить /выключить шим ( если это так важно) можно командой SPL TIM_ForcedOC1Config().
- Реклама
Re: STM32F030K6 настройка программы
Оказалось все дело было в delay_ms(10);, заменил на delay_mc(100);, светодиод перестал мигать.
Теперь нужно сделать чтение из EEPROM или FLASH памяти. Запись соответственно так:
И еще при включении АЦП stm32 зависает:
Возможно ли с помощью ЦАП генерировать мелодии на звукоизлучатель, как описано тут:
http://we.easyelectronics.ru/KT3012/odn ... stm32.html
Как выйти из спящего режима через нулевой уровень на пине РА0, если вход такой:
Теперь нужно сделать чтение из EEPROM или FLASH памяти. Запись соответственно так:
Спойлер
Код: Выделить всё
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
#ifdef STM32F072
#define FLASH_PAGE_SIZE ((uint32_t)0x00000800) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08009000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08020000) /* End @ of user Flash area */
#elif defined (STM32F091)
#define FLASH_PAGE_SIZE ((uint32_t)0x00000800) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08009000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08040000) /* End @ of user Flash area */
#else
#define FLASH_PAGE_SIZE ((uint32_t)0x00000400) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08006000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08007000) /* End @ of user Flash area */
#endif /* STM32F072 */
#define DATA_32 ((uint32_t)0x12345678)
uint32_t EraseCounter = 0x00, Address = 0x00;
uint32_t Data = 0x3210ABCD;
uint32_t NbrOfPage = 0x00;
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
__IO TestStatus MemoryProgramStatus = PASSED;
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
void Writetoflash(void)
{
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock();
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
if (FLASH_ProgramWord(Address, DATA_32) == FLASH_COMPLETE)
{
Address = Address + 4;
}
else
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
while (1)
{
}
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
/* Check if the programmed data is OK
MemoryProgramStatus = 0: data programmed correctly
MemoryProgramStatus != 0: number of words not programmed correctly ******/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = PASSED;
while (Address < FLASH_USER_END_ADDR)
{
Data = *(__IO uint32_t *)Address;
if (Data != DATA_32)
{
MemoryProgramStatus = FAILED;
}
Address = Address + 4;
}
}
void Eraseflash(void)
{
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock();
/* Erase the user Flash area
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
/* Clear pending flags (if any) */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
/* Define the number of page to be erased */
NbrOfPage = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;
/* Erase the FLASH pages */
for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
if (FLASH_ErasePage(FLASH_USER_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter))!= FLASH_COMPLETE)
{
/* Error occurred while sector erase.
User can add here some code to deal with this error */
while (1)
{
}
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
}
И еще при включении АЦП stm32 зависает:
Спойлер
Код: Выделить всё
#define ADC_VREF_TYPE 0xC0
__IO uint16_t ADC0ConvertedValue = 0, ADC1ConvertedValue = 0, ADC1ConvertedVoltage = 0;
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
ADC0ConvertedValue = ADC_GetConversionValue(ADC1);
return ADC0ConvertedValue;
}
static void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// GPIOC Periph clock enable
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
// ADC1 Periph clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// Configure ADC Channel11 as analog input
#ifdef USE_STM320518_EVAL
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
#else
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
#endif // USE_STM320518_EVAL
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADCs DeInit
ADC_DeInit(ADC1);
// Initialize ADC structure
ADC_StructInit(&ADC_InitStructure);
// Configure the ADC1 in continuous mode with a resolution equal to 12 bits
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure);
// Convert the ADC1 Channel 11 with 239.5 Cycles as sampling time
#ifdef USE_STM320518_EVAL
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
#else
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
#endif // USE_STM320518_EVAL
// ADC Calibration
ADC_GetCalibrationFactor(ADC1);
// Enable the ADC peripheral
ADC_Cmd(ADC1, ENABLE);
// Wait the ADRDY flag
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
// ADC1 regular Software Start Conv
ADC_StartOfConversion(ADC1);
}
http://we.easyelectronics.ru/KT3012/odn ... stm32.html
Спойлер
Код: Выделить всё
void TIM3_IRQHandler(void)
{
TIM3->SR &= ~TIM_SR_UIF;//сбросить флаг
t++; //инкремент
b=t*(t>>5|t>>8)>>(t>>16);//wan1
//некоторые не проверял еще
///adc=t*((t>>9|t>>8)&63&t>>4);
///adc=t*((t>>12|t>>8)&63&t>>4);
///adc=t*((t>>9|t>>13)&25&t>>6);
///adc=t*(t>>11&t>>8&123&t>>3);//
///adc=t*(t>>8*(t>>15|t>>8)&(20|(t>>19)*5>>t|t>>3));//15 sec minitunes by visy PONG
///adc=(-t*4095)*(255&t*(t&t>>13)>>12)+(127&t*(234&t>>8&t>>3)>>(3&t>>14));// fg
//adc=t*(t>>(t>>9&t>>8)&63&t>>4);//
//adc=((t*(t>>8|t>>9)&46&t>>8)^(t&t>>13|t>>6));//Lost
//adc=t*5&(t>>7)|t*3&(t*4>>10);//)>>(t>>16);///Crash
DAC->DHR12R1 = b<<4; // загрузка в ЦАП1
}
Как выйти из спящего режима через нулевой уровень на пине РА0, если вход такой:
Спойлер
Код: Выделить всё
sleep_counter++;
if((sleep_counter>=400000)&&(lamp_start==0))
{
GPIO_ResetBits(GPIOF, GPIO_Pin_0); //A
GPIO_ResetBits(GPIOF, GPIO_Pin_1); //B
GPIO_ResetBits(GPIOA, GPIO_Pin_3); //C
GPIO_ResetBits(GPIOB, GPIO_Pin_1); //D
GPIO_ResetBits(GPIOA, GPIO_Pin_9); //E
GPIO_ResetBits(GPIOA, GPIO_Pin_10); //F
GPIO_ResetBits(GPIOA, GPIO_Pin_13); //G
GPIO_SetBits(GPIOA, GPIO_Pin_14); //DP
//sleep=1;
sleep_counter=0;
/* Clear Wakeup flag */
PWR->CR |= PWR_CR_CWUF;
/* Select STANDBY mode */
PWR->CR |= PWR_CR_PDDS;
/* Set SLEEPDEEP bit of Cortex-M0 System Control Register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* Request Wait For Interrupt */
__WFI();
}
Re: STM32F030K6 настройка программы
Имеются мелодии для ATmega88PA-AU, одна функция nota, сами мелодии и настройка таймера с обработчиком прерывания. Нужно перенести мелодии под stm32. Как правильно настроить таймер.
Даташит на ATmega88PA: http://www.atmel.com/images/Atmel-8271- ... mplete.pdf
Даташит под stm32: http://www.st.com/web/en/resource/techn ... 091010.pdf
Программа для ATmega88PA-AU:
Для stm32:
Даташит на ATmega88PA: http://www.atmel.com/images/Atmel-8271- ... mplete.pdf
Даташит под stm32: http://www.st.com/web/en/resource/techn ... 091010.pdf
Программа для ATmega88PA-AU:
Спойлер
Код: Выделить всё
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 31,250 kHz
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x04;
TCNT0=222;
OCR0A=0x00;
OCR0B=0x00;
// Timer 0 overflow interrupt service routine
#pragma vector=TIMER0_OVF_vect
__interrupt void TIMER0_OVF(void)
{
i_temp++;
TCNT0=216;
}
void nota (unsigned int ton, unsigned int dlit, unsigned int pause)
{
unsigned int k=0, d;
TCCR0B=0x04;
TIMSK0=0x01;
i_temp=0;
d=dlit;
dlit=(dlit*95)/100;
while (i_temp<dlit)
{
asm("wdr");
for (k=0; k<ton; k++)
{
asm("wdr");
__delay_cycles(10);
}
Zum=!Zum;
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
for (k=0; k<ton; k++)
{
__delay_cycles(10);
asm("wdr");
}
Zum=0;
while (i_temp<d)
{
asm("wdr");
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
while (i_temp<=pause)
{
asm("wdr");
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
Zum=0;
TCCR0B=0x00;
TIMSK0=0x01;
}
Спойлер
Код: Выделить всё
#define _inverse_pin_() (GPIOA->ODR = GPIOA->ODR^(1UL<<2))
#define Zum (GPIOA->IDR & GPIO_IDR_2)
static void TIM_Config3(void) //
{
// Clock value: 31,250 kHz
// Mode: Normal top=FFh
TIM3->CR1 |= (TIM_CR1_CMS_1 | TIM_CR1_CEN);
TIM3->DIER |= (TIM_DIER_UIE);
TIM3->CNT=0xDE;
TIM3->PSC=0x255;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA clock enable */
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA , ENABLE);
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);
/* GPIOA Configuration: Channel 1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_4);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 1023;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// Channel 1 Configuration in PWM mode
//TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1022;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
NVIC_EnableIRQ(TIM3_IRQn); // (1)
NVIC_SetPriority(TIM3_IRQn, 1); // (2)
}
void TIM3_IRQHandler(void) //
{
i_temp++;
TIM3->CNT=216;
TIM3->SR &= ~TIM_SR_UIF; // clear the UIF flag
}
void nota (unsigned int ton, unsigned int dlit, unsigned int pause)
{
unsigned int k=0, d;
TIM3->PSC=0x255;
TIM3->CR1 |= (TIM_CR1_CMS_1 | TIM_CR1_CEN);
i_temp=0;
d=dlit;
dlit=(dlit*95)/100;
while (i_temp<dlit)
{
//asm("wdr");
for (k=0; k<ton; k++)
{
//asm("wdr");
__delay_cycles(10);
}
_inverse_pin_(); //Zum=!Zum;
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
for (k=0; k<ton; k++)
{
__delay_cycles(10);
//asm("wdr");
}
GPIOA ->ODR &= ~(1<<2); //Zum=0;
while (i_temp<d)
{
//asm("wdr");
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
while (i_temp<=pause)
{
//asm("wdr");
if ((Start==0||Select==0)&&sz_start_musik==1)
break;
}
GPIOA ->ODR &= ~(1<<2); //Zum=0;
TIM3->CR1 &= ~TIM_CR1_CEN; //TCCR0B=0x00;
//TIM3->DIER &= ~TIM_DIER_CC1IE; //TIMSK0=0x01;
TIM3->DIER &= ~TIM_DIER_UIE; //TIMSK0=0x01;
TIM3->DIER |= (TIM_DIER_UIE);
}
Re: STM32F030K6 настройка программы
C AЦП - программу нужно поправить под вашу схему.
У вас два канала ? Время выборки будет ~17us . Так и нужно ?
АЦП у вас работает постоянно , а считаваете вы с него толко с одного канала.
Если нжны данные с двух каналов , то нужно или DMA настроить - это во всех примерах есть ,
или давать команду софтом на каждое преобразование.
с таймерами полная каша.
если прескалер настривается на 31250 гц , то PRS = 20000000 / 31250 = 640.
Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер.
и перенастроить c 4 на 2 канала
void ADC_GetSlowSensorsData(void)
{
/*
1. Prefix : Switch ADC from sampling of the fast sensor by DMA
to single shot measurements of the slow sensors.
2. Get ADC samples from all the temperature sensors.
3. Switch ADC back to measure coil current
*/
uint32_t i;
// 1. Prefix :
// // Disable ADC_DMA //
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, DISABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// do not multiple channels acquisition
ADC_DiscModeCmd(ADC1, ENABLE); // это важно, а то будет все каналы проходить с однoго пинка .
// SwitchToSlowSensorPool
// change chanels
ADC1->CHSELR =
(uint32_t)(
ADC_Channel_CoilTempSensor
|ADC_Channel_TempSensor
|ADC_Channel_Vrefint
|ADC_Channel_Vbat
);
// change sampling time
ADC1->SMPR &= ~ADC_SMPR_SMP;
ADC1->SMPR = ADC_SampleTime_239_5Cycles;
// ADC1 is ready for slow sensors pool
// 2. Get data from slow sensors pool
for ( i=0; i<4; i++)
{
ADC_StartOfConversion(ADC1);
// Wait until conversion complete
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
slow_sensors_data = ADC_GetConversionValue(ADC1);
}
ADC_StopOfConversion(ADC1);
// 3. Switch back to the fast sensor
// Enable ADC_DMA
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, ENABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// Adc1_SwitchToFastChannel();
// // ADC1 is ready for coil current sensors
}
У вас два канала ? Время выборки будет ~17us . Так и нужно ?
АЦП у вас работает постоянно , а считаваете вы с него толко с одного канала.
Если нжны данные с двух каналов , то нужно или DMA настроить - это во всех примерах есть ,
или давать команду софтом на каждое преобразование.
с таймерами полная каша.
если прескалер настривается на 31250 гц , то PRS = 20000000 / 31250 = 640.
Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер.
Спойлер
это из рабочего проекта , ненужное вам - в комментахи перенастроить c 4 на 2 канала
void ADC_GetSlowSensorsData(void)
{
/*
1. Prefix : Switch ADC from sampling of the fast sensor by DMA
to single shot measurements of the slow sensors.
2. Get ADC samples from all the temperature sensors.
3. Switch ADC back to measure coil current
*/
uint32_t i;
// 1. Prefix :
// // Disable ADC_DMA //
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, DISABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// do not multiple channels acquisition
ADC_DiscModeCmd(ADC1, ENABLE); // это важно, а то будет все каналы проходить с однoго пинка .
// SwitchToSlowSensorPool
// change chanels
ADC1->CHSELR =
(uint32_t)(
ADC_Channel_CoilTempSensor
|ADC_Channel_TempSensor
|ADC_Channel_Vrefint
|ADC_Channel_Vbat
);
// change sampling time
ADC1->SMPR &= ~ADC_SMPR_SMP;
ADC1->SMPR = ADC_SampleTime_239_5Cycles;
// ADC1 is ready for slow sensors pool
// 2. Get data from slow sensors pool
for ( i=0; i<4; i++)
{
ADC_StartOfConversion(ADC1);
// Wait until conversion complete
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
slow_sensors_data = ADC_GetConversionValue(ADC1);
}
ADC_StopOfConversion(ADC1);
// 3. Switch back to the fast sensor
// Enable ADC_DMA
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, ENABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// Adc1_SwitchToFastChannel();
// // ADC1 is ready for coil current sensors
}
Re: STM32F030K6 настройка программы
Нифига не проще и не правильно. Прескалером можно задавать только октаву. ARR должна задавать саму ноту. CCR задаёт 50 % ШИМ. Юзая DMAR можно из буфера выталкивать всю эту канитель одновременно.Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер.
Чтобы замутить оркестр можно поискать статьи по OSA tester или testerplus. Там на пальцах раскидывалось что к чему.
- Реклама
Re: STM32F030K6 настройка программы
Вы же прескалером не пополам частоту делите . Если 16 бит таймер , ARR = 4 , CCR = 2 , то для полосы 50 ~ 3500 вполне всё равно .
На ноту не так уверенно попадаешь , но зато проще.
Три регистра менять, конечно , правильно , но человек и с одним разобраться не может.
Как освоит - потом и в трех сам поменяет, без проблем.
С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
На ноту не так уверенно попадаешь , но зато проще.
Три регистра менять, конечно , правильно , но человек и с одним разобраться не может.
Как освоит - потом и в трех сам поменяет, без проблем.
С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
Re: STM32F030K6 настройка программы
Вообщем АЦП никак не работает, пробовал даже так, но все равно bat_low=1, подавал на АЦП от 3В до 3.6В:
Спойлер
Код: Выделить всё
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
gpioConf.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2); //PA0 ADC0
gpioConf.GPIO_Mode = GPIO_Mode_AF;
gpioConf.GPIO_Speed = GPIO_Speed_50MHz;
gpioConf.GPIO_OType = GPIO_OType_PP;
gpioConf.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpioConf);
static void ConfigureGPIO(void)
{
/* (1) Enable the peripheral clock of GPIOA */
/* (2) Select output mode (01) on GPIOA pin 0 and 1 */
RCC->AHBENR |= RCC_AHBENR_GPIOCEN; /* (1) */
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER0|GPIO_MODER_MODER1)) \
| (GPIO_MODER_MODER0_0|GPIO_MODER_MODER1_0); /* (2) */
}
/**
* @brief This function enables the clock in the RCC for the ADC
* and start HSI 14MHz dedicated RC oscillator
* @param None
* @retval None
*/
static void SetClockForADC(void)
{
/* (1) Enable the peripheral clock of the ADC */
/* (2) Start HSI14 RC oscillator */
/* (3) Wait HSI14 is ready */
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */
RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) /* (3) */
{
/* For robust implementation, add here time-out management */
}
}
/**
* @brief This function performs a self-calibration of the ADC
* @param None
* @retval None
*/
static void CalibrateADC(void)
{
/* (1) Ensure that ADEN = 0 */
/* (2) Clear ADEN */
/* (3) Launch the calibration by setting ADCAL */
/* (4) Wait until ADCAL=0 */
if ((ADC1->CR & ADC_CR_ADEN) != 0) /* (1) */
{
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); /* (2) */
}
ADC1->CR |= ADC_CR_ADCAL; /* (3) */
while ((ADC1->CR & ADC_CR_ADCAL) != 0) /* (4) */
{
/* For robust implementation, add here time-out management */
}
}
/**
* @brief This function configure the ADC to convert the internal reference voltage (VRefInt)
* The conversion frequency is 14MHz
* @param None
* @retval None
*/
static void ConfigureADC(void)
{
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
/* (2) Select the auto off mode */
/* (3) Select CHSEL17 for VRefInt */
/* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
/* (5) Wake-up the VREFINT (only for VBAT, Temp sensor and VRefInt) */
//ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_AUTOFF | ADC_CFGR1_RES_1; /* (2) */ //8bit
ADC1->CHSELR = ADC_CHSELR_CHSEL0; /* (3) */
ADC1->SMPR |= 0x7; /* (4) */
//ADC->CCR |= ADC_CCR_VREFEN; /* (5) */
}
/**
* @brief This function enables the ADC
* @param None
* @retval None
*/
static void EnableADC(void)
{
/* (1) Enable the ADC */
/* (2) Wait until ADC ready */
do
{
/* For robust implementation, add here time-out management */
ADC1->CR |= ADC_CR_ADEN; /* (1) */
}while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) /* (2) */;
}
/**
* @brief This function disables the ADC
* @param None
* @retval None
*/
static void DisableADC(void)
{
/* (1) Ensure that no conversion on going */
/* (2) Stop any ongoing conversion */
/* (3) Wait until ADSTP is reset by hardware i.e. conversion is stopped */
/* (4) Disable the ADC */
/* (5) Wait until the ADC is fully disabled */
if ((ADC1->CR & ADC_CR_ADSTART) != 0) /* (1) */
{
ADC1->CR |= ADC_CR_ADSTP; /* (2) */
}
while ((ADC1->CR & ADC_CR_ADSTP) != 0) /* (3) */
{
/* For robust implementation, add here time-out management */
}
ADC1->CR |= ADC_CR_ADDIS; /* (4) */
while ((ADC1->CR & ADC_CR_ADEN) != 0) /* (5) */
{
/* For robust implementation, add here time-out management */
}
}
ConfigureGPIO();
SetClockForADC();
CalibrateADC();
EnableADC();
ConfigureADC();
/* Performs the AD converion */
ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversion */
while ((ADC1->ISR & ADC_ISR_EOC) == 0); /* wait end of conversion */
adc0=ADC_DR_DATA;
if(adc0>247) bat_low=1; //3.5V 247<...
if((adc0>240)&&(adc0<=247)) bat_low=2; // 3.4V 240<247 3.5V
if((adc0>133)&&(adc0<=240)) bat_low=3; // 3.3V 233<240 3.4V
if(adc0<=133) bat_low=4; // 3.3V ...<233
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
Код: Выделить всё
/* (1) Enable the peripheral clock of GPIOA */
/* (2) Select output mode (01) on GPIOA pin 0 and 1 */
RCC->AHBENR |= RCC_AHBENR_GPIOCEN; /* (1) */ ????????????????????????????????????????????
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER0|GPIO_MODER_MODER1)) \
| (GPIO_MODER_MODER0_0|GPIO_MODER_MODER1_0); /* (2) */ из сниппетсов:
Код: Выделить всё
void ConfigureGPIOasAnalog(void)
{
/* (1) Enable the peripheral clock of GPIOA */
/* (2) Select analog mode for PA0 PA4 */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* (1) */
GPIOA->MODER |= (GPIO_MODER_MODER0 | GPIO_MODER_MODER4); /* (2) */
}Re: STM32F030K6 настройка программы
Вредно давать вредные советы а не с ДМА связываться. Как и вредно без надобности торчать в программных задержках.pixar писал(а): С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
Re: STM32F030K6 настройка программы
я соглашусь.
а вы киньте человеку конкретный кусок кода под его проц.
посмотрим как быстро он его запустит.
а вы киньте человеку конкретный кусок кода под его проц.
посмотрим как быстро он его запустит.
Re: STM32F030K6 настройка программы
То же самое, АЦП не работает. На индикаторе постоянно отображается цифра 9 если по условию if значение больше 255, т.е. АЦП настроен на 8 бит, а значение превышено. На вход пина подается от 3В до 3.6В. GPIO перенастроил. Stm32 настроен на 20 МГц.
Спойлер
Код: Выделить всё
static void ConfigureGPIO(void)
{
/* (1) Enable the peripheral clock of GPIOA */
/* (2) Select output mode (01) on GPIOA pin 0 and 1 */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* (1) */
GPIOA->MODER |= GPIO_MODER_MODER0_1;/* (2) */
}
/**
* @brief This function enables the clock in the RCC for the ADC
* and start HSI 14MHz dedicated RC oscillator
* @param None
* @retval None
*/
static void SetClockForADC(void)
{
/* (1) Enable the peripheral clock of the ADC */
/* (2) Start HSI14 RC oscillator */
/* (3) Wait HSI14 is ready */
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */
RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) /* (3) */
{
/* For robust implementation, add here time-out management */
}
}
/**
* @brief This function performs a self-calibration of the ADC
* @param None
* @retval None
*/
static void CalibrateADC(void)
{
/* (1) Ensure that ADEN = 0 */
/* (2) Clear ADEN */
/* (3) Launch the calibration by setting ADCAL */
/* (4) Wait until ADCAL=0 */
if ((ADC1->CR & ADC_CR_ADEN) != 0) /* (1) */
{
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); /* (2) */
}
ADC1->CR |= ADC_CR_ADCAL; /* (3) */
while ((ADC1->CR & ADC_CR_ADCAL) != 0) /* (4) */
{
/* For robust implementation, add here time-out management */
}
}
/**
* @brief This function configure the ADC to convert the internal reference voltage (VRefInt)
* The conversion frequency is 14MHz
* @param None
* @retval None
*/
static void ConfigureADC(void)
{
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
/* (2) Select the auto off mode */
/* (3) Select CHSEL17 for VRefInt */
/* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
/* (5) Wake-up the VREFINT (only for VBAT, Temp sensor and VRefInt) */
ADC1->CFGR2 |= 0x80000000;//ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_AUTOFF | ADC_CFGR1_RES_1; /* (2) */ //8bit
ADC1->CHSELR = ADC_CHSELR_CHSEL0; /* (3) */
ADC1->SMPR |= 0x7; // 239.5 ADC clock cycles (4)
//ADC->CCR |= ADC_CCR_VREFEN; /* (5) */
}
/**
* @brief This function enables the ADC
* @param None
* @retval None
*/
static void EnableADC(void)
{
/* (1) Enable the ADC */
/* (2) Wait until ADC ready */
do
{
/* For robust implementation, add here time-out management */
ADC1->CR |= ADC_CR_ADEN; /* (1) */
}while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) /* (2) */;
}
void main(void)
{
ConfigureGPIO();
SetClockForADC();
EnableADC();
ConfigureADC();
while (1)
{
/* Performs the AD converion */
ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversion */
while ((ADC1->ISR & ADC_ISR_EOC) == 0); /* wait end of conversion */
adc0=ADC_DR_DATA;
if(adc0<100) timer=6;
if((adc0>100)&&(adc0<=200)) timer=7;
if((adc0>200)&&(adc0<=255)) timer=8;
if(adc0>255) timer=9;
}
}
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
вы на какую ногу измеряемое напряжение подаете? Если на PA0, то ее надо перевести в analog mode:
Код: Выделить всё
GPIOA->MODER |= GPIO_MODER_MODER0;Re: STM32F030K6 настройка программы
На РА0 через делитель напряжения, на пине от 3В до 3.6В. Заменил на:
Тоже самое, значение в АЦП 255 и при уменьшении напряжения до 3В не уменьшается.
Правильная ли схема включения во вложении.
Код: Выделить всё
GPIOA->MODER |= GPIO_MODER_MODER0;Правильная ли схема включения во вложении.
- Вложения
-
- Scheme_1.gif
- (32.11 КБ) 396 скачиваний
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
5 ногу VDDA надо к 3.5V подключить, как пример см. схему тут: https://andybrown.me.uk/2015/10/31/stm32f042dev/
з.ы. проверьте на вашей схеме как электролитические конденсаторы подключены - полярность как попало
з.ы. проверьте на вашей схеме как электролитические конденсаторы подключены - полярность как попало
Re: STM32F030K6 настройка программы
Подключил 5 пин к +Vdd. Теперь проблема в том, что при уменьшении напряжения питания с 4В до 3В, опорное напряжение тоже уменьшается и значение в регистре АЦП не меняется. В даташите что-то написано про Vrefint и ADC_IN17. Но как его настроить к примеру на 2.7В.
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
откуда взялось 4В? Параметры микроконтроллера:
– Digital & I/Os supply: VDD= 2.4 V to 3.6 V
– Analog supply: VDDA= VDDto 3.6 V
Опорное напряжение АЦП VREF= VDDA, потому и меняется.
VREFINT Internal reference voltage, значение 1.16В - 1.24В, да можно измерить на channel ADC_IN17, как использовать можно тут почитать:
http://www.rtos.be/2013/05/stm32f100-wh ... e-for-adc/
– Digital & I/Os supply: VDD= 2.4 V to 3.6 V
– Analog supply: VDDA= VDDto 3.6 V
Опорное напряжение АЦП VREF= VDDA, потому и меняется.
VREFINT Internal reference voltage, значение 1.16В - 1.24В, да можно измерить на channel ADC_IN17, как использовать можно тут почитать:
http://www.rtos.be/2013/05/stm32f100-wh ... e-for-adc/
Re: STM32F030K6 настройка программы
Как сделать если это возможно, чтобы изменение опорного напряжения АЦП VREF = VDDA не влияло на значение ADC_DR_DATA.
А так зависает:
А так зависает:
Код: Выделить всё
sample_ch17 = *(__IO uint32_t *)0x1FFFF7BA;
adc0 = ADC_DR_DATA * 3300 / sample_ch17;
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
Опорное напряжение на то и опорное, чтоб быть стабильным.
Как прочитать несколько каналов есть в примерах документации RM:
остается подсчитать значение в милливольтах для нужного канала (CHSEL0):
Как прочитать несколько каналов есть в примерах документации RM:
Спойлер
Код: Выделить всё
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
/* (2) Select CHSEL0, CHSEL9, CHSEL10 andCHSEL17 for VRefInt */
/* (3) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater
than 17.1us */
/* (4) Wake-up the VREFINT (only for VBAT, Temp sensor and VRefInt) */
//ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL9
| ADC_CHSELR_CHSEL10 | ADC_CHSELR_CHSEL17; /* (2) */
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (3) */
ADC->CCR |= ADC_CCR_VREFEN; /* (4) */
while (1)
{
/* Performs the AD conversion */
ADC1->CR |= ADC_CR_ADSTART; /* Start the ADC conversion */
for (i = 0; i < 4; i++)
{
while ((ADC1->ISR & ADC_ISR_EOC) == 0) /* Wait end of conversion */
{
/* For robust implementation, add here time-out management */
}
ADC_Result[i] = ADC1->DR; /* Store the ADC conversion result */
}
ADC1->CFGR1 ^= ADC_CFGR1_SCANDIR; /* Toggle the scan direction */
}
Код: Выделить всё
XmV = ADC_Result[0] * 1200 / ADC_Result[3]; Re: STM32F030K6 настройка программы
в процессоре есть регистр , в котором хранится калиброванное значение внутреней опоры, снятое своим АЦП при питании 3.3вольт +/-1% .
Если измерять внутренюю опору при нестабильном AVdd и сравнивать результат с калиброванным значением, считываемым из регистра процессора , то можно просчитать реальное напряжение питания AVdd и учитывать его изменение при расчёте напряжения на входе АЦП. Процесс итерационный, AVdd_calc сходится после двух-трех итераций.
Точность не очень, у меня даёт , например, расчётное 3.30~3.35 вольта при реальном 3.25.
Но если батарейка плавает , то хоть что-то.
#define VDDA_ADC 3300
#define VREF_CAL_ADDR ((uint16_t*)((uint32_t) 0x1FFFF7BA))
#define cal_const_v_ref (uint16_t)*VREF_CAL_ADDR
uint16_t vdda_adc = VDDA_ADC;
....
void ADC_ProcessData(void)
{
ADC_GetSlowSensorsData();
пересчитанное напряжение питания AVDD
// 3300 is voltage of the factory calibration for STM32. Do not replace 3300 by VDDA_ADC.
vdda_adc = (3300*cal_const_v_ref )/adc_data_v_ref;
пересчитанное напряжение внутреннего источника
v_ref_int = (adc_data_v_ref * vdda_adc )/ADC_FULL_SCALE;
напряжение на входе батарейки
v_bat = (adc_data_v_bat * vdda_adc) /ADC_FULL_SCALE;
} // ADC_ProcessData()
Если измерять внутренюю опору при нестабильном AVdd и сравнивать результат с калиброванным значением, считываемым из регистра процессора , то можно просчитать реальное напряжение питания AVdd и учитывать его изменение при расчёте напряжения на входе АЦП. Процесс итерационный, AVdd_calc сходится после двух-трех итераций.
Точность не очень, у меня даёт , например, расчётное 3.30~3.35 вольта при реальном 3.25.
Но если батарейка плавает , то хоть что-то.
Спойлер
#define ADC_FULL_SCALE 4095#define VDDA_ADC 3300
#define VREF_CAL_ADDR ((uint16_t*)((uint32_t) 0x1FFFF7BA))
#define cal_const_v_ref (uint16_t)*VREF_CAL_ADDR
uint16_t vdda_adc = VDDA_ADC;
....
void ADC_ProcessData(void)
{
ADC_GetSlowSensorsData();
пересчитанное напряжение питания AVDD
// 3300 is voltage of the factory calibration for STM32. Do not replace 3300 by VDDA_ADC.
vdda_adc = (3300*cal_const_v_ref )/adc_data_v_ref;
пересчитанное напряжение внутреннего источника
v_ref_int = (adc_data_v_ref * vdda_adc )/ADC_FULL_SCALE;
напряжение на входе батарейки
v_bat = (adc_data_v_bat * vdda_adc) /ADC_FULL_SCALE;
} // ADC_ProcessData()
Re: STM32F030K6 настройка программы
Значение на индикаторе timer=3, т.е. ADC<100 или = 0.
Сделал так:
Почему величина adc_data_v_bat при увеличении напряжения уменьшается. Как прочитать значение в АЦП с пина VDDA.
Спойлер
Код: Выделить всё
int v_ref_int, v_bat, adc_data_v_ref, adc_data_v_bat;
void ADC_GetSlowSensorsData(void)
{
/*
1. Prefix : Switch ADC from sampling of the fast sensor by DMA
to single shot measurements of the slow sensors.
2. Get ADC samples from all the temperature sensors.
3. Switch ADC back to measure coil current
*/
uint32_t i;
char slow_sensors_data[2] = {adc_data_v_ref, adc_data_v_bat};
// 1. Prefix :
// // Disable ADC_DMA //
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, DISABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// do not multiple channels acquisition
ADC_DiscModeCmd(ADC1, ENABLE); // это важно, а то будет все каналы проходить с однoго пинка .
// SwitchToSlowSensorPool
// change chanels
ADC1->CHSELR = (uint32_t)(ADC_Channel_Vrefint|ADC_Channel_Vbat);
// change sampling time
ADC1->SMPR=0x7; //&= ~ADC_SMPR_SMP;
ADC1->SMPR = ADC_SampleTime_239_5Cycles;
// ADC1 is ready for slow sensors pool
// 2. Get data from slow sensors pool
for ( i=0; i<2; i++)
{
ADC_StartOfConversion(ADC1);
// Wait until conversion complete
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
slow_sensors_data[i] = ADC_GetConversionValue(ADC1);
}
ADC_StopOfConversion(ADC1);
// 3. Switch back to the fast sensor
// Enable ADC_DMA
// ADC_Cmd(ADC1, DISABLE);
// ADC_DMACmd(ADC1, ENABLE);
// ADC_Cmd(ADC1, ENABLE);
// while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)) {;}
// Adc1_SwitchToFastChannel();
// // ADC1 is ready for coil current sensors
}
#define ADC_FULL_SCALE 4095
#define VDDA_ADC 3300
#define VREF_CAL_ADDR ((uint16_t*)((uint32_t) 0x1FFFF7BA))
#define cal_const_v_ref (uint16_t)*VREF_CAL_ADDR
uint16_t vdda_adc = VDDA_ADC;
void ADC_ProcessData(void)
{
ADC_GetSlowSensorsData();
//пересчитанное напряжение питания AVDD
// 3300 is voltage of the factory calibration for STM32. Do not replace 3300 by VDDA_ADC.
vdda_adc = (3300*cal_const_v_ref )/adc_data_v_ref;
//пересчитанное напряжение внутреннего источника
v_ref_int = (adc_data_v_ref * vdda_adc )/ADC_FULL_SCALE;
//напряжение на входе батарейки
v_bat = (adc_data_v_bat * vdda_adc) /ADC_FULL_SCALE;
} // ADC_ProcessData()
while(1)
{
ADC_ProcessData();
adc0 = v_bat;
if(adc0<100) timer=3;
if((adc0>100)&&(adc0<=200)) timer=4;
if((adc0>200)&&(adc0<=240)) timer=5;
if((adc0>240)&&(adc0<=245)) timer=6;
if((adc0>245)&&(adc0<=250)) timer=7;
if((adc0>250)&&(adc0<=255)) timer=8;
if(adc0>255) timer=9;
}
Сделал так:
Спойлер
Код: Выделить всё
void ADC_adc_data_v_ref(void)
{
uint32_t i;
// do not multiple channels acquisition
ADC_DiscModeCmd(ADC1, ENABLE); // это важно, а то будет все каналы проходить с однoго пинка .
// SwitchToSlowSensorPool
// change chanels
ADC1->CHSELR = (uint32_t)(ADC_Channel_Vrefint);
// change sampling time
ADC1->SMPR=0x7; //&= ~ADC_SMPR_SMP;
ADC1->SMPR = ADC_SampleTime_239_5Cycles;
// ADC1 is ready for slow sensors pool
// 2. Get data from slow sensors pool
for ( i=0; i<1; i++)
{
ADC_StartOfConversion(ADC1);
// Wait until conversion complete
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
adc_data_v_ref = ADC_GetConversionValue(ADC1);
}
ADC_StopOfConversion(ADC1);
}
void ADC_adc_data_v_bat(void)
{
uint32_t i;
// do not multiple channels acquisition
ADC_DiscModeCmd(ADC1, ENABLE); // это важно, а то будет все каналы проходить с однoго пинка .
// SwitchToSlowSensorPool
// change chanels
ADC1->CHSELR = (uint32_t)(ADC_Channel_Vbat);
// change sampling time
ADC1->SMPR=0x7; //&= ~ADC_SMPR_SMP;
ADC1->SMPR = ADC_SampleTime_239_5Cycles;
// ADC1 is ready for slow sensors pool
// 2. Get data from slow sensors pool
for ( i=0; i<1; i++)
{
ADC_StartOfConversion(ADC1);
// Wait until conversion complete
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
adc_data_v_bat = ADC_GetConversionValue(ADC1);
}
ADC_StopOfConversion(ADC1);
}
#define ADC_FULL_SCALE 4095
#define VDDA_ADC 3300
#define VREF_CAL_ADDR ((uint16_t*)((uint32_t) 0x1FFFF7BA))
#define cal_const_v_ref (uint16_t)*VREF_CAL_ADDR
uint16_t vdda_adc = VDDA_ADC;
void ADC_ProcessData(void)
{
//ADC_GetSlowSensorsData();
//пересчитанное напряжение питания AVDD
// 3300 is voltage of the factory calibration for STM32. Do not replace 3300 by VDDA_ADC.
vdda_adc = (3300*cal_const_v_ref )/adc_data_v_ref;
//пересчитанное напряжение внутреннего источника
v_ref_int = (adc_data_v_ref * vdda_adc )/ADC_FULL_SCALE;
//напряжение на входе батарейки
v_bat = (adc_data_v_bat * vdda_adc) /ADC_FULL_SCALE;
} // ADC_ProcessData()
ADC_adc_data_v_ref();
ADC_adc_data_v_bat();
ADC_ProcessData();
adc0 = v_bat;
if(adc0<100) timer=3;
if((adc0>100)&&(adc0<=1800)) timer=4; //adc_data_v_bat 3.0V >2100> 3.5V >2000> 3.9V
if((adc0>1800)&&(adc0<=1900)) timer=5; //adc_data_v_ref 3.8V <2000< 3.9V
if((adc0>1900)&&(adc0<=2000)) timer=6; //adc_data_v_ref 3.7V <1900<2100< 3.8V
if((adc0>2000)&&(adc0<=2100)) timer=7;
if((adc0>2100)&&(adc0<=2200)) timer=8;
if(adc0>2200) timer=9;


