Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.77/30: Рейтинг темы: голосов - 30, средняя оценка - 4.77
Somik
0 / 0 / 0
Регистрация: 18.11.2015
Сообщений: 5
1

Данные с двух каналов АЦП по очередно.[Решено]

09.01.2017, 23:48. Просмотров 5676. Ответов 16
Метки нет (Все метки)

Всем привет.
Столкнулся с непоняткой, чип stm8s003f на время теста подцепил два переменных резистора на 100к и 68к на пины PD3 и PD2
код чтения ацп для канала 3 для канал 4 такой же
Код
int ADC_ch_3(void){

int data=0, t=0;
ADC_CSR_CH3;           //Выбераем канал
ADC_CR1_SPSEL8;        //Делитель на 18
ADC_TDRL_DIS(0);       //Отключаем тригер Шмидта
ADC_CR2_ALIGN_LEFT;    //Выравнивание по левому краю
ADC_CR1_ADON_ON;       //Запуск ADC

for(t=0;t<64;t++){     //Пауза
__asm__("nop\n");
}
data=ADC_DRH;          //Считываем показания
return data;
}
в программе сначала читаю 3 канал сохраняю в переменную, затем читаю 4 канал и сохраняю в другую переменную и по очиредно вывожу эти переменные в порт РС.
МК виснет.
Если опрашивать только один канал не важно 3 или 4 все работает.
НО на stm8s003k3 этот код работает как задумано.
Вопрос: я что то упустил/не правильно сделал в программе или я не учел каких то особенностей 003f3 ?
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.01.2017, 23:48
Ответы с готовыми решениями:

Опрос нескольких регулярных каналов АЦП STM32F100
Всем привет! Проблема с опросом нескольких регулярных каналов АЦП STM32F100 (Отл плата STM32F100VL...

stm32f4 нужен медленный АЦП (решено)
(решено , ошибка в названии флага в прерывании ДМА = DMA_IT_TCIF0) Работаю с ацп 4 канала ...

АЦП несколько каналов
Нужно замерять сигналы с трех выводов АЦП МК, как это сделать грамотно?

Использование нескольких каналов АЦП
Всем привет. Пишу небольшую прогу для ATmega8, и возник вопрос как считывать данные сразу с двух...

Переключение каналов АЦП atmega88
Добрый день. В который раз сталкиваюсь с АЦП на меге и никак не могу понять как правильно...

16
Kitvym
0 / 0 / 0
Регистрация: 07.08.2016
Сообщений: 432
10.01.2017, 13:00 2
А если на stm8s003k3 опрашивать существующие каналы, например 2 и 3, то работает?
0
Iddy_Im
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,406
10.01.2017, 13:31 3
А если еще и вот так сделать после считывания:
Код
ADC_CSR &= 0x3f; // clear EOC & AWD flags
?
Кстати, а что делает функция ADC_TDRL_DIS(0); ?
Скажем, у меня конфигурация третьего канала такова:
Код
    // select PD2[AIN3] & enable interrupt for EOC
ADC_CSR = 0x23;
ADC_TDRL = 0x08; // disable Schmitt triger for AIN3
// right otygnment
ADC_CR2 = 0x08; // dont forget: first read ADC_DRL!
// f_{ADC} = f/18 & continuous non-buffered conversion & wake it up
ADC_CR1 = 0x73;
ADC_CR1 = 0x73; // turn on ADC (this needs second write operation)
И почему у вас младший регистр АЦП не считывается?
0
Somik
0 / 0 / 0
Регистрация: 18.11.2015
Сообщений: 5
10.01.2017, 23:09 4
Цитата Сообщение от Kitvym
А если на stm8s003k3 опрашивать существующие каналы, например 2 и 3, то работает?
С stm8s003k3 ошибся, я проверял на 0 и 1 каналах - работает, если 2 и 3 то данные выводит только с 3 канала.
Цитата Сообщение от Iddy_Im
А если еще и вот так сделать после считывания:
Код:
ADC_CSR &= 0x3f; // clear EOC & AWD flags

?
не чего не меняется

Цитата Сообщение от Iddy_Im
Кстати, а что делает функция ADC_TDRL_DIS(0); ?
ADC_TDRL_DIS(номер канала)-->#define ADC_TDRL_DIS(bit) ADC_TDRL|=(1<<bit)
Цитата Сообщение от Iddy_Im
И почему у вас младший регистр АЦП не считывается?
У меня выравнивание по левому краю, в регистре ADC_DRL остаются "моргающие биты"
или считывание ADC_DRL обязательно?
0
10.01.2017, 23:09
Sovo
0 / 0 / 0
Регистрация: 05.10.2007
Сообщений: 498
12.01.2017, 00:30 5
Обязательно!
0
worobo
0 / 0 / 0
Регистрация: 04.11.2012
Сообщений: 81
12.01.2017, 18:25 6
Причем в строго определенном порядке, в зависимости от выравнивания.
0
Somik
0 / 0 / 0
Регистрация: 18.11.2015
Сообщений: 5
12.01.2017, 23:23 7
Проблема решена.
Причина: невнимательность(в принципе как всегда)
#define ADC_CSR_CH3 ADC_CSR|=(1<<1)|(1<<0) тут устанавливается 1 в нулевой бит
#define ADC_CSR_CH2 ADC_CSR|=(1<<1) а тут этот бит не сбрасывается и получается всегда выбран 3 канал

Спасибо ребята, ваши советы учтены, код подправлен.
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
13.01.2017, 00:35 8
Скинь пожалуйста последний вариант, сохраню себе чтобы потом долго не разбираться...
С одним каналом я давно разобрался, а вот с несколькими - вдруг там нюансы какие...
0
Iddy_Im
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,406
13.01.2017, 00:44 9
Не нужно magick numbers использовать. Лучше все в заголовочном файле определить!!
0
Somik
0 / 0 / 0
Регистрация: 18.11.2015
Сообщений: 5
13.01.2017, 22:58 10
Вот код, ни чего специфического если внимательно)
Код
void main(void)
{
unsykned int i=1, s=0;       //переменные для хранения данных
Init_HSE();                           //инициализируем переферию
gpio_init();

ADC_CR1|=(1<<6);         //Делитель на 18
ADC_TDRH|=(1<<5);       //Отключаем тригер Шмидта для канала 5
ADC_TDRH|=(1<<6);       //Отключаем тригер Шмидта для канала 6
ADC_CR2&=~(1<<3);      //Выравнивание по левому краю
ADC_CR1|=(1<<0);         //Первый запуск ADC

while(1)
{
/***********************читаем 5 канал************************************/
ADC_CSR&=~((1<<3)|(1<<2)|(1<<1)|(1<<0)); //сбрасываем выбранный до этого канал
ADC_CSR|=(1<<2)|(1<<0);                                 //Выбераем канал 5
ADC_CR1|=(1<<0);                                              //запуск преобразования
while(!(ADC_CSR&(1<<7)))                                 //ждем окончания преобразования
{
__asm__("nop\n");
}
s=ADC_DRH;                                                         //первым читается значемый регистр в данном случае ADC_DRH
i=ADC_DRL;
ADC_CSR&=~(1<<7);                                           //очищаем флаг окончания преобразования
PC_ODR=s;                                                           //выводим данные в порт С
delay(100);
s=i=0;
/***********************читаем 6 канал*************************************/
ADC_CSR&=~((1<<3)|(1<<2)|(1<<1)|(1<<0));
ADC_CSR|=(1<<2)|(1<<1);
ADC_CR1|=(1<<0);
while(!(ADC_CSR&(1<<7)))
{
__asm__("nop\n");
}
s=ADC_DRH;
i=ADC_DRL;
ADC_CSR&=~(1<<7);
PC_ODR=s;
delay(100);
s=i=0;
/**************************************************************/
}

}
0
Iddy_Im
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,406
13.01.2017, 23:14 11
АЦП можно обрабатывать в прерываниях, например, вот так.
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
14.01.2017, 04:15 12
Код
   ADC_CR1|=(1<<6);         //Делитель на 18
ADC_TDRH|=(1<<5);       //Отключаем тригер Шмидта для канала 5
ADC_TDRH|=(1<<6);       //Отключаем тригер Шмидта для канала 6
ADC_CR2&=~(1<<3);      //Выравнивание по левому краю
ADC_CR1|=(1<<0);         //Первый запуск ADC
Почему так сделал?

у меня сделано так:

Код
   //настройка ADC
ADC_CR1_bit.ADON = 1;               //включить ADC
ADC_CSR_bit.CH = 0x03;               //номер канала
ADC_CR1_bit.SPSEL = 0x07;            //делитель скорости
ADC_CR2_bit.ALIGN = 0;               //выровнять влево
ADC_CR1_bit.ADON = 1;               //включить ADC
Или твой вариант (битовые операции) меньше кода занимает?
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
14.01.2017, 04:20 13
Цитата Сообщение от Iddy_Im
И почему у вас младший регистр АЦП не считывается?
У меня вроде тоже не читается младший регистр, и все работает.
Код
   if (ADC_DRH < ADC_MARK_VOT)      PWR_ODR_bit = 1;   //шунтируется балласт и питание увеличивается
else                     PWR_ODR_bit = 0;   //добавляется балласт и питание уменьшается
ADC_CR1_bit.ADON = 1;                        //старт ADC
А какая может быть проблема, если не читать младший разряд?
0
Sovo
0 / 0 / 0
Регистрация: 05.10.2007
Сообщений: 498
14.01.2017, 11:05 14
Цитата Сообщение от ShodS
А какая может быть проблема, если не читать младший разряд?
Потом замахаешься искать, почему код то работает, то нет. АЦП устроен так, что при считывании первого байта второй считывается в промежуточный буфер. Если не считать второй, нарушается логика работы АЦП. В даташите картинки нарисованы.

У меня инит АЦП сделан так:
Код
#define ADC1_TDRH_MASK ((u8)((1 << (ADC1_CSR_CH8 - 8))      * 0 \
| (1 << (ADC1_CSR_CH9 - 8))      * 0 \
| (1 << (ADC1_CSR_CH10 - 8))   * 0 \
| (1 << (ADC1_CSR_CH11 - 8))   * 0 \
| (1 << (ADC1_CSR_CH12 - 8))   * 0 \
| (1 << (ADC1_CSR_CH13 - 8))   * 0 \
| (1 << (ADC1_CSR_CH14 - 8))   * 0 \
| (1 << (ADC1_CSR_CH15 - 8))   * 0))      // маска триггеров шмитта каналов 8-12

#define ADC1_TDRL_MASK   ((u8)((1 << ADC1_CSR_CH0)   * 1 \
| (1 << ADC1_CSR_CH1)   * 1 \
| (1 << ADC1_CSR_CH2)   * 1 \
| (1 << ADC1_CSR_CH3)   * 1 \
| (1 << ADC1_CSR_CH4)   * 1 \
| (1 << ADC1_CSR_CH5)   * 1 \
| (1 << ADC1_CSR_CH6)   * 1 \
| (1 << ADC1_CSR_CH7)   * 0))   // маска триггеров шмитта каналов 0-7

/*****************************************************************************
* Настройка АЦП
*****************************************************************************/
void init_adc (void)
{
// Инициализация АЦП
ADC1->CR1 &= ~ADC1_CR1_ADON;   // выключить АЦП для изменения настроек
ADC1->TDRH = ADC1_TDRH_MASK;   // маска используемых входов
ADC1->TDRL = ADC1_TDRL_MASK;   // маска используемых входов

ADC1->CSR = ADC_IN                   // измерять до входа 6
| ADC1_CSR_AWDIE   * 0      // запретить прерывания аналогового вочдога
| ADC1_CSR_EOCIE   * 1;   // Разрешить прерывание по окончании измерения
ADC1->CR1 = ADC1_CR1_SPSEL4            // частота преобразования 16МГц / 4 = 4 МГц
| ADC1_CR1_CONT    * 0      // режим однократного измерения
| ADC1_CR1_ADON      * 0;
ADC1->CR2 = ADC1_CR2_EXTTRIG   * 0      // внутренний триггер
| ADC1_CR2_EXTSEL   * 0      // внешний триггер не используется
| ADC1_CR2_ALIGN    * 0      // выравнивание влево
| ADC1_CR2_SCAN    * 1;   // Режим сканирования
ADC1->CR3 = ADC1_CR3_DBUF      * 1;   // с использованием буфера

ADC1->CR1 |= ADC1_CR1_ADON;            // включить АЦП
}
Использую сканирование сразу семи каналов.
Запускаю из прерывания таймера:
Код
/******************************************************************************
* Системное прерывание 1 мс
******************************************************************************/
INTERRUPT_HANDLER (SysTick_Timer_ISR, 23)
{
static u16         ADC_timer      = 0;

TIM4->SR1 = 0;   // Сбросим флаг прерывания
// счётчики работают с интервалом в 1 мс
system_time++;   // системный счётчик времени
if ((system_time - ADC_timer) >= ADC_TIMER)
{
ADC_timer = system_time;
ADC1->CR1 |= ADC1_CR1_ADON;   // запустить АЦП
}
}
И получаю результаты:
Код
static u8   buf [7];   // массив отсчётов ацп

/*****************************************************************************
* прерывание по окончании измерения
* здесь считывается напряжение сети
*****************************************************************************/
INTERRUPT_HANDLER (ADC1_End_of_conversion_ISR, 22)
{
u8 flags = ADC1->CSR;
flags &= ~ADC1_CSR_EOC;      // снять флаг прерывания
ADC1->CSR = flags;

buf [0] = ADC1->DB0RH;   // сохраняем значения
buf [1] = ADC1->DB1RH;
buf [2] = ADC1->DB2RH;
buf [3] = ADC1->DB3RH;
buf [4] = ADC1->DB4RH;
buf [5] = ADC1->DB5RH;
buf [6] = ADC1->DB6RH;

control_func ();
}
Кстати, при использовании буфера отпадает необходимость считывать два байта результата.
0
Somik
0 / 0 / 0
Регистрация: 18.11.2015
Сообщений: 5
14.01.2017, 16:09 15
Цитата Сообщение от ShodS
Код:
ADC_CR1|=(1<<6); //Делитель на 18
ADC_TDRH|=(1<<5); //Отключаем тригер Шмидта для канала 5
ADC_TDRH|=(1<<6); //Отключаем тригер Шмидта для канала 6
ADC_CR2&=~(1<<3); //Выравнивание по левому краю
ADC_CR1|=(1<<0); //Первый запуск ADC
Почему так сделал?

у меня сделано так:

Код
   //настройка ADC
ADC_CR1_bit.ADON = 1;               //включить ADC
ADC_CSR_bit.CH = 0x03;               //номер канала
ADC_CR1_bit.SPSEL = 0x07;            //делитель скорости
ADC_CR2_bit.ALIGN = 0;               //выровнять влево
ADC_CR1_bit.ADON = 1;               //включить ADC
Или твой вариант (битовые операции) меньше кода занимает?

нет, я пользуюсь SDCC, там нет библиотек, а свою пока не написал.

Цитата Сообщение от ShodS
У меня вроде тоже не читается младший регистр, и все работает.
Код:
if (ADC_DRH < ADC_MARK_VOT) PWR_ODR_bit = 1; //шунтируется балласт и питание увеличивается
else PWR_ODR_bit = 0; //добавляется балласт и питание уменьшается
ADC_CR1_bit.ADON = 1; //старт ADC

А какая может быть проблема, если не читать младший разряд?
у меня тоже работает без чтения младшего регистра, насколько я понял из мануала очистка этих регистров происходит автоматически после их прочтения. как и где это используется я пока не знаю.
0
Iddy_Im
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,406
14.01.2017, 16:15 16
У меня тоже как раз под sdcc писано: https://sourceforge.net/projects/stm8samples/
Правда, сейчас больше в сторону STM32F0 смотрю. Интересней они. Хотя, конечно, можно и с STM8 что-нибудь интересное сделать. Заказал "про запас" на работе десяток STM8S003 — их можно хоть даже как "умные регистры/триггеры" использовать.
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
15.01.2017, 02:06 17
Цитата Сообщение от Iddy_Im
И почему у вас младший регистр АЦП не считывается?
Цитата Сообщение от SOVO
Потом замахаешься искать, почему код то работает, то нет. АЦП устроен так, что при считывании первого байта второй считывается в промежуточный буфер. Если не считать второй, нарушается логика работы АЦП.
Цитата Сообщение от somyk
у меня тоже работает без чтения младшего регистра, насколько я понял из мануала очистка этих регистров происходит автоматически после их прочтения. как и где это используется я пока не знаю.
Заинтересовало меня это...

Почитал DS, и вроде - правильное чтение двух регистров важно только в случае использования 10 бит значения... иначе, при чтении 8 бит - нет необходимости в чтении второго регистра...
так что в нашем случае - чтение только ADC_DRH - это нормально...

Еще у меня не выключались триггеры шмидта на задействованных ADC входах, я смотрю все их выключают, я сначала подумал что это как то влияет на результаты замеров ADC, но опять же из DS следует что это нужно только для уменьшения энергопотребления, и как я понял - никак не влияет на результаты замеров, так что тоже не критично...
0
15.01.2017, 02:06
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.01.2017, 02:06

Большое количество АЦП каналов
Здравствуйте! Подскажите микроконтроллеры с количеством АЦП 50 или больше каналов. И есть ли...

AVR АЦП использование нескольких каналов
Кто пробовал использовать несколько каналов АЦП одновременно (ну, почти одновременно) - как это...

Защита каналов АЦП от импульсных помех
На входы ацп МК подаются сигналы обратной связи с двигателя и необходимо защитить АЦП от импульсных...


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

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

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