Goedemorgen,
Ik moet voor mijn stage een sensor uitlezen. Deze sensor registreert stof. Hij werkt met een led die moet knipperen. Hier moet volgens de datasheethttp://sharp-world.com/products/device/lineup/data/pdf/datasheet/gp2y1…(pagina 5) een ongeveer 100Hz signaal op aangevoerd worden. De puls moet ongeveer 0.32ms hoog zijn, er moet dan op 0,28 seconden gesampled worden. Ik heb nu een 100Hz signaal uit de micro maar dat is met de CTC functie, nu kan ik de PW niet instellen. Is het mogelijk om dit voor elkaar te krijgen en hoe?
Deze code heb ik tot zo ver om de registers in te stellen:
TCCR0A = 0x42;//01010010 PWM CTC MODE, output op OC0A
TCCR0B = 0x05;//00000100 prescaler van 1024
TCNT0=0x00;
OCR0A = 77;
Alvast bedankt voor antwoorden!
Groeten.
[Bericht gewijzigd door Tjaah op (15%)]
Nou kan ik het mis hebben, maar mijn eerste blik op die datasheet zegt dat je die LED aan moet zetten, 280μS wachten, samplen en LED uit, waarbij de led niet meer dan 320μS mag branden. Dat laatste omdat je waarschijnlijk fors boven de continu stroom zit en je dus een correct pulsgedrag moet hebben.
Je zou een timer van 280μS kunnen maken. LED aan, timer een schop, op het einde van je timer krijg je een interrupt waarop je de output sampled en als de donder die LED weer uit zet.
Dan wacht je 10mS en dan herhaal je eea.
Naar *mijn* idee is dat veel simpeler dan die wave op te wekken en dan daarmee te syncen. Als je je interruptroutines goed schrijft gaat het ook met meerdere interrupts active gewoon goed.
Groot nadeel van deze constructie: als je tijdens development een keer een f*ck-up hebt met je software, dan zou je sensor wel eens dood kunnen gaan.
Als je met hardware PWM werkt heb je dat niet. De truc zou dan zijn dat je een 2de timer een schop geeft op het moment dat je cylce begint en op de interrupt daarvan je read doet. Op zich wel mooier als je de hardware ter beschikking hebt (en dus niet voor andere doeleinden nodig hebt; ik neem aan dat die AVR veel meer moet gaan doen dan alleen een sensortje samplen.)
Afijn, geen antwoord op je vraag... Volgens mij moet je paragraaf 15.9.3 van je datasheet eens goed lezen. Feitelijk staat daar hoe je een counter van BOTTOM naar TOP kunt laten lopen. Vervolgens kun je dan met een COMPARE register daar PWM uit halen met de dutycycle die jij leuk vindt.
Voordeel is wel dat als dit eenmaal draait je er geen omkijken meer naar hebt en het bij de gemiddelde software crash ook gewoon blijft draaien.
Bedankt voor je antwoord!!
Gewoon hard setten bedoel je, dit heb ik al werkend. Gewoon output hoog maken lezen en laag maken. Maar aangezien er nog een verder programma aan moet, de waarde moet op LCD worden weer gegeven, menutje er achter misschien nog meerdere sensoren... zit je dan de hele tijd hier op te wachten. Dit is dus dan ook geen goede optie. Is het mogelijk om het 100Hz signaal met de goede PW uit de micro te krijgen, of moet ik gewoon een stukje hardware toepassen?
Groeten.
Eh.. Lezen is blijkbaar moeilijk...
Lees mijn vorige post nou nog eens en dan die van jou erachter aan.
1. Ik heb nergens iets over wait loops geschreven. Dat is not-done, zeker niet op een μC. '10mS wachten' kan ook prima op basis van een timer die een interrupt schopt. Zo kun je feitelijk je hele sensor interrupt-driven uitlezen zonder dat je mainloop er ook maar *iets* van ziet. Die timer ben je anders aan PWM kwijt, dus qua hardware resources maakt het ook niet uit. Afgezien van het nadeel van een flaw in de software zie ik niet waarom dat geen goede optie is.
2. Ik geef je een hint waar je de info voor PWM kunt vinden. Wat verwacht je? Dat ik het over ga tikken?
De fast PWM mode gebruiken dus waar de OCR0A gebruikt wordt voor de frequentie, en de OCR0B voor de Pulse Width? Ik heb het 8 bits timer verhaal al een aardig tijdje uitgespit maar kom dus niet echt verder.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Ik zou resoluut voor timer1 kiezen (tenzij je die voor wat anders nodig hebt, natuurlijk). Die kan je laten tellen tot de waarde in ICR1, waarmee je de frequentie veel precieser kan vastleggen dan met timer0 mogelijk is. Met OCR1A bepaal je dan de puls/pause-verhouding.
Bedankt voor je antwoord!
Heb nu wat gemaakt met Timer1:
TCCR1A = 0x42;//01000010 Fast PWM mode TOP = ICR1 COM1A TOGGLE OC1A
TCCR1B = 0x1D;//00011101 Fast PWM mode TOP = ICR1 Prescaler van 1024
TCNT1=0x00;
ICR1 = 150;
OCR1A = 50;
het werkt alleen niet wat gaat er verkeerd?
Als je met timer intterupts werkt, moet er ook iets in het TIMSK register gedaan worden. En er moet ook een intterrupt afhandeling zijn.
[Bericht gewijzigd door Rafarion op (21%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Bedankt voor jullie hulp.
als je dan TIMSK1 set moet TIFR1 ook geset worden toch?
dan krijg je zoiets:
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
TCCR1A = 0x42;//Fast PWM mode TOP = ICR1 COM1A TOGGLE OC1A
TCCR1B = 0x1D;//Fast PWM mode TOP = ICR1 Prescaler van 1024
TIMSK1 = 0x22;
TIFR1 = 0x22;
TCNT1 = 0x00;
ICR1 = 100;
OCR1A = 20;
ik heb alle poorten open staan het is een arduino dus vandaar de simpele pinMode. Het zou nu moeten werken maar als ik de scope aan 1 van de uitgangen hang gebeurt er niks.
groeten.
TIFR hoef je niet te setten die wordt geset door de atmega zelf als er dus een interrupt plaats vind.
Wat je wel waarschijnlijk moet doen is de interrupt vector afhandelen. Dat is een routine waar die als er een interrupt is naar toe springt om code uit te voeren.
Hier kan je dus dan je eigen code in zetten om nog wat te doen.
Maar als je hem niet afhandeld komt volgens mij je atmega niet verder want dan loopt die soort van vast.
Handel je hem af dan wordt die interrupt flag die in het TIFR staat weer unset.
kijk maar eens naar 11.4 Interrupt Vectors in ATmega328P van de datasheets en 6.7 intterrupt afhandeling
edit: typo. en nog wat toegevoegd
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
@Tjaah: Wat ik zou willen toevoegen: gebruik de namen uit de datasheet, ipv. ze in je broncode op te geven als hexadecimale getallen. Dan krijg je zoiets:
void InitTimer1(void)
{
// Init timer1 volgens mode 14 uit tabel 15.4 (datasheet)
TCCR1A = (1 << WGM11) | (1 << COM1A1);
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
ICR1 = 100;
OCR1A = 20;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
sei();
}
Hieruit kan iedereen --met de datasheet naast hem-- moeiteloos zien welke bits hoog zijn. Het kost extra-toetsaanslagen, maar de broncode wint aan leesbaarheid.
Oh, ja, ik zet TCCR1B helemaal op het einde. Daar is een reden voor: het PWM-spul begint pas te lopen als je de klok (en de prescaler) instelt. Op dat ogenblik zijn de andere registers naar wens ingevuld, zodat onverwachte resultaten uitgesloten zijn.
Merk ook, dat ik in het TIMSK1-register het ICIE1-bit niet heb geset, zoals in jouw code. Dat lijkt me nergens voor nodig. Je wil toch enkel een interrupt als TCNT1 gelijk is aan OCR1A?
[Edit]
Er stond twee maal "(1 << WGM12)" ipv. "(1 << WGM13) | (1 << WGM12)"
Zoals het zo staat is het inderdaad voor iedereen in 1 oog opslag duidelijk bedankt voor die tip!
Bedankt voor je hulp en tijd ik ga het even testen! En laat het dan horen!
Groeten.
Die dubbele WGM had ik inderdaad al gezien.
Nu heb ik het zo:
pinMode(9, OUTPUT);\\set pin 9 als output
TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << WGM11);\\Set on Compare match
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
ICR1 = 145;
OCR1A = 144;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);\\Fast PWM
sei();
het werkt er komt een mooie puls uit van 100Hz, maar ik kan de PW niet instellen. zoals je ziet is de OCR1A 1 punt verschil van de ICR1. als dat niet zo is blijft de ingang de heletijd hoog. De Pulse Breedte is nu 60µs. iemand nog een idee hoe. Ik blijf klooien!
groeten
Maar als je hem niet afhandel
dt komt volgens mij je atmega niet verder want dan loopt die soort van vast.
Dat hangt erg van je programmeertaal af. Het ding doet feitelijk een jump naar z'n vectoraddress en gaat verder met wat daar staat.
GCC bijvoorbeeld vangt dat netjes op met code die een reset tot gevolg heeft. Als je in assembly geen voorziening treft, tjsa... who knows?
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Persoonlijk vind ik de wachtlusjes in de microcontroller niet zo'n probleem. Zelf zou ik:
enable_led ();
usleep (280);
sample();
disable_led ();
msleep (9.7);
doen.
Dat je dan niet helemaal exact 100Hz krijgt is dan jammer. Mogelijk wel van belang voor de calibratie.
Helemaal "not done" voor de meeste mensen is om het stuk:
enable_led ();
usleep (280);
sample();
disable_led ();onder een 100Hz interrupt te hangen. Je interrupt routine is dus zo'n 0.3ms bezig iedere 10ms. Dat kost je dus 3% van je CPU tijd. Soit!
zoals al eerder omschreven is dat not done. Ik kan het hele programma hier niet op laten wachten. das nie handig!
TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << WGM11) | (0 << WGM10);//Set on Compare match
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
OCR1A = 149;
ICR1 = 150;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);//Fast PWM
sei();
Iemand enig idee waarom ik m'n Pulse Width niet kan instellen? het instellen van de frequentie gaat fantastisch maar ik moet de OCR1A op 1 punt verschil houden anders wordt hij continu hoog, kan dus niet de Width instellen. Als ik OCR1A op 0 set krijg ik een geïnverteerd signaal. Wat gaat er mis. Alvast bedankt voor de antwoorden!
groeten.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Ik heb even dit uitgetest op een ATmega88:
ISR (TIMER1_COMPA_vect)
{
}
int main(void)
{
// Init timer1 volgens mode 14 uit tabel 15.4
TCCR1A = (1 << WGM11) | (1 << COM1A1);
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
ICR1 = 100;
OCR1A = 20;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
DDRB |= (1 << PB1);
sei();
while (1) {
}
}
Dat werkt naar behoren. Puls/pauze-verhouding is netjes 1/4.
Mogelijk een verschil tussen de '88 en de '328 dat roet in het eten gooit?
Goedemorgen,
Zo, na een heel weekend klooien nog geen stap verder dan het signaal wat ik had. iemand nog enig idee wat ik kan proberen?
pinMode(9, OUTPUT);
//set de PWM Frequentie
TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << WGM11) | (0 << WGM10);//Set on Compare match
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
OCR1A = 149;
ICR1 = 150;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);//Fast PWM prescaler 1024
sei();
groeten.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Waarom maak je ook het WGM10-bit hoog? Daardoor telt timer1 van 0 tot de waarde in OCR1A ipv. 0 ... ICR1.
En wat doet "pinMode(9, OUTPUT);"? Pin 9 als PWM-uitgang schakelen? Maar het is toch OC1A/PB1/pin15 die het PWM-signaal levert?
Het is gelukt! na nog even brainstormen en klooien viel het kwartje! Heb hem op klok 2 met de Fast PWM mode gezet met de topwaarde op OCR1A en een prescale factor van 64 om een beetje precies alles in te stellen. Dan kan de PW met de OCR1B ingesteld worden. Door beetje te klooien met een scope kwam ik voor de frequentie dan op ICR1A = 2389 en voor de PW ICR1B = 79. Precies een signaal van 0,32ms en een frequentie van 100 hz. Zie hier de code:
TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (1 << WGM10);//Set OCR1A on Compare match, Clear OCR1B on Compare match
TIMSK1 = (1 << OCIE1A);
TCNT1 = 0x00;
OCR1A = 2389;//stel de frequentie in.
OCR1B = 79; //stel de PW in
TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (1 << CS10);//Fast PWM, top = OCR1A, prescaler 64
sei();
Bedankt voor het helpen!
groeten.
[edit] milliseconden [/edit]
0.32mega seconde? Ik dacht dat je mili seconden moest hebben...
Overigens is dat 'beetje klooien met de scoop' in deze context een slecht plan. Je weet de snelheid van je Xtal, vanuit daar is het gewoon rekenen. Het zit nu net boven de 15MHz, maar niet op een bestaande waarde...
Op 12 oktober 2009 09:49:04 schreef Marco69:
0.32mega seconde? Ik dacht dat je mili seconden moest hebben...Overigens is dat 'beetje klooien met de scoop' in deze context een slecht plan. Je weet de snelheid van je Xtal, vanuit daar is het gewoon rekenen. Het zit nu net boven de 15MHz, maar niet op een bestaande waarde...
typefoutje...had het ook berekend maar kwam toen toch niet op deze waarde vandaar beetje bijstellen met de scoop.
Op 12 oktober 2009 09:31:38 schreef pros:
Waarom maak je ook het WGM10-bit hoog? Daardoor telt timer1 van 0 tot de waarde in OCR1A ipv. 0 ... ICR1.En wat doet "pinMode(9, OUTPUT);"? Pin 9 als PWM-uitgang schakelen? Maar het is toch OC1A/PB1/pin15 die het PWM-signaal levert?
Het WGM10 bit is laag "(0 << WGM10)" Het is een arduino dus kan je met zulke jip en janneke taal de pin als output zetten. Heb nu de OC1B pin als output dat is digitale pin 10 op de arduino.
[Bericht gewijzigd door Tjaah op (35%)]
Dan klopt er iets niet in je berekening - of je Xtal doet rare dingen. Toch nog maar eens naar kijken - het is mooi als het werkt, maar als je niet weet waarom is dat toch 'eng' - zeker als de door jou berekende waarden andere resultaten opleveren.