Ich lerne etwas über die Programmierung von AVR-Mikrocontrollern und habe derzeit einen einfachen LED-Blinker auf einem ATtiny26 eingerichtet.
Ein 10k-Potentiometer wird gemäß dem Beispiel in Teil 1 dieses Tutorials an ADC7 (Pin 7) angeschlossen . Die Ausgangspins von Port B sind über Transistoren in einem Multiplex-Array mit LEDs verbunden. (Die Schaltung funktioniert ohne den beteiligten ADC einwandfrei.)
Zum Testen/Lernen lasse ich eine einzelne LED blinken und warte auf eine Anzahl von Millisekunden, die dem entspricht, was vom ADC gelesen wird. Ich habe ein Problem, wenn ich versuche, den Wert zu multiplizieren, um längere Verzögerungen zu implementieren.
Ich dachte, das Problem sei, dass die Variable, in der ich den ADCH speichere, eine war, int
aber etwas anderes sein muss, da dies ein 8-Bit-Mikrocontroller ist und int
nur 0-255 sein kann. Das Ersetzen long
hat jedoch nicht funktioniert.
Hier ist der Code, der funktioniert:
#define F_CPU 1000000UL
#define ADC_VREF_TYPE = 0x40
int SD = 1;
int main()
{
// Set port A to output (1)
DDRA = 0b11111111;
// Set port B, pin 3, to input (0)
DDRB &= ~(1 << PB3);
// Set control and status register
ADCSR = 0b11100111;
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCH;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
}
Das Problem tritt auf, wenn ich versuche, einen Multiplikator wie diesen zu verwenden:
SD = ADCH * 10;
Wenn Sie dies tun, blinkt die LED schnell an einem Ende des Potentiometer-Sweeps, leuchtet aber dauerhaft und bleibt irgendwann so, während Sie das Poti auf langsamere Geschwindigkeiten drehen (größere ADCH-Werte); im Wesentlichen "einrasten" und einen Reset erfordern, während sich das Potentiometer wieder in der ursprünglichen Position befindet. Ich vermute, dass ich versuche, einen Wert zu speichern, der größer ist als der numerische Typ, aber ich kann dies anscheinend nicht überwinden, indem ich den Variablentyp ändere. Ich habe es versucht long
und uint32_t
verstehe nicht wirklich, was die numerischen Typen auf diesem Mikro beinhalten.
F: Was muss ich tun, damit ich Verzögerungen im Bereich von 0 bis sagen wir 2000 Millisekunden implementieren kann?
FYI Ich habe die folgenden Bibliotheken enthalten:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>
Bearbeiten:
Ich hatte _delay_ms(x)
direkt in meinem Beispiel platziert, um zu vermeiden, dass die Funktionen, die ich tatsächlich verwende, welche Aufrufe _delay_ms(1)
innerhalb einer Schleife posten. Mein Gedanke war, dass es prägnanter wäre, aber wie eine Antwort darauf hinwies, schien es tatsächlich ein Fehler zu sein.
int
kann nur 0-255 sein
Das ist nicht richtig. In der C
Programmiersprache int
ist an immer mindestens 16 Bit breit, auch auf 8-Bit-Mikros. A char
ist 8 Bit breit.
Aber bei der Verwendung inttypes.h
empfehle ich dringend, die expliziten Typen wie uint8_t
, int16_t
oder zu verwenden uint32_t
.
Ihr echter Fehler ist die Verwendung _delay_ms()
mit einem variablen Parameter. Dies ist nicht zulässig, da es sich um ein Makro mit Gleitkommaberechnungen handelt - zumindest in avr gcc. Sie sollten so etwas verwenden:
void DelayMs(int delay) {
while(delay--) _delay_ms(1);
}
ADCH * 10
einwandfrei funktionieren würde. Gibt es zusätzliche Erkenntnisse darüber, warum dies möglicherweise nicht der Fall ist?Ich denke, das Problem ist, dass Sie das ADC-Ergebnis linksbündig im Ergebnisregister haben:
Ihr Code unten zeigt, dass Sie ADLAR auf 1 gesetzt haben (linksbündig):
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
Dies bedeutet, dass Sie beim Lesen des ADC-Werts in ADCH die beiden niederwertigsten Bits (LSBs) vollständig überspringen. Dies bedeutet, dass Sie die Zahl einlesen, als ob sie 4-mal kleiner wäre (zwei Bitverschiebungen nach rechts).
Was Sie tun möchten, ist es auf RECHTS ausgerichtet zu setzen:
// Set ADC multiplexer selection register
ADMUX = 0b00000111;
und lesen Sie Ihren ADC-Wert aus ADCL (dem unteren ADC-Ergebnisregister):
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCL;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
justieren
JYelton