Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.95/105: Рейтинг темы: голосов - 105, средняя оценка - 4.95
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739

Stm32f303vc + ADC (Dual Mode) + DMA. Оцифровываем синхронно

05.04.2017, 10:44. Показов 24057. Ответов 20

Студворк — интернет-сервис помощи студентам
Добрый день. Поковырялся немного с АЦП в f303 и решил осилить Dual Mode. Вкратце зачем он нужен: у STMов заожена куча возможностей АЦП : оцифровка регулярных каналов, инжектированных каналов, и того и другого. Оцифровка одного канала или сразу секции с различными приоритетами и временами накопления для каждого канала. Так же есть прерывистый режим, когда секция разбивается на подсекции и они оцифровываются по очереди, по каждому пинку программного или внутреннего триггера. Ну и конечно данные можно вытаскивать с помощью DMA.
У меня появилась необходимость снимать показания с датчика подключенного по трехпроводной линии. Кто не в курсе, объясню: датчик представляет собой сопротивление меняющееся от температуры, казалось бы что сложного, кидаем один конец на землю пропускаем через него постоянный(известный нам) ток, а на верхнем выводе меряем падение напряжения. Но прелесть таких датчиков, в том, что они находятся непосредственно на плате, а могут находиться за углом на длинных проводах. И эти самые провода получаются включены последовательно с самим термосопротивлением. Учитывая, что dR/dT составляет доли Ома на градус, при большой длине проводов, можем обмануться на несколько градусов, что не хорошо. И тут придумали умные люди компенсацию сопротивления проводов. К верхнему или нижнему выводу присоединяется провод, параллельный выводному, и он заводится на второй канал АЦП. Зачем все это нужно: после оцифровки двух каналов мы получаем два падения напряжения : 1 - датчик + паразитные сопротивления, 2 датчик + паразитные сопротивления + паразитное сопротивления доп. провода. Найдем их разность и получим падение на проводе, ну и вычтем из первого значения две эти разности и получим чистое сопротивление датчика. При условии, что провода одной длины, одного сечения и материала. Для большей точности могут применять четырехпроводные схемы.
Мое первое решение: настраиваем 2 канала АЦП в одну секцию и оцифровываем по очереди.
Инициализация:
Кликните здесь для просмотра всего текста
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
void InitADC1()
{
     //Тактирование ADC1, DMA1, и GPIOA 
     RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
 
     //Настроим 2 канала 1 и 2
     ADC1_GPIO_Structure.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1);
     ADC1_GPIO_Structure.GPIO_Mode = GPIO_Mode_AN;
     GPIO_Init(GPIOA, &ADC1_GPIO_Structure);
     DMA_DeInit(DMA1_Channel1);
     DMA1_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&ADC1->DR; // Откуда берем
     DMA1_InitStructure.DMA_MemoryBaseAddr = (unsigned int)&MB_table.regs[20]; // Куда кладем
     DMA1_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Напраление из периферии в память
     DMA1_InitStructure.DMA_BufferSize = 2; // Два канала - 2 значения
     DMA1_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Адрес переферии не инкрементируем
     DMA1_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Адрес в памяти увеличиваем, чтобы данные не накладывались 
     DMA1_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Размер результата преобразования 2 байта    
     DMA1_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //размер ячейки в памяти 2 байта
     DMA1_InitStructure.DMA_Mode = DMA_Mode_Circular; // Зацикливаем работу DMA
     DMA1_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
     DMA1_InitStructure.DMA_M2M = DMA_M2M_Disable;
     DMA_Init(DMA1_Channel1, &DMA1_InitStructure);
 
     // стандартная процедура по даташиту - калибровка и регулятор 
     ADC_DeInit(ADC1);
     ADC_VoltageRegulatorCmd(ADC1, ENABLE);
     ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
     ADC_StartCalibration(ADC1);
     while(ADC_GetCalibrationStatus(ADC1) != RESET );
 
     // Циклическую оцифровку можем включить, но я хочу пинать АЦП программно   
     ADC1_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable;
     ADC1_InitStructure.ADC_Resolution = ADC_Resolution_12b; // Разрешение 12 бит
     ADC1_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0; // Программный триггер
     ADC1_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
     ADC1_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // выравнивание вправо
     ADC1_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
     ADC1_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
     ADC1_InitStructure.ADC_NbrOfRegChannel = 2; // два канала оцифровываем
     ADC_Init(ADC1, &ADC1_InitStructure);
     //Тут приоритет и время сэмплирования
     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_601Cycles5);
     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_601Cycles5);
     
     //Вторая структура: независимый режим и асинхронное тактирование
     ADC1_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
     ADC1_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
     //Это доступ DMA к общему регистру данных, не путать с нашим ADC1->DR
     ADC1_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
     ADC_CommonInit(ADC1, &ADC1_CommonInitStructure);
    //Ну и тут мы все включаем и поехали
     ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
     ADC_DMACmd(ADC1, ENABLE);
     DMA_Cmd(DMA1_Channel1, ENABLE);
     ADC_Cmd(ADC1, ENABLE);
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
}

Пинаем АЦП в main:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
void vMeasurements(void *pvParameters)
{
    portTickType xLastWakenTime;
    xLastWakenTime = xTaskGetTickCount();
    while(1)
    {
        ADC_StartConversion(ADC1);
        vTaskDelayUntil(&xLastWakenTime, 20);
    }
}

Первые грабли: значения АЦП всегда плавают и флуктуируют, при хорошей схемотехнике флуктуации малы, но младшие разряды гуляют вверх да вниз от точного значения, да и черт с ними, потом отфильтруем. Так как преобразование происходит последовательно, между ними есть временной промежуток в который наши любимые шумы могут воздействовать по разному. Получаем картинку номер 1. Очевидно, что U(датчик+провод) должно быть > U(датчик). Но по факту из-за задержки между оцифровками показания хаотичны из за шумов. Возможно после фильтрации Условие выполнится, а вдруг нет? Тогда вся компенсация коту под хвост.
И тут вступает в игру режим Dual Mode. Что это такое: в данном камне 4 независимых АЦП, 1 и 2, 3 и 4 мы можем настроить в парную работу где 1 и 3 АЦП мастера, а 2 и 4 их слейвы. В чем прелесть? В том что мы можем настроить по одному канала 1 и 2 АЦП и по пинку мастера они синхронно оцифруют данные. Так же в данном режиме есть куча разных плюшек см. в мануале.
Проинициализируем и посмотрим на результаты:
Кликните здесь для просмотра всего текста
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
 void InitADC1()
{
     //Тактирование ADC12, DMA1, и GPIOA
     RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
 
 
     //Настроим 2 канала #2 для ADC1 и #2 для ADC2
     ADC1_GPIO_Structure.GPIO_Pin = ( GPIO_Pin_1 | GPIO_Pin_5);
     ADC1_GPIO_Structure.GPIO_Mode = GPIO_Mode_AN;
     GPIO_Init(GPIOA, &ADC1_GPIO_Structure);
 
     DMA_DeInit(DMA1_Channel1);
     // Данные берем из общего регистра(!) он 4 байтный старшие 2 байта с ADC2, младшие ADC1
     DMA1_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&ADC1_2->CDR;
     //Кладем куда надо ( у меня массив с двухбайтными ячейками, поэтому аказываем адрес первой
     // размер буффера указываю 1, и длину слова целиком. Таким образом
     //результат преобразование аккуратно поместится в 2 ячейки моего массива
     DMA1_InitStructure.DMA_MemoryBaseAddr = (unsigned int)&MB_table.regs[20];
     DMA1_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
     DMA1_InitStructure.DMA_BufferSize = 1;
     DMA1_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
     DMA1_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
     DMA1_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; // Слово целиком
     DMA1_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; // Слово целиком
     DMA1_InitStructure.DMA_Mode = DMA_Mode_Circular;
     DMA1_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
     DMA1_InitStructure.DMA_M2M = DMA_M2M_Disable;
     DMA_Init(DMA1_Channel1, &DMA1_InitStructure);
 
     //Настраиваем каждый АЦП отдельно, аналогично с первым опытом
 
     ADC_DeInit(ADC1);
     ADC_VoltageRegulatorCmd(ADC1, ENABLE);
     ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
     ADC_StartCalibration(ADC1);
     while(ADC_GetCalibrationStatus(ADC1) != RESET );
 
     ADC1_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable;
     ADC1_InitStructure.ADC_Resolution = ADC_Resolution_12b;
     ADC1_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
     ADC1_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
     ADC1_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
     ADC1_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
     ADC1_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
     ADC1_InitStructure.ADC_NbrOfRegChannel = 1;
     ADC_Init(ADC1, &ADC1_InitStructure);
     //второй канал ADC1
     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_601Cycles5);
 
     //ADC_DeInit(ADC1); (!) Вот так не делаем! Иначе получится лажа.
     ADC_VoltageRegulatorCmd(ADC2, ENABLE);
     ADC_SelectCalibrationMode(ADC2, ADC_CalibrationMode_Single);
     ADC_StartCalibration(ADC2);
     while(ADC_GetCalibrationStatus(ADC2) != RESET );
 
    //Аналогичная настройка
     ADC2_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable;
     ADC2_InitStructure.ADC_Resolution = ADC_Resolution_12b;
     ADC2_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
     ADC2_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
     ADC2_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
     ADC2_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
     ADC2_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
     ADC2_InitStructure.ADC_NbrOfRegChannel = 1;
     ADC_Init(ADC2, &ADC2_InitStructure);
    //Второй канал ADC2
     ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_601Cycles5);
 
    //Вот тут основа:
     ADC1_CommonInitStructure.ADC_Mode = ADC_Mode_RegSimul; // Dual-mode синхронная оцифровка регулярных каналов
     ADC1_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
     ADC1_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // Доступ DMA к общему регистру, при 12-бит оцифровке
     ADC1_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
     ADC1_CommonInitStructure.ADC_TwoSamplingDelay = 0x0;
     ADC_CommonInit(ADC1, &ADC1_CommonInitStructure);
 
 
     //Все включаем и поехали
     ADC_Cmd(ADC1, ENABLE);
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
 
 
     ADC_Cmd(ADC2, ENABLE);
     while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_RDY));
 
 
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

На графике видно, что все стало гораздо приятнее. На глаз заметна разница между измерениями, эта разница и есть сопротивление провода. Остается только отфильтровать данные и можно считать сопротивление датчика.
Данный режим может быть полезен при измерении мощности, чтобы оцифровывать ток и напряжении в один момент времени.
Может кому пригодится
Миниатюры
Stm32f303vc + ADC (Dual Mode) + DMA. Оцифровываем синхронно   Stm32f303vc + ADC (Dual Mode) + DMA. Оцифровываем синхронно  
Изображения
 
4
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.04.2017, 10:44
Ответы с готовыми решениями:

Stm32f303vc+ADC(Dual mode)+DMA
Добрый день! никак не могу стартануть АЦП1 и 2 в дуал моде. Вот код: RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2); ...

STM32F4 Dual ADC mode
Не могу найти как работать dual ADC mode, что бы одновременно стартовать 2 АЦП и снимать с них значения? Можешь кто сталкивался с этим?

Нет прерывания от DMA в режиме ADC DMA
Вроде всё логично. Настраиваем прерывание от DMA и конфигурим работу ADC что бы через DMA сваливало данные в массив adc; потом вызов...

20
-80 / 1 / 0
Регистрация: 15.12.2019
Сообщений: 346
10.05.2021, 20:45
Студворк — интернет-сервис помощи студентам
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/**
 ******************************************************************************
 * @file           : main.c
 * @author         : Auto-generated by STM32CubeIDE
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
 
#include "main.h"
   volatile unsigned int   bufer;
     volatile unsigned int   bufer1;
static uint16_t pauza=0;
volatile unsigned int adc_data=0;
 void NMI_Handler(void)
{
  if((RCC->CIR & RCC_CIR_CSSF) != 0) // HSE fail
  {
    RCC->CIR |= RCC_CIR_CSSC; // Clear CSSF flag
 
  }
}
 void DMA2_Stream0_IRQHandler (void)
{
     if(DMA2->LISR &DMA_LISR_TCIF0)
     {
         DMA2->LIFCR |= DMA_LIFCR_CTCIF0;
 
                 if(bufer1>2040)
                 {
                     GPIOC-> BSRR |=GPIO_BSRR_BS13;
                 }
                 else
                 {
                     GPIOC-> BSRR |=GPIO_BSRR_BR13;
                 }
     }
      if(DMA2->LISR &DMA_LISR_TEIF0)
     {
         DMA2->LIFCR |= DMA_LIFCR_CTEIF0;
     }
 
}
void TIM4_IRQHandler (void)
{
    if(TIM4->SR & TIM_SR_UIF)
    {
        TIM4->SR &= ~ TIM_SR_UIF;
        //IWDG->KR = 0xAAAA;
        pauza++;
                if(pauza>20)
                {
                    //GPIOC->BSRR |= GPIO_BSRR_BS1;
                    //GPIOC-> BSRR |=GPIO_BSRR_BS13;
                }
                if(pauza>40)
                {
 
                    // GPIOC-> BSRR |=GPIO_BSRR_BR13;
                    // GPIOD->BSRR |= GPIO_BSRR_BR1;
                            pauza=0;
                }
 
 
    }
}
  void RCC_init(void)
{
    FLASH->ACR |= FLASH_ACR_PRFTEN ;
        //FLASH->ACR &=~ (FLASH_ACR_LATENCY_2WS) ;
    FLASH->ACR |= FLASH_ACR_LATENCY_3WS ;
 
    //PWR->CR|= PWR_CR_VOS;
    RCC->CR|=RCC_CR_HSEON;                                          // Enable HSE
    while (!(RCC->CR & RCC_CR_HSERDY));
 
 
    RCC->CR|=RCC_CR_CSSON;
 
     RCC->PLLCFGR |=RCC_PLLCFGR_PLLSRC_HSE  ;
        RCC->PLLCFGR |=_VAL2FLD(RCC_PLLCFGR_PLLM,4);
 
        RCC->PLLCFGR |=_VAL2FLD(RCC_PLLCFGR_PLLN,168);
 
         RCC->PLLCFGR&=~RCC_PLLCFGR_PLLP_0 ;
         RCC->PLLCFGR&=~RCC_PLLCFGR_PLLP_1 ;
         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;// ��������� ����  AHB
                        RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;// ��������� ����  APB1
 
                       RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
 
            RCC->CR |= RCC_CR_PLLON;                                                // enable PLL
            while(!(RCC->CR & RCC_CR_PLLRDY))
            {
 
            }
 
            RCC->CFGR |= RCC_CFGR_SW_PLL;                                           // select source SYSCLK = PLL
            while(!(RCC->CFGR&  RCC_CFGR_SWS_PLL))
 
                {
 
                }
 
 
 
}
 void init_IWDGtimer(void)
 {
    RCC->CSR|= RCC_CSR_LSION;
 
 
 
       IWDG->KR = 0x5555; // Access to registers
       IWDG->PR&= ~(IWDG_PR_PR_0 | IWDG_PR_PR_1 | IWDG_PR_PR_2); // 4096
       IWDG->RLR =  2000;//0x7FF;
       while (!((IWDG->SR & IWDG_SR_PVU) && (IWDG->SR & IWDG_SR_RVU))){} // wait while bist of PVU and RVU will be set.
       IWDG->KR = 0xCCCC; // Start count down;
 }
 void adc_init(void)
 {
      GPIOA->MODER |= GPIO_MODER_MODER1;
      GPIOA->MODER |= GPIO_MODER_MODER2;
 
          RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;
          ADC1->CR2 &=~ADC_CR2_CONT;//�������� ���
             //ADC1->CR2=ADC_CR2_EXTSEL;
                 ADC1->CR2 |=ADC_CR2_EXTEN;
 
          ADC1->SMPR2 &=~ ADC_SMPR2_SMP1_0; //1
         ADC1->SMPR2&=~ADC_SMPR2_SMP1_1; //1
          ADC1->SMPR2 &=~ ADC_SMPR2_SMP1_2; //1
 
             // ADC1->SMPR2 &=~ ADC_SMPR2_SMP2_0; //1
            //   ADC1->SMPR2&=~ADC_SMPR2_SMP2_1; //1
            //    ADC1->SMPR2 &=~ ADC_SMPR2_SMP2_2; //1
 
                //ADC1->SQR3|=_VAL2FLD(ADC_SQR1_L,2);
                ADC1->SQR3|= _VAL2FLD(ADC_SQR3_SQ1,1);//первый канал
                //ADC1->SQR3|= _VAL2FLD(ADC_SQR3_SQ1,2);//второй канал
                //ADC1->SQR3|=_VAL2FLD(ADC_SQR1_L,2);//настройка на два канала конверсии
            // ADC1->SQR3   |=ADC_SQR3_SQ1_0;   //1 IN1
            //  ADC1->SQR3   &= ~ ADC_SQR3_SQ1_1;     //0
            //  ADC1->SQR3   &= ~ADC_SQR3_SQ1_2;   //0
            //  ADC1->SQR3   &=~  ADC_SQR3_SQ1_3;     //0
            //  ADC1->SQR3   &= ~ADC_SQR3_SQ1_4;
                // ADC1->CR1|= ADC_CR1_AUTO;
            //ADC1->CR1|=ADC_CR1_SCAN;
            ADC1->CR2|=ADC_CR2_DDS;
              ADC1->CR2|=ADC_CR2_DMA;
             ADC1->CR2 |=  ADC_CR2_ADON;
 
 }
 void DMA1_init(void)
 {
 
    RCC->AHB1ENR|= RCC_AHB1ENR_DMA1EN;
    //DMA1_Stream0->CR = 0;
    DMA1_Stream0->M0AR |=(uint32_t)& bufer;
    DMA1_Stream0->PAR |=(uint32_t)&TIM4->CCR1 ;
    DMA1_Stream0->NDTR = 2;
    DMA1_Stream0->CR&= ~DMA_SxCR_PINC;
    DMA1_Stream0->CR&= ~DMA_SxCR_MINC;
    DMA1_Stream0->CR|= DMA_SxCR_PSIZE_0;
    DMA1_Stream0->CR|= DMA_SxCR_MSIZE_0;
 
           DMA1_Stream0->CR|=DMA_SxCR_CHSEL_0;
           DMA1_Stream0->CR|= DMA_SxCR_CHSEL_1;
           DMA1_Stream0->CR&=~ DMA_SxCR_CHSEL_2 ;
           DMA1_Stream0->CR&=~ DMA_SxCR_PFCTRL;//DMA ma
                 DMA1_Stream0->CR|= DMA_SxCR_PL; //DMA ma
                 DMA1_Stream0->FCR|=DMA_SxFCR_DMDIS;//��������� fIFO
                 DMA1_Stream0->CR|= DMA_SxCR_DIR_0;
                 DMA1_Stream0->CR|= DMA_SxCR_CIRC;
                 DMA1_Stream0->CR|= DMA_SxCR_EN;//��
 }
 void DMA2_init(void)
  {
 
       RCC->AHB1ENR|= RCC_AHB1ENR_DMA2EN;
       DMA2_Stream0->CR = 0;
 
       DMA2_Stream0->PAR |=(uint32_t)& ADC1->DR;
        DMA2_Stream0->M0AR |=(uint32_t)& bufer1;
      //  TIM4->CCR1= bufer;
        DMA2_Stream0->NDTR = 1;
 
        DMA2_Stream0->CR&= ~DMA_SxCR_PINC;
        DMA2_Stream0->CR&= ~DMA_SxCR_MINC;
        DMA2_Stream0->CR|= DMA_SxCR_PSIZE_0;
        DMA2_Stream0->CR|= DMA_SxCR_MSIZE_0;
        DMA2_Stream0->CR&=~ DMA_SxCR_CHSEL_0 ;
        DMA2_Stream0->CR&=~ DMA_SxCR_CHSEL_1;
        DMA2_Stream0->CR&=~ DMA_SxCR_CHSEL_2 ;
      DMA2_Stream0->CR&=~ DMA_SxCR_PFCTRL;//DMA ma
        DMA2_Stream0->CR|= DMA_SxCR_PL; //DMA ma
        //DMA2_Stream0->FCR|=DMA_SxFCR_DMDIS;//��������� fIFO
        DMA2_Stream0->CR&=~ DMA_SxCR_DIR;
        DMA2_Stream0->CR|= DMA_SxCR_CIRC;
        DMA2_Stream0->CR|=DMA_SxCR_TCIE;
        DMA2_Stream0->CR|=DMA_SxCR_TEIE;
        //DMA2_Stream0->CR|=DMA_SxCR_DMEIE;
        DMA2_Stream0->CR|= DMA_SxCR_EN;//���   DMA2_Stream0
        NVIC_EnableIRQ(DMA2_Stream0_IRQn);
        //ADC1->CR2|=ADC_CR2_DMA;
 
  }
 static void AHB1ER_init(void)
{
    RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
    RCC->AHB1ENR|=RCC_AHB1ENR_GPIOBEN;
    RCC->AHB1ENR|=RCC_AHB1ENR_GPIOCEN;
    RCC->AHB1ENR|=RCC_AHB1ENR_GPIODEN;
}
 static void GPIO_init(void)
{
                        GPIOC->MODER &=~ GPIO_MODER_MODER13_1;
                      GPIOC->MODER |= GPIO_MODER_MODER13_0;
                     // GPIOC ->OTYPER |=GPIO_OTYPER_OT13;
                      //���0 ���������� �������� ������ GPIO
                       GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_1; //���1
                       GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_0;
                      GPIOC->PUPDR |=GPIO_PUPDR_PUPDR13_1;
                        GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR13_0;
                        GPIOC->MODER &=~ GPIO_MODER_MODER13_1;
 
                                          GPIOC->MODER |= GPIO_MODER_MODER0_0;
                                         // GPIOC ->OTYPER |=GPIO_OTYPER_OT13;
                                          //���0 ���������� �������� ������ GPIO
                                           GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0_1; //���1
                                           GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0_0;
                                          GPIOC->PUPDR |=GPIO_PUPDR_PUPDR0_1;
                                            GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR0_0;
}
 void timer2_init(void)
 {
 
 
      RCC->APB1ENR |=RCC_APB1ENR_TIM2EN;
 
       TIM2->PSC=9; // ����������� �������� ��� ������ ����� 1000 ��� � �������
        TIM2->ARR  = 7000;
 
          TIM2->CR2|=TIM_CR2_MMS_1;//бит управлени ацп
 
        TIM2->EGR = TIM_EGR_UG ;
 
 
 
         TIM2->CR1|= TIM_CR1_CEN;
 
 }
 static void timer4_init(void)
{
    RCC->APB1ENR|=RCC_APB1ENR_TIM4EN;
            TIM4->PSC=3500-1;
             TIM4->ARR=100-1;
            // TIM4->EGR|= TIM_EGR_UG;
             TIM4->DIER = TIM_DIER_UIE;
                TIM4->CR1=  TIM_CR1_CEN;
                 NVIC_EnableIRQ(TIM4_IRQn);
}
 
int main(void)
{
    RCC_init();
 
    AHB1ER_init();
    GPIO_init();
    timer2_init();
    timer4_init();
    adc_init();
    DMA2_init();
 
    //ADC1->CR2 |= ADC_CR2_SWSTART;
        ADC1->CR2|=ADC_CR2_EXTSEL_2 |ADC_CR2_EXTSEL_1;
    while(1)
    {
        //ADC1->CR2 |= ADC_CR2_SWSTART;
    //  ADC1->CR2|=ADC_CR2_EXTSEL_2 |ADC_CR2_EXTSEL_1;
    //  while(!(ADC1->SR & ADC_SR_EOC));
    //   ADC1->SR &=~ ADC_SR_EOC;
    //   adc_data = ADC1->DR;
    //   if(adc_data>595)
    //   {
    //       GPIOC-> BSRR |=GPIO_BSRR_BS13;
    //   }
    //   else
    //   {
            // GPIOC-> BSRR |=GPIO_BSRR_BR13;
    //   }
        //GPIOC-> BSRR |=GPIO_BSRR_BS13;
    }
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.05.2021, 20:45

stm32f407+ADC+DMA. Проблема с DMA
Доброго дня! Новичок в stm, первый проект, начальные наброски, не понимаю,почему не работает эта связка(в заголовке). Есть несколько...

STM32F4Discovery - ADC DMA и FSMC DMA
Привет всем. Вынужден опять обратиться за Вашей помощью :) Ситуация такая. 1. Дисплей работает через FSMC. Написал драйвер...

ADC->DMA->SDIO (или NAND через FSMC) без остановки в обработчике прерываний DMA на STM32F407VG, реально или нет?
Добрый день. Столкнулся с необходимостью писать большой объём данных АЦП с высокой скоростью. Каналов 8. Частота АЦП максимальная. ...

ADC +DMA
может кому то понадобится буфер приема данных необходимо выравнивать по 32х битному типу

ADC+DMA пример
Нужен примерчик для K40 (или вообще для любого из семейства кинетис), для передачи ADC-память, что-то с кондачка не получилось запустить.


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

Или воспользуйтесь поиском по форуму:
21
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru