Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
1

АЦП и таймер STM32F103 - ARM, Cortex, STM32 микроконтроллер

27.07.2018, 14:14. Просмотров 3644. Ответов 13


Здравствуйте, уважаемые форумчане. Ковыряюсь я с ацп и хочу запускать его по таймеру с частотой 1 КГц. Оцифрованные данные передаю по юсарт. Я не знаю как проверить реальную скорость всего этого, так как когда я подключался по программе terminal v1.9 и сохранял все в лог файл, то скорости и близкой к килогерцу нет. Я конечно не совсем правильно настроил ацп. я по таймеру запускаю преобразование программно, а вроде как можно аппаратно сделать. Вот я не понял как. Да и вообще, товарищи - специалисты, посмотрите пожалуйста на код и направьте в нужное русло.

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
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "misc.h"
 
uint8_t flag = 0;
uint16_t adc_value = 0;
char buffer[2] = {'\0'};
 
 
void adc_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1EN, ENABLE); //Включаем тактирование АЦП
    ADC1->CR2 |= ADC_CR2_CAL; //Запуск калибровки АЦП
    while (!(ADC1->CR2 & ADC_CR2_CAL)); //Ожидаем окончания калибровки
    ADC1->SQR1 | ADC_SQR1_L_0; //выбираем количество каналов оцифровки - 1 канал
    ADC1->SQR3 |= ADC_SQR3_SQ1_1;//выбырается нужный канал(здесь выбран первый)
    ADC1->SMPR2 |= (ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0); //Задаем длительность выборки
    ADC1->CR2 |= ADC_CR2_EXTSEL; //Преобразование регулярной группы запустится установкой бита SWSTART
    ADC1->CR2 |= ADC_CR2_EXTTRIG; //Разрешаем внешний запуск регулярной группы
    ADC1->CR2 |= ADC_CR2_ADON;
}
 
void usart_init(void)
{
    /* Enable USORT1 and GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USORT1 | RCC_APB2Periph_GPIOA, ENABLE);
 
    /* NVIC Configuration */
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the USORTx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USORT1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
    /* Configure the GPIOs */
    //GPIO_Configuration();
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /* Configure USORT1 Tx (PA.09) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    /* Configure USORT1 Rx (PA.10) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    /* Configure the USORT1 */
    //USORT_Configuration();
    USORT_InitTypeDef USORT_InitStructure;
    USORT_InitStructure.USORT_BaudRate = 115200;
    USORT_InitStructure.USORT_WordLength = USORT_WordLength_8b;
    USORT_InitStructure.USORT_StopBits = USORT_StopBits_1;
    USORT_InitStructure.USORT_Parity = USORT_Parity_No;
    USORT_InitStructure.USORT_HardwareFlowControl = USORT_HardwareFlowControl_None;
    USORT_InitStructure.USORT_Mode = USORT_Mode_Rx | USORT_Mode_Tx;
 
    USORT_Init(USORT1, &USORT_InitStructure);
 
    /* Enable USORT1 */
    USORT_Cmd(USORT1, ENABLE);
}
 
void USORTSend(const unsigned char *pucBuffer, unsigned long ulCount)
{
    while(ulCount--)
    {
        USORT_SendData(USORT1, *pucBuffer++);// Last Version USORT_SendData(USORT1,(uint16_t) *pucBuffer++);
        /* Loop until the end of transmission */
        while(USORT_GetFlagStatus(USORT1, USORT_FLAG_TC) == RESET)
        {
        }
    }
}
 
 
void init_timer(void)
{
    // TIMER4
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
 
    TIM_TimeBaseInitTypeDef TIMER_InitStructure;
    TIM_TimeBaseStructInit(&TIMER_InitStructure);
    TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIMER_InitStructure.TIM_Prescaler = 8000;
    TIMER_InitStructure.TIM_Period = 10;
    TIM_TimeBaseInit(TIM3, &TIMER_InitStructure);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM3, ENABLE);
    /* NVIC Configuration */
    /* Enable the TIM4_IRQn Interrupt */
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
 
void TIM3_IRQHandler(void)
{
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
        {
            // Обязательно сбрасываем флаг
            TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
            ADC1->CR2 |= ADC_CR2_SWSTART; //запускаем преобразование ацп
            flag = 1;
        }
}
 
 
 
int main(void)
{
    adc_init();
    usart_init();
    init_timer();
 
    while(1)
    {
        if(flag == 1)
        {
            while (!(ADC1->SR & ADC_SR_EOC));
            adc_value = ADC1->DR;
            buffer[1] = adc_value & 0xFF; // получаем младший разр¤д числа
            buffer[0] = adc_value >> 8;// получаем старший разр¤д числа
            USORTSend(buffer, sizeof(buffer));
        }
        flag = 0;
    }
}
Добавлено через 9 минут
Кстати речь идет о STM32F103CBT6
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.07.2018, 14:14
Ответы с готовыми решениями:

Внешние прерывания EXTI STM32F303VC - ARM, Cortex, STM32 микроконтроллер
Добрый день. Возникла проблема, пытаюсь заставить мигать светодиоды в 2 режимах меняющихся по...

Микроконтроллер ARM с 5В АЦП
А существует ли микроконтроллер архитектуры ARM с 5В АЦП. Питанием 5 вольт. и производительностью...

Проект для стенда на базе ARM Cortex STM32
Нужна помощь! Нужно разработать проект для Стенда с периферией на основе STM32F102C6. Но мой...

Алгоритм работы с ацп АЦП STM32F103
Здравствуйте, уважаемые форумчане. Подскажите пожалуйста алгоритм работы с ацп. Допустим мне надо...

13
Модератор
Эксперт по электронике
8360 / 6206 / 834
Регистрация: 14.02.2011
Сообщений: 21,566
27.07.2018, 14:21 2
Цитата Сообщение от Dim_Dimich Посмотреть сообщение
Я не знаю как проверить реальную скорость всего этого,
осциллографом
Цитата Сообщение от Dim_Dimich Посмотреть сообщение
так как когда я подключался по программе terminal v1.9
Виндос не система реального времени, плюс USORT вносит свои погрешности
Цитата Сообщение от Dim_Dimich Посмотреть сообщение
C
1
2
TIMER_InitStructure.TIM_Prescaler = 8000;
 TIMER_InitStructure.TIM_Period = 10;
а частоту камня как настроил?
если по умолчанию 8 МГц то при таких настройках таймера частота срабатывания около 90 Гц
(8000000/8001)/11=90
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
27.07.2018, 14:27 3
Dim_Dimich, А еще зачем отдельно в прерывании таймера запускать АЦП, если можно настроить таймер, чтобы он автоматически пинал ацп. В прикрепленных темах я делал подобное, только там контроллер F3 серии.
0
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
27.07.2018, 14:31  [ТС] 4
да я знаю что можно, но как настроить не вкурил. надо в регистре ADC_CR2 в EXTSEL[2:0] прописать 100 и тогда будет автоматически запускаться от таймера. Но какой писать обработчик прерывания по переполнению таймера?
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
27.07.2018, 14:36 5
Dim_Dimich, во первых там не от всех таймеров еще будет срабатывать, и совсем не по переполнению.
Вот например список
АЦП и таймер STM32F103 - ARM, Cortex, STM32 микроконтроллер

В основном по флагам Capture compare идет оцифровка.
Никакого прерывания не надо
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
27.07.2018, 14:42 6
Что то подобное должно быть
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
     
     TIM_TimeBaseInitTypeDef Timer1;
     Timer1.TIM_Period          = 1000-1; //1  кГц
     Timer1.TIM_Prescaler       = 8-1; // 1 МГц
     Timer1.TIM_CounterMode     = TIM_CounterMode_Up;
     Timer1.TIM_ClockDivision   = 0;
     TIM_TimeBaseInit(TIM4, &Timer1);
 
     TIM_OCInitTypeDef Timer1OC;
     TIM_OCStructInit(&Timer1OC);
     Timer1OC.TIM_Pulse = 10;
     Timer1OC.TIM_OCMode = TIM_OCMode_PWM1;
     TIM_OC4Init(TIM4, &Timer1OC);
     TIM_SelectOutputTrigger(TIM4,  TIM_TRGOSource_OC4Ref); // триггер для АЦП
     TIM_SetCompare4(TIM4, 100); // Сравниваем со 100
     TIM_Cmd(TIM4);
0
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
27.07.2018, 14:44  [ТС] 7
Спасибо за ответы, буду разбираться.
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
27.07.2018, 14:52 8
Лучший ответ Сообщение было отмечено Dim_Dimich как решение

Решение

Dim_Dimich, смотри схема простая,
1) Смотришь список событий которые могут дать внешний триггер для АЦП. НАпример таймер 4 событие по сравнению канал 4.
2) Настраиваешь таймер на нужную частоту. Делаешь настройку режима захвата/сравнения канал 4. Настраиваешь его как внешний триггер.
3) Настраиваешь АЦП на оцифровку по триггеру от таймера 4.
4) Настраиваешь прерывание АЦП по окончанию оцифровки
5) Включаешь таймер и АЦП. Первый раз дергаешь АЦП самостоятельно. Дальше все пойдет автоматом.
6) В прерывании складываешь в буффер и выставляешь флаг для отправки.
Можно запариться и заставить DMA складывать в буффер без прерываний.
В выходные могу код инициализации накидать. Только нету 103 под рукой, отлаживать и проверять сам будешь)
1
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
27.07.2018, 14:58  [ТС] 9
буду очень благодарен за код инициализации! Я и сам стараюсь разобраться, но пока сложновато.
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
29.07.2018, 13:19 10
Dim_Dimich, попробуй код
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
void Init_ADC();
void Init_USORT();
 
uint16_t ADC_result = 0;
uint16_t Flag_Send  = 0;
 
 
int main(void)
{
    Init_USORT();
    Init_ADC();
    while(1)
    {
        if(Flag_Send)
        {
            USORT_SendData(USORT1, (uint8_t)((ADC_result & 0xFF00) >> 8));
            while(!USORT_GetFlagStatus(USORT1, USORT_FLAG_TC));
            USORT_SendData(USORT1, (uint8_t)ADC_result);
            while(!USORT_GetFlagStatus(USORT1, USORT_FLAG_TC));
            USORT_SendData(USORT1, '\r');
            while(!USORT_GetFlagStatus(USORT1, USORT_FLAG_TC));
            USORT_SendData(USORT1, '\n');
            while(!USORT_GetFlagStatus(USORT1, USORT_FLAG_TC));
            Flag_Send = 0;
        }
    }
}
 
void Init_USORT()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USORT1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 
    GPIO_InitTypeDef pin;
 
    pin.GPIO_Pin    =   GPIO_Pin_9;
    pin.GPIO_Mode   =   GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &pin);
 
    pin.GPIO_Pin    =   GPIO_Pin_10;
    pin.GPIO_Mode   =   GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &pin);
 
    USORT_InitTypeDef usart;
 
    usart.USORT_BaudRate    =   115200;
    usart.USORT_Mode        =   USORT_Mode_Rx | USORT_Mode_Tx;
    usart.USORT_Parity      =   USORT_Parity_No;
    usart.USORT_StopBits    =   USORT_StopBits_1;
    usart.USORT_WordLength  =   USORT_WordLength_8b;
    usart.USORT_HardwareFlowControl =   USORT_HardwareFlowControl_None;
    USORT_Init(USORT1, &usart);
 
    USORT_Cmd(USORT1, ENABLE);
 
 
}
void Init_ADC()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div2);
 
    GPIO_InitTypeDef pin;
 
    pin.GPIO_Pin        =       GPIO_Pin_1;
    pin.GPIO_Mode       =       GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &pin);
 
    TIM_TimeBaseInitTypeDef basetimer;
 
    basetimer.TIM_CounterMode       =   TIM_CounterMode_Up;
    basetimer.TIM_ClockDivision     =   TIM_CKD_DIV1;
    basetimer.TIM_Prescaler         =   8 - 1;
    basetimer.TIM_Period            =   1000 - 1;
    TIM_TimeBaseInit(TIM4, &basetimer);
 
    TIM_OCInitTypeDef octimer;
    TIM_OCStructInit(&octimer);
    TIM_OC4Init(TIM4, &octimer);
    TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_OC4Ref);
    TIM_SetCompare4(TIM4, 100);
 
 
    ADC_InitTypeDef adc;
 
    adc.ADC_Mode                =   ADC_Mode_Independent;
    adc.ADC_ContinuousConvMode  =   ENABLE;
    adc.ADC_DataAlign           =   ADC_DataAlign_Right;
    adc.ADC_ScanConvMode        =   DISABLE;
    adc.ADC_ExternalTrigConv    =   ADC_ExternalTrigConv_T4_CC4;
    adc.ADC_NbrOfChannel        =   1;
    ADC_Init(ADC1, &adc);
 
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_71Cycles5);
 
    NVIC_InitTypeDef nvic;
 
    nvic.NVIC_IRQChannel                    =   ADC1_2_IRQn;
    nvic.NVIC_IRQChannelPreemptionPriority  =   1;
    nvic.NVIC_IRQChannelCmd                 =   ENABLE;
    NVIC_Init(&nvic);
 
    ADC_ExternalTrigConvCmd(ADC1, ENABLE);
    ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
    ADC_Cmd(ADC1, ENABLE);
 
 
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));
    TIM_Cmd(TIM4, ENABLE);
}
 
void ADC1_2_IRQHandler()
{
    if(ADC_GetITStatus(ADC1, ADC_IT_EOC))
    {
        ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
        ADC_result  =   ADC1->DR;
        Flag_Send   =   1;
    }
}
0
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
29.07.2018, 13:30  [ТС] 11
Спасибо большое за помощь! К вечеру ближе попробую. И ещё вопрос у меня. С частотой 1 килогерц на своём коде я запустил АЦП. Осциллографом убедился что есть такая скорость. Но какой бы программой на компьютере принимать данные. Terminal v.1.9 зависает сразу. Мне бы данные принять, записать в лог файл хотя бы
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
29.07.2018, 13:32 12
Dim_Dimich, попробуй PuTTY
0
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 62
30.07.2018, 08:58  [ТС] 13
вопрос наверное не для этой темы, но я не нашел как настроить PUTTY для отображения принятых данных в hex виде. Умеет ли она вообще такое?
0
845 / 518 / 169
Регистрация: 30.07.2015
Сообщений: 1,697
30.07.2018, 09:07 14
Dim_Dimich, нет не умеет. Можешь записать все в файл, а потом каким нибудь hex эдитором воспользоваться
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.07.2018, 09:07

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Обсуждение ARM и Cortex
Пояснение было для того что бы люди поняли как работает компилятор. Хотите поговорить о скорости...

Изучение ARM на примере Cortex-M4
Здравствуйте,у меня избитый вопрос... "С чего начать изучение ARM?" Есть знания C++, C#, основы...

Микроконтроллеры с ядром ARM Cortex-M4
Здравствуйте, никак не могу найти подробного описания архитектуры и основных периферийных устройств...

Инструкция DSP в ARM Cortex M4
Здравствуйте товарищи. У меня такой вопрос: Если я правильно понимаю инструкция DSP реализована в...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.