Улыбнуло ... И функция и процедура выполняют указанную последовательность действий.Разница между процедурой и функцией лишь в том, что функция возвращает результат этих действий, а процедура нет.
Рассмотрим последовательность действий "На деньги и купи пиво" Результат: Функция - получивший деньги у программиста идет в магазин, покупает пиво и приносит его программисту,который дал деньги. Процедура - получивший деньги идет в магазин, покупает пиво и все. Что происходит с пивом - проблема программиста, давшего деньги.
Разница между процедурой и функцией лишь в том, что функция возвращает результат этих действий, а процедура нет.
Даже в этом разницы нет, так как и процедура, и функция, вполне в состоянии вернуть результат своих действий либо в данных, на которые ссылаются указатели, переданные им в качестве параметров, либо в глобальных переменных (если не требуется threadsafe). В 99% случаев мои функции возвращают только код завершения, а результат действий - по указателям в параметрах. Исключения делаются для функций, которые хочется использовать внутри выражений, или в местах, где производительность очень критична и желательно лишний раз в память не писать, обходясь регистрами.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Более того, а не является ли где-то глубоко внутри всех этих парсеров компилятора возвращаемый не-void функцией результат всего лишь более удобной записью того же аргумента? Просто скрытого от программиста, неявного?
Ну я не знаю всех архитектур, но раз тема про AVR, то тут возвращаемое значение функции почти всегда в регистрах. А указателей на регистры не бывает и аргументы-переменные в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Эх хотелось повторить срачик по терминологии процедур и функций, но сдержусь
Цитата:
А указателей на регистры не бывает
Как это не бывает? Регистр - такая же ячейка памяти, как остальные. Написать что-то вроде sts 0, r16 никто не мешает, результатом будет медленное (2 такта вместо 1) копирование r16 в r0
Цитата:
в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
Не забывайте про оптимизацию. На уровне ЯВУ это указатели, а на уровне машинных команд может быть прямая запись в регистры.
Цитата:
Функция - получивший деньги у программиста идет в магазин, покупает пиво и приносит его программисту,который дал деньги. Процедура - получивший деньги идет в магазин, покупает пиво и все. Что происходит с пивом - проблема программиста, давшего деньги.
Если целью программиста было пиво, то вызов функции вернет это пиво ему прямо в руку (прямо в то место откуда была вызвана), а процедура - в любое указанное место (задаваемое указателем). Если же программиста интересовал процесс - он может сразу выронить принесенное ему функцией пиво (не сохранять результат работы), либо не указывать процедуре адрес.
Как это не бывает? Регистр - такая же ячейка памяти, как остальные. Написать что-то вроде sts 0, r16 никто не мешает, результатом будет медленное (2 такта вместо 1) копирование r16 в r0
Оффтопик. Читайте внимательно название темы. Здесь речь про С.
COKPOWEHEU писал(а):
Цитата:
в C, по определению, при выходе из функции обязаны содержать значения, которые были до вызова функции.
Не забывайте про оптимизацию. На уровне ЯВУ это указатели, а на уровне машинных команд может быть прямая запись в регистры.
В виде исключения. Только для inline функций, когда они компилятором действительно сделаны inline и когда ячейка, на которую ссылается указатель, компилятором кешируется в регистре. Опять таки, читайте внимательно название темы.
Остальное еще более злостный оффтопик.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Что не так с кодом.? В Atmal Studia все работает а в Proteuse 8 не включается PORTB2 при case 20. Причем если убрать условие if (lampcontr==!2), то все заработает и в протеусе то есть получается что прерывания срабатывает. Хотя в симуляторе Atmal Studia все работает . Кому верить.
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;
//Инициализируем порты ввода вывода где 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); }
Если ставит так if (lampcontr!==2) ошибка типа Error 1 expected expression before '=' token А так if (lampcontr==!2 ) не ругается и все работает кроме Proteusa
Даже если я поставлю if (lampcontr==0) - все равно не работает в протеусе.
Подскажите пожалуйста как правильно отослать байт данных по 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);
Обработчик прерываний по UDREn должен или записать новый байт в UDRn, для того, чтобы очистить UDREn, или запретить дальнейшие прерывания в UDRIEn. Но не то и другое одновременно. То есть, алгоритм следующий: В основной программе 1. Проверяем бит UDREn до тех пор, пока он не будет 1 2. Записываем в UDRn первый передаваемый байт 3. Разрешаем прерывания, установкой UDRIEn. Не проверял, будет ли сформировано прерывание, если мы разрешим прерывания, когда UDREn уже установлен. Просто за ненадобностью, так как быстрее сразу отправить первый байт, а не тратить время на вызов прерывания перед началом передачи.
В обработчике прерываний 1. Проверяем, надо ли передавать очередной байт 2. Если надо - записываем его в UDRn и завершаем прерывание 3. Если не надо - запрещаем прерывания сбросом UDRIEn. Следующее прерывание произойдет только после того, как основная программа отработает пп. 1-3
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
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 } }
Нет, не сделали. 1. В прерывании Вы зачем-то проверяете UDRn, что совершенно не нужно. 2. Внутри if в прерывании все равно и отправляете байт, и запрещаете прерывания по опустошению буфера USART
Если Вам надо передавать всего 1 байт, то смысла в передаче по прерыванию нет вообще. Смысл передавать по прерыванию есть только если нужно передать блок данных. Тогда первый байт мы сразу отсылаем из основной программы, а все последующие отсылает уже обработчик прерываний. В основной программе же мы отслеживаем, все ли байты передал обработчик. Если нет - добавляем ему очередную порцию для передачи. Если да - снова посылаем первый байт, разрешая прерывания.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
//Вектор прерывания по опустошению буфера 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);
Я же писал: "Если Вам надо передавать всего 1 байт, то смысла в передаче по прерыванию нет вообще." Смысл в передаче по прерыванию в том, что в основной программе Вы только инициируете передачу последовательности байт, передав только первый и разрешив прерывание. А остальные байты последовательности уже передаст обработчик прерываний.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
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 } }
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения