DIODY- AVR- mikrokontroler

0

Cześć. Jak zaprogramować mikrokontroler ATMEGA 16 w AVR studio, tak aby zaświecić po dwie diody od lewej do prawej, a na końcu wszystkie naraz? Proszę o pomoc, jestem w tym zielony.

1

Od lewej do prawej czyli jak? Od PB0 aż do PA0?

Zakładając, że masz 8 diod, wszystkie na PB

DDRB = 0xFF; // Wszystkie PBx jako wyjścia
PORTB = 0x03; // 0000 0011 
_delay_ms(500); // Dołącz util/delay.h
for(int i = 0;i < 3; i++)
{
	PORTB <<= 2; // Przesunięcie o 2 miejsca
	_delay_ms(500);
}
PORTB = 0xFF;

DDRB to rejestr w którym ustawiasz jaka nóżka PB jest wejściem a jaka wyjściem.
PORTB natomiast to rejestr w którym ustawiasz stan wyjściowy nóżek PB

<<= 2 przypisuje wynik przesunięcia bitowego o dwa.
Dla przykładu:

0000 0001 <<= 1
0000 0010

0000 0001 <<= 2
0000 0100

Nie testowałem powyższego kodu na AVR, ale powinien działać

0

Parami po dwie diody na jedną sekundę, tj.: dwie się palą, po sekundzie gasną, i po nich następne pary. Tak od lewej strony do prawej. Na końcu mają zapalić się wszystkie diody. Podpinam je od PB0 do PB8. Każdy kabelek pojedyńczo.

0

No to masz rozwiązanie w moim pierwszym poście, jedyne co to musisz zwiększyć delay do 1000 (ms).

0

Proponuję zrezygnować z delay'a i zrobić to za pomocą switcha, który będzie wywoływany co jakiś określony czas, tak aby nie blokować uC.

0
lxs napisał(a):

Proponuję zrezygnować z delay'a i zrobić to za pomocą switcha, który będzie wywoływany co jakiś określony czas, tak aby nie blokować uC.

Podasz przykład?

0

Zmienna flag_1s jest ustawiana w przerwaniu od timera co 1000ms.

volatile uint8_t flag_1s = 0;
uint8_t led_state = 0;

DDRB = 0xFF; // Wszystkie PBx jako wyjścia

while (1)
{
	if (flag_1s)
	{
		switch (led_state)
		{
		case 0:
			PORTB = 0x03; // 0000 0011 
			led_state = 1;
			break;
		case 1:
			PORTB <<= 2;
			led_state = 2;
			break;
		case 2:
			PORTB <<= 2;
			led_state = 3;
			break;
		case 3:
			PORTB <<= 2;
			led_state = 4;
			break;
		case 4:
			PORTB = 0xFF;;
			break;
		}
		flag_1s = 0;
	}
}

0

A to świecenie diodami ma odbyć się tylko raz czy będzie się powtarzać?

I nie ładniej wyglądałoby to:

while(1)
{
	if(flag) // flag zmienia się na 1 co 1 sekundę
	{
		flag = 0;
		PORTB <<= 2;
		if(PORTB == 0x00)
		{
			PORTB = 0xFF;
		}
	}
}
0
atmal napisał(a):

A to świecenie diodami ma odbyć się tylko raz czy będzie się powtarzać?

I nie ładniej wyglądałoby to:

while(1)
{
	if(flag) // flag zmienia się na 1 co 1 sekundę
	{
		flag = 0;
		PORTB <<= 2;
		if(PORTB == 0x00)
		{
			PORTB = 0xFF;
		}
	}
}

Ma się powtarzać

0

To używając Timera co 1 który ustawia flag na 1 zrobiłbym tak:

uint8_t reset;
DDRB = 0xFF;
PORTB = 0x03;
while(1)
{

	if(flag)
	{
		flag = 0;
		if(reset)
		{
			PORTB = 0x03;
			reset = 0;
		}
		else
		{
			PORTB <<= 2;
			if(PORTB == 0x00)
			{
				PORTB = 0xFF;
				reset = 1;
			}
		}	
	}	
}
0

Ja jeszcze zaproponuję takie rozwiązanie:

#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#define LED_DDR DDRC
#define LED_PORT PORTC

enum {
  NUMBER_OF_EFFECTS = 5,
};

/* LEDS are driven by 0 */
const uint8_t effects[NUMBER_OF_EFFECTS] PROGMEM = {
  0xFC, 0xF3, 0xCF, 0x3F, 0x00,
};

volatile uint8_t currentEffect = 0;

/* Init port for LEDS */
void LED_Init();

/* Init timer to CTC mode with tick on every 1s */
void T1_CTC_Init();

int main(void) {
    LED_Init();
    T1_CTC_Init();

    set_sleep_mode(SLEEP_MODE_IDLE);
    sei();
    while (1) {
      LED_PORT = pgm_read_byte(&(effects[currentEffect]));
      sleep_mode();
    }
}

void LED_Init() {
  LED_DDR = 0xff;
  LED_PORT = 0xff;
}

void T1_CTC_Init() {
  TCCR1A = 0;
  TCCR1B =  _BV(WGM12) | _BV(CS12) | _BV(CS10);
  OCR1A = F_CPU / 1024 - 1;
  TIMSK1 |= _BV(OCIE1A);
}

ISR(TIMER1_COMPA_vect) {
  currentEffect = (currentEffect + 1) % NUMBER_OF_EFFECTS;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1