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.

- Rejestracja:około 8 lat
- Ostatnio:21 dni
- Postów:913
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ć
- Rejestracja:ponad 8 lat
- Ostatnio:około 5 lat
- Postów:13
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.
- Rejestracja:ponad 8 lat
- Ostatnio:około 5 lat
- Postów:13
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?

- Rejestracja:ponad 8 lat
- Ostatnio:ponad 3 lata
- Postów:45
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;
}
}

- Rejestracja:około 8 lat
- Ostatnio:21 dni
- Postów:913
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;
}
}
}
- Rejestracja:ponad 8 lat
- Ostatnio:około 5 lat
- Postów:13
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ć

- Rejestracja:około 8 lat
- Ostatnio:21 dni
- Postów:913
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;
}
}
}
}



- Rejestracja:prawie 13 lat
- Ostatnio:4 miesiące
- Lokalizacja:Katowice
- Postów:189
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;
}
Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.