Skocz do zawartości

Wychodzenie z funkcji


paczkaexpres

Pomocna odpowiedź

Cześć,
Ostatnio natknąłem się na taki problem otóż mój program nie wraca z funkcji Shift_register do maina. Objawia się to tym ,że gdy jest załadowany program w którym wszytko jest w funcki main program działa (ledy się przełączają , buzzer sygnalizuje poprawną pracę) jednak gdy obsługę rejestru umieszczę w oddzielnej funkji program przestaje działać (tak jakby się zawiesił /nie wraca do maina) ledy nie świecą buzzer nie gra. Dzieje się tak nawet wtedy gdy funkcja Shift_register jest pusta.

Programuję atmege 128, używam eclipsa z wtyczką avr , korzystam z optymalizacji kodu Op 1.

Shift_register.h

#ifndef SHIFT_REGISTER_H_
#define SHIFT_REGISTER_H_

//void Shift_register(int);
//output enable input (active LOW)
#define SR_OEI_SET        	PORTE |=  (1<<0)
#define SR_OEI_CLR       	PORTE &= ~(1<<0)
#define SR_OEI_OUT   		DDRE  |=  (1<<0)
//shift register clock input
#define SR_STCP_SET        	PORTE |=  (1<<1)
#define SR_STCP_CLR       	PORTE &= ~(1<<1)
#define SR_STCP_OUT   		DDRE  |=  (1<<1)
// master reset (active LOW)
#define SR_RESET_SET        PORTE |=  (1<<2)
#define SR_RESET_CLR       	PORTE &= ~(1<<2)
#define SR_RESET_OUT   		DDRE  |=  (1<<2)
// storage register clock input
#define SR_SHCP_SET        	PORTE |=  (1<<6)
#define SR_SHCP_CLR       	PORTE &= ~(1<<6)
#define SR_SHCP_OUT   		DDRE  |=  (1<<6)
//serial data input
#define SR_DATA_SET      	PORTE |=  (1<<7)
#define SR_DATA_CLR      	PORTE &= ~(1<<7)
#define SR_DATA_OUT  	DDRE  |=  (1<<7)


#endif /* SHIFT_REGISTER_H_ */

Program główny dla którego wszystko działa poprawnie.

Main.c

#include <avr/io.h>
#include <avr/iom128.h>
#include <util/delay.h>
#include "Shift_register.h"

#define BUZZER_CLR      PORTE |=  (1<<5)
#define BUZZER_SET      PORTE &= ~(1<<5)
#define BUZZER_OUT   	DDRE  |=  (1<<5)

static void Inicialization(void);

int a,b;
int main(void)
{

Inicialization();
while(1)
{
	b++;
	a=b;
	SR_STCP_SET;
	SR_STCP_CLR;
		for(int i=0;i<16;i++)
		{
			SR_DATA_CLR;
			if(!(a%2==1))
				SR_DATA_SET;
			SR_SHCP_SET;
			SR_SHCP_CLR;
			a=a/2;
		}
	SR_STCP_SET;
	SR_STCP_CLR;
	BUZZER_SET;
	_delay_us(1000);
	BUZZER_CLR;
	_delay_ms(20);

}
}

void Inicialization(void)
{
BUZZER_OUT;
BUZZER_CLR;
SR_OEI_OUT;
SR_DATA_OUT;
SR_STCP_OUT;
SR_SHCP_OUT;
SR_RESET_OUT;
SR_RESET_SET;
SR_OEI_CLR;
}

ale gdy w definicjach odkomentuję void Shift_register(int) i zmienie wywołanie funcji na:

main.c

#include <avr/io.h>
#include <avr/iom128.h>
#include <util/delay.h>
#include "Shift_register.h"

#define BUZZER_CLR      PORTE |=  (1<<5)
#define BUZZER_SET      PORTE &= ~(1<<5)
#define BUZZER_OUT   	DDRE  |=  (1<<5)

static void Inicialization(void);

int a,b;
int main(void)
{

Inicialization();
while(1)
{
	b++;
	a=b;
	Shift_register(a);
	BUZZER_SET;
	_delay_us(1000);
	BUZZER_CLR;
	_delay_ms(20);

}
}

void Inicialization(void)
{
BUZZER_OUT;
BUZZER_CLR;
SR_OEI_OUT;
SR_DATA_OUT;
SR_STCP_OUT;
SR_SHCP_OUT;
SR_RESET_OUT;
SR_RESET_SET;
SR_OEI_CLR;
}

Shift_register.c

#include <avr/io.h>
#include <util/delay.h>
#include <avr/iom128.h>
#include "Shift_register.h"

void Shift_register(int a)
{
	SR_STCP_SET;
	SR_STCP_CLR;
		for(int i=0;i<16;i++)
		{
			SR_DATA_CLR;
			if(!(a%2==0))
				SR_DATA_SET;
			SR_SHCP_SET;
			SR_SHCP_CLR;
			a=a/2;
		}
		SR_STCP_SET;
		SR_STCP_CLR;
}


Najlepsze jest to że nawet gdy funkcja Shift_register jest w środku pusta to program i tak nie działa (przez nie działa rozumiem że się kompiluje bez errorów i warningów ale buzzer nie sygnalizuje pracy).

Link do komentarza
Share on other sites

Witaj!

A nie zabrakło Ci w tej funkcji Shift_register return 0;?

raczej nie, to funkcja typu void i return był by błędem. Zastanawia mnie że dublujesz inicjalizację tej funkcji. Czyli na początku programu wstawiasz

#include "Shift_register.h" 

a na końcu programu wstawiasz:

void Shift_register(int a)
{
   SR_STCP_SET;
   SR_STCP_CLR;
       for(int i=0;i<16;i++)
       {
           SR_DATA_CLR;
           if(!(a%2==1))
               SR_DATA_SET;
           SR_SHCP_SET;
           SR_SHCP_CLR;
           a=a/2;
       }
   SR_STCP_SET;
   SR_STCP_CLR;
} 

- To co zawarte już było w bibliotece Shift_register.h

Czy to przypadkiem nie jest zbędne ?? Nie mam praktycznych podstaw by twierdzić że to błąd ale na zdrowy rozsądek i wyczucie wydaje mi się że właśnie to może być problemem.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Zastanawia mnie że dublujesz inicjalizację tej funkcji.
Najpierw jest deklaracja a potem definicja. Jak najzupełniej poprawne i zgodne z testamentem.

BTW, zmień wywołanie na shift_register(b++) i możesz się pozbyć 2 linijek wyżej. (Po co w ogóle to przypisanie a=b?)

Link do komentarza
Share on other sites

Hm, w kodzie nie widać niczego dziwnego. Masz gdzieś zdefiniowany symbol F_CPU? - to tak na marginesie.

Przede wszystkim sprawdź to samo dla ustawienia optymalizatora = 2. To pewnie banał ale upewnij się także, że używasz rzeczywiście pliku nagłówkowego odpowiadającego procesorowi na płytce. Ja kiedyś naciąłem się na projekt na ATmega2561 - niby to samo co 128 (tak myślałem) i kompilowałem na 128. A ten duży zaczął się sypać właśnie przez stos bo inaczej gospodaruje RAMem podczas wywołań funkcji. Instrukcja wywołania podprogramu CALL zapisuje na stosie 3 bajty a nie 2 jak w mega128 i dopóki funkcje były trywialne, działało. Wystarczyło jednak, że w funkcji użyłem zmiennej automatycznej a specyficznie generowana ramka na stosie podczas prologu, podczas epilogu funkcji była "zdejmowana" w zupełnie niesymetryczny sposób i niszczyła adres powrotu.

Deklaracja int wewnątrz nawiasu for nie jest zgodna z "kanonicznym" C ale jeśli masz włączone rozszerzenia C99, powinno być OK.

Shift_register jest pierwszą wywoływaną funkcją używającą argumentu ale przekazywanie tak prostych danych jest bezbolesne, bo odbywa się przez rejestry. To samo z wartością oddawaną.

Czy mógłbyś pokazać albo wkleić link do pliku .lss po kompilacji niedziałającej wersji? Być może tam jest wytłumaczenie.

Acha, wyrażenie a%2 naprawdę wywołuje funkcję dzielenia. Chyba optymalizator nie wyczaja, że chcodzi Ci o sprawdzenie najmłodszego bitu. Żaby go wyłuskać wystarczy zrobić a&1.

Link do komentarza
Share on other sites

Może komuś to pomoże : Gdy usunę static przy funkcji inicjalizacja to program też przestaje działać poprawnie.

Co ciekawe jeżeli w tej funkcji wywołam funkcję main() to program wraca do funckji main (ale zaczyna ją wykonywać od początku)

Debug.rar

Link do komentarza
Share on other sites

Co ciekawe jeżeli w tej funkcji wywołam funkcję main() to program wraca do funckji main (ale zaczyna ją wykonywać od początku)

Oj to coś bardzo namieszałeś. Nie możesz się dziwić, że main wykonuje się od początku. To normalna funkcja. Jeśli ją wywołasz z innej funkcji programu, to musi się rozpocząć od początku.

Pytanie jest - Dlaczego wywołujesz main() z innej funkcji?

Link do komentarza
Share on other sites

Funkcja main jest domyślnie wołana przez system jako poaczątek kodu. Raczej nie powinno się jej wołać bo to oznacza wzajemną rekurencję. W C nie jest to zakazane a wręcz są algorytmy które zgrabnie to wykorzystują. Ale sensu wywoływania akurat main z tego samego programu raczej nie widzę - chcesz zacząć od początku? Przecież funkcja wywołująca main musiała być z niej kiedyś wywołana - inaczej nie dostałaby sterowania.

Z pierwszego oglądu plików wynikowych wygląda że:

- Funkcja inicjująca została włączona do main jakby była inline. Być może optymaliztor uznał, że ponieważ wywołujesz ją tylko raz, można ją po prostu w to miejsce wstawić zamiast wywołania.

- Wielkości opóźnień wskazują (jeśli się nie pomyliłem) na zegar 20MHz (5000 obrotów 4-cyklowej pętli ma dać 1 milisekundę). Jeśli z takim zegarem pędzisz swoją megę128, ma prawo nie nadążać i coś jej się w RAMie kwasi.

- Dość dziwnie wygląda prolog w main. Cztery instrukcje PUSH wskazują na potrzebę ochrony zawartości dwóch par rejstrów ale ponieważ nie ma wyjścia z main bo wstawiłeś nieskończoną pętlę while, nie ma też instruckji RET ani zdjęcia ze stosu zachowanych rejestrów. W każdym razie to dziwne.

- Sama funkcja Shift_register wywoływana jest poprawnie i także prawidłowo wraca do main.

Co więc nie działa? Czyżby ten za szybki zegar?

OT:

Generalnie używasz zmiennych typu int czyli 16-bitowych ze znakiem tam, gdzie to jest zupełnie niepotrzebne. Np. operacje na zmiennej "a" zamiast prostej instrukcji przesunięcia w prawo próbują powielać bit znaku na MSB i cały shift robią na 16-bitach. Procesor jest 8-bitowy więc warto mu zaoszczędzić roboty, bo to dla niego duża różnica. Przykład kolejny: 16-bitowy licznik "i" liczący tylko do 16.

Link do komentarza
Share on other sites

Nieważne co ustawiłeś, najwyżej będą źle liczyły się opóźnienia, ale co masz na płytce przy procesorze. Swoją drogą chyba o tym 1MHz kompilator nie wie. Jak weryfikujesz poprawność wykonania programu? Po wynikach działania funkcji Shift... która coś gdzieś wysyła czy po buzzerku?

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.