Помогите с быстродействием прошивки ATtiny13

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 5
Зарегистрирован: Пт сен 20, 2013 21:07:14

Сообщение Rialto »

Помогите разобраться почему медленно работает программа CV Avr на ATTiny13. 8 ног, без кварца. Скорость работы отслеживается по 5ому порту осциллографом (зажигание радарного светодиода). В моделировании протеусом длительность зажигания, гашения 350мкс, 525мкс соответственно. В реальности же мигания заметны глазом и имеют длительность примерно 30 и 50 мс. Возможно делитель частоты можно взять и поменьше для АЦП для 8 бит? Но дело явно не только в нём, если разница в 100 раз. Единственный выставленный фьюз - на снятие блокировки программирования 5го порта, который ресет (ног не хватало).
#include <tiny13.h>
#include <delay.h>
//определили биты для данной переменной 0b100000
#define ADC_VREF_TYPE 0x20
unsigned char Y;
int L0,R0,L1,R1;
//функция,переменная - номер канала, аргумент десятичный или бинарный
unsigned char read_adc(unsigned char adc_input)
{
// сравниваем и дописываем adc_input в незанятые биты
ADMUX=(adc_input | (ADC_VREF_TYPE & 0xff));
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// добавляет в регистры 0b1000000 - ADSC запускает преобразование
ADCSRA|=0x40;
// пока не станет из ADCSRA ADIF=1 продолжается, просто задержка, до срабатывания флага выполнения преобразования
while ((ADCSRA & 0x10)==0);
//кажется пишем в бит завершения преобразования,ADIF=1, 0x10=0b10000, раньше проверяли, должен ставиться автоматом?Хз зачем
ADCSRA|=0x10;
//возвращает старшие (при выравнивании влево) 8 битов числа с ацп
return ADCH;
}
void main(void)
{
//Data Direction Register сконфигурировали PB0,PB1,PB4,PB5 как выходы, остальные как входы контакты порта B
DDRB = 0b110011;
//выставляет начально выравнивание влево, питание внешнее Vcc
ADMUX=((ADC_VREF_TYPE) & (0xff));
//выствляет 0b10000101, включение ацп и делитель частоты, одиночное преобразование,без запроса на прерывание
ADCSRA=0x87;
//параметр чувствительности
Y=15;
while(1){ //этот цикл будет выполняться бесконечно
PORTB.5=1;
delay_us(50);
R1=read_adc(1);
L1=read_adc(3);
PORTB.5=0;
delay_us(50);
R0=read_adc(1);
L0=read_adc(3);
//условие поездки прямо, отражение за вычетом фона
if ((((L1-L0)-(R1-R0))<=(((R1-R0)+(L1-L0))/(Y*2)))&&(((R1-R0)-(L1-L0))<=(((R1-R0)+(L1-L0))/(Y*2)))){
PORTB.0=0;
PORTB.1=0;
PORTB.4=1;
delay_ms(1);
};
//условие поездки вправо, отражение за вычетом фона
if ((((L1-L0)-(R1-R0))>0)&&(((L1-L0)-(R1-R0))>(((R1-R0)+(L1-L0))/(Y*2)))) {
PORTB.0=0;
PORTB.1=1;
PORTB.4=0;
delay_ms(1);
};
//условие поездки влево, отражение за вычетом фона
if ((((R1-R0)-(L1-L0))>0)&&(((R1-R0)-(L1-L0))>(((R1-R0)+(L1-L0))/(Y*2)))) {
PORTB.0=1;
PORTB.1=0;
PORTB.4=0;
delay_ms(1);
};
}
}
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4751
Зарегистрирован: Вс янв 24, 2010 13:14:02
Откуда: Омск

Сообщение vem566 »

Наступил на те же грабли. По умолчанию, у новой тиньки13, в фузах у тиньки стоит деление тактовой частоты на 8 (бит CKDIV8). Убрал, и проблема иссякла.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Но разница-то не в 8 раз, а в 85, если конечно автор не ошибся в подсчетах :dont_know:
Кстати, там 4 раза встречается деление на Y*2, советую во-первых сократить его (считать переменные по одному разу, а уже их потом сравнивать, сомневаюсь что компилятор до этого додумается), во-вторых не умножать на 2, а сдвигать влево на 1 бит, а лучше вместо 15 взять 16 и делить сразу на 32 (сдвиг вправо на 5 разрядов). У тинек нет ни операций умножения, ни деления, такая оптимизация увеличит быстродействие на порядок.
Родился
Сообщения: 5
Зарегистрирован: Пт сен 20, 2013 21:07:14

Сообщение Rialto »

Спасибо за советы. Насчёт вычислений. Все вычисления выполняются во второй части программы.Пока горит диод должно выполняться только 2 преобразования АЦП. Я пока новичок в побитовых операциях.Собственно, как и в СИ и микроконтроллерах. Но ваши рекомендации учту и постараюсь применить. Спасибо :)
Кстати ещё кое-что. По совету решил полазать в фьюзах. Там в настройках фьюзов CKSEL0..1 было по умолчанию 11. Что если верить протеусу и даташиту даёт тактовую частоту около 128кГц. Притом что 10 если верить ему же должно давать 9,6 МГц внутренних. Просто я в фьюзы старался без лишней необходимости не лезть, ибо на всех курсах для начинающих говорится, что это может лишить возможности перепрошивки устройство. Впрочем я итак её запорол использовав последнюю ногу. Но искусство требует жертв :3
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Rialto писал(а):Кстати ещё кое-что. По совету решил полазать в фьюзах. Там в настройках фьюзов CKSEL0..1 было по умолчанию 11. Что если верить протеусу и даташиту даёт тактовую частоту около 128кГц. Притом что 10 если верить ему же должно давать 9,6 МГц внутренних.
По умолчанию в AVRках идет тактирование от внутреннего RC на 8 или 9.6 МГц с делением частоты на 8 (если такая настройка есть).
Раз там стоит 128к, значит его уже прошивали. Сбросить делитель можно программно, не трогая фьюзы, через регистр CLKPR.
Rialto писал(а):Просто я в фьюзы старался без лишней необходимости не лезть, ибо на всех курсах для начинающих говорится, что это может лишить возможности перепрошивки устройство.
Рано или поздно придется :)))
Rialto писал(а):Впрочем я итак её запорол использовав последнюю ногу. Но искусство требует жертв :3
Reset тоже можно вернуть на место, не без проблем конечно...
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

Код: Выделить всё

delay_ms(1);
Надо учесть, что такие команды зависят от настроек компилятора - тактирование мк.
Изображение
Docendo discimus
Контактная информация:
Реклама
Родился
Сообщения: 5
Зарегистрирован: Пт сен 20, 2013 21:07:14

Сообщение Rialto »

Т.е. настройки компилятора влияют именно на дэлэи, поскольку они вычисляются исходя из них? Но не влияют на работу ацп и скорость вычислений?
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

delay - библиотечная функция. И рассчетом ее занимается компилятор. А АЦП вы настраиваете сами регистрами.
Docendo discimus
Контактная информация:
Родился
Сообщения: 5
Зарегистрирован: Пт сен 20, 2013 21:07:14

Сообщение Rialto »

CKDIV8 при включении программирования фьюзов прошивки автоматически стоит в 1 (не запрограммирован), так что всё дело видимо было в тактовой частоте (11 опять же из-за включения программирования фьзов даёт 128кГц, переключил на 10 по идее 9,6 МГц тактовых) и задержках (стояли от 1МГц, т.к. видимо считаются такты, то скорее всего на 9,6 МГц они даже медленнее). Делитель как был так и остался 32 судя по таблице. Что должно на 9,6 МГц давать частоту ацп 300кГц. Как я понимаю в режиме одиночного запуска ацп всё идёт как для первого и преобразорвание выполняется за 25 тактов. Что должно давать время преобразования ацп примерно 75 мкс плюс 10мкс стабилизирующей задержки =85мкс. Проверил на протеусе, т.к. осциллограф не дома и немного надоело портить тиньки, (первая часть программы - 50 мкс ожидания и 2 ацп преобрназования) выполняются за 0,4 мс. А значит на каждое преобразование должно приходиться 175мс. Получается медленнее примерно в 2 раза. В чём может быть дело?
П.с. Почему то хром на ХР рабочего ноута не даёт поставить одобрение сообщениям с советом, вращается загрузка и ничего не происходит.
П.п.с. Гоняюсь за скоростью, поскольку будущий проект - создание ударного силомера, а там желательно взять быстродействие с запасом, >1000 сэмплов в секунду. И ещё 1 вопрос, не знает ли кто как сбросить запрограммированные тиньки, с фьзом запрета ресета? Как я понимаю просто подачи высокого напряжения на ресет будет не достаточно?
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Rialto писал(а):как сбросить запрограммированные тиньки, с фьзом запрета ресета? Как я понимаю просто подачи высокого напряжения на ресет будет не достаточно?
Нужен высоковольтный программатор или Доктор.
Родился
Сообщения: 5
Зарегистрирован: Пт сен 20, 2013 21:07:14

Сообщение Rialto »

Снова здравствуйте. Доработал прошивку, протестировал на протеусе - всё работает (разве что задержки зажигания диода поставил побольше,поскольку не знаю где там высокоскоростные реле для имитации отражения). Прошил.Поставил...всё время прямо, если менять внешние условия (поставить что-нибудь отражающее перед одной фарой и фототранзистором) может чуть начинать уходить в право. Не понимаю в чём дело. Ниже привожу код и настройки компилятора.
Изображение
Изображение

#include <tiny13.h>
#include <delay.h>
int L0,R0,L1,R1,k,n,m,buf,buf1,buf2; //16 бит плюс знак
//функция,переменная - номер канала, аргумент десятичный или бинарный
unsigned int read_adc(unsigned char adc_input)
{
buf=0;
// сравниваем и дописываем adc_input в незанятые биты
ADMUX=(adc_input | 0x20);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// добавляет в регистры 0b1000000 - ADSC запускает преобразование
ADCSRA|=0x40;
// пока не станет из ADCSRA ADIF=1 продолжается, просто задержка, до срабатывания флага выполнения преобразования
while ((ADCSRA & 0x10)==0);
//запись старших 8и разрядов
buf1=ADCL;
buf2=ADCH;
buf=(buf2*4)+(buf1/64);
return buf; //работает чуть медленнее,но не критично
}
void main(void)
{
//Data Direction Register сконфигурировали PB0,PB1,PB4,PB5 как выходы, остальные как входы контакты порта B
DDRB = 0b110011;
//0b100000, выставляет начально выравнивание влево, питание внешнее Vcc
ADMUX=0x20;
//выствляет 0b01010101, включение ацп и делитель частоты, одиночное преобразование,без запроса на прерывание
ADCSRA=0x85;
while(1){ //этот цикл будет выполняться бесконечно
PORTB.5=1;
delay_us(50);
R1=read_adc(1);
L1=read_adc(3);
PORTB.5=0;
delay_us(50);
R0=read_adc(1);
L0=read_adc(3);
k=((R1-R0)+(L1-L0))/32;
n=(L1-L0)-(R1-R0);
m=(R1-R0)-(L1-L0);
//условие поездки прямо, отражение за вычетом фона
if ((n<=k)&&(m<=k)){
PORTB.0=0;
PORTB.1=0;
delay_ms(2);
PORTB.4=1;
delay_ms(2);
};
//условие поездки вправо, отражение за вычетом фона
if ((n>0)&&(n>k)) {
PORTB.0=0;
PORTB.4=0;
delay_ms(2);
PORTB.1=1;
delay_ms(2);
};
//условие поездки влево, отражение за вычетом фона
if ((m>0)&&(m>k)) {
PORTB.1=0;
PORTB.4=0;
delay_ms(2);
PORTB.0=1;
delay_ms(2);
};
}
}
Ответить

Вернуться в «AVR»