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

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

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

Сообщение _dark »

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

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

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

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

Сообщение ptr128 »

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

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

Сообщение WiseLord »

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

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

Сообщение ptr128 »

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

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

Сообщение COKPOWEHEU »

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

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

Сообщение ptr128 »

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

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

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

Сообщение 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 КБ) 494 скачивания
Аватара пользователя
prinv
Вымогатель припоя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь
Контактная информация:

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

Сообщение prinv »

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

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

Сообщение strengerst »

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

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

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

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

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

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

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

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

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

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

Сообщение prinv »

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

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

Сообщение strengerst »

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

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

Сообщение strengerst »

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

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

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

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

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

Сообщение 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 
    }
}
Аватара пользователя
ptr128
Вымогатель припоя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

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

Сообщение ptr128 »

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

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

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

Сообщение 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 
    }
}
Аватара пользователя
ptr128
Вымогатель припоя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

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

Сообщение ptr128 »

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

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

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

Сообщение 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 
    }
}
Аватара пользователя
ptr128
Вымогатель припоя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

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

Сообщение ptr128 »

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

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

Сообщение 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»