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

Материал из MIK32 микроконтроллер
Нет описания правки
м (Исправление орфографических ошибок)
 
(не показано 10 промежуточных версий 2 участников)
Строка 2: Строка 2:


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


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


После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9.  
После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9.  
[[Файл:Настройки ADC в конфигураторе.png|мини|Настройки ADC в конфигураторе]]
[[Файл:Настройки ADC в конфигураторе.png|мини|Рисунок 2 - настройки ADC в конфигураторе]]
В АЦП есть 3 источника опорного напряжения. Внутренний считается встроенным в АЦП. Настраиваемый ИОН и источник от внешнего вывода ADC_REF считаются внешними по отношению к внутреннему ИОН АЦП. Выберем "Внутренний".
В АЦП есть 3 источника опорного напряжения. Внутренний считается встроенным в АЦП. Настраиваемый ИОН и источник от внешнего вывода ADC_REF считаются внешними по отношению к внутреннему ИОН АЦП. Выберем "Внутренний".


Строка 17: Строка 17:


== Использование библиотеки HAL_ADC ==
== Использование библиотеки HAL_ADC ==
В сгенерированном проекте в файле main.c должна быть функция ADC_Init, в которой будут заданы настройки для ADC. Выглядит она так:<syntaxhighlight lang="c" line="1">
В сгенерированном проекте в файле main.c должна быть функция ADC_Init, в которой будут заданы настройки для ADC. Выглядит она так:
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
static void ADC_Init(void)
static void ADC_Init(void)
{
{
Строка 28: Строка 30:
     HAL_ADC_Init(&hadc);
     HAL_ADC_Init(&hadc);
}
}
</syntaxhighlight>Кроме этого в функции SystemClock_Config приведены настройки для тактирования. Убедитесь что в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_ANALOG_REG_M. Для смены функции вывода на аналоговую должен быть затактирован контроллер выводов (в PeriphClkInit.PMClockAPB_M должен быть PM_CLOCK_PAD_CONFIG_M или PMCLOCKAPB_M_DEFAULT).  Сама функция должна выглядеть примерно так:
</syntaxhighlight>
 
}}
Кроме этого в функции SystemClock_Config приведены настройки для тактирования. Убедитесь что в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_ANALOG_REG_M. Для смены функции вывода на аналоговую должен быть затактирован контроллер выводов (в PeriphClkInit.PMClockAPB_M должен быть PM_CLOCK_PAD_CONFIG_M или PMCLOCKAPB_M_DEFAULT).  Сама функция должна выглядеть примерно так:
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
<syntaxhighlight lang="c" line="1">
void SystemClock_Config(void)
void SystemClock_Config(void)
Строка 52: Строка 56:
     HAL_RCC_ClockConfig(&PeriphClkInit);
     HAL_RCC_ClockConfig(&PeriphClkInit);
}
}
</syntaxhighlight>Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно.  
</syntaxhighlight>
}}
Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. Для этого нужно подключить библиотеки uart_lib и xprintf.
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
#include "mik32_hal_rcc.h"
#include "mik32_hal_adc.h"
 
#include "uart_lib.h"
#include "xprintf.h"
</syntaxhighlight>
}}
Для инициализации UART в функции main, после функции тактирования SystemClock_Config, следует написать:
<syntaxhighlight lang="c" line="1" start="1">
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
</syntaxhighlight>
Скорость UART задается делителем во втором аргументе функции. При такой записи скорость будет 9600 бод.


В начале main.c можно видеть объявление структуры с набором настроек для АЦП, которую использует функция инициализации ADC_Init.<syntaxhighlight lang="c" line="1">
В начале main.c можно видеть объявление структуры с набором настроек для АЦП, которую использует функция инициализации ADC_Init.
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
ADC_HandleTypeDef hadc;
ADC_HandleTypeDef hadc;


void SystemClock_Config(void);
void SystemClock_Config(void);
static void ADC_Init(void);
static void ADC_Init(void);
</syntaxhighlight>Для запуска однократного измерения следует использовать функцию HAL_ADC_Single. Для получения значения используйте функцию HAL_ADC_WaitAndGetValue.
</syntaxhighlight>
}}
Для запуска однократного измерения следует использовать функцию HAL_ADC_Single. Для получения значения используйте функцию HAL_ADC_WaitAndGetValue.


Функция main должна выглядеть примерно так:<syntaxhighlight lang="c" line="1">
Функция main должна выглядеть примерно так:
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
int main()
int main()
{     
{     


     SystemClock_Config();
     SystemClock_Config();
      
 
     UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
 
     ADC_Init();
     ADC_Init();


Строка 75: Строка 103:
         HAL_ADC_Single(&hadc);
         HAL_ADC_Single(&hadc);
         value = HAL_ADC_WaitAndGetValue(&hadc);
         value = HAL_ADC_WaitAndGetValue(&hadc);
         xprintf("ADC%d: %d (V = %d,%d)\n", hadc.Init.Sel, value, (value*1200/4095)/1000, (value*1200/4095)%1000);
 
         xprintf("ADC: %d (V = %d,%03d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);
 
        for (volatile int i = 0; i < 1000000; i++);
    }
     
}
</syntaxhighlight>
}}
[[Файл:АЦП пример 1.png|мини|Рисунок 3 - вывод UART]]
[[Файл:АЦП пример 2.png|мини|Рисунок 4 - вывод UART в примере с внешнем ОИН]]
[[Файл:АЦП пример 3.png|мини|Рисунок 5 - Вывод UART в примере с АЦП в непрерывном режиме]]
Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке 3. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.
 
Теперь изменим ИОН на внешний от вывода ADC_REF - Port1.10. Это можно сделать в конфигураторе, либо в функции ADC_Init, которая должна выглядеть так:
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
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);
}
</syntaxhighlight>
}}
Функция main без изменений.
 
Подадим на вывод ADC_REF (Port1.10 ) 1.2В, а на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке 4. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.
 
Для запуска АЦП в непрерывном режиме следует использовать функцию HAL_ADC_ContiniusEnable, а для считывания результата преобразования HAL_ADC_GetValue.
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<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 должна выглядеть примерно так:
{{#spoiler:show=Развернуть код|hide=Свернуть код|
<syntaxhighlight lang="c" line="1">
int main()
{   
 
    SystemClock_Config();
 
    UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
 
    ADC_Init();
 
    uint16_t value = 0;
    HAL_ADC_ContiniusEnable(&hadc);
 
    while (1)
    {   
        value = HAL_ADC_GetValue(&hadc);
 
        xprintf("ADC: %d (V = %d,%03d)\n", value, ((value*1200)/4095)/1000, ((value*1200)/4095)%1000);


         for (volatile int i = 0; i < 1000000; i++);
         for (volatile int i = 0; i < 1000000; i++);
Строка 82: Строка 177:
}
}
</syntaxhighlight>
</syntaxhighlight>
[[Файл:Вывод UART в примере один.png|мини|Вывод UART в примере 1]]
}}
Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке.
Подадим на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке 5. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.

Текущая версия от 15:40, 27 августа 2023

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

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

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

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

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

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

Рисунок 2 - настройки ADC в конфигураторе

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

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

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

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

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

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

Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. Для этого нужно подключить библиотеки uart_lib и xprintf.

Для инициализации UART в функции main, после функции тактирования SystemClock_Config, следует написать:

UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);

Скорость UART задается делителем во втором аргументе функции. При такой записи скорость будет 9600 бод.

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

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

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

Рисунок 3 - вывод UART
Рисунок 4 - вывод UART в примере с внешнем ОИН
Рисунок 5 - Вывод UART в примере с АЦП в непрерывном режиме

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

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

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

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

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

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

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