Forum: Mikrocontroller und Digitale Elektronik PPM Signal von Positiv in negativ ändern


von Willwissen (Gast)


Lesenswert?

Hallo ich habe eine Platine die in eine Fernsteuerung kommt und in das 
vorhandene PPM Signal 3 weitere einfügt.Die Platine funktioniert auch 
tadellos.Jetzt habe ich noch eine zweite Funke wo ich es auch gerne 
einbauen möchte aber sie benutzt ein Negatives PPM Signal.Was muss ich 
am Code andern damit es klapt?

main.C


#define ENABLE_BIT_DEFINITIONS
//#include <ioavr.h>
//#include <inavr.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "main.h"


enum{
  stPPM_SYNC,
  stPPM_SYNC_WAIT,
  stPPM_CHANNEL_START,
  stPPM_CHANNEL_DATA,
  stPPM_CHANNEL_7_DATA_TRIGGER,
  stPPM_CHANNEL_7_DATA,
  stPPM_CHANNEL_8_START,
  stPPM_CHANNEL_8_DATA,
  stPPM_CHANNEL_9_START,
  stPPM_CHANNEL_9_DATA,
  stPPM_FINISH_PULSE,
  stPPM_FINISH_FRAME,
  stPPM_FRAME_END,
  stPCM_MODE_PULSE_LOW,
  stPCM_MODE_PULSE_HIGH,
};

unsigned char          channel_number   = 0;
unsigned char          ppm_state        = stPPM_SYNC;
unsigned char          adc_channel      = 0;
unsigned char          sync_retry_count = 0;
volatile unsigned int  channel_7        = 0xffff; 
// set to max. for testing if conversion is valid
volatile unsigned int  channel_8        = 0xffff; 
// set to max. for testing if conversion is valid
volatile unsigned int  channel_9        = 0xffff; 
// set to max. for testing if conversion is valid


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  init_pin(void) 
**
**  purpose  :  Initialise I/O pins 
**
** 
**
**---------------------------------------------------------------------- 
------*/
void init_pin(void)
{

  DDRA &= ~(1<<PPM_IN); 
// set Input Capture Pin as input
  PORTA |= (1<<PPM_IN); 
// enable pullup

  DDRB  |=  (1<<PPM_OUT_PIN); 
// configure PPM_OUT pin as output
  SET_PPM_OUT_LOW; 
// set low

  DDRA  &= ~(1 << CHANNEL_7_ADC); 
// Channel 7 (pin12) input
  PORTA &= ~(1 << CHANNEL_7_ADC); 
// disable pullup

  DDRA  &= ~(1 << CHANNEL_8_ADC); 
// Channel 8 (pin11) input
  PORTA &= ~(1 << CHANNEL_8_ADC); 
// disable pullup

  DDRA  &= ~(1 << CHANNEL_9_ADC); 
// Channel 8 (pin11) input
  PORTA &= ~(1 << CHANNEL_9_ADC); 
// disable pullup

}
/*-init_pin------------------------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  init_adc(void) 
**
**  purpose  :  Initialise ADC registers 
**
** 
**
**---------------------------------------------------------------------- 
------*/
void init_adc(void)
{

  cli(); 
// disable interrupts

  DIDR0 |= ((1<<ADC2D)|(1<<ADC1D)); 
// digital input disable for pin 11 and 12
  ADMUX  = 0x00; 
// VCC as reference voltage, select channel 0
  ADCSRA = (1 << ADPS2) | (1 << ADPS1)|| (0 << ADPS0); 
// 8.0 [Mhz] / 128 = 62,5 [kHz]
  ADCSRB = 0x00; 
// free running mode

  ADC_ENABLE;

  sei(); 
// enable interrupts
}
/*-init_adc------------------------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  init_timer1(void) 
**
**  purpose  :  Initialise timer0 
**
**  Note(s)  :  Frequency : 8.0 [Mhz] 
**
**              8 / 8.0 Mhz : 1.00 [us] 
**
** 
**
**---------------------------------------------------------------------- 
------*/
void init_timer1(void)
{
  cli(); 
// disable interrupts

  TCCR1A = ((0<<WGM11)|(0<<WGM10)); 
// CTC mode
  TCCR1B = ((0<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10)); 
// CTC mode for COMPA, prescaler 8 / 8MHz => [1.0us]

  CLEAR_INPUT_CAPTURE_INTERRUPT_FLAG; 
// reset ICF flag

  SET_COUNTER_TO_ZERO;
  SET_COMPARE_COUNTER_TO_ZERO;
  ENABLE_INPUT_CAPTURE;
  DISABLE_OUTPUT_COMPARE;
  RISING_EDGE_TRIGGER;

  sei(); 
// enable interrupts
}
/*-init_timer1---------------------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  timer1_capture_interrupt(void) 
**
**  purpose  :  Synchronise PPM frame and copy input events to PPM_OUT, 
**
**              start mixing Ch7, 8 and 9 data when detect start pulse 
of Ch7 **
** 
**
**---------------------------------------------------------------------- 
------*/
//#pragma vector=TIM1_CAPT_vect
//static __nested __interrupt void timer1_capture_interrupt (void)
ISR(TIMER1_CAPT_vect)
{
   cli(); 
// disable interrupts
   unsigned int data;

   switch (ppm_state)
   {
      case stPPM_SYNC: 
// detect rising edge pulse
         data = ICR1; 
// get timer value after input capture
         SET_COUNTER_TO_ZERO;
         FALLING_EDGE_TRIGGER;
         if(data >= MIN_SYNC_TIME && data <= MAX_SYNC_TIME) 
// valid sync trigger
         {
            SET_PPM_OUT_HIGH;
            ppm_state = stPPM_CHANNEL_DATA; 
// next state: get data
            channel_number = 0;
            sync_retry_count = 0; 
// when valid data, reset sync retry counter        (v1.3)
                 }
         else 
// trigger but not a valid sync time
         {
            SET_PPM_OUT_LOW;
            ppm_state = stPPM_SYNC_WAIT; 
// next state: wait for next sync event
         }
         break;

      case stPPM_SYNC_WAIT:
         sync_retry_count++; 
// count number of retry's                          (v1.3)
                 SET_PPM_OUT_LOW; 
// not nessecery, output should already be low
         SET_COUNTER_TO_ZERO;
         SET_CAPTURE_COUNTER_TO_ZERO;
         RISING_EDGE_TRIGGER;
                 if(sync_retry_count > 10) 
// 10x retry is to much, no PPM                     (v1.3)
            ppm_state = stPCM_MODE_PULSE_HIGH; 
// set to mode PCM pass thrue                       (v1.3)
                 else 
//                                                  (v1.3)
            ppm_state = stPPM_SYNC; 
// next state: try again for new sync
         break;

      case stPPM_CHANNEL_START: 
// detect rising edge pulse
         SET_COUNTER_TO_ZERO;
         SET_PPM_OUT_HIGH;
         FALLING_EDGE_TRIGGER;
         channel_number++; 
// prepare for next MX12 channel clock
         if(channel_number>5) 
// all six channels read
         {
            ppm_state = stPPM_CHANNEL_7_DATA_TRIGGER; 
// 7th. channel but now self created
            channel_number = 0;
         }
         else
            ppm_state = stPPM_CHANNEL_DATA;
         break;

      case stPPM_CHANNEL_DATA: 
// detect falling edge pulse
         SET_COUNTER_TO_ZERO;
         SET_PPM_OUT_LOW;
         RISING_EDGE_TRIGGER;
         ppm_state = stPPM_CHANNEL_START; 
// wait for next channel rising edge pulse
         break;

      case stPPM_CHANNEL_7_DATA_TRIGGER: 
// detect rising edge pulse
         SET_COUNTER_TO_ZERO;
         SET_PPM_OUT_LOW;
         SET_TIMER_TO_COMPA_CTC;
         DISABLE_INPUT_CAPTURE;
         ENABLE_OUTPUT_COMPARE;
         OCR1A = START_PULSE_LOW; 
// startpulse length 0.3ms
         TRIGGER_INPUT_COMPARE_INTERRUPT;
         ppm_state = stPPM_CHANNEL_7_DATA;
         break;

      case stPCM_MODE_PULSE_LOW: 
// detect falling edge pulse                        (v1.3)
         SET_COUNTER_TO_ZERO; 
// prevent overflow interrupt
         SET_PPM_OUT_LOW;
         RISING_EDGE_TRIGGER;
         ppm_state = stPCM_MODE_PULSE_HIGH;
         break;

      case stPCM_MODE_PULSE_HIGH: 
// detect rising edge pulse                         (v1.3)
         SET_COUNTER_TO_ZERO; 
// prevent overflow interrupt
         SET_PPM_OUT_HIGH;
         FALLING_EDGE_TRIGGER;
         ppm_state = stPCM_MODE_PULSE_LOW;
         break;

      default:
         SET_PPM_OUT_LOW; 
// not nessecery, output should already be low
         SET_COUNTER_TO_ZERO;
         SET_CAPTURE_COUNTER_TO_ZERO;
         RISING_EDGE_TRIGGER;
         ppm_state = stPPM_SYNC; 
// next state: try again for new sync
         break;

   }
   sei();
}
/*-timer1_capture_interrupt--------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  timer1_compare_interrupt(void) 
**
**  purpose  :  Mixing channel 7, 8 and 9 data into ppm out, 
**
**              start input capture for frame synchronisation 
**
** 
**
**---------------------------------------------------------------------- 
------*/
//#pragma vector=TIM1_COMPA_vect
//__interrupt void timer1_compare_interrupt (void)
ISR(TIM1_COMPA_vect)
{
   cli();
   switch (ppm_state)
   {
      case stPPM_CHANNEL_7_DATA: 
// create 7th channel data
         SET_PPM_OUT_LOW;
         SET_COUNTER_TO_ZERO;
         OCR1A = channel_7; 
// COMPA: 0,7ms + channel 7 ADC value
         ppm_state = stPPM_CHANNEL_8_START; 
// next State
         break;

      case stPPM_CHANNEL_8_START: 
// create 8th channel start pulse
         SET_PPM_OUT_HIGH;
         SET_COUNTER_TO_ZERO;
         OCR1A = START_PULSE_HIGH; 
// startpulse length 0.3ms
         ppm_state = stPPM_CHANNEL_8_DATA; 
// next State
         break;

      case stPPM_CHANNEL_8_DATA: 
// create 8th channel data
         SET_PPM_OUT_LOW;
         SET_COUNTER_TO_ZERO;
         OCR1A = START_PULSE_LOW + channel_8; 
// COMPA: 0,7ms + channel 7 ADC value
         ppm_state = stPPM_CHANNEL_9_START; 
// next State
         break;

      case stPPM_CHANNEL_9_START: 
// create 8th channel start pulse
         SET_PPM_OUT_HIGH;
         SET_COUNTER_TO_ZERO;
         OCR1A = START_PULSE_HIGH; 
// startpulse length 0.3ms
         ppm_state = stPPM_CHANNEL_9_DATA; 
// next State
         break;

      case stPPM_CHANNEL_9_DATA: 
// create 8th channel data
         SET_PPM_OUT_LOW;
         SET_COUNTER_TO_ZERO;
         OCR1A = START_PULSE_LOW + channel_9; 
// COMPA: 0,7ms + channel 7 ADC value
         ppm_state = stPPM_FINISH_PULSE; 
// next State
         break;

    case stPPM_FINISH_PULSE: 
// create last pulse
         SET_PPM_OUT_HIGH;
         SET_COUNTER_TO_ZERO;
         OCR1A = START_PULSE_HIGH; 
// startpulse length 0.3ms
         ppm_state = stPPM_FINISH_FRAME; 
// next State
         break;

      case stPPM_FINISH_FRAME: 
// create extra low pulse for masking PPM_IN data of channel 7 and 8
         SET_PPM_OUT_LOW;
         SET_COUNTER_TO_ZERO;
         OCR1A = FORCE_LOW_END_FRAME; 
// keep last end low; 2 channels max - 2 channels min => 2x2ms - 2x1ms + 
extra length = 2 ms + 1 ms = 3ms => 3000 ticks
         ppm_state = stPPM_FRAME_END; 
// next State
         break;

      case stPPM_FRAME_END:
      default:
         RISING_EDGE_TRIGGER;
         DISABLE_OUTPUT_COMPARE;
         ENABLE_INPUT_CAPTURE;
         SET_TIMER_TO_COMPA_CTC;
         SET_COUNTER_TO_ZERO;
         SET_COMPARE_COUNTER_TO_ZERO;
         SET_CAPTURE_COUNTER_TO_ZERO;
         ppm_state = stPPM_SYNC; 
// next State
         TRIGGER_INPUT_CAPTURE_INTERRUPT;
         break;

   }
   sei();
}
/*-timer1_compare_interrupt--------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  adc_server(void) 
**
**  purpose  :  Handle Analog conversion of RC channel 7, 8 and 9 
**
** 
**
**---------------------------------------------------------------------- 
------*/
//#pragma vector=ADC_vect
//__interrupt void adc_server(void)
ISR(ADC_vect)
{
  unsigned int AdcResult;

  ADC_DISABLE;

  AdcResult = ADC;
  if(AdcResult > 1000) 
// limit conversion value
     AdcResult = 1000; 
// 1000 => 1ms

  ADMUX &= ~(ADC_CHANNEL_MASK); 
// clear channel select bits

  if(adc_channel == ADC_CHANNEL_7)
  {
    channel_7 = AdcResult; 
// set channel 7 value;
    adc_channel = ADC_CHANNEL_8; 
// set next event for channel 8 conversion
  }
  else if(adc_channel == ADC_CHANNEL_8)
  {
    channel_8 = AdcResult; 
// set channel 8 value;
    adc_channel = ADC_CHANNEL_9; 
// set next event for channel 9 conversion
  }
  else
  {
    channel_9 = AdcResult; 
// set channel 9 value;
    adc_channel = ADC_CHANNEL_7; 
// set next event for channel 7 conversion
  }

  ADMUX  |= adc_channel; 
// select new conversion channel

  ADC_ENABLE;
}
/*-adc_server----------------------------------------------------------- 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  check_valid_adc_value(void) 
**
**  purpose  :  wait until 3 ADC channels are processed at least once 
**
**              before init Input Capture/Timer1 
**
** 
**
**---------------------------------------------------------------------- 
------*/
void check_valid_adc_value (void)
{
  unsigned char exit = FALSE;

  do
  {
     if(channel_7 < 0xffff && channel_8 < 0xffff && channel_9 < 0xffff) 
// All three channels must be processed
        exit = TRUE;

  }while (!exit);
}
/*-check_valid_adc_value------------------------------------------------ 
------*/


/*---------------------------------------------------------------------- 
--------
** 
**
**  function :  main(void) 
**
** 
**
**---------------------------------------------------------------------- 
------*/
int main(void)
{

  init_pin();
  init_adc();
  check_valid_adc_value(); 
// wait until both ADC channels are processed at least once
  init_timer1();

  while(1)
  {}
}

/*-main----------------------------------------------------------------- 
------*/


hier main.h

#include <avr/io.h>
#include <inttypes.h>

/* CONSTANTS */
#define TRUE                                      0xFF
#define FALSE                                     0x00

#define CHANNEL_7_ADC                             PORTA1 
// (pin12)
#define CHANNEL_8_ADC                             PORTA2 
// (pin11)
#define CHANNEL_9_ADC                             PORTA3 
// (pin11)
#define PPM_IN                                    PORTA7 
// (pin6)
#define PPM_OUT_PIN                               PORTB2 
// (pin5)

#define ADC_CHANNEL_7                             0x01 
// ADC1 - PORTA1 (pin12)
#define ADC_CHANNEL_8                             0x02 
// ADC2 - PORTA2 (pin11)
#define ADC_CHANNEL_9                             0x03 
// ADC3 - PORTA3 (pin10)
#define ADC_CHANNEL_MASK                          0x03

#define START_PULSE_HIGH                          400 
// [0.4ms]
#define START_PULSE_LOW                           600 
// [0.6ms]
//#define FORCE_LOW_END_FRAME                       2100 
// [2.1ms]
//#define MIN_SYNC_TIME                             2400 
// [2.4ms]
//NEW definition in main.h
#define FORCE_LOW_END_FRAME                       500 
// [0,5ms]
#define MIN_SYNC_TIME                             3000 
// [3.0ms]
#define MAX_SYNC_TIME                             22000 
// total frame time - 8 x min channel frame time = 22ms - 8 x 1ms = 22 - 
8

// minimum channel frame = START_PULSE_HIGH + START_PULSE_LOW = 400 + 
600 counts = 1000 counts = 1ms
// PPM frame length = 22ms = 22000 counts

/**** MACROS 
******************************************************************/

#define SET_PPM_OUT_HIGH                          PORTB  |= 
(1<<PPM_OUT_PIN)
#define SET_PPM_OUT_LOW                           PORTB  &= 
~(1<<PPM_OUT_PIN)

#define FALLING_EDGE_TRIGGER                      TCCR1B &= ~(1<<ICES1)
#define RISING_EDGE_TRIGGER                       TCCR1B |=  (1<<ICES1)

#define SET_COMPARE_COUNTER_TO_ZERO               OCR1A   = 0
#define SET_COUNTER_TO_ZERO                       TCNT1   = 0
#define SET_CAPTURE_COUNTER_TO_ZERO               ICR1    = 0

#define DISABLE_INPUT_CAPTURE                     TIMSK1 &= ~(1<<ICIE1) 
// disable input capture
#define ENABLE_INPUT_CAPTURE                      TIMSK1 |=  (1 << 
ICIE1)       // enable input capture

#define DISABLE_OUTPUT_COMPARE                    TIMSK1 &= ~(1<<OCIE1A) 
// disable Output Compare A Match Interrupt
#define ENABLE_OUTPUT_COMPARE                     TIMSK1 |=  (1<<OCIE1A) 
// enable Output Compare A Match Interrupt

#define TRIGGER_INPUT_CAPTURE_INTERRUPT           TIFR1  |=  (1<<ICF1) 
//
#define CLEAR_INPUT_CAPTURE_INTERRUPT_FLAG        TIFR1  &= ~(1<<ICF1) 
// reset ICF flag

#define TRIGGER_INPUT_COMPARE_INTERRUPT           TIFR1  |=  (1<<OCF1A)

#define SET_TIMER_TO_ICP_CTC                      TCCR1B |=  (1<<WGM13) 
// CTC mode for ICP, prescaler 8 / 8MHz => [1.0us]
#define SET_TIMER_TO_COMPA_CTC                    TCCR1B &= ~(1<<WGM13) 
// CTC mode for COMPA, prescaler 8 / 8MHz => [1.0us]

// clear ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
#define ADC_DISABLE                               ADCSRA &= 
~((1<<ADEN)|(1<<ADSC)|(1<<ADIE))
// set ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
#define ADC_ENABLE                                ADCSRA |= 
(1<<ADEN)|(1<<ADSC)|(1<<ADIE)

/**** END MACROS 
************************************************************************ 
*****/

//#define cli()       __disable_interrupt()
//#define sei()       __enable_interrupt()

von holger (Gast)


Lesenswert?

>aber sie benutzt ein Negatives PPM Signal.Was muss ich
>am Code andern damit es klapt

Den Code so lassen wie er ist. Eine negative Spannungsversorgung
besorgen und einen einfachen invertierenden Verstärker
an den PPM Ausgang hängen.

von Blackbird (Gast)


Lesenswert?

> Eine negative Spannungsversorgung
> besorgen und einen einfachen invertierenden Verstärker
> an den PPM Ausgang hängen.

Nix negative Spannung. Nur einen Inverter, z.B. mit einem Transistor, 
verwenden. Und zwar am Ausgang der zusätzlichen Platine, damit das 
Signal zur anderen Fernsteuerung paßt.
Was noch zu tun wäre, ist am Eingang auch einen Inverter zu schalten, 
damit die Polarität der Abfrage stimmt.

Das ist das Orginal (hier nur 5 Kanäle)?
   ___   _____   ___   _______   ____
__|    |_|     |_|   |_|       |_|     |____________________________

Das ist das das "negative" Signal (nach dem Inverter)?

_      _       _     _         _       ___________________________
  |____| |_____| |___| |_______| |_____|

Blackbird

von Blackbird (Gast)


Lesenswert?

Hätte ich doch als C-Code eingefügen sollen =(

Blackbird

von Klaus (Gast)


Lesenswert?

Willwissen schrieb:
> einbauen möchte aber sie benutzt ein Negatives PPM Signal.Was muss ich
> am Code andern damit es klapt?

Einfach den Programmierer des Codes fragen?

MfG Klaus

von Willwissen (Gast)


Lesenswert?

Das problem ist das es mit einem Inventierer nicht funktioniert ich weiß 
nicht wieso.

von Blackbird (Gast)


Lesenswert?

ZWEI Inverter!


Oder wie Klaus (Gast) schrieb:
-- Frage den Programmierer ---


Blackbird

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.