AT90S2313 i program z kursu C - problem

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
mathieiov
Moderator
Posty: 829
Rejestracja: 31 lip 2005, 9:04
Lokalizacja: --

AT90S2313 i program z kursu C - problem

Post autor: mathieiov » 17 gru 2006, 21:53

Złożyłem na solderless-bredboard układzik z prockiem '2313 i pojedynczym wyświetlaczem LED.

Program:

Kod: Zaznacz cały

#include <avr\io.h>
#include <inttypes.h>
#include <avr\signal.h>
#include <avr\interrupt.h>
#include <avr\pgmspace.h>
#include <avr\delay.h>

// Definicje wyprowadzeń
#define LED_A 0
#define LED_B 1
#define LED_C 2
#define LED_D 3
#define LED_E 4
#define LED_F 5
#define LED_G 6
#define LED_DP 7
#define LEDPORT PORTB
#define LEDDDR DDRB
#define COM1 6
#define COM2 5
#define COM3 4
#define COM4 3
#define COMPORT PORTD
#define COMDDR DDRD

uint8_t g_DaneWyswietlacza[4]; 
prog_uint8_t g_DaneCom[4] = 
	{~(1<<COM1)}; 

prog_uint8_t g_WzorCyfr[16] = 
	{
		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F), // 0	
		~(1<<LED_B | 1<<LED_C), // 1
		~(1<<LED_A | 1<<LED_B | 1<<LED_G | 1<<LED_E | 1<<LED_D), // 2
		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_G), // 3
		~(1<<LED_B | 1<<LED_C | 1<<LED_G | 1<<LED_F), // 4
		~(1<<LED_A | 1<<LED_F | 1<<LED_G | 1<<LED_C | 1<<LED_D), // 5
		~(1<<LED_A | 1<<LED_F | 1<<LED_E | 1<<LED_D | 1<<LED_C |1<< LED_G), // 6
		~(1<<LED_A | 1<<LED_B | 1<<LED_C), // 7
		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // 8
		~(1<<LED_G | 1<<LED_F | 1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D), // 9
		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_E | 1<<LED_F | 1<<LED_G), // A
		~(1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // B
		~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F), // C
		~(1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_G), // D
		~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // E
		~(1<<LED_A | 1<<LED_E | 1<<LED_F | 1<<LED_G) // F
	}; 

uint16_t g_Licznik = 0; 


// Funkcja wyświetla w kodzie heksadecymalnym podaną liczbę
void WyswietlHex(uint16_t var)
{
	g_DaneWyswietlacza[0] = pgm_read_byte(&g_WzorCyfr[var>>(3*4)]); 
	g_DaneWyswietlacza[1] = pgm_read_byte(&g_WzorCyfr[(var>>(2*4))&0xf]);
	g_DaneWyswietlacza[2] = pgm_read_byte(&g_WzorCyfr[(var>>(1*4))&0xf]);
	g_DaneWyswietlacza[3] = pgm_read_byte(&g_WzorCyfr[var&0xf]);
}

// Start
int main(void)
{
	/////////////////////////////
	// inicjacja
	LEDDDR = 0xff; 
	COMDDR = 1<<COM1; 
	// Timer0
	TCCR0 = 1<<CS01|1<<CS00; 
	TIMSK = 1<<TOIE0; 
	// Globalne zezwolenie na przerwania
	sei(); 
	// koniec inicjacji
	/////////////////////////////
	
	
	for(;;)
	{
		WyswietlHex(g_Licznik); 
		_delay_loop_2(0xffff); 
		g_Licznik++; 
	}

	return 0; 
}

//________________________________________
// Obsługa przerwań
SIGNAL(SIG_OVERFLOW0)
{
	// Wpisanie do licznika początkowej wartości
	TCNT0 = 128; 
	// Wygaszenie wyświetlaczy
	COMPORT |= 1<<COM1; 
	// Wysłanie odpowiedniej danej
	LEDPORT = g_DaneWyswietlacza;
}
Program pochodzi z 4 części kursu C i jest nieco zmodyfikowany (usunięta została zmienna przechowująca numer aktualnego wyświetlacza) ponieważ używam tylko jednego wyświetlacza. Program kompiluje się i wgrywa do procka. Niby wszystko jest ok, lecz na wyświetlaczu zamiast pojawiać sie kolejne znaki świeci się kilka segmentów (losowo przy podłączaniu i odłączaniau zasilania). Zastanawiam się czy przyczyną może być zbyt niskie napięcie zasilania (4,6V). Czy przyczyną jest błąd w programie czy zbit niskie napięcie?

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 18 gru 2006, 1:33

Błąd programu.
1. Po co przerwania jeśli jest tylko jeden wyświetlacz? Usuń przerwania a dane zamiast wysyłać do tablicy przesyłaj bezpośrednio na port.
2. Jeśli już są przerwania, w procedurze obsługi wysyłasz na port adres pod jakim znajduje się tablica z danymi wyświetlacza a powinieneś przesyłać odpowiednią wartość.

To tyle ile zauważyłem zerkając na sprawę "na szybko".

mathieiov
Moderator
Posty: 829
Rejestracja: 31 lip 2005, 9:04
Lokalizacja: --

Post autor: mathieiov » 18 gru 2006, 14:49

Koppel pisze:1. Po co przerwania jeśli jest tylko jeden wyświetlacz? Usuń przerwania a dane zamiast wysyłać do tablicy przesyłaj bezpośrednio na port.
Jak je wysłać bezpośrednio? Chciałbym je przesłać z tablicy.

Czy może być tak?:

Kod: Zaznacz cały

(...)
for(;;)
	{
		PORTD = g_WzorCyfr; 
		_delay_loop_2(0xffff); 
		g_Licznik++; 
	}
(...)
Wybaczcie ale dopiero od kilku dni uczę sie C :oops:

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 18 gru 2006, 16:00

mathieiov pisze:Czy może być tak?:

Kod: Zaznacz cały

(...)
for(;;)
	{
		PORTD = g_WzorCyfr; 
		_delay_loop_2(0xffff); 
		g_Licznik++; 
	}
(...)
Ponownie przesyłasz adres tablicy a nie zawartość komórki. Powinno być raczej tak:

Kod: Zaznacz cały

PORTD = g_WzorCyfr[0]; 
Gdzie "0" może wskazywać na dowolną inną komórkę, która istnieje (została utworzona na początku pliku)

// Edit:
Nie przyjrzałem się dokładnie i bzdury piszę...
Tablicę g_WzorCyfr tworzysz jako "zmienną" w pamięci programu. Aby ją odczytać trzeba to zrobić jeszcze troszkę inaczej:

Kod: Zaznacz cały

PORTD = pgm_read_byte(g_WzorCyfr); 
Wyświetli to cyfrę 0
..
Analogocznie:

Kod: Zaznacz cały

PORTD = pgm_read_byte(g_WzorCyfr+n); 
albo

Kod: Zaznacz cały

PORTD = pgm_read_byte(&g_WzorCyfr[n]); 
Wyświetli cyfrę n

mathieiov
Moderator
Posty: 829
Rejestracja: 31 lip 2005, 9:04
Lokalizacja: --

Post autor: mathieiov » 18 gru 2006, 17:02

Aha. Dzięki. Niewiedziałem jak wysłać komórkę tablicy na port :wink:

[ Dodano: 2006-12-19, 19:53 ]
Niestety mam kolejny problem:

po wgraniu tego programu:

Kod: Zaznacz cały

#include <avr\io.h>
#include <avr\pgmspace.h>
#include <avr\delay.h>

#define LED_A 0
#define LED_B 1
#define LED_C 2
#define LED_D 3
#define LED_E 4
#define LED_F 5
#define LED_G 6
#define LED_DP 7
#define LEDPORT PORTB
#define LEDDDR DDRB

prog_uint8_t g_WzorCyfr[16] =
    {
        ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F), // 0   
        ~(1<<LED_B | 1<<LED_C), // 1
        ~(1<<LED_A | 1<<LED_B | 1<<LED_G | 1<<LED_E | 1<<LED_D), // 2
        ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_G), // 3
        ~(1<<LED_B | 1<<LED_C | 1<<LED_G | 1<<LED_F), // 4
        ~(1<<LED_A | 1<<LED_F | 1<<LED_G | 1<<LED_C | 1<<LED_D), // 5
        ~(1<<LED_A | 1<<LED_F | 1<<LED_E | 1<<LED_D | 1<<LED_C |1<< LED_G), // 6
        ~(1<<LED_A | 1<<LED_B | 1<<LED_C), // 7
        ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // 8
        ~(1<<LED_G | 1<<LED_F | 1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D), // 9
        ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_E | 1<<LED_F | 1<<LED_G), // A
        ~(1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // B
        ~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F), // C
        ~(1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_G), // D
        ~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // E
        ~(1<<LED_A | 1<<LED_E | 1<<LED_F | 1<<LED_G) // F
    };

uint16_t g_Licznik = 0;

// Start
int main(void)
{
    // inicjacja
    LEDDDR = 0xff;
   
   
    for(;;)
    {
        LEDPORT = pgm_read_byte(&g_WzorCyfr[g_Licznik]); 
        _delay_loop_2(0xffff);
	g_Licznik++;
    }

    return 0;
}
na wyświetlaczu zamiast pojawiać się kolejno cyfry 0...9 i litery A...F leci takie coś:
0,1..7 i znowu 0,1...7, A,B,C,D,E,F a poźniej pojedyncze losowe segmenty.

ODPOWIEDZ