TauLabs/PicoC: Ansteuerung von GPIO Pins, z.B. Buzzer

Exec

Erfahrener Benutzer
#1
Hallo,
da ich darum gebten wurde, und es im großen Thread nicht untergehen soll hier mal deutschsprachige Info`s zu der PicoC GPIO Implementierung und Erklärungen sowie Beispiele für die Benutzung mit einem Buzzer.

Da ich auf meinem PDB für nen ZMR250 einen aktiven Buzzer drauf habe (http://forum.taulabs.org/viewtopic.php?f=10&t=682), und der Buzzer Ausgang auf dem Quanton nach Blick auf den Schaltplan scheinbar für die Ansteurung eines solchen ausgelegt ist wollte ich das gerne mit meinem Quanton und Taulabs auch machen.

Ich bin bei den Treibern (PIOS) im Source Code auf rudimentäre GPIO (General Purpose Inpnut/Output) Funktionaliätet gestoßen, die aber bisher nirgendwo genutzt wurde. Die habe ich dann überarbeitet und erweitert, sowie in PicoC Wrapper dafür geschrieben.
Die GPIO Pins müssen in den Treibern definiert sein, damit man von PicoC darauf zugreifen kann.
Damit sollte man aus PicoC damit nicht zuviel Unfug anstellen können ;), wenn die Definition sorgfältig erfolgt ist.

Es war auch mal überlegt worden, das ganze offener zu machen, so daß man aus PicoC auch selber Pins umdefinieren, und auch auf beliebige Pins zugreifen kann (https://github.com/TauLabs/TauLabs/pull/1628#issuecomment-105016769) aber mangels Nachfrage und da dies potentiell große Sicherheitsprobleme bedeuten kann wurde es bisher nicht weiter verfolgt.

Bisher sind nur GPIO Pins für das Quanton definiert und zwar in der pios_board.h folgende: https://github.com/TauLabs/TauLabs/...ets/quanton/board-info/pios_board.h#L266-L274

Code:
//-------------------------
// GPIO
//-------------------------
// [0]: Output-> Quanton Buzzer Pin, with active driver connected to GND
// [1]: Output-> Quanton Battery Pin, take care of the voltage divider connected to this pin
// [2]-[9]: Input-> Quanton PWN IN Pins 1-8, take care of the RcvrPort configuration in GCS and that the Pins are configured with a PullUp Resistor
#define PIOS_GPIO_PORTS				{ GPIOA,      GPIOC,       GPIOA,       GPIOC,      GPIOC,      GPIOC,      GPIOA,       GPIOB,      GPIOA,      GPIOA }
#define PIOS_GPIO_PINS				{ GPIO_Pin_4, GPIO_Pin_15, GPIO_Pin_10, GPIO_Pin_6, GPIO_Pin_7, GPIO_Pin_8, GPIO_Pin_15, GPIO_Pin_3, GPIO_Pin_0, GPIO_Pin_1 }
#define PIOS_GPIO_NUM				10
(Für andere Targets sollten die Definitionen dann entsprechend auch nach flight/targets/TARGETXYZ/board-info/pios_board.h)

Um die Pins aus PicoC anzusprechen, müssen sie mit ihrer Position im Array als Pin Nummer adressiert werden
Code:
// [0]: Output-> Quanton Buzzer Pin, with active driver connected to GND
// [1]: Output-> Quanton Battery Pin, take care of the voltage divider connected to this pin
// [2]-[9]: Input-> Quanton PWN IN Pins 1-8, take care of the RcvrPort configuration in GCS and that the Pins are configured with a PullUp Resistor
In PicoC stehen folgende Funktionen zur Verfügung:

Code:
/*Reads the value of a general purpose input pin, returns 0 if pin  voltage level is low, and 1 if pin  voltage level is high */

int GPIORead(unsigned int pin_num) 
 
/*unsigned int pin_num: Number of the defined GPIO pin from target/board-info/pios_board.h; starting from 0; user has to check if it is a input or output pin*
und

Code:
/*Writes/sets a general purpose output pin */

void GPIOWrite(unsigned int  pin_num, unsigned int command)

/*unsigned int pin_num: Number of the defined GPIO pin from target/board-info/pios_board.h; starting from 0; user has to check if it is a input or output pin*/
/*unsigned int command: 0=resets the pin to low voltage , 1=sets the pin to high voltage, 2=toggle between high and low voltage*/
Ich will den Buzzer dann später als Lipo Alarm benutzen, getriggert über einen Kanal der Funke zum wiederfinden falls mal verloren, und zum Signalisieren von verschiedenen Dingen wie z.B. Arm/Disarm, Flight Mode Wechsel, etc.

Zum Testen habe ich schon ein paar einfache Beispielskripte für die Benutzung eines Buzzers geschrieben.
Die nutzen dann Pin Nummer 0, nach der oben gezeigten Definition der Buzzer Ausgang vom Quanton.
Zum testen habe ich mich erstmal an anderen PicoC Skripten hier orientiert, und nutze Testval zum umschalten zwischen verschiedenen Modi, bzw. zum beenden des Skriptes.
Im finalen Einsatz sollten denke ich auch noch die Kommentare entfernt werden, um den Overhead zu reduzieren.

Erstmal das Abspielen von "Beep" Sequenzen beliebiger Länge. An die Funktion wird ein Array und die Länge des Arrays übergeben, sowie die Pin Nummer. Die Werte im Array mit geradem Index (0,2,...) sind "On" Zeitdauern, Werte mit ungeradem Index (1,3,...) sind "Off" Zeitendauern.

Code:
#include "system.h"

int b_arm[5] = {300,100,100,100,100};
int b_disarm[5] = {100,100,100,100,300};

void beepX(unsigned int t[], unsigned int x,unsigned int p)
{
  unsigned int  k;
  GPIOWrite(p,0);
  for(k=0; k<x; ++k) {
    GPIOWrite(p,((k&1)?0:1));
    sync(t[k]);
    }
  GPIOWrite(p,0);
  TestValSet(1);
}

TestValSet(1);
sync(0);

while(TestValGet() > 0)
{
  switch (TestValGet()) {
    case 1: break;
    case 2: beepX(b_arm,5,0); TestValSet(1); break;
    case 3: beepX(b_disarm,5,0); TestValSet(1); break;
  }
   sync(500);
}
TestValSet(99);

Hier eine PWM mit festem 50% DutyCycle und variabler Frequenz:

Code:
#include "system.h"

// global variables for buzzer pwm
short b_p_on = 0; // buzzer pwm status
unsigned int  b_p_d = 1000; // period time for buzzer pwm

unsigned long b_p_t = 0; //DO NOT CHANGE,  point in time, used for switching buzzer pwm

// Buzzer PWM with 50% fixed duty cycle
//PWM with variable duty cycle
//p : Pin number
//on: PWM status
//t1: Period time for PWM
void p_50(unsigned int p, short on, unsigned int t1)
{
  if(on && time()>b_p_t) {
    GPIOWrite(p,2);
    b_p_t  = (unsigned long)(time()+t1/2);
  }
  else if(!on && b_p_t>0) {
   GPIOWrite(p,0);
   b_p_t = 0;
  }   
}

TestValSet(1);
sync(0);

while(TestValGet() > 0)
{
  switch (TestValGet()) {
    case 1: b_p_on = 0; break;
    case 2: b_p_on = 1; b_p_d = 2000; break;
    case 3: b_p_on = 1; b_p_d = 1000; break;
    case 4: b_p_on = 1; b_p_d =  500; break;
  }
 
   p_50(0,b_p_on,b_p_d);
   sync(50);
}
TestValSet(99);

Und eine PWM mit variablem DutyCycle und variabler Frequenz. Die hatte ich für den Lipo Alarm angedacht. Dabei dann die "On" Zeit konstant lassen, aber die Periodendauer mit fallender Spannung zu reduzieren bzw. die Frequenz zu erhöhen:

Code:
#include "system.h"

// global variables for buzzer pwm
short b_p_on = 0; // buzzer pwm status
unsigned int  b_p_d = 1000; // period time for buzzer pwm
#define b_p_dc  150 // on time for buzzer pwm with variable duty cycle, should be smaller than period time
 
unsigned long b_p_t = 0; //DO NOT CHANGE, point in time, used for switching buzzer pwm

// Buzzer PWM with variable duty cycle
//PWM with variable duty cycle
//p : Pin number
//on: PWM status
//t1: Period time for PWM
//t2: ON time / duty cycle for PWM, should be smaller than period time
void p_dc(unsigned int p, short on, unsigned int t1,unsigned int t2)
{
  if(on && time()>b_p_t) {
     if(GPIORead(p)) {
        b_p_t  = (unsigned long)(time()+t1-t2);
        GPIOWrite(p,0);
     }
     else {
        b_p_t  = (unsigned long)(time()+t2);
        GPIOWrite(p,1);
     }
  }
  else if(!on && b_p_t>0) {
   GPIOWrite(p,0);
   b_p_t = 0;
  } 
}
 
TestValSet(1);
sync(0);

while(TestValGet() > 0)
{
  switch (TestValGet()) {
    case 1: b_p_on = 0; break;
    case 2: b_p_on = 1; b_p_d = 2000; break;
    case 3: b_p_on = 1; b_p_d = 1000; break;
    case 4: b_p_on = 1; b_p_d =  500; break;
  }

   p_dc(0,b_p_on,b_p_d,b_p_dc);
   sync(50);
}
TestValSet(99);

Genaueres zur Implementierung kann im Pull Request gefunden werden: https://github.com/TauLabs/TauLabs/pull/1628
Der ist inzwischen auch gemerged und daher sollte dies in neuen next builds zur Verfügung stehen.
Ansosnten gibt es auch im Taulabs Forum einen Thread dazu: http://forum.taulabs.org/viewtopic.php?f=17&t=715
 
FPV1

Banggood

Oben Unten