Obsługa wejść analogowych w NET MF jest bardzo prosta. Na STM32F4Discovery mamy dostępne 7 wejść analogowych, wszystkie mają rozdzielczość 12 bitów (0...4096):
Cpu.AnalogChannel.ANALOG_0: PA1
Cpu.AnalogChannel.ANALOG_1: PA2
Cpu.AnalogChannel.ANALOG_2: PA3
Cpu.AnalogChannel.ANALOG_3: PB0
Cpu.AnalogChannel.ANALOG_4: PB1
Cpu.AnalogChannel.ANALOG_5: PC4
Cpu.AnalogChannel.ANALOG_6: PC5
Do testów możemy po prostu do wejścia podłączyć potencjometr. Ja akurat miałem o wartości 10K, ale w zasadzie każdy może być powiedzmy w zakresie od 1K do 100K.
Inicjalizacja i użycie jest bardzo proste. Odczytujemy wartości bezpośrednio z wejścia. Kręcimy potencjometrem zmieniając wartość napięcia na wejściu w zakresie od 0 do 3V:
using (var analogInput = new AnalogInput(Cpu.AnalogChannel.ANALOG_0))
{
for (;;)
{
double readVal = analogInput.Read();
int rawVal = analogInput.ReadRaw();
Debug.Print("Sample: " + readVal + " (" + rawVal + ")");
Thread.Sleep(5000);
}
}
Jak widać powyżej mamy dwie funkcje do odczytu: ReadRaw i Read. Funkcja ReadRaw zwraca wartość nieprzetworzoną (u nas w zakresie od 0 do 4096), a Read wartość przeskalowaną i przesuniętą (przetworzoną). Szczególnie druga funkcja jest bardzo użyteczna. Na przykład, aby otrzymać wartość napięcia na wejściu analogowym (od 0 do +3V) wystarczy ustawić następujące parametry:
using (var analogInput = new AnalogInput(Cpu.AnalogChannel.ANALOG_0))
{
analogInput.Scale = 3; //+3V
analogInput.Offset = 0; //od 0
for (;;)
{
double readVal = analogInput.Read();
Debug.Print("U=" + readVal);
Thread.Sleep(1000);
}
}
Prawda, że proste? Parametr Offset pozwala przesunąć pozycję zerową. Na przykład gdyby pozycja środkowa potencjometru była dla nas wartością zerową i chcielibyśmy, aby wartości były z przedziału -100 w jednym skrajnym położeniu i +100 w drugim skrajnym położeniu (-100%..+100%), to trzeba ustawić Scale na 200, a Offset na -100.
Jeszcze jeden przykład. Sterowanie jasnością świecenia diody (przez PWM) w zależności od ustawienia potencjometru:
var analog = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
analog.Scale = 100; //brightness: 0..100%
var pwm = new PWM(Cpu.PWMChannel.PWM_0, 300, 0, false);
pwm.Start();
double prev = Double.MinValue;
for (;;)
{
double curr = analog.Read();
if (Math.Abs(curr - prev) >= 1)
{
pwm.DutyCycle = ToDutyCycle(curr);
prev = curr;
}
}
Funkcja przeliczająca oczekiwaną jasność na wypełnienie taka jak w poprzednim wpisie o PWM:
private static double ToDutyCycle(double brightness)
{
if (brightness < 1)
return 0;
if (brightness > 99)
return 1;
return Math.Pow(10, (2.55 * brightness - 1) / 84.33 - 1) / 100;
}
A niech będzie jeszcze jeden przykład, z użyciem interfejsu sieciowego, bo na razie nie było żadnego. Potencjometr przez wejście analogowe będzie sterował głośnością w XBMC uruchomionym na innym komputerze. Oczywiście trzeba w XBM włączyć Webserver, będziemy zdalnie wywoływać JSON-RPC_API.
Najważniejsza jest funkcja wysyłająca odpowiednio spreparowany request do XBMC. Trzeba jedynie pamiętać o tym, że wysyłając żądanie POST musimy ustawić odpowiednio ContentType, no i nie zapomnieć o użytkowniku i haśle do serwisu XBMC.
private static void SendXbmcVolume(int volume)
{
const string xbmcHost = "192.168.1.2";
const string xbmcPort = "8081";
const string xbmcUser = "xbmc";
const string xbmcPassword = "xbmc";
string json = "{\"jsonrpc\": \"2.0\", " +
"\"method\": \"Application.SetVolume\", " +
"\"params\": {\"volume\": " + volume + "}, " +
"\"id\": 1}";
const string xbmcRpc = @"http://" + xbmcHost + ":" + xbmcPort + "/jsonrpc";
using (var request = (HttpWebRequest) WebRequest.Create(xbmcRpc))
{
byte[] content = Encoding.UTF8.GetBytes(json);
request.Method = "POST";
request.ContentType = "application/json";
request.Accept = "application/json";
request.ContentLength = content.Length;
request.KeepAlive = false;
request.Credentials = new NetworkCredential(xbmcUser,
xbmcPassword,
AuthenticationType.Basic);
using (var stream = request.GetRequestStream())
stream.Write(content, 0, content.Length);
}
}
Wywołanie powyższej funkcji można zrealizować tak:
using (var analogInput = new AnalogInput(Cpu.AnalogChannel.ANALOG_0))
{
analogInput.Scale = 100;
double prevVal = Double.MinValue;
for (;;)
{
double currentVal = analogInput.Read();
if (Math.Abs(currentVal - prevVal) >= 1)
{
int volume = ToVolume(currentVal);
SendXbmcVolume(volume);
prevVal = currentVal;
}
}
}
Pozostaje jeszcze funkcja ToVolume. Dostosowuje ona wartość podawaną z potencjometru do logarytmicznej charakterystyki ucha ludzkiego. Funkcję naprędce wymyśliłem, aby tylko miała charakterystykę logarytmiczną, więc może nie być w pełni poprawna. Ale działa!
private static int ToVolume(double volume)
{
double loud = 50*Math.Log10(volume);
if (loud < 0)
return 0;
if (loud > 100)
return 100;
return (int) Math.Round(loud);
}
Pełny kot: DemoAnalogInput


Brak komentarzy:
Prześlij komentarz