Однократное и непрерывное измерение ADC: различия между версиями
Андрей (обсуждение | вклад) |
Андрей (обсуждение | вклад) |
||
| (не показано 11 промежуточных версий этого же участника) | |||
| Строка 9: | Строка 9: | ||
После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9. | После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9. | ||
| − | [[Файл:Настройки | + | [[Файл:Настройки ADC в конфигураторе.png|мини|Настройки ADC в конфигураторе]] |
| − | В АЦП есть 3 источника опорного напряжения. Внутренний считается встроенным в АЦП. Настраиваемый ИОН и источник от внешнего вывода ADC_REF считаются внешними по отношению к внутреннему ИОН АЦП. Выберем " | + | В АЦП есть 3 источника опорного напряжения. Внутренний считается встроенным в АЦП. Настраиваемый ИОН и источник от внешнего вывода ADC_REF считаются внешними по отношению к внутреннему ИОН АЦП. Выберем "Внутренний". |
В итоге настройки таймера в конфигураторе должны выглядеть как на рисунке. | В итоге настройки таймера в конфигураторе должны выглядеть как на рисунке. | ||
| Строка 54: | Строка 54: | ||
</syntaxhighlight>Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. | </syntaxhighlight>Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. | ||
| − | В начале main.c можно видеть объявление структуры с набором настроек для АЦП, которую использует функция инициализации ADC_Init. | + | В начале main.c можно видеть объявление структуры с набором настроек для АЦП, которую использует функция инициализации ADC_Init.<syntaxhighlight lang="c" line="1"> |
| + | ADC_HandleTypeDef hadc; | ||
| + | |||
| + | void SystemClock_Config(void); | ||
| + | static void ADC_Init(void); | ||
| + | </syntaxhighlight>Для запуска однократного измерения следует использовать функцию HAL_ADC_Single. Для получения значения используйте функцию HAL_ADC_WaitAndGetValue. | ||
| + | |||
| + | Функция main должна выглядеть примерно так:<syntaxhighlight lang="c" line="1"> | ||
| + | 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++); | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | [[Файл:АЦП пример 1.png|мини|Вывод UART]] | ||
| + | [[Файл:АЦП пример 2.png|мини|Вывод UART в примере с внешнем ОИН]] | ||
| + | [[Файл:АЦП пример 3.png|мини|Вывод UART в примере с АЦП в непрерывном режиме]] | ||
| + | Подадим на вывод Port0.9 напряжение 0.6В. Вывод UART можно видеть на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность. | ||
| + | |||
| + | Теперь изменим ИОН на внешний от вывода ADC_REF - Port1.10. Это можно сделать в конфигураторе, либо в функции ADC_Init, которая должна выглядеть так:<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 изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность. | ||
| + | |||
| + | Для запуска АЦП в непрерывном режиме следует использовать функцию 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"> | ||
| + | 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++); | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </syntaxhighlight>Подадим на вывод АЦП5 (Port0.9) 0.6В. Вывод UART изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность. | ||
Текущая версия на 17:35, 17 февраля 2023
В примере будут запущены измерения ADC (АЦП) в однократном и непрерывном режиме.
Работа с конфигуратором (В разработке)
Для начала настроем в конфигураторе тактирование mik32, например, от внешнего кварца 32МГц. Затем настроем делители шины. Так как АЦП тактируется от шины APB_P_CLK, то зададим делители AHB_DIV и APB_P_DIV. В данном примере оставим делители по умолчанию. В итоге вкладка с тактированием должна выглядеть так:
(Картинка тактирования из конфигуратора. В работе)
Затем перейдем к настройке самого АЦП. Для этого откроем вкладку АЦП и нажмем включить.
После этого появится настройки канала и источника опорного напряжения (ИОН). Выберем 5-й канал АЦП, которому соответствует вывод Port0.9.
В АЦП есть 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++);
}
}
Подадим на вывод 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 изображен на рисунке. АЦП может выводить немного другое значение, так как источники напряжения и сам АЦП имеют погрешность.