Нескольно простых вопросов о программировании AVR на Си.

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 93
Зарегистрирован: Чт апр 26, 2012 14:30:40
Откуда: под Москвой

Сообщение _dark »

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

Рассмотрим последовательность действий "На деньги и купи пиво"
Результат:
Функция - получивший деньги у программиста идет в магазин, покупает пиво и приносит его программисту,который дал деньги.
Процедура - получивший деньги идет в магазин, покупает пиво и все. Что происходит с пивом - проблема программиста, давшего деньги.

:))
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

_dark писал(а):Разница между процедурой и функцией лишь в том, что функция возвращает результат этих действий, а процедура нет.
Даже в этом разницы нет, так как и процедура, и функция, вполне в состоянии вернуть результат своих действий либо в данных, на которые ссылаются указатели, переданные им в качестве параметров, либо в глобальных переменных (если не требуется threadsafe). В 99% случаев мои функции возвращают только код завершения, а результат действий - по указателям в параметрах. Исключения делаются для функций, которые хочется использовать внутри выражений, или в местах, где производительность очень критична и желательно лишний раз в память не писать, обходясь регистрами.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Более того, а не является ли где-то глубоко внутри всех этих парсеров компилятора возвращаемый не-void функцией результат всего лишь более удобной записью того же аргумента? Просто скрытого от программиста, неявного?
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

Ну я не знаю всех архитектур, но раз тема про AVR, то тут возвращаемое значение функции почти всегда в регистрах. А указателей на регистры не бывает и аргументы-переменные в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Реклама
Эиком - электронные компоненты и радиодетали
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Эх хотелось повторить срачик по терминологии процедур и функций, но сдержусь :-)
А указателей на регистры не бывает
Как это не бывает? Регистр - такая же ячейка памяти, как остальные. Написать что-то вроде sts 0, r16 никто не мешает, результатом будет медленное (2 такта вместо 1) копирование r16 в r0
в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
Не забывайте про оптимизацию. На уровне ЯВУ это указатели, а на уровне машинных команд может быть прямая запись в регистры.
Функция - получивший деньги у программиста идет в магазин, покупает пиво и приносит его программисту,который дал деньги.
Процедура - получивший деньги идет в магазин, покупает пиво и все. Что происходит с пивом - проблема программиста, давшего деньги.
Если целью программиста было пиво, то вызов функции вернет это пиво ему прямо в руку (прямо в то место откуда была вызвана), а процедура - в любое указанное место (задаваемое указателем). Если же программиста интересовал процесс - он может сразу выронить принесенное ему функцией пиво (не сохранять результат работы), либо не указывать процедуре адрес.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

COKPOWEHEU писал(а):
А указателей на регистры не бывает
Как это не бывает? Регистр - такая же ячейка памяти, как остальные. Написать что-то вроде sts 0, r16 никто не мешает, результатом будет медленное (2 такта вместо 1) копирование r16 в r0
Оффтопик. Читайте внимательно название темы. Здесь речь про С.
COKPOWEHEU писал(а):
в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
Не забывайте про оптимизацию. На уровне ЯВУ это указатели, а на уровне машинных команд может быть прямая запись в регистры.
В виде исключения. Только для inline функций, когда они компилятором действительно сделаны inline и когда ячейка, на которую ссылается указатель, компилятором кешируется в регистре. Опять таки, читайте внимательно название темы.

Остальное еще более злостный оффтопик.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Что не так с кодом.? В Atmal Studia все работает а в Proteuse 8 не включается PORTB2 при case 20.
Причем если убрать условие if (lampcontr==!2), то все заработает и в протеусе то есть получается что прерывания срабатывает. Хотя в симуляторе Atmal Studia все работает . Кому верить.
Спойлер

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


#include <avr/io.h>
#include "FnctionTimer.h"
#include <avr/interrupt.h>
unsigned char chetTimer1, lampcontr,TimerProsto;


ISR(PCINT0_vect)
{//Отключаем прерывания от изменения сигнала на порта 
GIMSK&=~(1<<PCIE);
Timeperpolneniy();
}

ISR(INT0_vect)
{ GIMSK&=~(1<<INT0);
lampcontr=2;
asm("nop");}

ISR(TIM0_OVF_vect)
{chetTimer1++;
}

  

int main(void)
{
	//Дает 0 вслучаи если 0 и 0  или (|) а так везде 1;
	//Дает 1 вслучаи если только 1 и 1 и (&) а так везде 0;
	//~ - инверсия чисел.
	//! - если 0 то даст 1 а если 1 то даст 0 (Логическое отрицание)
	// Отключаем внешнее прерывание на время выставленеия параметров.
	asm("cli");
	//Отключаем аналоговый компаратор
	//Отключаем прерывания компаратора
	ACSR&=~(1<<ACIE);//Установит 0 в ячейки ACIE аналогична записи ACSR|=(0<<ACIE); ACSR=0x08;
	//Отключение самого компоратора.
	ACSR|=(1<<ACD);///Установит 1 в ячейки ACIE;
	
	//Отключение аналогово-цифрового преобразователя
	ADCSRA|=(1<<ADEN);
	
	//Инициализируем порты ввода вывода где 1 то порт работает на выход.
	DDRB|=(1<<DDB2)|(1<<DDB3)|(1<<DDB4)|(1<<DDB1)|(1<<DDB0);
	//Подключаем подтягивающий резистор
	PORTB|=(1<<PORTB0);
	//Включаем зажигания ДВС;
	PORTB|=(1<<PORTB4);
	//Cкидываем флаг прерывания если он имеется
	GIFR&=~(0<<PCIF);//Записываем 1 в ячейку PCIF что бы сбросить флаг или можно так GIFR|=(1<<PCIF);
	//Подколючаем  прерывания от изменения порта 
	GIMSK|=(1<<PCIE);
	//Выбираем порт работающий от прерывания
	PCMSK|=(1<<PCINT0);
	//Скидываем флаг прерывания если он имеется
	GIFR|=(1<<INTF0);
	//Подключаем внешнее прерывание по int0, высокий уровень сигнала
	GIMSK|=(1<<INT0);
	MCUCR|=(1<<ISC01)|(1<<ISC00);
	//Разрешаем глобальные прерывания
	asm("sei");
	
	
	
	
    while(1) { 
				
			asm("sei");
				
		
		
		//Если не сработала контрольная лампочка включения двигателя крутим стартер.
		

					
//lampcontr - если переменная равнна 2 значит двингатель заработал если 0
//то прокручиваем стартер для пуска двигателя
//chetTimer1 - переменная показывает сколько таймер насчитал.

	if (lampcontr==!2)
	{
	
	
		switch (chetTimer1) {
		
		//Запусаем работу стартера 
					case 40:
					PORTB|=(1<<PORTB2);
					chetTimer1++;
					break;
					//Отключаем работу стартера
					case 120:
					PORTB&=~(1<<PORTB2);
					chetTimer1=0;
					break;			}}
											
					
					//Увеличивае таймер времени для отсчета прогрева Двигателя
					
					//Значит двигатель начал работать отсчитываем время работы
					if (lampcontr==2)
					{
					switch (chetTimer1){
					case 250:
					TimerProsto++;
					chetTimer1++;
					break; }}
					
					
				
	
	//Ждем пока двигатель поработает и отключаем зажигание
		if(TimerProsto==10)
		{
	//ОТключаем работу двигателя отключая зажигания
			PORTB&=~(1<<PORTB4);
			TimerProsto++;
							}
								
	//Подключаем зажигание и обнуляем таймер
		if(TimerProsto==230) 
		{
			
			PORTB|=(1<<PORTB4);
			TimerProsto=0;
			chetTimer1=0;
			lampcontr=0;
	//Скидываем флаг прерывания если он имеется
			GIFR|=(1<<INTF0);
	//Подключаем внешнее прерывание по int0, высокий уровень сигнала
			GIMSK|=(1<<INT0); 
								}
		
	
    }
}




СпойлерИзображение
Вложения
prot.png
(155.26 КБ) 496 скачиваний
Вымогатель припоя
Аватара пользователя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь

Сообщение prinv »

if (lampcontr==!2)
Это что значит?
Не равно обозначается !=
Никакая контра не уйдёт от нас
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Если ставит так if (lampcontr!==2) ошибка типа Error 1 expected expression before '=' token
А так if (lampcontr==!2 ) не ругается и все работает кроме Proteusa

Даже если я поставлю if (lampcontr==0) - все равно не работает в протеусе.
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

strengerst писал(а):if (lampcontr!==2)
Найдите 5 отличий :
prinv писал(а):Не равно обозначается !=
:facepalm:
Даже если я поставлю if (lampcontr==0) - все равно не работает в протеусе.
Кстати

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

if (lampcontr==0)
эквивалентно

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

if (lampcontr==!2 )
Вымогатель припоя
Аватара пользователя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь

Сообщение prinv »

Один знак равно, а не два
Никакая контра не уйдёт от нас
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Один знак равно, а не два
А теперь понял спасибо, исправил но все равно в протеусе не работает, в чем может быть причина.
СпойлерИзображение
Вложения
prot2.png
(152.56 КБ) 460 скачиваний
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Проблема в PROTEUSE устранилась как только

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

 PORTB|=(1<<PORTB1);
добавил эту строчку в начале кода, так и не понял почему это произошло. Если эту строчку убрать то опять глюк в протеусе.

Наверное все дело в прерывании от INT0, при неправильном подключении ложно срабатывает прерывания.
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Подскажите пожалуйста как правильно отослать байт данных по Usart используя прерывания по опустошению буфера.
Я что то не правильно делаю подправьте пожалуйста.

Спойлер

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

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

ISR(USART_UDRE_vect)
{
	//Вектор прерывания по опустошению буфера
	UDR=0x53; //Отправляем значения
	UCSRB&=~(1<<UDRIE);//Отключаем прерывани на время
}
int main(void)
{
//Код будет работать передатчиком устанавливаем соответсвующий порт на выход TXD - PD1.
PORTD|=(1<<PD1);
//Оперделяем скоросто обмена данными 9600 бит;UBRRH - записывается младший байт,UBRRL-старший,
//Только эти два региста отвечают за скорость передачи данных в битах
	
	UBRRH=0;
	UBRRL=25;
	
//Так как мы работаем в режими передачика устанавливаем сооответствующий бит.
UCSRB|=(1<<TXEN);	
//Устанавливаем длину передоваемого слова 8бит  
UCSRC|=(1<< URSEL)|(1<< UCSZ1)|(1<< UCSZ0);

    while(1)
    {
	_delay_ms(1000);
		UCSRB|=(1<<UDRIE);
        
		//TODO:: Please write your application code 
    }
}
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

Обработчик прерываний по UDREn должен или записать новый байт в UDRn, для того, чтобы очистить UDREn, или запретить дальнейшие прерывания в UDRIEn. Но не то и другое одновременно.
То есть, алгоритм следующий:
В основной программе
1. Проверяем бит UDREn до тех пор, пока он не будет 1
2. Записываем в UDRn первый передаваемый байт
3. Разрешаем прерывания, установкой UDRIEn. Не проверял, будет ли сформировано прерывание, если мы разрешим прерывания, когда UDREn уже установлен. Просто за ненадобностью, так как быстрее сразу отправить первый байт, а не тратить время на вызов прерывания перед началом передачи.

В обработчике прерываний
1. Проверяем, надо ли передавать очередной байт
2. Если надо - записываем его в UDRn и завершаем прерывание
3. Если не надо - запрещаем прерывания сбросом UDRIEn. Следующее прерывание произойдет только после того, как основная программа отработает пп. 1-3
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Попробовал сделать так как описали
Спойлер

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

/*
 * USARTTEST.c
 *
 * Created: 30.11.2016 9:22:13
 *  Author: st
 */ 


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

ISR(USART_UDRE_vect)
{
	//Вектор прерывания по опустошению буфера
	//Проверяем надо ли передовать очередной байт
	if (UDR!=0)
	{ UDR=0x53; //Отправляем значения
	UCSRB&=~(1<<UDRIE);//Отключаем прерывани на время
	}
	
}
int main(void)
{
//Код будет работать передатчиком устанавливаем соответсвующий порт на выход TXD - PD1.
PORTD|=(1<<PD1);
//Оперделяем скоросто обмена данными 9600 бит;UBRRH - записывается младший байт,UBRRL-старший,
//Только эти два региста отвечают за скорость передачи данных в битах
	
	UBRRH=0;
	UBRRL=25;
	
//Так как мы работаем в режими передачика устанавливаем сооответствующий бит.
UCSRB|=(1<<TXEN);	
//Устанавливаем длину передоваемого слова 8бит  
UCSRC|=(1<< URSEL)|(1<< UCSZ1)|(1<< UCSZ0);

    while(1)
    {
		//Сравниваем не равен флаг UDRE 1 то есть не установлен ли он.
	if (!(UCSRA&(1<<UDRE)))
	{//Если флаг установлен записываем передавваемые  данные UDR.
		UDR=0x53;
		//Разрешаем прерывание по опустошению буфера
		UCSRB|=(1<<UDRIE);
	}
		//TODO:: Please write your application code 
    }
}
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

Нет, не сделали.
1. В прерывании Вы зачем-то проверяете UDRn, что совершенно не нужно.
2. Внутри if в прерывании все равно и отправляете байт, и запрещаете прерывания по опустошению буфера USART

Если Вам надо передавать всего 1 байт, то смысла в передаче по прерыванию нет вообще. Смысл передавать по прерыванию есть только если нужно передать блок данных. Тогда первый байт мы сразу отсылаем из основной программы, а все последующие отсылает уже обработчик прерываний. В основной программе же мы отслеживаем, все ли байты передал обработчик. Если нет - добавляем ему очередную порцию для передачи. Если да - снова посылаем первый байт, разрешая прерывания.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

А так что не так? Не как не могу въехать. Когда мы передаем данные, первый раз из основного цикла While а после еще и в прерывании?
Спойлер

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

/*
 * USARTTEST.c
 *
 * Created: 30.11.2016 9:22:13
 *  Author: st
 */ 


#include <avr/io.h>
unsigned char Danue[3]={0x53,0x2D,0x45}, Chet, Nomer=0;

ISR(USART_UDRE_vect)
{
	
	
	//Вектор прерывания по опустошению буфера
	UDR=Chet; //Отправляем значения
	UCSRB&=~(1<<UDRIE);//Отключаем прерывани на время
	Nomer++;
}


int main(void)
{
//Код будет работать передатчиком устанавливаем соответсвующий порт на выход TXD - PD1.
PORTD|=(1<<PD1);
//Оперделяем скоросто обмена данными 9600 бит;UBRRH - записывается младший байт,UBRRL-старший,
//Только эти два региста отвечают за скорость передачи данных в битах
	
	UBRRH=0;
	UBRRL=25;
	
//Так как мы работаем в режими передачика устанавливаем сооответствующий бит.
UCSRB|=(1<<TXEN);	
//Устанавливаем длину передоваемого слова 8бит  
UCSRC|=(1<< URSEL)|(1<< UCSZ1)|(1<< UCSZ0);

    while(1)
    { 
		if (Nomer>3)
		{Nomer=0;
		}
		//Сравниваем не равен флаг UDRE 1 то есть не установлен ли он.
	if (!(UCSRA|(1<<UDRE)))
	{//Если флаг установлен записываем передавваемые  данные UDR.
		//Флаг опустошения регистра данных, если 1 , то буфер передатчика пуст и можно передовать.
		
		Chet=Danue[Nomer];
		//Разрешаем прерывание по опустошению буфера
		UCSRB|=(1<<UDRIE);
		
	}
		//TODO:: Please write your application code 
    }
}
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

Я же писал:
"Если Вам надо передавать всего 1 байт, то смысла в передаче по прерыванию нет вообще."
Смысл в передаче по прерыванию в том, что в основной программе Вы только инициируете передачу последовательности байт, передав только первый и разрешив прерывание. А остальные байты последовательности уже передаст обработчик прерываний.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

А как правильно передать один байт, просто записав значение UDR.
Так что ли:
Спойлер

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


/*
 * USARTTEST.c
 *
 * Created: 30.11.2016 9:22:13
 *  Author: st
 */ 


#include <avr/io.h>

int main(void)
{
//Код будет работать передатчиком устанавливаем соответсвующий порт на выход TXD - PD1.
PORTD|=(1<<PD1);
//Оперделяем скоросто обмена данными 9600 бит;UBRRH - записывается младший байт,UBRRL-старший,
//Только эти два региста отвечают за скорость передачи данных в битах
	
	UBRRH=0;
	UBRRL=25;
	
//Так как мы работаем в режими передачика устанавливаем сооответствующий бит.
UCSRB|=(1<<TXEN);	
//Устанавливаем длину передоваемого слова 8бит  
UCSRC|=(1<< URSEL)|(1<< UCSZ1)|(1<< UCSZ0);

    while(1)
    { 
		
		//Сравниваем не равен флаг UDRE 1 то есть не установлен ли он.
	if (!(UCSRA&(1<<UDRE)))
	{//Если флаг установлен записываем передавваемые  данные UDR.
		//Флаг опустошения регистра данных, если 1 , то буфер передатчика пуст и можно передовать.
		
		//Разрешаем прерывание по опустошению буфера
		UCSRB|=(1<<UDRIE);
		UDR=0x53;
	}
		//TODO:: Please write your application code 
    }
}
Ответить

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