Однократное и непрерывное измерение ADC: различия между версиями

Материал из MIK32 микроконтроллер
Нет описания правки
Нет описания правки
Строка 90: Строка 90:
}
}
</syntaxhighlight>
</syntaxhighlight>
[[Файл:Вывод UART в примере один.png|мини|Вывод UART]]
[[Файл:АЦП пример 1.png|мини|Вывод UART]]
[[Файл:Вывод UART в примере с внешнем ОИН.png|мини|Вывод UART в примере с внешнем ОИН]]
[[Файл:АЦП пример 2.png|мини|Вывод UART в примере с внешнем ОИН]]
[[Файл:Вывод UART в примере с АЦП в непрерывном режиме.png|мини|Вывод UART в примере с АЦП в непрерывном режиме]]
[[Файл:АЦП пример 3.png|мини|Вывод UART в примере с АЦП в непрерывном режиме]]
Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке.
Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.


Теперь изменим ИОН на внешний от вывода ADC_REF - Port1.10. Это можно сделать в конфигураторе, либо в функции ADC_Init, которая должна выглядеть так:<syntaxhighlight lang="c" line="1">
Теперь изменим ИОН на внешний от вывода ADC_REF - Port1.10. Это можно сделать в конфигураторе, либо в функции ADC_Init, которая должна выглядеть так:<syntaxhighlight lang="c" line="1">
Строка 106: Строка 106:
     HAL_ADC_Init(&hadc);
     HAL_ADC_Init(&hadc);
}
}
</syntaxhighlight>Подадим на вывод ADC_REF (Port1.10 ) 1.2В, а на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке.
</syntaxhighlight>Функция main без изменений.  


Для запуска АЦП в непрерывном режиме следует использовать функцию HAL_ADC_ContiniusEnable, а для считывания результата преобразования HAL_ADC_GetValue.
Подадим на вывод ADC_REF (Port1.10 ) 1.2В, а на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.
 
Для запуска АЦП в непрерывном режиме следует использовать функцию HAL_ADC_ContiniusEnable, а для считывания результата преобразования HAL_ADC_GetValue.<syntaxhighlight lang="c" line="1">
static void ADC_Init(void)
{
    hadc.Instance = ANALOG_REG;
 
    hadc.Init.Sel = ADC_CHANNEL5;
    hadc.Init.EXTRef = ADC_EXTREF_OFF; /* Выбор источника опорного напряжения: «1» - внешний; «0» - встроенный */
    hadc.Init.EXTClb = ADC_EXTCLB_ADCREF; /* Выбор источника внешнего опорного напряжения: «1» - внешний вывод; «0» - настраиваемый ОИН */
 
    HAL_ADC_Init(&hadc);
}
</syntaxhighlight>


Функция main должна выглядеть примерно так:<syntaxhighlight lang="c" line="1">
Функция main должна выглядеть примерно так:<syntaxhighlight lang="c" line="1">
Строка 138: Строка 151:
        
        
}
}
</syntaxhighlight>Подадим на вывод ADC_REF (Port1.10 ) 1.2В, а на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке.
</syntaxhighlight>Подадим на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.

Версия от 14:35, 17 февраля 2023

В примере будут запущены измерения ADC (АЦП) в однократном и непрерывном режиме.

Работа с конфигуратором (В разработке)

Для начала настроем в конфигураторе тактирование mik32, например, от внешнего кварца 32МГц. Затем настроем делители шины. Так как АЦП тактируется от шины APB_P_CLK, то зададим делители AHB_DIV и APB_P_DIV. В данном примере оставим делители по умолчанию. В итоге вкладка с тактированием должна выглядеть так:

(Картинка тактирования из конфигуратора. В работе)

Затем перейдем к настройке самого АЦП. Для этого откроем вкладку АЦП и нажмем включить.

После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9.

Настройки ADC в конфигураторе

В АЦП есть 3 источника опорного напряжения. Внутренний считается встроенным в АЦП. Настраиваемый ИОН и источник от внешнего вывода ADC_REF считаются внешними по отношению к внутреннему ИОН АЦП. Выберем "Внутренний".

В итоге настройки таймера в конфигураторе должны выглядеть как на рисунке.

Нажимаем кнопку сохранения и генерации. В итоге у нас появится проект для PlatformIo. Далее работа идет в visual studio code.

Использование библиотеки HAL_ADC

В сгенерированном проекте в файле main.c должна быть функция ADC_Init, в которой будут заданы настройки для ADC. Выглядит она так:

static void ADC_Init(void)
{
    hadc.Instance = ANALOG_REG;

    hadc.Init.Sel = ADC_CHANNEL5;
    hadc.Init.EXTRef = ADC_EXTREF_OFF; /* Выбор источника опорного напряжения (внешний или встроенный) */
    hadc.Init.EXTClb = ADC_EXTCLB_ADCREF; /* Выбор источника внешнего опорного напряжения (внешний вывод или настраиваемый ОИН) */

    HAL_ADC_Init(&hadc);
}

Кроме этого в функции SystemClock_Config приведены настройки для тактирования. Убедитесь что в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_ANALOG_REG_M. Для смены функции вывода на аналоговую должен быть затактирован контроллер выводов (в PeriphClkInit.PMClockAPB_M должен быть PM_CLOCK_PAD_CONFIG_M или PMCLOCKAPB_M_DEFAULT). Сама функция должна выглядеть примерно так:

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInit = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

    RCC_OscInit.OscillatorEnable = RCC_OSCILLATORTYPE_OSC32K | RCC_OSCILLATORTYPE_OSC32M;   
    RCC_OscInit.OscillatorSystem = RCC_OSCILLATORTYPE_OSC32M;                          
    RCC_OscInit.AHBDivider = 0;                             
    RCC_OscInit.APBMDivider = 0;                             
    RCC_OscInit.APBPDivider = 0;                             
    RCC_OscInit.HSI32MCalibrationValue = 0;                  
    RCC_OscInit.LSI32KCalibrationValue = 0;
    HAL_RCC_OscConfig(&RCC_OscInit);

    PeriphClkInit.PMClockAHB = PMCLOCKAHB_DEFAULT;    
    PeriphClkInit.PMClockAPB_M = PMCLOCKAPB_M_DEFAULT | PM_CLOCK_WU_M | PM_CLOCK_PAD_CONFIG_M;     
    PeriphClkInit.PMClockAPB_P = PMCLOCKAPB_P_DEFAULT | PM_CLOCK_UART_0_M | PM_CLOCK_ANALOG_REG_M;     
    PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_NO_CLK;
    PeriphClkInit.RTCClockCPUSelection = RCC_RTCCLKCPUSOURCE_NO_CLK;
    HAL_RCC_ClockConfig(&PeriphClkInit);
}

Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. В начале main.c можно видеть объявление структуры с набором настроек для АЦП, которую использует функция инициализации ADC_Init.

ADC_HandleTypeDef hadc;

void SystemClock_Config(void);
static void ADC_Init(void);

Для запуска однократного измерения следует использовать функцию HAL_ADC_Single. Для получения значения используйте функцию HAL_ADC_WaitAndGetValue. Функция main должна выглядеть примерно так:

int main()
{    

    SystemClock_Config();
    
    ADC_Init();

    uint16_t value = 0;

    while (1)
    {    
        HAL_ADC_Single(&hadc);
        value = HAL_ADC_WaitAndGetValue(&hadc);

        if(( (value*1200/4095)%1000 ) > 99)
        {
            xprintf("ADC: %d (V = %d,%d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);
        }
        else
        {
            xprintf("ADC: %d (V = %d,0%d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);
        }

        for (volatile int i = 0; i < 1000000; i++);
    }
       
}
Вывод UART
Вывод UART в примере с внешнем ОИН
Вывод UART в примере с АЦП в непрерывном режиме

Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.

Теперь изменим ИОН на внешний от вывода ADC_REF - Port1.10. Это можно сделать в конфигураторе, либо в функции ADC_Init, которая должна выглядеть так:

static void ADC_Init(void)
{
    hadc.Instance = ANALOG_REG;

    hadc.Init.Sel = ADC_CHANNEL5;
    hadc.Init.EXTRef = ADC_EXTREF_ON; /* Выбор источника опорного напряжения: «1» - внешний; «0» - встроенный */
    hadc.Init.EXTClb = ADC_EXTCLB_ADCREF; /* Выбор источника внешнего опорного напряжения: «1» - внешний вывод; «0» - настраиваемый ОИН */

    HAL_ADC_Init(&hadc);
}

Функция main без изменений.

Подадим на вывод ADC_REF (Port1.10 ) 1.2В, а на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.

Для запуска АЦП в непрерывном режиме следует использовать функцию HAL_ADC_ContiniusEnable, а для считывания результата преобразования HAL_ADC_GetValue.

static void ADC_Init(void)
{
    hadc.Instance = ANALOG_REG;

    hadc.Init.Sel = ADC_CHANNEL5;
    hadc.Init.EXTRef = ADC_EXTREF_OFF; /* Выбор источника опорного напряжения: «1» - внешний; «0» - встроенный */
    hadc.Init.EXTClb = ADC_EXTCLB_ADCREF; /* Выбор источника внешнего опорного напряжения: «1» - внешний вывод; «0» - настраиваемый ОИН */

    HAL_ADC_Init(&hadc);
}

Функция main должна выглядеть примерно так:

int main()
{    

    SystemClock_Config();
    
    ADC_Init();

    uint16_t value = 0;
    HAL_ADC_ContiniusEnable(&hadc);

    while (1)
    {    
        value = HAL_ADC_GetValue(&hadc);

        if(( (value*1200/4095)%1000 ) > 99)
        {
            xprintf("ADC: %d (V = %d,%d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);
        }
        else
        {
            xprintf("ADC: %d (V = %d,0%d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);
        }

        for (volatile int i = 0; i < 1000000; i++);
    }
       
}

Подадим на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.