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

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

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

Сообщение oleg110592 »

значение АЦП одного канала находится в ADC_array[0], другого канала в ADC_array[1]
Реклама
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

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

Сообщение service47 »

Значит читать так:
adc1 = *(__IO uint32_t *)ADC_array[0];
adc2 = *(__IO uint32_t *)ADC_array[1];
Т.е. по адресам 0x00000000 и 0x00000001 ?

Будет ли АЦП работать так:
Спойлер

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

static void ADC_Config3(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;
  /* ADC1 DeInit */  
  ADC_DeInit(ADC1);
  
  /* GPIOC Periph clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  
   /* ADC1 Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  /* Configure ADC Channel11 and channel10 as analog input */

  GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_1 | GPIO_Pin_2) ;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /* Initialize ADC structure */
  ADC_StructInit(&ADC_InitStructure);
  
  /* Configure the ADC1 in continuous mode withe 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_Backward;  //SCANDIR=1: backward scan Channel 18 to Channel 0
  ADC_Init(ADC1, &ADC_InitStructure); 

  /* Convert the ADC1 Channel1 and channel2 with 55.5 Cycles as sampling time */ 

  ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_55_5Cycles); 
  ADC_ChannelConfig(ADC1, ADC_Channel_2 , ADC_SampleTime_55_5Cycles); 
  
  /* Convert the ADC1 temperature sensor  with 55.5 Cycles as sampling time */ 
  ADC_ChannelConfig(ADC1, ADC_Channel_TempSensor , ADC_SampleTime_55_5Cycles);  //ADC_IN16 
  ADC_TempSensorCmd(ENABLE);
  
  /* Convert the ADC1 Vref  with 55.5 Cycles as sampling time */ 
  ADC_ChannelConfig(ADC1, ADC_Channel_Vrefint , ADC_SampleTime_55_5Cycles); //ADC_IN17
  ADC_VrefintCmd(ENABLE);
  
  /* Convert the ADC1 Vbat with 55.5 Cycles as sampling time */ 
  ADC_ChannelConfig(ADC1, ADC_Channel_Vbat , ADC_SampleTime_55_5Cycles);  
  ADC_VbatCmd(ENABLE);
  
  /* ADC Calibration */
  ADC_GetCalibrationFactor(ADC1);
  
  /* ADC DMA request in circular mode */
  ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
  
  /* Enable ADC_DMA */
  ADC_DMACmd(ADC1, ENABLE);  
  
  /* 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);
}



unsigned int v_bat, v_ref_int, adc1, adc2, TempSensor, adc_data_v_ref, adc_data_v_bat;

void ADC_ProcessDataRead(void)
{
  ADC1->CHSELR |= (ADC_CHSELR_CHSEL1);
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL2);
  ADC1->CHSELR &= ~(uint32_t)(ADC_Channel_Vbat);
  ADC1->CHSELR &= ~(uint32_t)(ADC_Channel_Vrefint);
  ADC_StartOfConversion(ADC1);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
  adc1 = ADC_GetConversionValue(ADC1); 
  ADC_StopOfConversion(ADC1);
  
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL1);
  ADC1->CHSELR |= (ADC_CHSELR_CHSEL2);
  ADC_StartOfConversion(ADC1);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
  adc2 = ADC_GetConversionValue(ADC1); 
  ADC_StopOfConversion(ADC1);
  
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL1);
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL2);
  ADC1->CHSELR &= ~(uint32_t)(ADC_Channel_Vrefint);	
  ADC1->CHSELR = (uint32_t)(ADC_Channel_Vbat);
  ADC_StartOfConversion(ADC1);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
  adc_data_v_bat = ADC_GetConversionValue(ADC1); 
  ADC_StopOfConversion(ADC1);
  
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL1);
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL2);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
  TempSensor = ADC_GetConversionValue(ADC1); 
  ADC_StopOfConversion(ADC1);
  
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL1);
  ADC1->CHSELR &= ~(ADC_CHSELR_CHSEL2);
  ADC1->CHSELR &= ~(uint32_t)(ADC_Channel_Vbat);
  ADC1->CHSELR = (uint32_t)(ADC_Channel_Vrefint);
  ADC_StartOfConversion(ADC1);	
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){;}
  adc_data_v_ref = 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;

  //пересчитанное напряжение питания 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;
}


void main(void)
{
 ADC_Config3();
while (1)
  {
    ADC_ProcessDataRead();
  }
}
Реклама
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

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

Сообщение oleg110592 »

adc1 = ADC_array[0];
adc2 = ADC_array[1];

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

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

Сообщение service47 »

В предпредыдущей приведенной программе было:
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
Регистр CMAR хранит адрес, по которому записываются значения АЦП, т.е. ADC_array адрес. Вот и читать его через __IO или нет?

АЦП через DMA не работает, поэтому ADC_ProcessDataRead();.

Сделал, чтобы значения АЦП записывались во FLASH, получились такие (уровни напряжения немного преувеличены 4.1-3.7В):
Спойлер

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

            ADC_FULL_SCALE 4095         4.1V    4.0V    3.9V    3.8V    3.7V
                      adc0              0       0       0       0       0
                      adc1              0xff    0xff    0xff    0xff    0xff
                      adc2              0x24    0x25    0x25    0x24    0x23
                      adc_data_v_bat    0       0       0       0       0
                    //TempSensor        0       0       0       0       0
                      adc_data_v_ref    0x4b    0x4d    0x50    0x53    0x53

                      vdda_adc          0x6a0   0xffcd  0xf636  0xed4f  0xed4f
                      v_ref_int         0x1f    0x4cf   0x4cf   0x4cf   0x4cf
                      v_bat             0       0       0       0       0

            ADC_FULL_SCALE 255          4.1V    4.0V    3.9V    3.8V    3.7V
                      adc0              0       0       0       0       0
                      adc1              0xff    0xff    0xff    0xff    0xff
                      adc2              0x24    0x24    0x24    0x24    0x25
                      adc_data_v_bat    0       0       0       0       0
                    //TempSensor        0       0       0       0       0
                      adc_data_v_ref    0x4b    0x4e    0x4f    0x51    0x53

                      vdda_adc          0x6a0   0xfc86  0xf953  0xf32b  0xed4f
                      v_ref_int         0x1f2   0x4d3e  0x4d3d  0x4d3d  0x4d3d
                      v_bat             0       0       0       0       0

  //пересчитанное напряжение питания 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_data_v_ref и рассчитываемое vdda_adc, еще немного v_ref_int. Остальные не меняются.
Также пишут, что ADC_Channel_Vbat ((uint32_t)ADC_Channel_18) /*!< Not available for STM32F030 devices */

Вопрос: как правильно измерить напряжение на входе АЦП с учетом изменения уровня напряжения на пине VDDA и заводским значением записанным во FLASH?
Реклама
Эиком - электронные компоненты и радиодетали
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

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

Сообщение pixar »

АЦП через DMA не работает,
adc настраивается на работу с дма, работает автоматом без остановки после однократного запуска. Как оно может не работать ? просто забирать данные из массива. Через _IO ничего забрать не получиться , _IO это директива компилятору не выбрасвать эту переменную при оптимизации.
Регистр CMAR хранит адрес, по которому записываются значения АЦП - хранит адрес , начиная с которого будет записываться массив из N значений.
adc настраивался на 2 канала , вы хотите получать 4 канала - adc0, adc1, vref, vbat.
Not available for STM32F030 devices - это в даташите нужно смотреть. Канал батарейки доступен только в корпусах 48 ног и больше . для 030 его вобще нет ни в каких корпусах.
Реклама
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

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

Сообщение service47 »

Можно подробнее. Имеются измеренные значения АЦП на пине PA2 для нескольких значений напряжения VDDA. Также имеются измеренные значения adc_data_v_ref для ADC_Channel_Vrefint, тоже разные. Как правильно рассчитать примерное значение напряжения на пине РА2 с учетом изменения напряжения на пине VDDA и зная фабричное измеренное значение напряжения, записанное во FLASH. Разрешение АЦП 8 бит, т.е. 255 предел.

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

VDDA              4.1V    4.0V    3.9V    3.8V    3.7V
adc2              0x24    0x24    0x24    0x24    0x25
adc_data_v_ref    0x4b    0x4e    0x4f    0x51    0x53
Подойдет ли данная формула:

Vin=Din*Vrefint/Drefint
Din — измеренное напряжение 255
Vrefint — значение опорного напряжения в вольтах. Взятое из даташита или измеренное ранее.
Drefint — результат замера опорного напряжения.
Реклама
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

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

Сообщение a5021 »

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

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

Сообщение service47 »

Сделал так:

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

  adc_bit++;
  v_in=adc2*3300/adc_data_v_ref;
  v_in2=v_in2+v_in;
  if(adc_bit>=100)
  {
    adc_bit=0;
    v_in3=v_in2/100;
  }
Значение v_in в пределах 0x550-0x620, почему значение v_in3 получается около 0x5D500.
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

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

Сообщение a5021 »

Вам не надоело генерировать бред, заниматься ракообразием и пребывать в уверенности, что нечеловеческое упорство заменит элементарные знания ? Я вам сказал, где посмотреть, как правильно делать измерения с помощью АЦП. Вы продолжаете изобретать ахинею и удивляться полученным результатам. Зачем вы тогда задаете здесь вопросы, если вас совершенно не интересуют ответы на них?
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

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

Сообщение pixar »

#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

//Raw data acquired at a temperature of 30 °C (+/- 5 °C),
//@ VDDA= 3.3 V (+/- 10 mV)
/// kept uint16 @ 0x1FFFF7BA - 0x1FFFF7BB

// 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;

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

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

Сообщение service47 »

АЦП работает, спасибо. Теперь необходимо сделать вход и выход из спящего режима. Если закомментировать строки:
if (SysTick_Config(SystemCoreClock/2000-1))
{ while(1){;} }
то в спящий режим входит и выходит. Если строки оставить как есть, то в спящий режим не входит.
Если перед входом в спящий режим отключить этот таймер, так:
SysTick->LOAD=0x00000000;
SysTick->CTRL=0x00000000; //отключение системного таймера
SysTick->VAL=0x00000000; //сброс текущего значения системного таймера
SysTick->CTRL &= ~(SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk | SysTick_CLKSource_HCLK | SysTick_CLKSource_HCLK_Div8);
//NVIC_SetPriority(SysTick_IRQn, 0);
NVIC_DisableIRQ(SysTick_IRQn);
то в спящий режим по прежнему не входит. Как сделать, чтобы STM32 входил в спящий режим.
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

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

Сообщение service47 »

Сделал так:
Спойлер

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

  if (SysTick_Config(SystemCoreClock/2000-1))
  { while(1){;} }
while (1)
  {
      SysTick->LOAD=0x00000000;
      SysTick->CTRL=0x00000000;   //отключение системного таймера
      SysTick->VAL=0x00000000;   //сброс текущего значения системного таймера
     DisableADC();
     Configure_PA0();
     PWR->CSR |= PWR_CSR_EWUP1;
     sleep_counter=0;
     PWR->CR |= PWR_CR_CWUF;
     PWR_EnterSTANDBYMode();
        if (SysTick_Config(SystemCoreClock/2000-1))
        { while(1){;} }

  }
Причем по прежнему не работает вход из-за SysTick в:
//PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_SLEEPONEXIT);
или
//PWR_EnterSleepMode(PWR_SLEEPEntry_WFE);
но standby работает.

Входит в ждущий режим и выходит по нажатию на кнопку на пине РА0. Только вот ток потребления на одном приборе меряется 1056мА, на другом спадает очень медленно от 500 до 30мА. В даташите указан ток потребления для этого режима 1.4мкА.
Ответить

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