STM32F030K6 настройка программы
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: STM32F030K6 настройка программы
значение АЦП одного канала находится в ADC_array[0], другого канала в ADC_array[1]
- Реклама
Re: STM32F030K6 настройка программы
Значит читать так:
adc1 = *(__IO uint32_t *)ADC_array[0];
adc2 = *(__IO uint32_t *)ADC_array[1];
Т.е. по адресам 0x00000000 и 0x00000001 ?
Будет ли АЦП работать так:
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 настройка программы
adc1 = ADC_array[0];
adc2 = ADC_array[1];
зачем ADC_ProcessDataRead();, если у вас ацп и так через дма считывается
adc2 = ADC_array[1];
зачем ADC_ProcessDataRead();, если у вас ацп и так через дма считывается
Re: STM32F030K6 настройка программы
В предпредыдущей приведенной программе было:
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
Регистр CMAR хранит адрес, по которому записываются значения АЦП, т.е. ADC_array адрес. Вот и читать его через __IO или нет?
АЦП через DMA не работает, поэтому ADC_ProcessDataRead();.
Сделал, чтобы значения АЦП записывались во FLASH, получились такие (уровни напряжения немного преувеличены 4.1-3.7В):
Изменяется только adc_data_v_ref и рассчитываемое vdda_adc, еще немного v_ref_int. Остальные не меняются.
Также пишут, что ADC_Channel_Vbat ((uint32_t)ADC_Channel_18) /*!< Not available for STM32F030 devices */
Вопрос: как правильно измерить напряжение на входе АЦП с учетом изменения уровня напряжения на пине VDDA и заводским значением записанным во FLASH?
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_Channel_Vbat ((uint32_t)ADC_Channel_18) /*!< Not available for STM32F030 devices */
Вопрос: как правильно измерить напряжение на входе АЦП с учетом изменения уровня напряжения на пине VDDA и заводским значением записанным во FLASH?
Re: STM32F030K6 настройка программы
adc настраивается на работу с дма, работает автоматом без остановки после однократного запуска. Как оно может не работать ? просто забирать данные из массива. Через _IO ничего забрать не получиться , _IO это директива компилятору не выбрасвать эту переменную при оптимизации.АЦП через DMA не работает,
Регистр CMAR хранит адрес, по которому записываются значения АЦП - хранит адрес , начиная с которого будет записываться массив из N значений.
adc настраивался на 2 канала , вы хотите получать 4 канала - adc0, adc1, vref, vbat.
Not available for STM32F030 devices - это в даташите нужно смотреть. Канал батарейки доступен только в корпусах 48 ног и больше . для 030 его вобще нет ни в каких корпусах.
- Реклама
Re: STM32F030K6 настройка программы
Можно подробнее. Имеются измеренные значения АЦП на пине PA2 для нескольких значений напряжения VDDA. Также имеются измеренные значения adc_data_v_ref для ADC_Channel_Vrefint, тоже разные. Как правильно рассчитать примерное значение напряжения на пине РА2 с учетом изменения напряжения на пине VDDA и зная фабричное измеренное значение напряжения, записанное во FLASH. Разрешение АЦП 8 бит, т.е. 255 предел.
Подойдет ли данная формула:
Vin=Din*Vrefint/Drefint
Din — измеренное напряжение 255
Vrefint — значение опорного напряжения в вольтах. Взятое из даташита или измеренное ранее.
Drefint — результат замера опорного напряжения.
Код: Выделить всё
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 0x53Vin=Din*Vrefint/Drefint
Din — измеренное напряжение 255
Vrefint — значение опорного напряжения в вольтах. Взятое из даташита или измеренное ранее.
Drefint — результат замера опорного напряжения.
Re: STM32F030K6 настройка программы
Скачайте уже Codesnippets с сайта st. Там в примерах показано, как измерять напряжения питания, температуру и т.п.
Re: STM32F030K6 настройка программы
Сделал так:
Значение v_in в пределах 0x550-0x620, почему значение v_in3 получается около 0x5D500.
Код: Выделить всё
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;
}Re: STM32F030K6 настройка программы
Вам не надоело генерировать бред, заниматься ракообразием и пребывать в уверенности, что нечеловеческое упорство заменит элементарные знания ? Я вам сказал, где посмотреть, как правильно делать измерения с помощью АЦП. Вы продолжаете изобретать ахинею и удивляться полученным результатам. Зачем вы тогда задаете здесь вопросы, если вас совершенно не интересуют ответы на них?
Re: STM32F030K6 настройка программы
#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 бит уж самостоятельно как нибудь
#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 бит уж самостоятельно как нибудь
Re: STM32F030K6 настройка программы
АЦП работает, спасибо. Теперь необходимо сделать вход и выход из спящего режима. Если закомментировать строки:
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 входил в спящий режим.
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 входил в спящий режим.
Re: STM32F030K6 настройка программы
Сделал так:
Причем по прежнему не работает вход из-за SysTick в:
//PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_SLEEPONEXIT);
или
//PWR_EnterSleepMode(PWR_SLEEPEntry_WFE);
но standby работает.
Входит в ждущий режим и выходит по нажатию на кнопку на пине РА0. Только вот ток потребления на одном приборе меряется 1056мА, на другом спадает очень медленно от 500 до 30мА. В даташите указан ток потребления для этого режима 1.4мкА.
Спойлер
Код: Выделить всё
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){;} }
}
//PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_SLEEPONEXIT);
или
//PWR_EnterSleepMode(PWR_SLEEPEntry_WFE);
но standby работает.
Входит в ждущий режим и выходит по нажатию на кнопку на пине РА0. Только вот ток потребления на одном приборе меряется 1056мА, на другом спадает очень медленно от 500 до 30мА. В даташите указан ток потребления для этого режима 1.4мкА.


