Stránka 1 z 1

74HC575 a multiplex na atmega

Napsal: 08 pro 2013, 19:45
od Aktuell
Zdravím, mám takový problém, dělám program pro multiplexování BCD displeje pomocí shift registru 595, program jako takový pro posílání stringu a pouštění potřebných bitů na výstup se zdá že funguje dobře, ale když chci přepínat anody pomocí funkce switch case, tak proběhne nejspíš jen první case a druhý už ne a nevím si s tím vůbec rady, kde může být chyba. Na ukázku sem vybral část kódu a zapojení v ISIS, kde by správně mělo být **56, ale je jen ***6 (adresování zjednodušeno jen na dvě poslední cifry).

Kód: Vybrat vše

int i=3456;

unsigned char znaky [10] = {
    0b00000011,		 //0
    0b10011111,		 //1
    0b00100101,		 //2
    0b00001101,		 //3
    0b10011001,		 //4
    0b01101001,		 //5
    0b01000001,		 //6
    0b00011111,		 //7
    0b00000001,		 //8
    0b00001001   };	 //9


unsigned char anody [4] = {
    0b0001,     //0  - 4.digit
    0b0010,     //1  - 3.digit
    0b0100,     //2  - 2.digit 
    0b1000	};  //3  - 1.digit


ISR(TIMER0_OVF_vect)
{
	
tisice=i/1000;  // 4-cif. cislo rozsekej na cifry
pom=i%1000;
stovky=pom/100;
pom=pom%100;
desitky=pom/10;
jednotky=pom%10;
	
			
	switch (cyklus) {
		
	case 0:
			
		data_k_odeslani= (znaky[jednotky]<<4) | anody[0];   // sluč registry pro katody a anody
			
		while(pocet_odeslanych < 12)      //posilam 12 bitu
	
         {  PORTC=PORTC&0b11111110;     //hodiny do nuly
            if(data_k_odeslani & 0x01) PORTC=PORTC|0b00000010;
                   else PORTC=PORTC&0b11111101;
            PORTC=PORTC|0b00000001; // hodiny do jednicky
            data_k_odeslani>>=1; //posun data o bit doprava
            pocet_odeslanych++;
          }

           PORTC=PORTC|0b00000100;  // pusť data na paralelní výstupy
           asm("nop");
           PORTC=PORTC&0b11111011;  // výstupy uzavři

					
	 cyklus=1;
	 break;


	case 1:
			
		data_k_odeslani= (znaky[desitky]<<4) | anody[1];   // sluč registry pro katody a anody
			
		while(pocet_odeslanych < 12)      //posilam 12 bitu
	
         {  PORTC=PORTC&0b11111110;     //hodiny do nuly
            if(data_k_odeslani & 0x01) PORTC=PORTC|0b00000010;
                   else PORTC=PORTC&0b11111101;
            PORTC=PORTC|0b00000001; // hodiny do jednicky
            data_k_odeslani>>=1; //posun data o bit doprava
            pocet_odeslanych++;
          }

           PORTC=PORTC|0b00000100;  // vpusť data na paralelní výstupy
           asm("nop");
           PORTC=PORTC&0b11111011;  // výstupyuzavři
					
					
	 cyklus=0;
	 break;

       } // konec switch
	
TCNT0=217; 
		
}

Napsal: 09 pro 2013, 07:36
od AB1
Zkus přemýšlet jak se budou měnit bity v posuvných registrech když pokaždé pošleš 12 bitů.

Buď musíš posílat 16 bitů, nebo před posláním 12-ti bitů registry vynulovat.

A pošli kompletní kód.

Napsal: 09 pro 2013, 14:09
od procesor
Žeby rozmýšlal? a vyšlo mu, že 12 stačí.
Posledné 4 bity v registri mu môžu byť ukradnuté.
Kde nuluješ "pocet_odeslanych"

Napsal: 09 pro 2013, 17:08
od Aktuell
Nemá být počet odeslaných < 11 (pokud teda počítáme od nuly)?
No já bych se vsadil, že určitě ne, protože 0,1,2,3,4,5,6,7,8,9,10 určitě dohromady nedá 12...

Nechtěl jsem tu zbytečně spamovat celým kódem, tak jsem vybral podstatnou část a doufal že si zbytek každý domyslí, ale asi ne, tak tady pro pořádek celý kód. Uvnitř smyčky while bych problém neviděl, odeslání stringu se zdá že funguje, nefunguje však její ukončení a skočení na další case. Program sem se snažil nějak okomentovat.

Kód: Vybrat vše

#include <avr/interrupt.h>
#include <avr/io.h>			
#include <stdlib.h>
#include <stdio.h>

unsigned char znaky [10] = {   // definuj pole znaků kombinací katod segmentů
    0b00000011,		 //0
    0b10011111,		 //1
    0b00100101,		 //2
    0b00001101,		 //3
    0b10011001,		 //4
    0b01101001,		 //5
    0b01000001,		 //6
    0b00011111,		 //7
    0b00000001,		 //8
    0b00001001   };   //9


unsigned char anody [4] = {   // definuj pole pro anody jednotlivých sedmisegmentovek
    0b0001,     //0  - 4.digit
    0b0010,     //1  - 3.digit
    0b0100,     //2  - 2.digit 
    0b1000	}; //3  - 1.digit

unsigned short int data_k_odeslani, pom, i=3456;
unsigned char pocet_odeslanych = 0, jednotky, desitky, stovky, tisice, cyklus=0;


void main(void)
{
    PORTC=0;         // vynuluj port
    DDRC=0b11111111; // port C jako výstupní
    TIMSK=0b00000001;     // čítač 0 povoleno přerušení (bit0 TIMER0, bit2 TIMER1, bit6 TIMER2)	
	
 //  Nastavení čítač 0
    TCCR0 = 0b00000100;   //   clk/1024 – 101 ; clk/256 – 100 ; clk/64 – 011 ; for clk/8 – 010 ; no presc. - 001
    TCNT0 = 217;          //   2^8 - 1000000 / 256 / 100 = 217  -> 100 Hz

asm("sei");   // Global enable interrupts
	
			while(1)
			{
				
			}
}

ISR(TIMER0_OVF_vect)       //  přerušení overflow timer
{
	
tisice=i/1000;  // 4-cif. cislo rozsekej na cifry
pom=i%1000;
stovky=pom/100;
pom=pom%100;
desitky=pom/10;
jednotky=pom%10;
	
			
	switch (cyklus) {
		
	case 0:
			
		data_k_odeslani= (znaky[jednotky]<<4) | anody[0];   // sluč registry pro katody a anody
			
		while(pocet_odeslanych < 12)      //posilam 12 bitu
	
         {  PORTC=PORTC&0b11111110;     //hodiny do nuly
            if(data_k_odeslani & 1) PORTC=PORTC|0b00000010;  // pokud vymaskovaný bit v proměné není roven nule, pošli jedničku do sériového výstupu
                   else PORTC=PORTC&0b11111101;   // jinak pošli nulu
            PORTC=PORTC|0b00000001; // hodiny do jednicky, povolení vstupu bitu 1 z předch.podm. na sériový výstup
            data_k_odeslani>>=1; //posuň data o bit doprava
            pocet_odeslanych++;
          }

           PORTC=PORTC|0b00000100;  // pusť data na paralelní výstupy
           asm("nop");
           PORTC=PORTC&0b11111011;  // výstupy uzavři

					
	 cyklus=1;
	 break;


	case 1:
			
		data_k_odeslani= (znaky[desitky]<<4) | anody[1];   
			
		while(pocet_odeslanych < 12)     
	
         {  PORTC=PORTC&0b11111110;     
            if(data_k_odeslani & 1) PORTC=PORTC|0b00000010;
                   else PORTC=PORTC&0b11111101;
            PORTC=PORTC|0b00000001; 
            data_k_odeslani>>=1; 
            pocet_odeslanych++;
          }

           PORTC=PORTC|0b00000100;  
           asm("nop");
           PORTC=PORTC&0b11111011;  
					
					
	 cyklus=0;
	 break;

       } // konec switch
	
TCNT0=217; // znovu nastav čítač
		
}

Napsal: 09 pro 2013, 17:51
od FHonza
zkus deklarovat proměnnou cyklus jako volatile char

Napsal: 09 pro 2013, 18:17
od Aktuell
FHonza píše:zkus deklarovat proměnnou cyklus jako volatile char
Bohužel nepomohlo :?

Napsal: 09 pro 2013, 18:32
od FHonza
zkus přeložit kód bez optimalizace nebo všechny proměnné, které se používají v obsluze přerušení, deklarovat jako volatile. Obecně by globální proměnné, které se používají v obsluze přerušení, měly být takto deklarovány. Jinak hrozí že se po návratu z obsluhy nezachová jejich hodnota.

Napsal: 09 pro 2013, 19:37
od piitr
Přijde mi, že nenuluješ pocet_odeslanych před whilem.

Napsal: 09 pro 2013, 20:48
od Aktuell
piitr píše:Přijde mi, že nenuluješ pocet_odeslanych před whilem.
Přišlo ti to správně. A já se domníval že vynulování v deklaraci bude stačit. Díky za vyřešení
Obrázek

Napsal: 09 pro 2013, 21:36
od procesor
procesor píše:Žeby rozmýšlal? a vyšlo mu, že 12 stačí.
Posledné 4 bity v registri mu môžu byť ukradnuté.
Kde nuluješ "pocet_odeslanych"
Stačilo by čítať...

Napsal: 10 pro 2013, 04:50
od AB1
procesor píše:Žeby rozmýšlal? a vyšlo mu, že 12 stačí.
Posledné 4 bity v registri mu môžu byť ukradnuté.
Máš pravdu.
Přemýšlet jsem měl já, než jsem to napsal.

Napsal: 10 pro 2013, 14:04
od procesor
Tvoj postup by tiež fungoval/nefungoval, mal by iba pár nadbytočných inštrukcií :) a chýbali potrebné-

Napsal: 11 pro 2013, 16:18
od procesor
Dnes je to mega... chýb a bežne mega naviac. Proste nikto netuší