Ey,

ik heb zo'n beetje heel google over gezocht. Maar wat ik wil hebben is een klok. Die gewoon telt in seconde. En bij een bepaald aantal seconde moet hij terugspringen( we hebben een sensor die een object detecteerd en als hij dat 20seconde niet meer doet moet hij terugspringen). Hoe gaat dit? (we gebruiken atmega32)

Groetjes Patrick

tosc1 en tosc2, zet daar een 32.768kHz kristal op en je heb een 1Hz klok.

Is misschien iets te precies voor jullie toepassing, dus als je een timer instelt dat hij elke seconde een overflow genereert en je dan een byte tot 20 laat tellen heb je ook 20 seconden.

gewoon een timer gebruiken op je kristal of RC oscillator (als het niet super nauwkeurig hoeft te zijn).
In de compare interrupt kun je code afhandelen die een vast tijd interval uitgevoerd moet worden.
Door het OCR register van de timer te zetten met een bepaalde waarde, bepaal je dit tijds interval.

Ey,

bedankt voor de snelle acties. Ik heb inmiddels bij wat mensen op mijn school geinformeerd en deze code in elkaar geknutseld. Alleen hij werkt niet goed.

Code:


#include <avr/io.h>
#include <avr/interrupt.h>
#include "rtc.h"

ISR(TIMER2_OVF_vect)
{
  updateRTC();
}

int main(void) {
  DDRA  = _BV(0);

  ASSR  = _BV(AS2);
  TCCR2 = _BV(CS22)|_BV(CS20);
  TCNT2 = 0;
  TIMSK = _BV(TOIE2);

  sei();

  while(1);
}

unsigned int second = 0;
unsigned int minute = 0;
unsigned int hour   = 0;
unsigned int day    = 1;
unsigned int month  = 1;
unsigned int year   = 2007;

unsigned char mTable[] = {31,28,31,30,31,30,31,31,30,31,30,31};

void updateRTC(void)
{
  if ( ++second < 60 ) return;
  second = 0;
  if ( ++minute < 60 ) return;
  minute = 0;
  if ( ++hour < 24 ) return;
  hour = 0;
  if ( ++ day < (mTable[month-1] + 1) ) return;
  if ( day == 29 ) {
    if ( (((year % 4)==0) && ((year % 100) != 0)) ||
         ((year % 400) == 0) ) {
      return;
    }
  }
  day = 1;
  if ( ++month <= 12) return;
  month = 1;
  year++;
}

Dit is voor een realtime clock de verdere bewerkingen hoef ik nog niet, maar ik vraag me af hoe we deze klok goed krijgen. De rest kunnen we zelf wel oplossen.

Bedankt alvast voor de hulp!

Groetjes Patrick

Zonder verder naar je code te kijken, is het eerste wat opvalt dat je variables aanpast in een ISR zonder ze volatile te maken.

Zonder verder naar je code te kijken, is het eerste wat opvalt dat je variables aanpast in een ISR zonder ze volatile te maken.

In dit specifieke geval maakt dat niet uit, omdat de variabelen niet buiten de ISR worden gebruikt.

C flikkert die lokale variabelen toch op de stack ?
En als je de routine verlaat, wat dan ?
lijkt me idd. dat je die variabelen op de een of andere manier moet beschermen, of je C-krompiler duidelijk moet maken dat die variabelen niet telkens bij het aanroepen van de ISR opnieuw geinitialiseerd hoeven te worden, en bij verlaten van de ISR moeten ze juist niet weer overschreven worden.

Uhm... 't zijn toch globale variabelen? De compiler moet 't niet in z'n hoofd halen die zomaar op de stack te plempen!

Op 6 mei 2009 16:25:08 schreef Marco69:
Zonder verder naar je code te kijken, is het eerste wat opvalt dat je variables aanpast in een ISR zonder ze volatile te maken.

Dat heeft helemaal niks met een interrupt te maken. Volatile heeft alleen met de optimalisatie te maken.

//Edit @DC2PCC: zou je mij misschien een mailtje kunnen sturen, ik wil je iets vragen over een dc-dc converter.

[Bericht gewijzigd door RedTiger op (15%)]

Je kan die _bv weglaten bij het zetten van je registers.

Op 6 mei 2009 17:13:17 schreef RedTiger:
[...]
Dat heeft helemaal niks met een interrupt te maken. Volatile heeft alleen met de optimalisatie te maken.

Het is hier nou al zo vaak uitgelegd... Maar strikt genomen heb je gelijk. Als je elke vorm van optimization uit zet, heb je het probleem ook niet. Gokje wagen dat de TS dat niet gedaan heeft?

(en ja, ze worden hier alleen in de ISR gebruikt. Echter, ik heb het idee dat als de TS zegt dat de clock niet klopt er ook nog wel ergens wat gedisplayed wordt...)

@patrick
Wat voor clock source gebruik je ? en wat is de frequentie daarvan?

Hier nog de uitleg over het gebruik van volatile.

bedankt voor de reacties =D,

we hebben inmiddels een andere oplossing. Een realtime clock.

<code>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "rtc.h"

ISR(TIMER2_OVF_vect)
{
updateRTC();
}

int main(void) {
DDRA = _BV(0);

ASSR = _BV(AS2);
TCCR2 = _BV(CS22)|_BV(CS20);
TCNT2 = 0;
TIMSK = _BV(TOIE2);

sei();

while(1);
}

unsigned int second = 0;
unsigned int minute = 0;
unsigned int hour = 0;
unsigned int day = 1;
unsigned int month = 1;
unsigned int year = 2007;

unsigned char mTable[] = {31,28,31,30,31,30,31,31,30,31,30,31};

void updateRTC(void)
{
if ( ++second < 60 ) return;
second = 0;
if ( ++minute < 60 ) return;
minute = 0;
if ( ++hour < 24 ) return;
hour = 0;
if ( ++ day < (mTable[month-1] + 1) ) return;
if ( day == 29 ) {
if ( (((year % 4)==0) && ((year % 100) != 0)) ||
((year % 400) == 0) ) {
return;
}
}
day = 1;
if ( ++month <= 12) return;
month = 1;
year++;
}
</code>

Mijn vraag is nu hoe stel ik een if functie in die bijvoorbeeld als PORTB(vb) 2,5V doorkrijgt dat hij stopt met tellen?

Groetjes Patrick

Bedankt voor de reacties!!!

2.5 volt is geen mooie spanning om in te lezen, of je moet de spanning op de adc van de microcontroller inlezen. Het mooiste is als de spanning 0 volt is, of de voedingsspanning van de microcontroller, de spanning kun je dan uit het PINX register uitlezen als 0 of 1. (als DDRX 0 is)

Wat bedoel je je trouwens met realtime clock? Dat is meestal een extern IC die je via bv i2c of spi uitleest, volgens mij heb jij die niet aangesloten. Dit even voor de duidelijkheid, dan weten anderen ook hoe je dit probleem opgelost hebt.

Ja,

er word een spanning ingelezen op ADC0 , een willikeurige waarde tussen de 0 volt en 5 volt. daarbij willen we instellen dat als de spanning hoger is dan bv 3, dat er een telling word gedaan (i++) . Dus dat er wordt geteld. Als de spanning dan weer onder de 3V komt dan moet hij weer stoppen.

[Bericht gewijzigd door Patrick18 op (74%)]

los van hoe je de ADC initialiseerd.
iets in de trand van:



uint8_t enableRtcCount = 0;
uint16_t adcLimit = 512;     //zeg even halve AVCC

ISR(TIMER2_OVF_vect)
{
   if (enableRtcCount == 1) {
     updateRTC();
   }
}

//om adc uit te lezen
if (ADC conversie is klaar, hiervoor bepaalde vlag checken in ADC status register) {
   if (ADC > adcLimit) {
       enableRtcCount = 1;
   } else {
      enableRtcCount = 0;
      second = 0;
      minute = 0;
      hour = 0;
      day = 0;
      month = 0;
      year = 0;
   }
}

je kan ook in plaats van de vlag enableRtcCount de TOIE2 bit clearen en setten. Dan treed je interrupt helemaal niet op als de spanning lager is dan adcLimit

In mijn code waar moet dit stuk code geplaatst worden???:


//om adc uit te lezen
if (ADC conversie is klaar, hiervoor bepaalde vlag checken in ADC status register) {
   if (ADC > adcLimit) {
       enableRtcCount = 1;
   } else {
      enableRtcCount = 0;
      second = 0;
      minute = 0;
      hour = 0;
      day = 0;
      month = 0;
      year = 0;
   }
}

Bedankt alvast voor snelle reactie!


wat jij wil
kan in je main, maar ik denk dat het niet nodig is om elke programmaslag je adc uit te lezen.
je kan bv een tellertje maken in je main dat hij het opm de 100 programma slagen doet ofzo.
Beter zou zijn om wat tijd gerelateerde vlaggen te maken.
komen altijd goed van pas.

Ik ben net nog bezig geweest met de adc:

http://www.uploadarchief.net/files/download/adc.c
http://www.uploadarchief.net/files/download/adc.h

In de init kun je aangeven welke channels je wilt gebruiken. Dus bijvoorbeeld alleen poort 1 en 3 dan wordt het adc_init(0b00001010)

Met adc_read lees je eenmalig de channels uit die je hebt ingesteld (dus 1 en 3), deze moet je continue opvragen. (Dit heb ik gedaan, zodat er alleen adc interrupt zijn als je die nodig hebt)

In je main.c kun je definieren wat voor naam de channels moet hebbben bijvoorbeeld:


#include "adc.h"
#define TRIGGER_SIGNAAL 0
an_value[TRIGGER_SIGNAAL] > adc_limit // zo kun je gaan vergelijken

Met an_value kun je de waardes weer teruglezen. Succes ermee.

[edit]Er kunnen mischien nog fouten in zitten, maar ik krijg wel de juiste waardes terug.

Ok bedankt voor de reacties mensen! Ik denk dat ik hier goed mee verder kom.

Bedankt!

Ik denk niet dat je de adc ready interrupt nodig hebt. ik zou in de main loop gewoon elke 100ms de adc ready interrupt ready vlag checken en dan adc lezen.
wat moet de applicatie gaan worden?

Teamlid van Patrick18 hier =P

Een Sharp Distance Sensor moet een voorwerp gaan zien en door middel van de afstand ervan een signaal doorgeven aan de ADC0 tussen de 0 volt en de 5 volt.

DMV een grens ergens tussen de 0 en 5 volt word er een telling gedaan.

Je zet de meting aan en beweegt het voorwerp.


If (Volt > 4) {   // laten we zeggen 1,5 meter afstand
 i++;
}

Als de teller dan een X seconden geen verandering in volt opmerkt, moet de meting stoppen.

Dus elke keer als het voorwerp langs die grens gaat moet bij de variable i, 1 opgeteld worden ?

Dus je beweegt het voorwerp naar achteren, de spanning wordt groter dan 4 dan wordt bij i 1 opgeteld. Je beweegt het voorwerp weer terug en de spanning wordt kleiner als 4 enz.

Zoals je nu dat stukje code hebt, zal bij een spanning groter als 4 elke cyclus bij i 1 opgeteld worden, dat is niet de bedoeling denk ik. Een beetje hysterese zal de werking ook ten goede komen.

Hier nog een voorbeeldje:


unsigned char flag

if((volt > 4) && (flag == 0))
{
  flag = 1;
  i++;
}

if(volt < 3.8)
{
  flag = 0;
}

We zijn nog beetje beginnelingen met C. Waar staat flag voor? en hoe staan de #includes en attributen aan het begin van de code als je de ADC0 wilt uitlezen?

Groetjes Team44=) (patrick)

flag is nu gedeclareerd als een unsigned char, dat is een unsigned 8 bit waarde (0-255), signed char is bijvoorbeeld een waarde van -128 tot 127. Flag is gewoon een naam die jezelf mag verzinnen. De variable flag wordt gebruikt om ervoor te zorgen als de spanning groter als 4 volt wordt, i niet elke cyclus wordt opgeteld. Met cyclus wordt een programma doorloop bedoeld en kan bijvoorbeeld een milliseconde duren, dus dan wordt elke milliseconde i++ uitgevoerd zolang de spanning groter dan 4 volt is.

Om ADC uit te lezen:


include "adc.h"

int main(void)
{
  adc_init(0b00000001);

  while(1)
  {
    adc_read();
  }
}

Over C programmeren staat heel veel ook op internet (wat niet tegenwoordig ;)). Bijvoorbeeld:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial