|
|
  |
Нелинейности внутреннего АЦП в STM32, STM32F103RET6 GH22S 9U |
|
|
|
Feb 25 2014, 09:09
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-08-06
Пользователь №: 19 654

|
И так работаю с контроллером STM32F103RET6 GH22S 9U (это полная маркировка, вдруг важно), работаю на частоте 72 МГц, и вот какая проблема, не зависимо от времени семплирования и настроек АЦП при подачи на вход плавно меняющейся функции (и сигнал с датчика температуры - терморезистора, так и просто источник опорного напряжения регулируемый пробовал) на выходи имеем нелинейности - ступеньки на определенных значениях, см. вложение. И так поиск по интернету не дал ответа на вопрос что это и как исправлять (ну кроме смены процессора, просто неисправность камня я исключил так как попробовал на двух идентичных контроллерах), положение ступенек не зависит от напряжения, то есть при изменении опорного напряжения ступеньки остаются в тех же точках, хоть это уже другие напряжения, точки в которых есть ступеньки характерные, в них одновременно сменяется сразу много разрядов (отметил это на графике).
Сообщение отредактировал zWitCh - Feb 25 2014, 09:10
|
|
|
|
|
Feb 25 2014, 14:30
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-08-06
Пользователь №: 19 654

|
Цитата(scifi @ Feb 25 2014, 15:56)  Вы, видимо не в курсе, что такое автоматическая калибровка АЦП в STM32F1xx. Процедура калибровки пройдена, на вход АЦП подаю напряжение с лабораторного источника, плавно его меняю, АЦП выдает совершенно точно оцифрованные значения, так что калибровка не только пройдена но и пройдена видимо успешно, что касается программной ошибки, то все замечательно работает пока на вход не подаше некое напряжение равное в цифровом выражении "1023" и вот тогда АЦП перестает чувствовать малые изменения входного сигнала постоянно выдавая "1023". Цитата(Aner @ Feb 25 2014, 15:32)  Программная проблема, разбирайтесь с прерываниями и записью в регистры. "missing code" SAR ADC - это немного не то, тут нет этого. Прерывания отключены, запись в регистр пишу не я а АЦП, я из него просто читаю в бесконечном цикле, придумайте мне хотя бы синтетический пусть невероятный но все же пример при котором АЦП будет выдавать ступенчатую характеристику только для определенного диапазона (очень узкого) а в остальном диапазоне работать идеально? думаю при всей фантазии такой пример будет придумать сложно ;-)
Сообщение отредактировал zWitCh - Feb 25 2014, 14:35
|
|
|
|
|
Feb 25 2014, 15:41
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-08-06
Пользователь №: 19 654

|
Цитата(Aner @ Feb 25 2014, 18:59)  Схему, прогу в студию. Телепатов пока нема. Может глюк связан с источником питания и наведенной гармоникой, если плохо отвязка сделана. Программно как сделано? Смотрите в дебаге или как? .. Проблема с циклом? ... читаю в бесконечном цикле -> и куда дале и как вывод данных делается? И так на ножке PC5 через резистор в 10к подключен лабораторный источник более ничего нет в схеме, минимальная обвязка со всеми рекомендованными блокирующими конденсаторами, подаю напряжение от полвольта до 2 вольт плавно регулируя вход, параллельно на входе висит осциллограф и мультиметр, и на том и на том приборах напряжения меняются плавно, нет ни всплесков, ни помех (осциллограф с 100 Мгц полосой пропускания, смотрю на хорошей развертке). Смотрю в консоле по СОМ порту. Питание платы идет от стабилизированного источника (другого, лабораторника, земли СОЕДИНЕНЫ). Питание первое что проверил, там все чисто настолько на сколько дает мне понять мой осциллограф. Код: CODE #include<stm32f10x_rcc.h> #include<stm32f10x_gpio.h> #include "stm32f10x.h" #include "stm32f10x_usart.h"
void _debug_print_byte(char c){ while(!(USART1->SR & USART_SR_TC)); USART1->DR = c; }
void _debug_print_str(char *s){ do{ _debug_print_byte(*s); }while(*(++s)); }
void _debug_print_num(uint16_t var){ char c, s[6], *p_s = &s[0], *p2_s; uint8_t i, j = 0;
do { *p_s++ = var % 10 + '0'; j++; } while ((var /= 10) > 0); *p_s = '\0';
for (i = 0, p_s--, p2_s = &s[0]; i<j; i++, j--) { c = *p2_s; *p2_s++ = *p_s; *p_s-- = c; } _debug_print_str(s); }
int main(void) {
uint32_t i; GPIO_InitTypeDef PORT;
// Initialize USART1 USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef PORT; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; PORT.GPIO_Pin = GPIO_Pin_6; PORT.GPIO_Speed = GPIO_Speed_2MHz; PORT.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &PORT);
USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1EN, ENABLE); ADC1->CR2 |= ADC_CR2_CAL; while (!(ADC1->CR2 & ADC_CR2_CAL)) ADC1->CR1 |= ADC_CR1_SCAN; ADC1->CR2 |= ADC_CR2_EXTSEL; ADC1->CR2 |= ADC_CR2_EXTTRIG; ADC1->SQR3 |= (ADC_SQR3_SQ1_3|ADC_SQR3_SQ1_2|ADC_SQR3_SQ1_1|ADC_SQR3_SQ1_0); ADC1->CR2 |= ADC_CR2_ADON; ADC1->CR2 |= ADC_CR2_SWSTART; while (!(ADC1->SR & ADC_SR_EOC)); while(1) { i = 0xffff; while(i--); ADC1->CR2 |= ADC_CR2_SWSTART; while (!(ADC1->SR & ADC_SR_EOC)); _debug_print_num(ADC1->DR); _debug_print_str("\r\n");
} } Кратенько суть того что делает программа вот: CODE int main(void) { uint32_t i; GPIO_InitTypeDef PORT;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1EN, ENABLE); ADC1->CR2 |= ADC_CR2_CAL; while (!(ADC1->CR2 & ADC_CR2_CAL)) ADC1->CR1 |= ADC_CR1_SCAN; ADC1->CR2 |= ADC_CR2_EXTSEL; ADC1->CR2 |= ADC_CR2_EXTTRIG; ADC1->SQR3 |= (ADC_SQR3_SQ1_3|ADC_SQR3_SQ1_2|ADC_SQR3_SQ1_1|ADC_SQR3_SQ1_0); ADC1->CR2 |= ADC_CR2_ADON; ADC1->CR2 |= ADC_CR2_SWSTART; while (!(ADC1->SR & ADC_SR_EOC)); while(1) { i = 0xffff; while(i--); ADC1->CR2 |= ADC_CR2_SWSTART; while (!(ADC1->SR & ADC_SR_EOC)); _debug_print_num(ADC1->DR); _debug_print_str("\r\n");
} } Сразу отмечу что время семплирования не влияет, ставил разное, делал то же самое но через инжектированные каналы, эффект тот же... Цитата(scifi @ Feb 25 2014, 18:40)  А может, лучше чуть пореже читать? Вдруг там что-то клинит от частого считывания? чуть выше код того как я делаю, тут мало того что не очень то и часто читается, но и читается только когда данные готовы, так что нет, дело не в чтении (да и чтение бы проявлялось не так, у меня сто процентная повторяемость на определенном значении (нескольких значениях) выдаваемых АЦП, при этом если подать опору другую и АЙП будет выдавать 1023 при другом входном напряжении, все равно ступенька именно в тех же точках оцифрованных, то есть это никак не связано с чтением или входом судя по всему...)
Сообщение отредактировал IgorKossak - Feb 25 2014, 17:46
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|