Jump to content
Jalui

Отладка ATTiny13A

Recommended Posts

Posted (edited)

Всем доброго дня.

Пишется программа для ATTiny13A. Есть проблема при отладке в AVR Studio 7 и симуляции в Proteus 8.9.

В в AVR Studio 7:

1) после команды

"ADMUX |= 0b01100010;"

отладчик показывает, что ADMUX == 0b01100000, пришлось после добавить

"ADMUX |= (1 << 1);"

почему не с первого раза?

2) команда

"ADCSRA |= 0b01000000;"

не стартует АЦП, при замене на

"ADCSRA |= 0b11000000;" или "ADCSRA |= (1 << ADSC);"

тоже самое.

Что я делаю не так?

3) Функцию задержки пришлось закомментировать, иначе наглухо виснет при входе в неё.

Можно ли как-то иначе решить такую проблему?

В Proteus 8.9:

После нажатия кнопки на выходе снимается 2,5 В - это вообще как? При переключении нагрузки это происходит на обоих выходах, чего по программе быть никак не должно...

02.jpg.d7da26a6a391f19225d7c345c810e283.jpg

Код программы:

#define F_CPU 9600000UL

#include <avr/io.h>
#include <util/delay.h>

#define D1_ON() PORTB |= (0x01 << PB1)			// Direction 1
#define D1_OFF() PORTB &= ~(0x01 << PB1)		//

#define D2_ON() PORTB |= (0x01 << PB2)			// Direction 2
#define D2_OFF() PORTB &= ~(0x01 << PB2)		//

int max_current=5000;							// max current (mA)
int action_delay=3000;							// max time for openning/closing (ms)

void delay200(void)								// delay function
{
	_delay_ms(200);								// delay of checking (ms)
	ADCSRA |= 0b01000000;						//ADSC=1;                   // start conversion
	ADCSRA |= (1 << ADSC);
	while ((0b00010000 & ADCSRA) == 0)			//(ADIF==0)					// check for end of conversion
	{
	}
	ADCSRA |= 0b00010000;						//ADIF=1;				    // reset flag of end of conversion
}

void action(void)								// waiting for ending of action
{
	int i;
	for (i = 0; ((ADCH*1000) < max_current) & (i < action_delay); i += 200)	// check for actual current and time
	{
		delay200();
	}
}

int main(void)
{
	DDRB=0b00000001;
	ADMUX |= 0b01100010;						// bit5 = "left adjusting"
	ADMUX |= (1 << 1); 
	ADCSRA=0b10000011;							// bit6 = "start"  (ADSC)   bit0..2 = "divider"
	while (1)
	{
		while ((0x01 & PINB) == 0x00)			// check for a positive input signal
		{
		}
		_delay_ms(300);							// signal length (ms)
		if ((0x01 & PINB) == 0x01)				// check for a true input signal
		{
			D1_ON();							//PINB.1=1;                    // start opening
			delay200();
			if ((ADCH*1000) < max_current)		// check for direction
			{
				action();						// continue opening
				D1_OFF();						//PINB.1=0;					   // end opening
			}
			else
			{
				D1_OFF();						//PINB.1=0;                   // end opening
				D2_ON();						//PINB.2=1;                   // start closing
				action();						// continue closing
				D2_OFF();						//PINB.2=0;                   // end closing
			}
			while ((0x01 & PINB) == 0x01)		// check for a negative input signal
			{
			}
			_delay_ms(300);						// signal length (ms)
			while ((0x01 & PINB) == 0x01)		// check for a true input signal
			{
			}
		}
	}
}

 

Edited by Jalui
опечатка

Share this post


Link to post
Share on other sites

Как управлять SiС-транзистором?

Преимущества карбид-кремниевых транзисторов (SiC MOSFET) – высокий КПД, повышенная, по сравнению с биполярными транзисторами с изолированным затвором (IGBT), частота переключения, экономия места на печатной плате. Для управления SiC MOSFET используются специализированные драйверы: как изолированные от транзистора, так и неизолированные. Выбор драйвера и расчет оптимального режима его работы играет ключевую роль в эффективной работе всего устройства на базе SiC MOSFET.

Подробнее

20 часов назад, aitras сказал:

Почему вход для кнопки не вход, а выход? И D1, D2 наверное должны быть выходами?

DDRB |= (1 << PB1) | (1 << PB2);

Рукалицо... Спасибо :)

20 часов назад, aitras сказал:

И почему бы не задействовать прерывание по окончании преобразования АЦП?

Потому что не умеем)
Просто смотреть флаг ADIF такое себе?


И чисто в справочных целях, если не затруднит. Не нашлось путного.
Правильно ли я чищу ADIF просто записывая в него единицу? Даташит говорит "Alternatively, ADIF is cleared by writing a logical one to the flag" при программном отслеживании этого флага... То есть это нормально, что он выставился единицей при завершении конвертации и я в него пишу единицу же?

Share this post


Link to post
Share on other sites

Новый ХИТ CR123A/SN стабильно в десятку

Новая батарейка имеет наименование для заказа CR123A/SN. Батарейка используется для приложений с повышенными импульсами тока. Широко применяется в охранно-пожарных датчиках, устройствах телеметрии, поисковых маячках, LED-фонарях и других промышленных и бытовых устройствах

Подробнее

1 час назад, Jalui сказал:

Правильно ли я чищу ADIF просто записывая в него единицу?

Да, правильно. Рассматривайте это как подачу сигнала на вход сброса.


Я не раздаю удочки. Я продаю рыбу.

Share this post


Link to post
Share on other sites

Сетевой источник питания с расширенным диапазоном входных напряжений на основе VIPER26xK

Питание стационарных устройств чаще осуществляется напряжением 220 В, получаемым от одной фазы трехфазной промышленной сети. Однако существует ряд приложений, которым необходима энергия из всех трех фаз, в т.ч. и в аварийных режимах. Решение этой задачи обычно требует введение в модули питания дополнительных узлов, увеличивающих как их размеры, так и стоимость. Упростить схемы источников питания от трехфазной сети переменного тока либо от других высоковольтных источников, позволяет использование преобразователей с расширенным диапазоном входного напряжения

Подробнее

9 hours ago, Jalui said:

Потому что не умеем)

Надо разрешить прерывание от АЦП

ADCSRA |= (1 << ADIE);

Запустить преобразование установкой бита ADSC и описать обработчик прерывания где-нибудь перед main:

volatile unsigned int data;

ISR(ADC_vect)
{
	data = ADC;
	// do something
}

И да, нужно не забыть перед бесконечным циклом глобально разрешить прерывания макросом sei();


3D модели радиодеталей + макросы

С уважением, Михаил.

Share this post


Link to post
Share on other sites
Posted (edited)

Не стоит браться за прерывания, если не умеете пока.

Смотреть ADIF - так себе идея, поскольку его надо чистить вручную. Куда логичнее и удобнее следить за ADSC - он сам падает после завершения одиночного преобразования.

Избавьтесь от вот этого всего 0b00011100 - используйте именованные константы. Например, запуск АЦП делается так: ADCSRA |= _BV(ADSC); - просто и понятно. Если смущает _BV(), то пишите (1<<ADSC) - это то же самое будет. Ожидание завершения преобразования делается так: while(ADCSRA & _BV(ADSC));

Каждому пину уже назначено имя, например, PB0 - это номер бита в порту B микроконтроллера, используйте не вот это 0b00000001, а PB0 или PB1 вместе с макросом _BV(), как показано выше.

Думаю, после этого "рефакторинга" вы или увидите, где ошиблись, или ошибки просто пропадут сами по себе, поскольку в общем код производит впечатление логичного - значит, где-то в битовой константе битик ошибочно не на том месте поставили. Замените число на буквы - и битик станет на свое место сам, ошибки пропадут.

Edited by ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites

@aitras попробую пока более простое для понимания, но вашу информацию забрал в заметки, спасибо!)

@солар спасибо!)

 

21.05.2020 в 08:59, ARV сказал:

логичнее и удобнее следить за ADSC

И то верно)

 

21.05.2020 в 08:59, ARV сказал:

Каждому пину уже назначено имя, например, PB0 - это номер бита в порту B микроконтроллера

Похоже, что компилятор не в курсе, кто такие PB0...PB4 (например, "PB2 = Unknown identifier"). Библиотеки <avr/io.h> недостаточно или что не так?

Виснет при попытке входа в "while (1)" же.

 

И чисто в справочных целях:

MUX1 пишется только в таком порядке:

ADMUX |= (1 << REFS0) | (1 << ADLAR) | (1 << MUX1);
ADMUX |= (1 << MUX1);

Если в коде:

ADMUX |= (1 << REFS0) | (1 << ADLAR);
ADMUX |= (1 << MUX1);

то MUX1 == 0. Это нормально?

 

Актуальный код:

#define F_CPU 9600000UL

#include <avr/io.h>
#include <util/delay.h>

#define D1_ON() PORTB |= (1 << PB1)							// Direction 1
#define D1_OFF() PORTB &= ~(1 << PB1)						//

#define D2_ON() PORTB |= (1 << PB2)							// Direction 2
#define D2_OFF() PORTB &= ~(1 << PB2)						//

int max_current=5000;										// max current (mA)
int action_delay=3000;										// max time for openning/closing (ms)


void delay200(void)											// delay function
{
	_delay_ms(200);											// delay of checking (ms)
	ADCSRA |= (1 << ADSC);									// start conversion
	while (ADCSRA & (1 << ADSC));							// check for end of conversion
}

void action(void)											// waiting for ending of action
{
	int i;
	for (i = 0; ((ADCH*1000) < max_current) & (i < action_delay); i += 200)	// check for actual current and time
	{
		delay200();
	}
}

int main(void)
{
	DDRB |= (1 << PB1) | (1 << PB2);				
	ADMUX |= (1 << REFS0) | (1 << ADLAR) | (1 << MUX1);		// Internal Voltage Reference, Left Adjust, Selected Channel is PB4
	ADMUX |= (1 << MUX1);
	ADCSRA |= (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0);	// ADC Enabled, Division Factor is 8									
	while (1)
	{
		while ((1 & PB0) == 0);								// check for a positive input signal
		_delay_ms(300);										// signal length (ms)
		if ((1 & PB0) == 1)									// check for a true input signal
		{
			D1_ON();										// start opening
			delay200();
			if ((ADCH*1000) < max_current)					// check for direction
			{
				action();									// continue opening
				D1_OFF();									// end opening
			}
			else
			{
				D1_OFF();									// end opening
				D2_ON();									// start closing
				action();									// continue closing
				D2_OFF();									// end closing
			}
			while ((1 & PB0) == 1);							// check for a negative input signal
			_delay_ms(300);									// delay before new signal (ms)
		}
	}
}

 

Share this post


Link to post
Share on other sites
Posted (edited)
13 минут назад, Jalui сказал:

Библиотеки <avr/io.h> недостаточно или что не так?

Похоже, что что-то не так. Вы уверены, что проект именно для attiny13 создан? 

13 минут назад, Jalui сказал:

Это нормально?

Не нормально. Всегда делал одной командой запись в ADMUX без всяких |= и никогда проблем не было.

DDRB = (1 << PB1) | (1 << PB2);				
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX1);
ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0);

 

А вот это что такое у вас:

if ((1 & PB0) == 1)

Вот что вы ожидаете этим добиться? проверить, будет ли 1 равно 1?

Но ранее у вас вдруг 

while ((1 & PB0) == 0);

Здесь вы надеетесь, что 1 станет почему-то равно 0?!

Edited by ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites
22.05.2020 в 16:27, ARV сказал:

Вы уверены, что проект именно для attiny13 создан?

Создал новый проект - предлагает включить только <avr/io.h>

Даже пробовал включить руками <avr/iotn13a.h>  - ошибки.

22.05.2020 в 16:27, ARV сказал:

Всегда делал одной командой запись в ADMUX без всяких |= и никогда проблем не было

Сделал по примеру - без изменений. :(
Похоже надо менять среду разработки... Никакой логики.
 

22.05.2020 в 16:27, ARV сказал:

if ((1 & PB0) == 1)

Вот что вы ожидаете этим добиться? проверить, будет ли 1 равно 1?

Я так понимаю:

если на PB0 приходит 5 вольт, то для контроллера это 1.

Если это так, то результатом "(1 & PB0)" будет "1" - мы это проверяем оператором сравнения же.

Или это не так работает?

22.05.2020 в 16:27, ARV сказал:

while ((1 & PB0) == 0);

Здесь вы надеетесь, что 1 станет почему-то равно 0?!

Исходя из вышенаписанного, тут наоборот: пока на входе 0 В - простаиваем.

Share this post


Link to post
Share on other sites

А что такое  здесь PB0, по-вашему?

Share this post


Link to post
Share on other sites
3 часа назад, Jalui сказал:

Похоже надо менять среду разработки...

Точно. Если вместо музыки вы слышите ерунду, то надо менять консерваторию :)

Вам надо изучать язык Си, а не среду разработки менять.

3 часа назад, Jalui сказал:

Или это не так работает?

См. выше - почитайте учебник Си... PB0 это всего лишь "синоним" числа 1. То есть запись

if ((1 & PB0) == 1)

и запись

if ((1 & 1) == 1)

абсолютно идентичны. В итоге это все иденично такой записи

if(1)

То есть всегда истинное условие. Ну и далее while аналогично... всегда ложное.


Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites

Вкратце, не в порядке выполнения:

  •  вернулся к записям типа
(PINB & 0b00000001) == 0
  •  исправил переполнение переменной по типу (логика проверки условия АЦП);
  •  установил непортативный Proteus (это оказалось важно);
  •  код скомпилировал прямо в Proteus с подключением WinAVR.

Заработало.

Интереса ради создал новый проект в Atmel Studio и он выдал ошибку

recipe for target 'main.o' failed

Да ну его :)

Всем спасибо!

Share this post


Link to post
Share on other sites
5 минут назад, Jalui сказал:
  • вернулся к записям типа

(PINB & 0b00000001) == 0

Ну и зря. Запись (PINB & _BV(PB0)) намного информативнее. Ну или так (PINB & (1<<PB0))

А вообще в WinAVR (и, разумеется, avr-gcc вообще) есть удобные стандартные макросы проверки битов bit_is_set и bit_is_clear, которыми могу порекомендовать пользоваться, если у вас проблемы с битовыми операциями. Эквивалент процитированной строчки будет тогда таким: bit_is_set(PINB, PB0)


Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...