Hoi,

Ik ben voor het eerst bezig met schuif registers, leuke dingen!
Als het werkt.....hier onder het schema wat ik gebruik. Heb de verbindingen met de programmer (avr dragon) niet getekend.

http://img252.imageshack.us/img252/3693/shiftx.png

Ik vind de namen van het schuif register in het schema wat raar, maar voor de duidelijkheid het zit zo:

SER - PD0 (bit's in)
OE - PD1 (data wel(0) / niet(1) laten zien (tijdens het inschuiven)
RCLK - PD2 (data "latchen" outputten(1))
SRCLK - PD3 (0->1 data inschuiven)
SRCLR- PD4 (reset(0) / anders(1))

Dit is mijn programma:


/*
*	SER 	        0		PORTD &= 0xfe;
*			1		PORTD |= 0x01;
*
*	OE		0		PORTD &= 0xfd;
*			1		PORTD |= 0x02;
*
*	RCLK	        0		PORTD &= 0xfb;
*			1		PORTD |= 0x04;
*
*	SRCLK	        0		PORTD &= 0xf7;
*			1		PORTD |= 0x08;
*
*	SRCLR	        0		PORTD &= 0xef;
*			1		PORTD |= 0x10;
*
*
*/

# define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
void pulse(void);

int main(void)
{
	DDRD = 0xff;
	PORTD &= 0xfd;			//OE 0 maken, inschuiven laten zien
	PORTD &= 0xfb;			//RCLK 0 maken, output niet laten zien.
	PORTD |= 0x10;			//Reset hoog maken.

	//8x 1 inschuiven
	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();

	PORTD &= 0xfe;
	pulse();



	while(1)
	{

	}

	return 0;
}


void pulse(void)
{
	_delay_ms(10);
	PORTD |= 0x08;
	_delay_ms(10);
	PORTD &= 0xf7;

}


Nu werkt dit, maar wanneer ik de uc reset door de reset pin laag te maken (door 10K weerstand) gaan de leds uit maar daarna niet meer aan. Hoe kan dit? Hij zou alles er dan toch weer opnieuw inschuiven?

Ik weet dat het programma veel effectiever kan worden geschreven, had mooi in een for loop gekund.....maar ben er voor het eerst mee bezig.

edit0: heb ook veel problemen met het programmeren zelf, de ene keer wil hij wel het programma laden en de andere keer niet.

edit1: Heb het zelf al ontdekt, ik maakte RCLK na afloop niet hoog. Het werkt nu wel. Waarschijnlijk door toeval dan dat alles al hoog was. En het dus wel gedeeltelijk deed wat ik wilde.

Zit nu alleen nog met het probleem dat hij hem alleen wil programmeren als ik het schuif register uit het breadboard haal. Het resetten gaat nu wel goed.

Ik neem aan dat je de program fuse bit(s) 3x of meer heb gecontroleerd ?

Op welke moet ik dan letten? Ik doe bijna niks met fuses en weet er ook niet zoveel van af.

edit0:
Printscreen van mijn fuses:

http://img155.imageshack.us/img155/8382/fuses.png

Waarom staat JTAGEN eigelijk aan? Ik gebruik ISP.
De onderste is niet heel goed te zien, ook niet belangrijk nu denk ik maar er staat: SUT_CKSEL Int. RC Osc.; Start-up time: 6 CK + 65 ms
Is dat vraag teken bij SPIEN normaal?

Het eerste dat ik zou doen, is je I/O-pinnen een passende naam geven:


#define PORT959 PORTD
#define DDR959  DDRD
#define SER   (1 << PD0)
#define OE    (1 << PD1)
#define RCLK  (1 << PD2)
#define SRCLK (1 << PD3)

SRCLR reset enkel het schuifregister, daar heb je dus weinig aan. Die kan je net zogoed vast met Vcc verbinden.
Die delay heb je evenmin nodig. De 74HC595 kan sneller data verwerken dan je µC kan aanleveren.
Nu kan je de code zo schrijven:


// Initialiseren
DDR959 = SER | OE | RCLK | SRCLK;

// Bit klaarzetten
if ("bit moet hoog zijn") {
    PORT959 |= SER;
} else {
    PORT959 &= ~SER;
}

// Bit serieel inklokken
PORT959 |= SRCLK;
PORT959 &= ~SRCLK;

// enz...

@pros
Maar een nop(); dan op zijn minst er tussen?
Hoe voorkom je anders dat de compiler in zijn optimalisatie denkt: he deze pin wordt hoog en daarna meteen weer laag, dus houd ik hem maar laag. Of is het bewezen dat dit enkel bij variabelen zo gaat en niet bij registers?

En het is een 595 pros, geen 959 ;)

Ik verwacht niet, dat avr-gcc gaat optimaliseren bij het schrijven naar I/O-pinnen of registers. Dat zou al te gek zijn. Denk maar aan het CLKPR-register, waarmee je bij sommige AVR's een deler kan instellen voor de CPU_CLK. Daar moet je twee maal onmiddelijk na mekaar naartoe schrijven, wil je de deler wijzigen.

En het is een 595 pros, geen 959

Proest! Waar was ik nu weer met mijn gedachten? :-)

Bedankt allemaal.
Ik heb gevonden waarom ik hem niet kon programmeren met het schuifregister in mijn breadboard en zonder was het geen probleem.

Ik heb het BODLEVEL (de brownout detection) van 4.3V naar uit gezet. En nu doet hij het wel gewoon? Kan iemand dat verklaren?

#define SER   (1 << PD0)

Wat gebeurd er in die regel? met (1 << PD0) wordt het desbetreffende bitje geselecteerd in dit geval PD0 en deze krijgt de naam SER. En de compiler veranderd al deze namen weer? Ben namelijk erg onbekend met dat schuiven (<<,>>).

En is dit nodig? DDR595 = SER | OE | RCLK | SRCLK; Wat gebeurd er dan?

En het desbetreffende bitje die op die manier gedefinieerd is krijg ik zo PORT595 |= SER; laat en zo hoog? PORT595 &= ~SER;

Hoort het dat de JTAGEN fuse aan staat als je ISP gebruikt, en waarom staat er een vraagteken bij het vinkje SPIEN?

PD0 is gewoon 0 (nul).
(1 << PD0) betekent: een 1 0 plaatsen naar links opschuiven. Resultaat = 1.

Met PD2 is het wat duidelijker.
PD2 = 2.
(1 << PD2) = een 1 twee plaatsen naar links schuiven. Resultaat = 0b00000100 = 4.

Bij avr-gcc kan je dat ook als _BV(PD2) schrijven. BV staat hier voor Bit Value.

En is dit nodig? DDR959 = SER | OE | RCLK | SRCLK; Wat gebeurd er dan?

Op die manier maak je de nodige bits in het DDR-register hoog, zonder iets aan de andere bits te wijzigen.
De '|' betekent OR. Daar maak je dus een bit mee hoog.
Met PORT595 &= ~SER; maak je het bit laag, zonder aan de andere bits iets te wijzigen. De '&' staat voor AND, en de '~' staat voor NOT.

Hier wat FAQ's.

En is dit nodig?

DDR959 = SER | OE | RCLK | SRCLK;

Wat gebeurd er dan?

Als je die regel zou ontleden staat er volgende:

DDRD = (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3);

Om de leesbaarheid te vergroten, word er aan het begin van het programma aan PORTD, PD1 etc een naampje gegeven met ' #define '.

Ok, het is me al een stuk duidelijker!

Alleen ik kan niet verklaren waarom ik hem niet kon programmeren met het schuif register in mijn breadboard en wel als hij uit mijn breadboard was. Na het uitzetten van de brownout detectie (stond op 4.3V) en nu op disable. Werkt het perfect.

En hoort het dat de JTAGEN fuse aan staat als je ISP gebruikt, en waarom staat er een vraagteken bij het vinkje SPIEN?

Bij een ATmega324 is JTAG geactiveerd als het IC de fabriek verlaat. Dat betekent, dat je enkele pinnen van PORTC niet op de gewone wijze kan gebruiken. Door JTAGEN uit te schakelen, is PORTC terug een gewone poort.

Het SPIEN- bit kan je niet wijzigen via een ISP-interface. Gelukkig maar!

Enne, ga niet in het wilde weg met fuse-bits stoeien. Voor je het weet verandert je AVR in een zombie... :-)

Gelukkig kun je JTAGEN wel via JTAG uitschakelen, SPIEN ook trouwens ;).

Ja maar dat vind ik niet slim.
Je kan de jtag interface beter in de software disablen voor je main loop
Dan kun je altijd nog programeren VIA jtag

Op 8 november 2011 17:49:47 schreef pros:
SRCLR reset enkel het schuifregister, daar heb je dus weinig aan. Die kan je net zogoed vast met Vcc verbinden.

Hoezo heb ik er weinig aan.
Als ik deze pin laag maakt wordt alles 0?

Kan het ook zelf inschuiven, scheelt me weer een pin maar goed...

[Bericht gewijzigd door Emielzij op (11%)]

Enkel de uitgangen van het (interne) schuifregister worden laag. Er verandert niets aan de uitgangen van het IC, tot de µC een latch-puls geeft.
Als je er zeker van wil zijn dat de uitgangen van het schuifregister laag zijn bij het inschakelen van de voedingsspanning (ook als de µC niet deftig start), of je wil ze met een "noodstop" laag maken, heb je de 74HC594 nodig. Die mist dan weer de OE-pin.

Je keuze hangt er van af, wat je met het schuifregister wil doen. Wat LED's sturen? Dan maakt het allemaal niet zo veel uit. Wil je met schuifregisters een R2R-ladder sturen, die op zijn beurt de uitgangsspanning van een labvoeding bepaald, dan wil je geen onvoorspelbare spanning op die uitgang en is de 74HC594 een must omdat je diens uitgangen laag kan maken met een simpel R/C-circuit.

Ok

Maar waarom zit die OE pin er dan?
Het is inderdaad voor wat led's.
Kan ik dit schuif register ook andersom gebruiken? parallel -> serieel?

Je kan de LED's dimmen door een PWM-signaal op de OE te zetten. Om maar iets te noemen.

Als je van parallel naar serieel wil gaan, heb je een ander IC nodig. De 74HC597 bv.
De 74HC598 kan het allebei: serieel naar parallel of parallel naar serieel.

Ok

Ik kan niet in de datasheet vinden hoeveel stroom elke pin kan leveren en hoeveel ze totaal kunnen leveren. Ik zal er vast wel weer eens overheen kijken...

Had dacht ik een keer ergens gelezen 20mA/pin en max 70mA totaal.

edit0: moet ik het schuifregister ook opnieuw latchen. Na het gebruik van de OE pin?

[Bericht gewijzigd door Emielzij op (16%)]

Ik kan niet in de datasheet vinden hoeveel stroom elke pin kan leveren

Een datasheet van Philips zegt: 4mA voor gewone poorten en 6mA voor buffers/drivers.
In de praktijk kunnen ze wel meer leveren, maar dan zakt de uitgangsspanning in.
Hier een voorbeeld van schuifregisters die flink belast worden. En hier een filmpje. Werkt al jaren probleemloos.

moet ik het schuifregister ook opnieuw latchen. Na het gebruik van de OE pin?

Nee. Het sturen van de OE-pin heeft geen invloed op het schuifregister, en evenmin op het uitgangsregister.

Tik in 74HC595 op google, en hit search. Eerste hit bij mij is het datasheet van NXP (ex philips). http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf

Pagina 6 ICC max 70mA. Klopt!!!

En IO max 35mA. Fors!

Pros welke datasheet heb jij zitten kijken?

Maar goed. Even verderop specificeren ze de output voltage bij diverse stromen, en dan zie je: typical 0.18V bij 6mA. Dus typical heeft de uitgangs FET een RDSON weerstand van ongeveer 30 ohm. Bij kortsluiten gaat er dus rond de 160mA lopen. Dit gaat fors buiten de specs en als je dat bij meer dan 1 pin tegelijk doet zal denk ik de voedings bonding wire doorfikken (max 70mA).