Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
20.03.2012, 16:34
|
#1
|
Временная регистрация
Регистрация: 24.11.2011
Адрес: Magdeburg
Сообщений: 81
Сказал спасибо: 10
Сказали Спасибо 16 раз(а) в 16 сообщении(ях)
|
Программирование АЦП. проблема с задержкой
Данная схема предназначается для задания ШИМ для управления двигателем и ПИ-регулирования. В качестве обратной связи используется аналоговый датчик тока, подключенный к одному из каналов АЦП.
Необходимо избежать скачков переключения, которые видны на графике (розовый цвет).
Atmega168 @ 20MHz, 20 kHz ШИМ
Задумка такова, чтобы измерять значение раз в 10-20 импульсов модуляции. При ШИМ ‹ ~50% мерить ток в середине отключенного времени в точке 1 (т.е. на спаде графика) и при ШИМ › 50% измерение производить в середине импульса (точка 2).
Проблема состоит в установке задержки измерения. Пробовал использовать тактовую частоту для этого (обработчик прерывания стоит в конце), но запутался с этим немного = не работает.
Может есть способ получше? Потому как целый день вожусь, ничего толком не добился...
Код:
|
#define ATMEGA168 1
#include "system.h"
#include "util/delay.h"
#define TERMINAL_PORT 0
char adc = 0;
char a,b;
char state = 0;
char i = 0;
char pwm = 0;
int main(void)
{
SREG |= (1‹‹7);
TIMSK0 |= (1‹‹OCIE0A);
TCCR0A = (2‹‹COM0A0) | (1‹‹WGM01);
TCCR0B = (1‹‹CS02) | (1‹‹CS01) | (1‹‹CS00);
OCR0A = 200;
USART_Init(19200, INT, 0);
Terminal_Init(0);
// ADC Aktivieren auf Kanal 0
ADC_Init(REFEXTERN, 128, 1);
ADC_Channel(SINGLE, 0, 0);
// PWM Initialisierung
PWM_Init_Timer1('A',8,FAST_PWM,124);
DDRB |= (1‹‹DDB3);
do
{
a=37+25;//+25*pwm*0.008;
b=37;//+25*pwm*0.008;
if (pwm › 62) state = 1;
else state = 0;
ADC_Start(SINGLE);
ADC_Finished();
if (PWM_Get_Mode())
{
pwm = ADC_Get_Value()/8;
}
else pwm = PWM_Get_Value();
a=62+25*pwm*0.008;
b=37+25*pwm*0.008;
if (pwm › 62) state = 1;
else state = 0;
// Begrenzung auf 94,4% PWM
if ( pwm ‹ 117) PWM_Set_Timer1('A',pwm);
else PWM_Set_Timer1('A',117);
}
while(1);
return 0;
}
ISR(TIMER0_COMPA_vect)
{
Set('B',3);
Clear('B',3);
switch(state)
{
case 0:
{
Set('B',3);
Clear('B',3);
_delay_us(a);
// while(i‹=1000) i++;
// Измерение тока в т.1
Set('B',3);
Clear('B',3);
break;
}
case 1:
{
Set('B',3);
Clear('B',3);
_delay_us(b);
// Измерение тока в т.2
Set('B',3);
Clear('B',3);
break;
};
};
} |
Последний раз редактировалось r0st; 21.03.2012 в 15:12.
|
|
|
|
21.03.2012, 15:07
|
#2
|
Временная регистрация
Регистрация: 24.11.2011
Адрес: Magdeburg
Сообщений: 81
Сказал спасибо: 10
Сказали Спасибо 16 раз(а) в 16 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Пробовал использовать _delay_us(), но эта функция работает как-то неровно, прыгает все время, тем более что чтение аргумента, даже записанного предварительно в переменную отнимает около 280 микросекунд, при том, что один цикл ШИМ длится 50. Приведу осциллограмму. Желтый - ШИМ (спасибо, кэп!), синий - сигнал с PB3, устанавливающийся/сбрасывающийся функциями Set(), Clear(), каждая по 2 микросекунды. на графике показан результат когда аргументом является просто число.
Последний раз редактировалось r0st; 21.03.2012 в 15:28.
|
|
|
|
21.03.2012, 15:17
|
#3
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,835
Сказал спасибо: 919
Сказали Спасибо 4,308 раз(а) в 2,573 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Запустите преобразование по прерыванию таймера. По прерыванию готовности АЦП снимайте результат. На какую частоту таймер настроете, такую и получите.
|
|
|
|
21.03.2012, 15:26
|
#4
|
Временная регистрация
Регистрация: 24.11.2011
Адрес: Magdeburg
Сообщений: 81
Сказал спасибо: 10
Сказали Спасибо 16 раз(а) в 16 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Сообщение от Easyrider83
|
Запустите преобразование по прерыванию таймера. По прерыванию готовности АЦП снимайте результат. На какую частоту таймер настроете, такую и получите.
|
т.е. задействовать третий таймер что ли? все равно мне нужно будет задавать его сдвиг каким то образом.
|
|
|
|
21.03.2012, 23:18
|
#5
|
Гражданин KAZUS.RU
Регистрация: 16.03.2011
Сообщений: 486
Сказал спасибо: 8
Сказали Спасибо 131 раз(а) в 116 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Сообщение от r0st
|
т.е. задействовать третий таймер что ли? все равно мне нужно будет задавать его сдвиг каким то образом.
|
Третьего таймера в м168 нет, есть 2-ой. Но он не годится: смысл совета - сделать источником запуска преобразования событие от таймера.
Для этого нужно настроить ADCSRB.ADTS: переполнение/совпадение от таймеров 0 или 1. Можете использовать тот же таймер что и для шима и читать результаты преобразования в прерывании по завершению АЦП.
PS. Странный код:
Сообщение от r0st
|
Set('B',3);
Clear('B',3);
_delay_us(a);
Set('B',3);
Clear('B',3);
break;
|
Делать задержку в прерывании на несколько десятков мкс, это плохая практика. Лучше читать результат преобразования на входе в прерывание и делать запуск следующего (это если не хотите пользоваться прерыванием от АЦП).
|
|
|
|
22.03.2012, 01:02
|
#6
|
Временная регистрация
Регистрация: 24.11.2011
Адрес: Magdeburg
Сообщений: 81
Сказал спасибо: 10
Сказали Спасибо 16 раз(а) в 16 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Сообщение от _Артём_
|
Третьего таймера в м168 нет, есть 2-ой.
|
Да, имелся в виду третий по счету, а не по номеру таймер.
Сделал программный счетчик импульсов и запускаю на каждом 20м такте ШИМ таймер0.
Вот тут возникла проблема - прерывание, связанное с этим таймером плывет по осциллограмме, хоть должно отстоять на заданном расстоянии от прерывания таймера1. Похоже я что-то неправильно делаю при запуске Т0...
Код:
|
#define ATMEGA168 1
#include "system.h"
#include "util/delay.h"
#define TERMINAL_PORT 0
char adc = 0;
double a,b;
char state = 0;
char i = 0;
char pwm = 0;
char count = 20;
int main(void)
{
SREG |= (1‹‹7);
TIMSK0 |= (1‹‹OCIE0A);
TCCR0A |= (1‹‹WGM01);
TCCR0B |= 0;
OCR0A = 0;
USART_Init(19200, INT, 0);
Terminal_Init(0);
// ADC Aktivieren auf Kanal 0
ADC_Init(REFEXTERN, 128, 1);
ADC_Channel(SINGLE, 0, 0);
// PWM Initialisierung
PWM_Init_Timer1('A',8,FAST_PWM,124);
TIMSK1 |= (1‹‹TOIE1);
DDRB |= (1‹‹DDB3);
do
{
ADC_Start(SINGLE);
ADC_Finished();
if (PWM_Get_Mode())
{
pwm = ADC_Get_Value()/8;
}
else pwm = PWM_Get_Value();
// Begrenzung auf 94,4% PWM
if ( pwm ‹ 117) PWM_Set_Timer1('A',pwm);
else PWM_Set_Timer1('A',117);
a=120+pwm/2;
b=pwm/2+182;
if (pwm › 62) OCR0A = a;
else OCR0A = b;
}
while(1);
return 0;
}
ISR(TIMER1_OVF_vect)
{
if (count == 0)
{
TCCR0B = (1‹‹CS01);
count=20;
};
count-=1;
Set('B',3);
Clear('B',3);
}
ISR(TIMER0_COMPA_vect)
{
TCCR0B = 0;
TCNT0=0;
Set('D',3);
Clear('D',3);
} |
|
|
|
|
22.03.2012, 18:23
|
#7
|
Временная регистрация
Регистрация: 24.11.2011
Адрес: Magdeburg
Сообщений: 81
Сказал спасибо: 10
Сказали Спасибо 16 раз(а) в 16 сообщении(ях)
|
Re: Программирование АЦП. проблема с задержкой
Все заработало по неведомым причинам - прошил сегодня снова и все функционирует как надо!) Так что буду разбираться с датчиком и плавно переходить к ПИ-регулированию.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 07:08.
|
|