Skocz do zawartości

Problem z wyzerowaniem sygnału PWM AVR Atmega8A


CTKL_PL

Pomocna odpowiedź

Cześć! Problem polega na tym, że nie wychodzi mi wyłączenie i zresetowanie sygnału PWM po ponownym jego włączeniu (tak aby zaczynał się od samego początku fazy).

Poniżej wrzucam kod programu:

Plik main.c:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "defs.h"

int main ()
{
	DDRB |= MOS_WARN_LIGHT_PIN | MOS_HIGHLIGHT_PIN | MOS_INF_LAMP_PIN;

	GICR |= (1<<INT0);

	timerCooldownButtonInit();
	timerPWMInit();

	sei();

	turnOffLights();

	while(1)
	{

	}
}

Plik defs.h:

#ifndef DEFS_H_
#define DEFS_H_

#define MOS_WARN_LIGHT_PIN (1<<PB1)
#define MOS_WARN_LIGHT_ON PORTB |= MOS_WARN_LIGHT_PIN
#define MOS_WARN_LIGHT_OFF PORTB &= ~MOS_WARN_LIGHT_PIN
#define MOS_WARN_LIGHT_TOG PORTB ^= MOS_WARN_LIGHT_PIN

#define MOS_HIGHLIGHT_PIN (1<<PB2)
#define MOS_HIGHLIGHT_ON PORTB &= ~MOS_HIGHLIGHT_PIN
#define MOS_HIGHLIGHT_OFF PORTB |= MOS_HIGHLIGHT_PIN
#define MOS_HIGHLIGHT_TOG PORTB ^= MOS_HIGHLIGHT_PIN

#define MOS_INF_LAMP_PIN (1<<PB0)
#define MOS_INF_LAMP_ON PORTB &= ~MOS_INF_LAMP_PIN
#define MOS_INF_LAMP_OFF PORTB |= MOS_INF_LAMP_PIN
#define MOS_INF_LAMP_TOG PORTB ^= MOS_INF_LAMP_PIN

typedef enum State {
	LIGHTS_ON,
	LIGHTS_OFF
} State_t;

volatile State_t currentState;

volatile int isButtonBlocked;

volatile int overflowCount;

void timerCooldownButtonInit();
void timerCooldownButtonStart();
void timerCooldownButtonStop();
void timerPWMInit();
void turnOffTimerPWM();
void turnOnTimerPWM();
void turnOffLights();
void turnOnLights();

#endif /* DEFS_H_ */

Plik defs.c:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "defs.h"

volatile State_t currentState = LIGHTS_OFF;

volatile int isButtonBlocked = 0;

volatile int overflowCount = 0;

void timerCooldownButtonInit()
{
	TIMSK |= (1<<TOIE0);
}

void timerCooldownButtonStart()
{
	TCCR0 |= (1<<CS02) | (1<<CS00);
}

void timerCooldownButtonStop()
{
	TCCR0 &= ~( (1<<CS02) | (1<<CS00) );
}

void timerPWMInit()
{
	TCCR1A |= (1<<WGM11);
	TCCR1B |= (1<<WGM12) | (1<<WGM13);
	ICR1 = 15624; // 2 seconds signal period
	OCR1A = 10936; // 70% signal fill
}

void turnOffTimerPWM()
{
	TCCR1B &= ~( (1<<CS10) | (1<<CS11 ) | (1<<CS12) );
	TCCR1A &= ~(1<<COM1A1);
	TCNT1 = 0;
}
void turnOnTimerPWM()
{
	TCCR1B |= (1<<CS10) | (1<<CS12);
	TCCR1A |= (1<<COM1A1);
}

void turnOnLights()
{
	turnOnTimerPWM();
	MOS_HIGHLIGHT_ON;
	MOS_INF_LAMP_ON;
}

void turnOffLights()
{
	turnOffTimerPWM();
	MOS_HIGHLIGHT_OFF;
	MOS_INF_LAMP_OFF;
}

ISR (INT0_vect)
{
	if(!(isButtonBlocked))
	{
		if(currentState == LIGHTS_OFF)
		{
			currentState = LIGHTS_ON;
			isButtonBlocked = 1;
			timerCooldownButtonStart();
			turnOnLights();
		}
		else{
			currentState = LIGHTS_OFF;
			isButtonBlocked = 1;
			timerCooldownButtonStart();
			turnOffLights();
		}
	}
}

ISR (TIMER0_OVF_vect)
{
	overflowCount++;
	if(overflowCount >= 21)
	{
		isButtonBlocked = 0;
		overflowCount = 0;
		timerCooldownButtonStop();
	}
}

A teraz troszkę wyjaśnienia kodu i tego co ma robić układ pomijając na razie jego sens. Po wciśnięciu przycisku dwie diody (czerwona i niebieska) się zapalają a dioda żółta zaczyna migać pod wpływem podawania sygnału PWM na mosfet. Po drugim wciśnięciu wszystkie diody mają bezzwłocznie zgasnąć. Póki co wszystko działa jak trzeba. Jednakże po drugim włączeniu diod dzieje się coś co mi nie odpowiada. Mianowicie żółta dioda nie zaczyna świecić tak samo jak na początku a zaczyna pracę w takim stanie w jakim została wyłączona. Natomiast odnoszę również wrażenie, że nie startuje z tego samego "fragmentu sygnału"  ponieważ nawet wyłączona pod koniec swojego świecenia, włączona następnym razem świeci pełną część sygnału a nie krótką chwilę. Tak samo jest, gdy dioda zostanie wyłączona podczas etapu gdy jest zgaszona. Po ponownym włączeniu zostaje zgaszona nawet dłużej niż powinna...
Mój cel jest następujący: chciałbym, aby po każdorazowym włączeniu diod przy pomocy przycisku, dioda żółta zawsze zaczynała migać jakby "od początku" sygnału PWM bez względu na to czy została wyłączona gdy świeciła czy też nie. Docelowo najlepiej żeby zaczynała od fazy świecenia ale to jest rzecz drugorzędna.

W kodzie widać moje próby "zresetowania" PWMa. Próbowałem już na różne sposoby. Zmieniać wartość licznika TCNT1, wyłączać prescaler i włączać go wtedy kiedy trzeba. Zmieniać tryb z PWM na normalny, zmieniać rejestr COM1A1 na wyzerowany. Nic nie przynosi żadnego oczekiwanego efektu. Najrozsądniejsze wydawał się dla mnie wyzerowanie licznika TCNT1, który odpowiada właśnie za "aktualną pozycję w sygnale" PWMa.

Wrzucam też link do google dysku gdzie jest filmik, który pokazuje jak zachowuje się układ:

https://drive.google.com/file/d/16nOAn3d4BTjz5JORQh7k1nRglN-SCGxY/view?usp=sharing

Edytowano przez CTKL_PL
  • Lubię! 1
Link do komentarza
Share on other sites

Rejestr OCR1A odpowiada za wypełnienie sygnału, jego wartość nie zmienia się w trakcie działania programu. Jedyne co się zmienia to licznik TNCT1, który jest porównywany z rejestrem OCR1A i w tym momencie zmienia stan na wyjściu, więc nie wiem zbytnio co miałoby wprowadzić resetowanie OCR1A. Jeśli dobrze zrozumiałem to zerowałem rejestr OCR po wyłączeniu jak i nawet po włączeniu PWM i nadal efekt był ten sam. Zmodyfikowałem ten kod już nawet w taki sposób żeby wyłączać i włączać za każdym razem wszystko co się da związane z PWMem i nadal to samo.

void turnOffTimerPWM()
{
	TCCR1A &= ~(1<<WGM11);
	TCCR1B &= ~( (1<<WGM12) | (1<<WGM13) );
	TCCR1B &= ~( (1<<CS10) | (1<<CS11 ) | (1<<CS12) );
	TCCR1A &= ~(1<<COM1A1);
	OCR1A = 0;
	ICR1 = 0;
	TCNT1 = 0;
}
void turnOnTimerPWM()
{
	TCCR1A |= (1<<WGM11);
	TCCR1B |= (1<<WGM12) | (1<<WGM13);
	TCCR1B |= (1<<CS10) | (1<<CS12);
	TCCR1A |= (1<<COM1A1);
	OCR1A = 10936;
	ICR1 = 15624;
	TCNT1 = 0;
}

 

Link do komentarza
Share on other sites

Już zacząłem odkurzać mojego devboard dla AVR... Tak patrzę na obsługę przycisku masz:
 

GICR |= (1<<INT0);

A w nocie jest:

chrome_SE1ndUj83c.thumb.png.01268dad063e754462fdd08e728142d7.png

Czyli jak długo masz wciśnięty przycisk tak długo program będzie wchodził w te przerwanie nie widzę nigdzie ustawień MCUCR, to tak ma być?

Edytowano przez _LM_
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

TCCR1B &= ~((1<<CS10)|(1<<CS11)|(1<<CS12));

To tak ma być? 😉

EDIT
Przepraszam, nie ma ten rejestr popatrzyłem 

Edytowano przez _LM_
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.