Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.50/64: Рейтинг темы: голосов - 64, средняя оценка - 4.50
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96

Опрос нескольких регулярных каналов АЦП STM32F100

20.11.2018, 09:17. Показов 14558. Ответов 30

Студворк — интернет-сервис помощи студентам
Всем привет! Проблема с опросом нескольких регулярных каналов АЦП STM32F100 (Отл плата STM32F100VL Discouvery). На входы PA0 и PA1 повесил потенциометры. При пошаговой отладке в IAR данные из ADC1->DR в a[0] попадают, а вот a[1] по нулям, как потенциометр ни крути.
Читал, что такие вещи лучше делать через DMA, но хотелось бы для начала попробовать без него...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "stm32f10x.h"
 
int a[2],b=0;
 
void ADC1_IRQHandler () {
  
  if(ADC1->SR &ADC_SR_EOC) {
  
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    a[b] = ADC1->DR;
    b++;
    ADC1->SR &= ~ADC_SR_EOC;
   
    if (b>=1) b=0;
    
  }
  
}
 
  
  
 
 
 
void  main () {
  
 
  
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);                      // Enable HSE
    while (!(RCC->CR & RCC_CR_HSERDY));                 // Ready start HSE      
    
    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;          // Cloclk Flash memory
    
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;                    // AHB = SYSCLK/1
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;                   // APB1 = HCLK/1
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;                   // APB2 = HCLK/1
    
    RCC->CFGR &= ~RCC_CFGR_PLLMULL;                             // clear PLLMULL bits
    RCC->CFGR &= ~RCC_CFGR_PLLSRC;                      // clearn PLLSRC bits
    RCC->CFGR &= ~RCC_CFGR_PLLXTPRE;                    // clearn PLLXTPRE bits
    
    RCC->CFGR |= RCC_CFGR_PLLSRC_PREDIV1;                   // source HSE
    RCC->CFGR |= RCC_CFGR_PLLXTPRE_PREDIV1_Div2;                // source HSE/2 = 4 MHz
    RCC->CFGR |= RCC_CFGR_PLLMULL6;                     // PLL x6: clock = 4 MHz * 6 = 24 MHz
    
    RCC->CR |= RCC_CR_PLLON;                                    // enable PLL
    while((RCC->CR & RCC_CR_PLLRDY) == 0) {}                    // wait till PLL is ready
    
    RCC->CFGR &= ~RCC_CFGR_SW;                                  // clear SW bits
        RCC->CFGR |= RCC_CFGR_SW_PLL;                                   // select source SYSCLK = PLL
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {}          // wait till PLL is used
        
        //Тактирование периферии
  
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN;
 
RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
 //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1; 
 
 
                                                                         //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;
while (ADC1->CR2 & ADC_CR2_CAL);
NVIC_EnableIRQ(ADC1_IRQn);
ADC1->CR1 |= ADC_CR1_EOCIE;
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0;
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT;
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= ADC_SQR3_SQ2_0;
ADC1->SQR1 |= ADC_SQR1_L_1;
//ADC1->CR1 |= ADC_CR1_SCAN;
//ADC1->CR1 |= ADC_CR1_DISCNUM_0 | ADC_CR1_DISCEN;
ADC1->CR2 |= ADC_CR2_SWSTART;
 
  
  while(1) //Крутимся в бесконечном цикле
 
  {
    
  
  
}
  
  
  }
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
20.11.2018, 09:17
Ответы с готовыми решениями:

Порядок оцифровки групп регулярных каналов АЦП в режиме dual mode
Ситуация... моделирую на плате stm32f103c8t6 режим АЦП dual regular simultaneous only. Настроил четыре канала (два для каждого АЦП): ...

AVR АЦП использование нескольких каналов
Кто пробовал использовать несколько каналов АЦП одновременно (ну, почти одновременно) - как это делать правильно? Используется два...

Измерение нескольких каналов АЦП один раз за период сигнала запуска
Всем привет! Встал в тупик с частью программы Работаю с АЦП. Нужно произвести последовательное измерение 11 каналов. Сигналом...

30
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
20.11.2018, 11:58
Vozz, оптимизация включена? Если да, то попробуй
C
1
2
volatile int a[2];
volatile int b=0;
Добавлено через 31 минуту

C
1
2
3
4
5
6
7
8
9
10
11
12
13
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   //включили модуль, включили калибровку
while (ADC1->CR2 & ADC_CR2_CAL);                                 // Ждем конца калибровки, все ОК
NVIC_EnableIRQ(ADC1_IRQn);                                           // Настроили вектор прерываний, ОК
ADC1->CR1 |= ADC_CR1_EOCIE;                                       // Разрешили модулю прерывания по событию EOC
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0;                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_1;    // Тут вы зачем то поставили количество каналов в группе равным 3(?)
//ADC1->CR1 |= ADC_CR1_SCAN;
//ADC1->CR1 |= ADC_CR1_DISCNUM_0 | ADC_CR1_DISCEN;
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
Так вот когда нужно оцифровать группу, нужно использовать режим сканирования. Проблема тут единственная в том что, насколько я помню в режиме сканирования событие EOC возникает не после оцифровки каждого канала, а после оцифровки группы. А DR регистр один, то есть по прерыванию EOC в DR лежит результат измерения последнего канала в группе. Поэтому тут без DMA никак. Либо Настраивать на первый канал, дергать, забирать результат, перенастраивать на второй канал, дергать , забирать результат и так по кругу.


C
1
2
3
4
5
6
7
8
9
10
11
12
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
NVIC_EnableIRQ(ADC1_IRQn);                                           
ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP2_0);                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // Тут вы зачем то поставили количество каналов в группе равным 2!
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
20.11.2018, 12:50  [ТС]
И правда, небольшая ссылочка под описанием бита SCAN в референс мануале . Да и в самом RM0041 прописано, ибо если используете несколько регулярных каналов, то только через DMA.
Второй вариант с ногодрыгом как-то не вызывает доверия ))) Дело в том, что DMA еще не юзал ни разу, а тут сразу АЦП через него... Ну, попробую, благо примеров много
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
20.11.2018, 12:53
Vozz, да там не особо есть разница АЦП или не АЦП запускать с DMA. Оно почти везде одинаково. Если что скидывай код поправим
0
19 / 19 / 2
Регистрация: 13.07.2012
Сообщений: 164
20.11.2018, 13:45
Vozz, вы меня конечно извините, но вот то что вы делаете это просто фантастика по современным меркам! Никогда в прикладных задачах не оперируют с аппаратной частью на уровне регистров, это чревато катастрофическими ошибками при увеличении объемов кода, а при работе с операционной системой на борту так вообще очень быстро приведет к серьезным гейзенбагам уже при двух-трех потоках. Прошивки пишут с использованием HAL(Hardware Abstraction Layer) - специального набора библиотек, задачей которого является максимальное абстрагирование от такого кода как у вас, сводя десятки строк подобного кода-лапши к функции HAL_ADC_GetValue(&hadc1). Самым мощным hal для stm32 на данный момент является оригинальный набор библиотек от ST Microelectronics идущий комплектом в пресловутом Stm32CubeMx. И изучать вопросы как работает ацп, нужно именно с позиции хала, попутно изучая код самих библиотечных функций, для общего понимания того, что же на самом делает низкоуровневый код.

Вот таких вот примеров кода в интернете масса, но проблема в том, что он не имеет никакой связью с реальностью, stm32 это довольно серьезные мк на которых решают прикладные задачи сильно отличающиеся от мигания светодиодом. У меня в практике есть прошивка состоящая из 22000 строк прикладного кода поверх HAL и FreeRTOS. Больше половины времени разработки были потрачены на отладочные мероприятия, если бы она писалась предлагаемыми методиками, то прошивка в релиз никогда бы и не вышла в принципе.

Поэтому мой вам совет, если хотите писать на данных мк что-то более серьезные чем снятие значение с канала ацп, изучайте данные мк со стороны CubeMx.
0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
20.11.2018, 14:02  [ТС]
Ну тут уж на вкус и цвет ... Я видел код для TFT-дисплея, написанный на CMSIS и ничего... Кто-то плюется от SPL и HAL, предпочитая CMSIS, кто-то наоборот.
Для меня понятнее, заглянув в reference manual, видеть регистры и непосредственно биты в них.
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
20.11.2018, 14:08
Serbis, не вводите ТСа и начинающих в заблуждение.
Цитата Сообщение от Serbis Посмотреть сообщение
а при работе с операционной системой на борту так вообще очень быстро приведет к серьезным гейзенбагам уже при двух-трех потоках.
Каким же образом функционирование/портирование FreeRTOS зависит от того какие либы ST вы используете? CMSIS как и HAL как и SPL это инструмент для работы с периферией контроллера. FreeRTOS из периферии использует только системный таймер. Остальное все - это софтварная оболочка.
Цитата Сообщение от Serbis Посмотреть сообщение
У меня в практике есть прошивка состоящая из 22000 строк прикладного кода поверх HAL и FreeRTOS. Больше половины времени разработки были потрачены на отладочные мероприятия, если бы она писалась предлагаемыми методиками, то прошивка в релиз никогда бы и не вышла в принципе
Это только ваши домыслы.

Цитата Сообщение от Serbis Посмотреть сообщение
Поэтому мой вам совет, если хотите писать на данных мк что-то более серьезные чем снятие значение с канала ацп, изучайте данные мк со стороны CubeMx.
HAL как и CMSIS как и SPL (до F7, L4 серии), LL являются равноправными инструментами которые поддерживает ST. Какой из них выбрать дело каждого.

Не по теме:

Топящих за CMSIS я уже видел, но ярые фаны HAL, да еще и в разработке - это что-то новенькое.

0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
21.11.2018, 11:56  [ТС]
Первая тренировка с DMA поставила в тупик .

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "stm32f10x.h"
 
 
uint16_t Buffer[4];
int a,b;
 
 
void ADC1_IRQHandler() {
  
  if(ADC1->SR & ADC_SR_EOC) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS8;
    
  }
  
}
 
 
void DMA1_Channel1_IRQHandler() {
  
  if(DMA1->ISR & DMA_ISR_TCIF1) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    
  }
  
}
 
void init_GPIOs() { 
                                    
  //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1;    
  
  //Светодиод PC8 синий
GPIOC->CRH &= ~GPIO_CRH_MODE8;     GPIOC->CRH &= ~GPIO_CRH_CNF8; 
GPIOC->CRH |= GPIO_CRH_MODE8_1;  
  
}
 
 
void init_ADC1 () {
  
   //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
//NVIC_EnableIRQ(ADC1_IRQn);                                           
//ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP0_0);                            // Установили время измерения  для 1 и 0  канала 7,5 циклов.
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // 
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
 
  
}
 
void init_DMA1()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_InitTypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
    DMA1_Channel1->CMAR = (uint16_t)Buffer[4]; //Задаем адрес памяти - базовый адрес массива во флэше
    DMA1_Channel1->CNDTR = 1; //Количество пересылаемых значений = 4;//Размер буфера DMA1 = 10
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
        
}
 
void main()
{
  
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN;
        RCC->AHBENR |= RCC_AHBENR_DMA1EN;
        
        RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
        init_GPIOs();
        init_ADC1();
    init_DMA1();
        __enable_irq();
    while(1);
}
Задача в том, чтобы передавать данные из АЦП в переменную buffer через DMA, но DMA1_CMAR1 почему то чист, а CPAR переполняется буквально. Все как по референс мануалу, а не работает, где ошибся .

Добавлено через 35 секунд
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
21.11.2018, 12:15
Лучший ответ Сообщение было отмечено Vozz как решение

Решение

Vozz, пока в регистры DMA не смотрел, а вот в настройке АЦП не увидел выставления бита разрешения DMA
C
1
ADC1->CR2 |= ADC_CR2_DMA;
Ну и чистить за собой флажок DMA не забываем
C
1
DMA1->IFCR |= DMA_IFCR_TCIF1;
Добавлено через 8 минут
Vozz, едем дальше
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void init_DMA1()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_InitTypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
// Вот тут ошибки
    DMA1_Channel1->CMAR = Buffer; //Задаем адрес буффера, а не ячейки!
    DMA1_Channel1->CNDTR = 2; //Количество пересылаемых значений = 2 так как 2 канала
/****************************************************************************/
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
}
1
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
21.11.2018, 14:11  [ТС]
Йесс, в CMAR1 появились данные от АЦП и загорелся зеленый светодиод на отладочной плате, что сигнализирует об окончании передачи 16 бит. В переменной Buffer валяются значения АЦП. Еще пару косяков у себя обнаружил, экпериментируем дальше)

Добавлено через 2 минуты
Да, спасибо уже увидел косяки, отладчик подсказывал предупреждением

Добавлено через 15 минут
Все, добил код. Надеюсь, если такой же новичек, как я будет ломать голову, то мой пример ему поможет). На PA0 и PA1 у меня висит по потенциометру. запитал их тут же на отладочной плате от 3,3В оба канала опрашивается нормально, прерывание DMA добавил просто по факту, чтобы его отследить (срабатывает или нет).

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "stm32f10x.h"
 
 
uint16_t Buffer[2];
int a,b;
 
 
void ADC1_IRQHandler() {
  
  if(ADC1->SR & ADC_SR_EOC) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS8;
    
  }
  
}
 
 
void DMA1_Channel1_IRQHandler() {
  
  if(DMA1->ISR & DMA_ISR_TCIF1) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    
    
  }
  
}
 
void init_GPIOs() { 
                                    
  //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1;    
  
  //Светодиод PC8 синий
GPIOC->CRH &= ~GPIO_CRH_MODE8;     GPIOC->CRH &= ~GPIO_CRH_CNF8; 
GPIOC->CRH |= GPIO_CRH_MODE8_1;  
  
}
 
 
void init_ADC1 () {
  
   //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
//NVIC_EnableIRQ(ADC1_IRQn);                                           
//ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP0_0);                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // Тут вы зачем то поставили количество каналов в группе равным 2!
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
ADC1->CR2 |= ADC_CR2_DMA;
 
  
}
 
void init_DMA1()
{
    
    
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
    DMA1_Channel1->CMAR = (uint32_t)Buffer; //Задаем адрес памяти - базовый адрес массива во флэше
    DMA1_Channel1->CNDTR = 2; //Количество пересылаемых значений = 2
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
        
}
 
void main()
{
  
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN;
        RCC->AHBENR |= RCC_AHBENR_DMA1EN;
        
        RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
        init_GPIOs();
        init_ADC1();
    init_DMA1();
        __enable_irq();
    while(1);
}
Спасибо за помощь!

Добавлено через 1 час 31 минуту
Без DMA тут получилась бы солянка. Удобно тем, что DMA по настройкам сам формирует кольцевой буфер. Его можно зациклить, можно сделать один проход ... и заполнить массив ну и плюс процессор не напрягается
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
21.11.2018, 14:14
Vozz,
Цитата Сообщение от Vozz Посмотреть сообщение
Без DMA тут получилась бы солянка. Удобно тем, что DMA по настройкам сам формирует кольцевой буфер. Его можно зациклить, можно сделать один проход ... и заполнить массив ну и плюс процессор не напрягается
Именно это является огромным плюсом STM. Практически к каждой периферии можно приделать так или иначе DMA. Если научиться с ним работать, то можно избежать многих костылей и косяков в будущем.
0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
21.11.2018, 14:25  [ТС]
Хотел поначалу использовать инжектированные каналы АЦП, но их всего 4... EXTI тоже всего 4 входа можно сделать (для регулирования выходного напряжения приделать инкрементальные энкодеры), а нужно 12 каналов, вот DMA и помог.
0
Эксперт по электронике
6825 / 3250 / 337
Регистрация: 28.10.2011
Сообщений: 12,702
Записей в блоге: 7
21.11.2018, 17:51
Цитата Сообщение от Vozz Посмотреть сообщение
(для регулирования выходного напряжения приделать инкрементальные энкодеры
С ними таймеры работают.
0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
21.11.2018, 18:19  [ТС]
Я думаю и через EXTIn можно ...
0
Эксперт по электронике
6825 / 3250 / 337
Регистрация: 28.10.2011
Сообщений: 12,702
Записей в блоге: 7
21.11.2018, 20:18
Зачем использовать программную работу с энкодером, если он аппаратно поддерживается?
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
21.11.2018, 20:35
Vozz, это как и ацп без дма, можно настраивать один канал и в прерывании перенастраивать. А можно использовать аппаратный ДМА.
Тут точно так же, зачем нагружать ядро, если есть специальный инструмент для работы с энкодерами.
0
 Аватар для Voland_
1983 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
27.11.2018, 09:59
Цитата Сообщение от _SayHello Посмотреть сообщение
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1

Не по теме:

что называется, "приехали"... )) Как же удобно было раньше на SPL'е...



Добавлено через 40 секунд
Vozz, почему вы не используете SPL, HAL и или готовые библиотеки?
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
27.11.2018, 10:07
Voland_,
Цитата Сообщение от Voland_ Посмотреть сообщение
что называется, "приехали"... )) Как же удобно было раньше на SPL'е...
А что тут такого?)
Это не SPL, это CMSIS)
0
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
27.11.2018, 12:32  [ТС]
Цитата Сообщение от Voland_ Посмотреть сообщение
почему вы не используете SPL, HAL и или готовые библиотеки?
Если пишешь через CMSIS, то приходится частенько заглядывать в мануал. Таким образом лучше запоминается принцип работы отдельных модулей контроллера, регистры, биты в них.
Да, это дольше, чем через библиотеки, но никаких срочных проектов у меня нет. Разбираться в коде легче, если что-то не прет. Вот так получилось, что полюбился мне CMSIS
1
 Аватар для Voland_
1983 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
27.11.2018, 13:37
Цитата Сообщение от _SayHello Посмотреть сообщение
А что тут такого?)
Это не SPL, это CMSIS)
Та я в курсе ). Просто я так понимаю, идея с портацией кода от чипа к чипу (как у AVR) у STM32 с треском провалилась, ввиду невозможности реализации идеи - народ "не оценил" SPL. а так вообще - HAL и SPL - попытки сделать код универсальным, как на R_Pi, или еще что-то там.

PS: просто для новичка (на платформах ST) использование трушных регистров довольно муторное дело.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
27.11.2018, 13:37
Помогаю со студенческими работами здесь

Использование нескольких каналов АЦП
Всем привет. Пишу небольшую прогу для ATmega8, и возник вопрос как считывать данные сразу с двух (ну или с нескольких) каналов АЦП,...

АЦП несколько каналов
Нужно замерять сигналы с трех выводов АЦП МК, как это сделать грамотно?

Переключение каналов АЦП atmega88
Добрый день. В который раз сталкиваюсь с АЦП на меге и никак не могу понять как правильно перекючать каналы АЦП. Помогите пожалуйста. Ниже...

Stm8l и несколько каналов АЦП
Здравствуйте! Помогите, пожалуйста разобраться в совместной работе ADC и DMA. Пробовал и в одиночном преобразовании и в циклическом ни чего...

Большое количество АЦП каналов
Здравствуйте! Подскажите микроконтроллеры с количеством АЦП 50 или больше каналов. И есть ли такое вообще ? :)


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере нетипового документа выдачи шин для спецтехники с табличной частью, разработанного в конфигурации КА2. Данные берутся из. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru