AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
17.10.2013, 17:20
|
#1
|
Частый гость
Регистрация: 30.08.2010
Сообщений: 46
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
мега8 программный 8и канальный ШИМ?
Добрый день.
Подскажите, можно ли добиться на меге8(8мГц) от программного 8-канального 8-битного ШИМ частоты хотя бы в 200 Гц?
Вот моя функция по работе с ШИМ:
Код:
|
void pwm_int(void)
{
char n;
if(++pwm_counter==0)
{
for (n=0;n‹8;n++){
if(unit[n].value || (!unit[n].enabled && unit[n].up)) v_reg|=nn[n];//(1‹‹n);
}
}
if(unit[n].off) //если можно выключить устройство
{
for (n=0;n‹8;n++){
if(pwm_counter == unit[n].value)v_reg&=~nn[n];//(1‹‹n);
}
}
f_reg=1;// передем изменения в регистр сдвига
} |
Код этот отрабатывает настолько долго, что я смог добиться только частоты в 60 Гц
Здесь 8 каналов, каждый канал может быть как простым переключателем on/off так и ШИМ с плавным нарастанием/затуханием, поэтому добавлены всякие проверки.
unit[n].value - значение ШИМ
unit[n].enabled - разрешен ли вообще ШИМ для данного устройства
unit[n].up - соятоние ШИМ (увеличивается или уменьшается значение ШИМ)
unit[n].off - флаг, можно ли отключить данное устройство
unsigned char nn[9]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0}, этот массив использую что бы каждый раз для каждого канала не выполнять (1‹‹n), массив немного прибавляет скорости.
Может быть вообще как то по другому можно реализовать ШИМ?
Читал про ВАМ, но что то не понял как это реализовать.
|
|
|
|
17.10.2013, 17:44
|
#2
|
Почётный гражданин KAZUS.RU
Регистрация: 13.10.2007
Адрес: Беларусь
Сообщений: 8,048
Сказал спасибо: 60
Сказали Спасибо 3,954 раз(а) в 2,309 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
Пиши в 8 регистров под ШИМ значения скважности 0...255, в прерывании инкрементируй 1 регистр и последовательно сравнивай все 8 ШИМ-регистра с этим. Если меньше - гаси соотв. канал, иначе - зажигай. Будет десяток килогерц на 24 каналах
|
|
|
|
17.10.2013, 19:42
|
#3
|
Почётный гражданин KAZUS.RU
Регистрация: 10.01.2007
Сообщений: 3,412
Сказал спасибо: 65
Сказали Спасибо 664 раз(а) в 443 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
И цикл лучше развернуть, плюс - работать с битами порта напрямую, а не через промежуточную переменную.
Код:
|
if (PwmPhase ›= PwmVal[0])
PwmPort.bit0 = HIGH;
else
PwmPort.bit0 = LOW;
...
if (PwmPhase ›= PwmVal[7])
PwmPort.bit7 = HIGH;
else
PwmPort.bit7 = LOW;
++PwmPhase; |
__________________
There's always more than one way to skin a cat.
|
|
|
|
17.10.2013, 20:24
|
#4
|
Почётный гражданин KAZUS.RU
Регистрация: 24.09.2007
Адрес: Полтава, UA
Сообщений: 2,450
Сказал спасибо: 376
Сказали Спасибо 1,060 раз(а) в 624 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
Sany81, переменную pwm_counter сделайте для начала локальной.
Чтобы достать глобальную переменную, тратится в 2 раза больше времени.
В листинг ASM загляните.
__________________
Мелочи не решают главного. Они решают всё!
|
|
|
|
18.10.2013, 09:41
|
#5
|
Частый гость
Регистрация: 30.08.2010
Сообщений: 46
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
Сообщение от gary2007
|
Sany81, переменную pwm_counter сделайте для начала локальной.
Чтобы достать глобальную переменную, тратится в 2 раза больше времени.
В листинг ASM загляните.
|
Но pwm_counter не может быть локальной, иначе каждый раз при входе в мою функцию, эта переменная будет всегда обнулена и тогда смысл в этой переменной отпадает так же как и смысл самой функции.
С АСМом к сожалению не дружу.
Сообщение от tempora
|
И цикл лучше развернуть, плюс - работать с битами порта напрямую, а не через промежуточную переменную.
Код:
|
if (PwmPhase ›= PwmVal[0])
PwmPort.bit0 = HIGH;
else
PwmPort.bit0 = LOW;
...
if (PwmPhase ›= PwmVal[7])
PwmPort.bit7 = HIGH;
else
PwmPort.bit7 = LOW;
++PwmPhase; |
|
Цикл попробую разверну, а вот на прямую с портом работать не получится, т.к. у меня на порту сидит регистр сдвига(3 ноги) а он уже в свою очередь управляет устройствами(8шт), поэтому приходится писать изменения ШИМ в переменную, а потом уже по состоянию флага передаю эту переменную в регистр сдвига.
Цитата:
|
Пиши в 8 регистров под ШИМ значения скважности 0...255, в прерывании инкрементируй 1 регистр и последовательно сравнивай все 8 ШИМ-регистра с этим. Если меньше - гаси соотв. канал, иначе - зажигай. Будет десяток килогерц на 24 каналах
|
Не совсем понял, можно по подробнее разжевать, или лучше кусочек кода в качестве примера привести.
И попутно еще вопрос:
У меня раз в секунду по прерыванию от часов(ds1307) считывается время и температура(ds18b20),а так же выводится информация на дисплей 2*16.
Эта процедура длится тоже очень продолжительное время, в итоге 1 раз в секунду мой ШИМ "зависает" на некоторое время в положении лог "0" либо лог "1".
Можно ли как то этого избежать?
Засунуть работы ШИМ в прерывание не могу, иначе боюсь нарушится работа с датчиками часов и температуры.
Большую часть времени пожирает функция sprintf(да и памяти жрет очень много). Можно ли от нее как то отвязаться(нужно всего лишь сложить в одну строку несколько строковых переменных и числовых значений)? Пробовал воспользоваться функцией с переменным числом параметров, но что то не срослось, видать из за незнания и не понимания работы с указателями. Вот эта функция:
Код:
|
char *f(char *s1, ...)
{ char **cp = &s1; //--адрес первого указателя
int len = 0;
// цикл для определения общей длины сцепляемых строк
while (*cp) { len += strlen(*cp); cp++; }
char *s = new char[len+1]; //--память для строки
s[0]=0; //-- "очищаем" строку
// цикл для сцепления строк
cp=&s1; //-- опять установка на 1-й параметр
while (*cp)
{ strcat(s, *cp); //-- прицепляем первую (и следующие)
cp++; //-- перемещаемся на следующую
}
return s;
} |
взята отсюда http://www.rsdn.ru/forum/cpp/418970.1
Как моей переменной unsigned char[17], присвоить результат этой функции?
Последний раз редактировалось Sany81; 18.10.2013 в 09:46.
|
|
|
|
18.10.2013, 10:32
|
#6
|
Почётный гражданин KAZUS.RU
Регистрация: 24.09.2007
Адрес: Полтава, UA
Сообщений: 2,450
Сказал спасибо: 376
Сказали Спасибо 1,060 раз(а) в 624 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
Сообщение от Sany81
|
Но pwm_counter не может быть локальной
|
Полохо, что вы не дружите с АСМ.
Времени на прерывание у вас на все про все всего 256 тактов, после этого пойдет уже следующее прерывание и вам надо бороться за каждый такт.
Как вариант: - после инкремента, переприсвоить ее значение локальной переменной. Для глобальной, компилятор грузит ей регистр каждый раз перед каждым вызовом, потому что он не знает изменилась она или нет, а для локальной это загрузка делается один раз, при входе в процедуру.
__________________
Мелочи не решают главного. Они решают всё!
|
|
|
|
18.10.2013, 10:55
|
#7
|
Частый гость
Регистрация: 30.08.2010
Сообщений: 46
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
ОК.
Сейчас попробую.
|
|
|
|
18.10.2013, 10:58
|
#8
|
Частый гость
Регистрация: 30.08.2010
Сообщений: 46
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
вот как изменилась функция:
Код:
|
void pwm_int(void)
{
unsigned char counter;
f_pwm=0;
counter=++pwm_counter;
if(counter==0)//включаем
{
if(unit[0].value) v_reg|=0x01;
if(unit[1].value) v_reg|=0x02;
if(unit[2].value) v_reg|=0x04;
if(unit[3].value) v_reg|=0x08;
if(unit[4].value) v_reg|=0x10;
if(unit[5].value) v_reg|=0x20;
if(unit[6].value) v_reg|=0x40;
if(unit[7].value) v_reg|=0x80;
}
//выключаем
if(counter › unit[0].value)v_reg&=0xFE;
if(counter › unit[1].value)v_reg&=0xFD;
if(counter › unit[2].value)v_reg&=0xFB;
if(counter › unit[3].value)v_reg&=0xF7;
if(counter › unit[4].value)v_reg&=0xEF;
if(counter › unit[5].value)v_reg&=0xDF;
if(counter › unit[6].value)v_reg&=0xBF;
if(counter › unit[7].value)v_reg&=0x7F;
f_reg=1;// передадим изменения в регистр сдвига
} |
скорость выполнения 255 проходов составляет0,0185сек, что соответствует примерно 54Гц ШИМ, мне надо как минимум вдвое поднять скорость выполнения функции, реально ли?
Кстати, может ли ПРОТЕУС показывать не верно время выполнения?
|
|
|
|
18.10.2013, 12:00
|
#9
|
Частый гость
Регистрация: 30.08.2010
Сообщений: 46
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
раньше при возникновении прерывания по таймеру устанавливал флаг f_pwm, в главной функции было так:
Код:
|
while (1)
{
if (btn_0) KeyMenu();
if (btn_1) KeyUp();
if (btn_2) KeyLeft();
if (btn_3) KeyRight();
if (btn_4) KeyDown();
if (f_pwm) pwm_int();
if (f_reg) SendReg();
if (f_ds1307) ds1307int();
} |
Сейчас заремарил строку if (f_pwm) pwm_int();
Содержимое функции pwm_int() перенес в вызов по прерыванию от таймера. И получил наконец то нужный мне результат, частота ШИМ стала примерно 150 Гц, этого вполне хватит под мои нужды.
Только не могу понять почему так произошло
Остался только один вопрос, заданный выше, на счет функции sprintf, сейчас только она мне вставляя палки в колеса.
|
|
|
|
18.10.2013, 12:19
|
#10
|
Гуру портала
Регистрация: 06.05.2005
Адрес: Краснодар, возле укротворного моря.
Сообщений: 19,087
Сказал спасибо: 2,565
Сказали Спасибо 11,899 раз(а) в 5,972 сообщении(ях)
|
Re: мега8 программный 8и канальный ШИМ?
Сообщение от Sany81
|
Остался только один вопрос, заданный выше, на счет функции sprintf, сейчас только она мне вставляя палки в колеса.
|
Что за числовые значения?
Просто строки выкидывать в УАРТ - не проблема. Адрес строки есть и строка кончается 0х00. А вот с числами - тут надо конкретней.
__________________
Не бейте больно, ежели чо, ну не удержался... А вааще,
"Мы за все хорошее, против всей х..., По лугам некошеным чтобы шли ступни,
Чтобы миром правила правда, а не ложь, Мы за все хорошее, нас не на...!
..." (Ленинград)
Я не несу ответственности за свои действия в Вашей голове.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 01:07.
|
|