STM32F030K6 настройка программы

Кто любит RISC в жизни, заходим, не стесняемся.
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F030K6 настройка программы

Сообщение pixar »

где то у вас с настройкой 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().
Реклама
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Оказалось все дело было в delay_ms(10);, заменил на delay_mc(100);, светодиод перестал мигать.

Теперь нужно сделать чтение из 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();
  }
Реклама
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Имеются мелодии для 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:
Спойлер

Код: Выделить всё

// 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;
}
Для stm32:
Спойлер

Код: Выделить всё

#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);
}
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F030K6 настройка программы

Сообщение pixar »

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
}
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
scorpi_0n
Вымогатель припоя
Сообщения: 616
Зарегистрирован: Вс ноя 01, 2015 13:13:49

Re: STM32F030K6 настройка программы

Сообщение scorpi_0n »

Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер.
Нифига не проще и не правильно. Прескалером можно задавать только октаву. ARR должна задавать саму ноту. CCR задаёт 50 % ШИМ. Юзая DMAR можно из буфера выталкивать всю эту канитель одновременно.
Чтобы замутить оркестр можно поискать статьи по OSA tester или testerplus. Там на пальцах раскидывалось что к чему.
Реклама
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F030K6 настройка программы

Сообщение pixar »

Вы же прескалером не пополам частоту делите . Если 16 бит таймер , ARR = 4 , CCR = 2 , то для полосы 50 ~ 3500 вполне всё равно .
На ноту не так уверенно попадаешь , но зато проще.
Три регистра менять, конечно , правильно , но человек и с одним разобраться не может.
Как освоит - потом и в трех сам поменяет, без проблем.
С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
Реклама
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Вообщем АЦП никак не работает, пробовал даже так, но все равно 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 настройка программы

Сообщение oleg110592 »

Код: Выделить всё

/* (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) */
}
Аватара пользователя
scorpi_0n
Вымогатель припоя
Сообщения: 616
Зарегистрирован: Вс ноя 01, 2015 13:13:49

Re: STM32F030K6 настройка программы

Сообщение scorpi_0n »

pixar писал(а): С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
Вредно давать вредные советы а не с ДМА связываться. Как и вредно без надобности торчать в программных задержках.
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F030K6 настройка программы

Сообщение pixar »

я соглашусь.
а вы киньте человеку конкретный кусок кода под его проц.
посмотрим как быстро он его запустит.
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

То же самое, АЦП не работает. На индикаторе постоянно отображается цифра 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 настройка программы

Сообщение oleg110592 »

вы на какую ногу измеряемое напряжение подаете? Если на PA0, то ее надо перевести в analog mode:

Код: Выделить всё

GPIOA->MODER |= GPIO_MODER_MODER0;
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

На РА0 через делитель напряжения, на пине от 3В до 3.6В. Заменил на:

Код: Выделить всё

GPIOA->MODER |= GPIO_MODER_MODER0;
Тоже самое, значение в АЦП 255 и при уменьшении напряжения до 3В не уменьшается.

Правильная ли схема включения во вложении.
Вложения
Scheme_1.gif
(32.11 КБ) 396 скачиваний
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: STM32F030K6 настройка программы

Сообщение oleg110592 »

5 ногу VDDA надо к 3.5V подключить, как пример см. схему тут: https://andybrown.me.uk/2015/10/31/stm32f042dev/
з.ы. проверьте на вашей схеме как электролитические конденсаторы подключены - полярность как попало
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Подключил 5 пин к +Vdd. Теперь проблема в том, что при уменьшении напряжения питания с 4В до 3В, опорное напряжение тоже уменьшается и значение в регистре АЦП не меняется. В даташите что-то написано про Vrefint и ADC_IN17. Но как его настроить к примеру на 2.7В.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: STM32F030K6 настройка программы

Сообщение oleg110592 »

откуда взялось 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/
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Как сделать если это возможно, чтобы изменение опорного напряжения АЦП 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 настройка программы

Сообщение oleg110592 »

Опорное напряжение на то и опорное, чтоб быть стабильным.
Как прочитать несколько каналов есть в примерах документации 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 */
}
остается подсчитать значение в милливольтах для нужного канала (CHSEL0):

Код: Выделить всё

XmV = ADC_Result[0] * 1200 / ADC_Result[3]; 
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F030K6 настройка программы

Сообщение pixar »

в процессоре есть регистр , в котором хранится калиброванное значение внутреней опоры, снятое своим АЦП при питании 3.3вольт +/-1% .
Если измерять внутренюю опору при нестабильном 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()
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: STM32F030K6 настройка программы

Сообщение service47 »

Значение на индикаторе timer=3, т.е. ADC<100 или = 0.

Спойлер

Код: Выделить всё

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;
Почему величина adc_data_v_bat при увеличении напряжения уменьшается. Как прочитать значение в АЦП с пина VDDA.
Ответить

Вернуться в «ARM»