Помогите найти парадокс в коде

Обсуждаем контроллеры компании Atmel.
Ответить
Прорезались зубы
Аватара пользователя
Сообщения: 211
Зарегистрирован: Чт авг 02, 2012 19:59:40

Сообщение Serbis »

Не особо сложная программа, но я в ней запутался. В коде имеется некий парадокс, не позволяющий изменить состояния выводов порта D кроме вывода PD0. Касательно аппаратной части - Atmega8. МК в полном порядке, порт тестировался другой прошивкой, он полностью работоспособен. Вкратце что делает программа. Она управляет печкой. На порту B висит три свитча. Если при включении один из свитчей замнут на землю, происходит вход в одну из подпрограмм, где происходит в зависимости от данных с ACD0(На нем висит термопара) руление выводом PD0(на нем реле с теном) по определенному сценарию. Весь механизм работал превосходно, пока мне не потребовалась одна из ножек порта D. Как выяснилось, весь порт D не але за исключением самого PD0. PORTD = (1>>PD1); в самом начале мейна ничего не делает, как PD1 как был 0, так и остался.

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

#include <avr/io.h>
#include <avr/interrupt.h>
 
#define StartConvAdc() ADCSRA |= (1<<ADSC)
#define F_CPU 8000000

volatile short int VBuff = 0;		//Буфер значения с АЦП входа 0
volatile short int LMBuff = 0;		//Буфер значения с АЦА входа 1
unsigned char mode = 0;			//Переменная режима работы устройства
float presc = 2.82960596;		//Делитель значения АЦП для определения градусов цельсия
volatile short int sec = 0;		//Счетчик секунд задержки
unsigned char adcan = 0;		//Номер активного канала АЦП

ISR( TIMER1_OVF_vect )
{
  TCNT1 = 57724; 
  sec++;
}

//Функция инициализации ражима работы устройства
void InitDev()
{
	if (bit_is_clear(PINB,0))		//Замыкание первого свитча
	{
		mode = 1;
	}	
	if (bit_is_clear(PINB,1))		//Замыкание второго свитча
	{	
		mode = 2;
	}	
	if (bit_is_clear(PINB,2))		//Замыкание третьего свитча
	{
		mode = 3;
	}		
}
//Подпрограмма режима дубления паяльной маски
void SolderMask()
{
	unsigned char cool;
	short int tmp;
	
	cool = 0;
	
	while(1)
	{
		tmp = VBuff/presc;
		if (tmp < 144)		//Если температура ниже условия, включаем тен
			{
				cool = 0;
				PORTD = (1>>PD0);
			}
			
		if ((tmp >= 144) && (tmp < 148))	
			{
				if (cool == 0)
					PORTD = (1>>PD0);
			}			
			
		if (tmp >= 148)
			{
				cool = 1;
				PORTD = (0>>PD0);
			}
				
	}
}
//Подпрограмма режима термовоздушной пайки
void Paste()
{
	short int tmp;
	
	PORTD = (1<<PD6);
	PORTD = (1<<PD0);
	while(1)
	{
		tmp = VBuff;
		if ((tmp/presc) >= 115)
		{
			PORTD = (0<<PD0);
			break;
		}		
	}	
	TIMSK = (1<<TOIE1); // разрешаем прерывание по переполнению таймера
	TCNT1 = 57724;	
 	while(sec != 3)
 	{
 		;
 	}	
	TIMSK = (0<<TOIE1);
	PORTD = (1<<PD0);
	while(1)
	{
		tmp = VBuff;
		if ((tmp/presc) >= 205)
		{
			PORTD = (0<<PD0);
			while(1);
		}	
	}			
}
//Подпрограмма режима сушки фоторезиста
void Resist()
{
	PORTD = (1<<PD5);
	unsigned char cool;
	short int tmp;
	
	cool = 0;
	
	while(1)
	{
		tmp = VBuff;
		if (tmp < 60)
			{
				cool = 0;
				PORTD = (1>>PD0);
			}
			
		if ((tmp >= 60) && (tmp < 65))
			{
				if (cool == 0)
					PORTD = (1>>PD0);
			}			
			
		if (tmp >= 65)
			{
				cool = 1;
				PORTD = (0>>PD0);
			}
				
	}
}
int main(void)
{
    while(1)
    {
		short int tmp;
        DDRD = 0xff;
		PORTD = 0xff;
		DDRB = 0x00;
		PORTB = 0xff;
		PORTD = (1>>PD1);

		//инициализируем АЦП
		//ион - напряжение питания, выравнивание влево, нулевой канал
		ADMUX = (0<<REFS1)|(1<<REFS0)|(0<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
		//вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
		ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADFR)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
		//Делитель частоты таймера - 1024
		TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10);
		//разрешаем прерывания и запускаем преобразование
		sei();
		//Запуск инициализации режима работы устройства
		InitDev();
		StartConvAdc();
		//основной цикл программы - опрос кнопочного буфера
		while(1)
		{
			tmp = VBuff;
			if (mode == 1)
			{
				SolderMask();
			}
			if (mode == 2)
			{
				Paste();
			}
			if (mode == 3)
			{
				Resist();
			}
		}
	}
	return 0;
}

ISR (ADC_vect)
{
	short int AdcBuf = ADCW;
 	VBuff = AdcBuf;	
 	StartConvAdc();
}


Реклама
Мудрый кот
Аватара пользователя
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Вот тут парадокс. Даже два!
PORTD = (1>>PD0);
PORTD = (0>>PD0);
:shock:
Внимательней надо быть!
А ещё лучше понимать что пишешь! :)
Дальше объяснять? Или сам додумаешься?
Последний раз редактировалось Kavka Чт янв 31, 2013 19:32:57, всего редактировалось 2 раза.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

PORTD = (0<<PD0);
тоже хорошо смотрится.
Вымогатель припоя
Аватара пользователя
Сообщения: 564
Зарегистрирован: Чт июл 21, 2011 19:56:10

Сообщение Зукс »

PORTD = (0<<PD0);
тоже хорошо смотрится.
:)))
Интересно о чем подумал компилятор когда увидел этот код
Делается это так:
PORTD |= (1<<PD0); - установка первого бита в единицу
PORTD |= (1<<PD1); - установка второго бита в единицу
PORTD |= (1<<PD2); - установка третьего бита в единицу
и так:
PORTD &= ~(1<<PD0); - установка первого бита в ноль
PORTD &= ~(1<<PD1); - установка второго бита в ноль
PORTD &= ~(1<<PD2); - установка третьего бита в ноль
Но не так:
PORTD = (0<<PD0); :)))

Это ведь обычная операция побитового сдвига. Пока не поймешь как работает будешь подобную ерунду писать...
если разобрать это: PORTD |= (1<<PD0);
то получается что порту Д присваеваешь единицу через оператор "или" со сдвигом. единица это 00000001 в битах, PD0, PD1, PD2 итд это просто номера. Если мы пишем PD2 то нужно сделать сдвиг влево на 2 (00000001 << 2) и получится в результате 00000100. Дальше используем это число как маску и складываем его с портом Д через оператор "или" чтобы получить возможность установить единицу только туда где у нас 1 и не трогать то где 0. По сути меняем только один бит. При этом физически меняется 3-й бит но мы пишем 2 так как счет начинается с ноля
С установкой ноля таже песня только нам нужно использовать оператор "И" плюс инверсия результата сдвига. Не забывай что эти операции все побитовые и ты работаешь с битами напрямую. Неважно регистр порта это или переменная...
В твоем случае ты берешь ноль, сдвигаешь его на ноль позиций влево и присваеваешь всему порту. Если тебе действительно очень нужно всему порту присвоить ноль то я тебе открою маленький секрет!!! Делается это так: PORTD = 0!!! :wink:
Надеюсь после подробного описания больше не будешь таким кодом кормить компилятор?)))
Шуруп забитый молотком держится намного лучше чем гвоздь закрученный отверткой!
Реклама
Эиком - электронные компоненты и радиодетали
Нашел транзистор. Понюхал.
Сообщения: 160
Зарегистрирован: Сб дек 08, 2012 16:40:40

Сообщение Триод »

Serbis, используйте следующее:

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

#define sbi(reg, bit)  (reg|=(1<<bit)) //Set Bit
#define cbi(reg, bit)  (reg&=~(1<<bit)) //Clear Bit
#define ckbi(reg, bit) reg & (1<<bit) //Check Bit
а там где нужно пишите например следующее:

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

cbi(PORTD, PD0);
И код будет более читаем и писать удобней
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 564
Зарегистрирован: Чт июл 21, 2011 19:56:10

Сообщение Зукс »

Триод писал(а): cbi(PORTD, PD0);
И код будет более читаем и писать удобней
Тоже этим постоянно пользуюсь но нужно сначала понять как это все работает а не копипастить и модифить непонятно что как в посте автора темы
Еще есть такая полезная штука как:

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

#define ibi(reg,bit) reg ^= (1<<bit)
Шуруп забитый молотком держится намного лучше чем гвоздь закрученный отверткой!
Реклама
Ответить

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