Перейти к содержанию
    

Опрос более 10 каналов АЦП STM32F103

Подскажите пожалуйста или укажите направление (примеры будут вообще СУПЕР) как реализовать опрос более 10 каналов АЦП на STM32F103 при том что есть еще I2C, SPI и USART. Опрос должен быть с частотой порядка 100мс. Сейчас начинаю изучать АЦП поэтому прошу снисхождения. Прочитал что есть два типа и т.д. Думаю мне подходит регулярный опрос по таймеру TIM3 и переносом результатов по DMA. Правильно ли я думаю. И еще вопросик. Есть такой analog watchdog при опросе с сравнении по границам. Это для меня конечно наилучший вариант НО как потом узначт в каком канале авария?????

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно настроить ADC на постоянное преобразование всей пачки каналов с заведомо большей скоростью, чем требуемые 100мс/канал, с пересылкой DMA в массив в памяти.

А отуда уже читать когда надо, хоть по таймеру раз в 100мс, и не думать про ADC вообще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здесь - пример одновременного опроса 10 каналов АЦП с буферизацией по 9 значений (для последующей медианной фильтрации).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здесь - пример одновременного опроса 10 каналов АЦП с буферизацией по 9 значений (для последующей медианной фильтрации).

 

 

Спасибо сейчас посмотрю

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите пожалуйста или укажите направление (примеры будут вообще СУПЕР) как реализовать опрос более 10 каналов АЦП на STM32F103 при том что есть еще I2C, SPI и USART. Опрос должен быть с частотой порядка 100мс. Сейчас начинаю изучать АЦП поэтому прошу снисхождения. Прочитал что есть два типа и т.д. Думаю мне подходит регулярный опрос по таймеру TIM3 и переносом результатов по DMA. Правильно ли я думаю. И еще вопросик. Есть такой analog watchdog при опросе с сравнении по границам. Это для меня конечно наилучший вариант НО как потом узначт в каком канале авария?????

 

Очень элегантно это будет сделать через DMA..необходимо задать в регистре последовательности SQR номера каналов,настроить DMA ну и собственно триггер старта-либо программно,либо по таймеру...в итоге надо будет проверять бит end transfer в DMA для определения окончания преобразования..завтра до работы дойду,вышлю пример расчета переменного напряжения,поступающего на каналы,с использованием БПФ по 256 точкам..Кстати,как мне кажется,analog watchdog штука хорошая,но по большому счету бессмысленная

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

НО как потом узначт в каком канале авария?????

Зависит от того в каком режиме работает АЦП, в случае сканирования с DMA просмотреть буфер.

(примеры будут вообще СУПЕР) как реализовать опрос более 10 каналов АЦП

Ниже фрагмент кода десятиканального вольтметра. Устройство сделал, когда только начинал осваивать STM32, еще на халявной дискавери. Код полностью рабочий, вырезал инициализацию портов и не имеющие к делу куски. Написано для STM32F100, работать должно и на F103.

 

Основной цикл!

   float adc_data [10];		   // Результат измерения
  u16 adc_buf	[10];			 // Буфер куда пишет DMA
  u32 adc_buf_t [10];		  // Накопление результата
  float adc_coff  [10] ={	   // Калибровочные константы

					0.00008467,// 0.0000893721,   // U 1
					0.00008455,   // U 2  
					0.00008653,   // U 3
					0.00008543,   // U 4
					0.00008529,   // U 5
					0.00008556,   // U 6
					0.00008333,   // U 7
					0.00008442,   // U 8
					0.00008475,   // U 9
					0.00008392// U 10				
					};  
float adc_zero[11] ={  // Нули
					28994.0,   // U 1
					28859.0,   // U 2	
					27527.0,   // U 3
					26274.0,   // U 4
					28885.0,   // U 5
					27621.0,   // U 6
					34047.0,   // U 7
					28648.0,   // U 8
					26955.0,   // U 9
					26136.0	// U 10					
					};	




u8 adc_data_rd = 0;   // Флаг есть результат


int main(void) 
{

while( 1)
{
if (adc_data_rd == 1){
		  adc_data_rd = 0;	  // Обнуляем флаг конца измерения		  

  for (u8 i = 0; i<=9;i++)
{
adc_data[i] = (((float)adc_buf_t[i] -  adc_zero[i]) * adc_coff[i]);  // Результат с учетом калибровочных констант и нулей
adc_buf_t[i] = 0;   // Обнуляем буфер усреднения
}

// Здесь отображаем результата или все что угодно! 

			  // Старт следующего измерения
		DMA1_Channel1->CCR |= DMA_CCR1_EN;			   // разрешаем работу DMA и ADC
		ADC1->CR2 |= ADC_CR2_ADON;


		  }  

}}

Инициализация АЦП и ДМА

//------------------------------------------------------------------------------
void AdcInit(void)
{
 RCC->AHBENR |= RCC_AHBENR_DMA1EN;			   // 
 DMA1_Channel1->CPAR = (uint32_t) &ADC1->DR;	 // адрес периферийного устройства
 DMA1_Channel1->CMAR = (unsigned int) adc_buf;   // адрес буфера в памяти

 DMA1_Channel1->CNDTR = 10;			  // количество данных для обмена
 DMA1_Channel1->CCR &=~DMA_CCR1_EN;			   // разрешаем работу 
 DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;		  // размер памяти 16 bit
 DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;		 // размер периферии 16 bit
 DMA1_Channel1->CCR |= DMA_CCR1_MINC;			  // memory increment mode
 DMA1_Channel1->CCR |= DMA_CCR1_CIRC;	
 DMA1_Channel1->CCR |= DMA_CCR1_TCIE;			  // прерывание по окончанию передачи  
 DMA1_Channel1->CCR |= DMA_CCR1_EN;				  // разрешаем работу
 NVIC_SetPriority(DMA1_Channel1_IRQn, 10);
 NVIC_EnableIRQ(DMA1_Channel1_IRQn); 


 RCC->CFGR &= ~RCC_CFGR_ADCPRE;
 RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8;
 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;


 ADC1->SQR3  = 0;							// 1 
 ADC1->SQR3 |= 1<<5;					 // 2 Слева номер канала справа сдвиг
 ADC1->SQR3 |= 2<<10;				   // 3
 ADC1->SQR3 |= 3<<15;				   // 4
 ADC1->SQR3 |= 4<<20;				   // 5 
 ADC1->SQR3 |= 5<<25;				   // 6 
 ADC1->SQR2  = 6;						   // 7 
 ADC1->SQR2 |= 7<<5;					// 8 
 ADC1->SQR2 |= 8<<10;				   // 9
 ADC1->SQR2 |= 9<<15;				   // 10


 ADC1->CR2 = ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTTRIG;
 ADC1->SMPR1   =  0;					  //очистка регистров времени выборки
 ADC1->SMPR2   =  0;					 //
 ADC1->SMPR2  |=  (uint32_t)(6<<(0*3));  //канал 0, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(1*3));  //канал 1, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(2*3));  //канал 2, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(3*3));  //канал 3, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(4*3));  //канал 4, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(5*3));  //канал 5, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(6*3));  //канал 6, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(7*3));  //канал 7, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(8*3));  //канал 8, время преобразования 6 мкс
 ADC1->SMPR2  |=  (uint32_t)(6<<(9*3));  //канал 9, время преобразования 6 мкс
 ADC1->SMPR1  |=  (uint32_t)(6<<(0*3));  //канал 10, время преобразования 6 мкс



 ADC1->CR2 |= ADC_CR2_ADON; 

 ADC1->CR2 |= ADC_CR2_RSTCAL;
 while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_RSTCAL){}

 ADC1->CR2 |= ADC_CR2_CAL;

 while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_CAL)  {}


 ADC1->SQR1 |= 9<<20;							 // Количество преобразования
 ADC1->CR1 |= ADC_CR1_SCAN;				// Режим сканирования  
 ADC1->CR2 |= ADC_CR2_DMA;				  // DMA on
// ADC1->CR2 |= ADC_CR2_CONT;   

//  ADC1->CR2 |= ADC_CR2_SWSTART;
 ADC1->CR2 |= ADC_CR2_ADON; 
}

Прерывание от ДМА

u32 adc_count = 0;				  // Счетчик числа усреднений
 void DMA1_Channel1_IRQHandler(void)
 { 
DMA1->IFCR = DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1;		// clear DMA interrupt flags
DMA1_Channel1->CCR &=~DMA_CCR1_EN;					// Запрещаем работу	

for (u8 i = 0; i<=9;i++)
{
 adc_buf_t[i]+= adc_buf[i];	  // Накапливаем сумму в буфере
}

adc_count++;
if (adc_count >=5000)	// Счетчик усреднений
{
adc_count = 0;
adc_data_rd = 1;	// Флаг готовности АЦП
test_count++;
return;
}

DMA1_Channel1->CCR |= DMA_CCR1_EN;			   // разрешаем работу   
ADC1->CR2 |= ADC_CR2_ADON; 
} 
//------------------------------------------------------------------------------

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ФЛП Потапов, использование флоатов здесь совершенно ни к чему!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всегда существует несколько вариантов решения задач, истины нет, есть точки зрения!

Здесь приведен фрагмент кода, отвечающий только за измерения, есть еще калибровка. Ноль действительно можно компенсировать в u32, но при калибровке float очень удобно, один стандартный алгоритм для любых измерений, вне зависимости от разрядности АЦП или количества усреднений. По быстродействию для STM32 разница небольшая, с учетом интервала 200mS это вообще не заметно!

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я все-таки придерживаюсь той логики, что если у микроконтроллера нет FPU, то числа с плавающей точкой под запретом! Это ж как long long какой-нибудь пихать в STM8!

И как-то еще ни разу не возникало желания флоаты забульбенить в F103... Если же они действительно понадобятся, то нужнобудет брать уже более жирный МК, где FPU аппаратно решит проблему вычислений.

 

P.S. Для вычисления юстировочных коэффициентов я использую цепные дроби. В итоге преобразования из ADU в число с фиксированной точкой имеет одно целочисленное деление и одно целочисленное умножение. Здесь, например. Настройки хранятся во Flash-памяти за отсутствием EEPROM (надо, кстати, нормальный виртуальный EEPROM in flash сделать, чтобы пореже стирать флеш-память при обновлении настроек).

P.P.S. Тот код тоже черезжопный: я opencm3 еще использовал. Сейчас все новое буду делать на голом CMSIS, чтобы от всяких рукожопых разработчиков не зависеть.

Изменено пользователем Эдди

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...