Wie man den Interrupt mit dem Timer im Mikrocontroller steuert

Hallo, ich verwende einen 8051 Mikrocontroller. Ich habe einen digitalen Wasserzähler, der binäre Daten vom Typ 0 1 0 1 liefert. Ich habe es mit 8051 INT1 verbunden, damit ich einen Interrupt bekommen kann. Wenn jetzt Wasser durch den Zähler fließt, beginnt er mit dem Senden von Interrupts (Impulse von 0101) an 8051 INT1. Jetzt möchte ich Gesamtimpulse zählen und senden.

Dafür verwende ich dieses Programm in Kiel in C-Sprache: [2nd Updated]

#include<reg51.h> // include at89x51 . h
#include<stdio.h>// include stdio . h
#include<stdlib.h>// include stdlib . h

unsigned long  value,x;
unsigned long check;
unsigned long time_overflow_count=0;
void initialize_GSM_modem(void);
void initialize_serialcommunication(void);
unsigned char Command_CMGF[]="AT+CMGF=1\r"; 
// AT+CMGF for selecting Text Mode
unsigned char CtrlZ=0x1A;                   
// CTRL+Z for sedning SMS after the message has been entered
unsigned char Command_CMGS[]="AT+CMGS=\"+9xxxxxxxxx\"\r"; 
// recepient mobile number
unsigned char Command_AT[]="AT\r";
unsigned char msg02[]="Hello!";

unsigned char buf[10]={0};


void send(void)interrupt 1
{
time_overflow_count=time_overflow_count+1;
if (time_overflow_count==5){
if(value==x){

sprintf((char*)buf, "R %lu", value);

time_overflow_count=0;

initialize_GSM_modem();
value=0;
}
}
TR0=1;
}

void input_counting(void) interrupt 2
{
TR0=0;
TL0=0x00;
TH0=0x00;

value=value+1;
TR0=1;

}


void main (void) {

TMOD = 0x21;
TH1 = 0xFD;
TL0=0x55;
TH0=0x55;
SCON = 0x50;
TR1=1;
EX1=1;///Enable external intrrupt 1
EA=1;
IE1=1;
IT1=1;
PX1=1;
ET0=1;

TI=1;
while(1)
{
x=value;
}
}

void delay(void){
unsigned int i;
for(i=0;i<50;i++);
}


 void delay2(void){
unsigned long i;
for(i=0;i<15000;i++);
}

 void initialize_GSM_modem(void)
 {
 delay2();
puts(Command_CMGS);
delay2();
puts((char *)buf);
delay2();

while(!TI); TI = 0;SBUF = 0x1A;
 }

* Aktualisiert: * Mit diesem versuche ich also, einen Timer-Interrupt zu erhalten, der prüft, ob für ein bestimmtes Zeitintervall keine Impulse vorhanden sind, und dann davon ausgeht, dass der Durchfluss des Zählers abgeschlossen ist, und die Nachricht sendet.

Aber da ist ein Fehler: Ich weiß nicht warum, aber unser Programm sendet immer wieder Nachrichten, auch wenn ich den Wasserzähler nicht starte. Wenn ich den Wasserzähler starte, sendet er den Gesamtwert beim Stoppen und wenn ich dies nicht tue, sendet er in regelmäßigen Abständen 0

Was ich will, ist, dass es auf den Wasserfluss wartet (oder den Start unterbricht) und dann nach dem letzten Wert sucht und ihn nur einmal sendet.

Wenn ich das Messgerät das nächste Mal starte, sollte es warten und den Wert erneut senden, aber es sollte nicht in regelmäßigen Abständen 0 senden.

UPDATE : Ich habe den Code aktualisiert und es funktioniert gut, aber es funktioniert nicht so, wie ich es mir wünsche

Bitte vorschlagen

Danke

Fordern Sie Ihren digitalen Wasserzähler auf, seinen Wasserstand zu senden, indem Sie ein serielles Bitmuster senden, und Sie müssen es lesen?

Antworten (2)

Es hört sich so an, als ob Ihr zugrunde liegender architektonischer Fehler darin besteht, dass Sie den Empfang von Impulsen mit dem Senden der Durchflussrate oder der gesammelten Wasserinformationen gekoppelt haben. Stellen Sie außerdem sicher, dass dieser Wasserzähler entweder bereits saubere digitale Impulse erzeugt oder dass Sie das Signal entprellen, falls es nur von einem mechanischen Schalter stammt.

Im allgemeinsten Fall, in dem Sie die Wasserimpulse entprellen müssen, unterbrechen Sie die Impulse überhaupt nicht. Unterbrechen Sie regelmäßig von einem Timer. Dies muss mindestens 10 Sekunden schneller sein als die Impulse bei maximaler Durchflussrate. Die Interrupt-Routine benötigt eine minimale Anzahl aufeinanderfolgender High- oder Low-Zustände, bevor sie davon ausgeht, dass das entprellte Signal in den neuen Zustand übergegangen ist. Sobald dies geschieht, wird ein Zähler erhöht. Mikrocontroller sind viel schneller als Wasserzähler, insbesondere mechanische, daher sollte es kein Problem sein, schnell genug zu unterbrechen. Normalerweise reicht dafür ein 1-ms-Interrupt aus, den Sie dann für andere Systemzeiten verwenden können.

Jetzt können Sie den Zählerwert oder ein beliebiges kumuliertes Delta asynchron in regelmäßigen Abständen senden. Um eine Konkurrenz um den Zähler mit der Interrupt-Routine zu vermeiden, kann der Zähler, den die Interrupt-Routine inkrementiert, ein einzelnes Byte sein. Der Vordergrundcode behält seine eigene Kopie des letzten bekannten Werts dieses Bytes. Er liest periodisch den Unterbrechungsroutinenzähler, vergleicht ihn mit dem letzten bekannten Wert, verarbeitet alle neuen Ticks, die die Differenz darstellt, und aktualisiert dann den letzten bekannten Wert. Solange die Vordergrundroutine dies oft genug tut, so dass der Einzelbytezähler nicht zwischen Abtastwerten umbrechen kann, gehen keine Daten verloren.

Der Vordergrundcode kann dann entscheiden, wann Informationen gesendet werden. Dies kann auf einem Timer-Tick basieren und/oder wenn neue Informationen zu senden sind.

Okay, hier ist ein guter:

Richten Sie einen Timer ein, der alle, sagen wir, 10 Sekunden unterbricht, wenn Sie können. Wenn Sie Ihr Programm starten, starten Sie den Timer.

Stoppen Sie jedes Mal, wenn Sie in die Funktion input_counting gelangen, den Timer und löschen Sie seine Zählung auf 0 (oder auf den Periodenwert, wenn er bei Null erreicht wird, wenn er rückwärts zählt). Dann, direkt bevor Sie den Interrupt verlassen, aktivieren Sie den Timer erneut.

Die Zeit zählt immer, aber jedes Mal, wenn Sie einen Impuls erhalten und Ihr Interrupt läuft, wird der Timer zurückgesetzt. Der Timer erzeugt nur dann einen Interrupt, wenn 10 Sekunden lang keine Impulse vorhanden sind (oder wie auch immer Sie die Periode des Timers eingestellt haben).

Also dann im Interrupt-Handler für den Timer einfach wieder Wert übertragen und dann den Timer deaktivieren. Das sollte es tun.

"Zähle auf 0 zurücksetzen", was du damit meinst ... Bitte erkläre es ...
Der Timer zählt entweder von 0 aufwärts oder von einem bestimmten Wert auf 0 abwärts. Wenn Sie den Timer „löschen“, setzen Sie das Zählregister auf seinen ursprünglichen Wert zurück: Wenn der Timer aufwärts zählt, setzen Sie den Zähler auf 0, falls dies der Fall ist herunterzählt, setzen Sie ihn auf den Wert zurück, den Sie eingegeben haben, um den gewünschten Zeitraum zu generieren.
Hallo ... Danke und gemäß Ihren Vorschlägen habe ich den Code aktualisiert ... [Auch in Frage aktualisiert] ... Bitte schauen Sie nach und antworten Sie ... Ich kann immer noch keine Lösung finden.
Sie setzen die Zählung im Interrupt nicht zurück - Sie deaktivieren nur den Timer und aktivieren ihn dann erneut. Außerdem haben Sie keinen Timer-Überlauf-Interrupt. Ich sehe auch nicht, dass Sie jemals den Timer-Interrupt aktivieren - er könnte dort drin sein, aber ich werde nicht das Datenblatt durchsuchen, um herauszufinden, welches Register es sein muss.
Hallo Sir, ich habe wie von Ihnen vorgeschlagen den Code und das Problem oben in Frage gestellt und aktualisiert ... Bitte schauen Sie nach und sagen Sie mir, warum das Senden von Nachrichten fortgesetzt wird, auch wenn ich keinen Startwasserzähler habe. ? Bitte vorschlagen
Aktivieren Sie den Timer nicht, bis Sie den ersten Impuls des Wasserzählers sehen. Wenn Sie meine Vorschläge verwenden, können Sie zumindest meine Antwort positiv bewerten.
Tut mir leid, Sir ... mein Ruf erlaubt es mir nicht, abzustimmen.