AND gate logic & the ATtiny85 (modulated carrier wave)

Good day all;

I have tried to port 'Modulating a 38 kHz carrier with a 500 Hz signal' (from the Gammon Forum) to the ATtiny85. Needless to say I failed. The timers are different between the Atmega328p and the ATtiny85. My reason for attempting this code port was to experiment with variable gating of a variable carrier wave.

I have two working pieces of code; One for the variable carrier wave function and the second for the variable gating function. The code for both parts (gate & carrier) is written with user definable parameters ie; min & max duty cycles, min & max on/off times, and user selectable Frequency from potentiometers, etc. Both sketches use software to generate the wave function/timing, and both sketches run on an ATtiny85 , no problem.

I have tried other methods to combine the two sketches, but as I learned in another post, we are dealing with a single threaded processor.

I can very easily use two ATtiny85 chips, one for the variable gating sketch and the second ATtiny85 for the variable carrier wave sketch. From there it is very easy to AND gate the two output signals and have my VGCW, (variable gated carrier wave)................ of course this requires 3 ICs. Not very elegant!!!

My question to the experienced Arduino programmers: Is it possible to call an interrupt to modulate a carrier wave using just one ATtiny85?

I have tried to figure out how this could be done by toggling the output pin (Carrier Wave) using an interrupt call. But, I come right back to the two timer timing issue: The variable gate sketch uses one timer and runs independent from the variable carrier wave sketch which of course uses another timer. The problem is compounded by the fact that the two variable signals are software generated.

When the interrupt is called: attachInterrupt(VariableGateoutPin, ToggleoutPinCarrierWave, CHANGE); to toggle the output pin of the carrier wave. At that moment, both the Variable gate signal and the Carrier Wave signal must be running simultaneously. I do not see how to do this with just ONE ATTiny85.

I don't really want to accept defeat, but it would be faster to finish my project with the ATtiny85 x2 & AND gate option.........

Take care, peace mjd

lost_bro: Good day all;

Back at ya.

Is it possible to call an interrupt to modulate a carrier wave using just one ATtiny85?

Yes.

I have two working pieces of code;

Sadly, unposted.

Is it possible to call an interrupt to modulate a carrier wave using just one ATtiny85?

I've seen an ATtiny85 implement an RFID reader. Also emulate a USB keyboard. Also do VGA output. So yes, I think the raw chip can do a lot.

Good day CodeBadly & Nick Gammon.

“Sadly, unposted.”

Sorry!!!

OK, below is the ‘Gating’ funcion:

//////////////////////GATE()loop////////////////////////  
 void GATE() {
  
  vpw = analogRead(pwPin);               // read pw voltage
  vbps = analogRead(bpsPin);             // read bps voltage and calc T and f.
  vgate = analogRead(gatePin)-offThresh; // read gate voltage

  /*
  turn off the coil completely when the voltage
  to the pulse-width is below some threshold (0.02volts)
  */

  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
    }

  else {

    gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depending on offThresh
    

    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
    */


    if (gating < 31) {

      gperiod = (1.0 / gating) * 1000;      // ms

      // Since 31 is a very low frequency, it will not exceed our
      // pulse width at 10% duty cycle, so we just calc ontime in us.

      gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime / 1000; // period in ms
      
      /*
         Now send the output signals  
     */    
      
       //digitalWrite(outPin, HIGH );          // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);             // On
       delayMicroseconds(gateontime);    // delay in us

       //digitalWrite(outPin, LOW);          // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);            // Off
       delay(gateofftime);                     // delay in ms
       
   

    }

    else {
      gperiod = (1.0 / gating) * 1000000; // us

      if (gating > gcritfreq) {
        gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
      }

      else {

        gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
      }

      // Calculate gateofftime, capping the on-time to some max

      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime;  // period in us
      
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);             // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);               // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);            // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);               // Off
      delayMicroseconds(gateofftime);     // delay in us
      

    }
  }

 }

& below is the ‘Carrierwave’ function:

void output() {
  vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0) {
    digitalWrite(outPin, LOW);        // Off
    digitalWrite(ledPin, LOW);        // Off
    delayMicroseconds(100);         // Short delay
  }

  else {

  freq = 1 + (vbps + 2) /2; // frequency varies from 1-290Hz depnding on offThresh
  
  if (freq < 31) {
    period = (1.0 / freq) * 1000;       // ms
    
   
    ontime = 1 + (vpw / 1023.0) * maxontime; // us

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime / 1000; // period in ms

    // Now send the output signals

    digitalWrite(outPin, HIGH);       // On
  // digitalWrite(ledPin, HIGH);      // On debug only
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);       // Off
  // digitalWrite(ledPin, LOW);      // Off debug only
    delay(offtime);                       // delay in ms

  }

  else {

    period = (1.0 / freq) * 1000000; // us

    if (freq > critfreq) {
      ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
    }
    else {
      ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
    }

    // Calculate off-times, capping the on-time to some max

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime;      // period in us

    // Now send the output signals in microseconds

    digitalWrite(outPin, HIGH);       // On
   // digitalWrite(ledPin, HIGH);     // On On debug only
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);        // Off
   // digitalWrite(ledPin, LOW);      // Off On debug only
    delayMicroseconds(offtime);     // delay in us
  }
  }
} 
/////////////////////END////////////////////

These two pieces of code work just fine (separately), no need to change anything with them…

My idea is two combine them using a PCINT1 interrrupt call. This will utilize the ledPin output pin from the ‘Gate’ function. Idealy I want to toggle (output/input) the outpin from the ‘output’ function by means of the PCINT1 interrupt. This should accomplish the ‘gating’ of the carrier wave.

I will post my tentative idea in next post.

I would appreciate any pointers or ‘hints’ as to the simplest way to code this.

take care, peace
mjd

Hello All

OK, here is the code that I have now… I know I have made mistakes with the ISR vector function, but I do get iffy results.

I have attached 2 scope shots of the wannabe gated signal. It is NOT following the Gated() function signal so I know my code is faulty.

*/

int maxontime = 2000;             // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 73;                   // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.30;                    // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;            // Max Gating Duty Cycle

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;

// Create other variables

float gperiod;                                // us
float gateontime ;                         // always us
int critfreq = (1000000 * duty) / maxontime;                           // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ;    // Hertz
float ontime = 0;                         // always us
float offtime = 0;                         // ms or us
float gateofftime = 0;                  // ms or us
float freq;                                   // BPS Hertz
float period;                                // us
float gating;                                // BPS Hertz

// Define pins for ATTiny85

int outPin = 0;     // PhysicalPin 5; P0
int ledPin = 1;     // PP 6; P1   
int gatePin = 3;   // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))            // if pin 1 now HIGH
     {
     PORTB ^= 1<<PB0; ;   // Toggle PB0
     }
 }
 

void setup() 
{                                          // initialize the digital pins as an output:
  pinMode(outPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  DDRB = _BV(PB0);             // PB0 is an output.
  GIFR   |= bit (PCIF);          // clear any outstanding interrupts 
  PCMSK |= 1<<PCINT1;      // Enable pin change interrupt only on PB1 PP6
  GIMSK  |= bit (PCIE);       // enable pin change interrupts 
   
  //sei();
  //PCMSK  |= bit (PCINT1);  // want pin D1 / PP 6
  
}
///////////////////////Main()loop/////////////////////////
void loop() 
{
   GATE();
   carrierwave();
}   
//////////////////////GATE()loop////////////////////////  
 void GATE() 
 {
  
  vpw = analogRead(pwPin);                     // read pw voltage
  vbps = analogRead(bpsPin);                   // read bps voltage and calc T and f.
  vgate = analogRead(gatePin)-offThresh; // read gate voltage

  /*
  Turn off the coil completely when the voltage
  to the pulse-width is below some threshold (0.02volts)
  */

  if (vgate < 0) {
    digitalWrite(outPin, LOW);       // Off
    digitalWrite(ledPin, LOW);       // Off
    delayMicroseconds(100);         // Short delay
    }

  else {

    gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depnding on offThresh
    

    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
    */


    if (gating < 31) {

      gperiod = (1.0 / gating) * 1000;      // ms

      // Since 31 is a very low frequency, it will not exceed our
      // pulse width at 10% duty cycle, so we just calc ontime in us.

               gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
     
      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime / 1000; // period in ms
      
      /*
         Now send the output signals  
     */    
      
      // digitalWrite(outPin, HIGH );         // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);            // On
       delayMicroseconds(gateontime);    // delay in us

      // digitalWrite(outPin, LOW);          // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);            // Off
       delay(gateofftime);                     // delay in ms
       
   

    }

    else {
      gperiod = (1.0 / gating) * 1000000; // us

      if (gating > gcritfreq) {
        gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
      }

      else {

        gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
      }

      // Calculate gateofftime, capping the on-time to some max

      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime;  // period in us
      
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);            // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);               // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);            // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);               // Off
      delayMicroseconds(gateofftime);     // delay in us
    }
  }
}

////////////carrierwave()LOOP///////////////

 void carrierwave() {
  
   vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0) {
    digitalWrite(outPin, LOW);       // Off
    digitalWrite(ledPin, LOW);       // Off
    delayMicroseconds(100);         // Short delay
  }

  else {

  freq = 1 + (vbps + 2) /2;         // frequency varies from 1-290Hz depending on offThresh
 
  if (freq < 31) {
    period = (1.0 / freq) * 1000;       // ms
    
   
    ontime = 1 + (vpw / 1023.0) * maxontime; // us

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime / 1000; // period in ms

    // Now send the output signals

    digitalWrite(outPin, HIGH);       // On
  // digitalWrite(ledPin, HIGH);      // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);       // Off
  // digitalWrite(ledPin, LOW);      // Off
    delay(offtime);                       // delay in ms

  }

  else {

    period = (1.0 / freq) * 1000000; // us

    if (freq > critfreq) {
      ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
    }
    else {
      ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
    }

    // Calculate off-times, capping the on-time to some max

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime;        // period in us

    // Now send the output signals in microseconds

    digitalWrite(outPin, HIGH);       // On
   // digitalWrite(ledPin, HIGH);     // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);        // Off
   // digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(offtime);     // delay in us
    } 
  }
} 
/////////////////////END////////////////////

This is my first attempt at interrupts, and would appreciate any & all constructive comments.
I need to learn how this works!!!

take care, peace
mjd

ISR (PCINT0_vect) 
{
  if (PINB & bit (1))            // if pin 1 now HIGH
  {
    PORTB ^= 1<<PB0; 
    ;   // Toggle PB0
  }
}

Can you write this more consistently? You are toggling the pin, right? Only if it is currently high? Like:

ISR (PCINT0_vect) 
{
  if (PINB & bit (1))            // if pin 1 now HIGH
  {
    PORTB ^= bit (1);      
  }
}

Probably better is to use the built-in toggle:

ISR (PCINT0_vect) 
{
  if (PINB & bit (1))            // if pin 1 now HIGH
  {
    PINB = bit (1);      
  }
}

BTW PB0 is bit (0) not bit (1).

Good day Nick G.

Thanks for taking the time to check out my code.

BTW PB0 is bit (0) not bit (1).

Yes, bit(0), PB0 is physical pin #5 on the ATtiny85 and bit(1), PB1 is pp #6.

This code is actually my first sketch that I have attempted to write for an Arduino. So I will probably make some major mistakes with my logic.

Basically what I want to do with this ISR vect. function is to have the interrupt trigger off of ‘ledPin’ PB1 (pp#6) which is controlled by the -Gate()- function.

Once triggered, the ISR vect. will then toggle pp #5. PB0 , bit(0) between input and output modes. PP #5, PB0, bit(0) is the output pin for -carrierwave()- function.

The reason that I want to toggle between output and input mode for bit(0) is because I do NOT want a ‘HIGH’ / ‘LOW’ signal upon toggle. My intention is to have the -carrierwave()- function output be switched ON / OFF or gated.

I suppose that to do this correctly, the code must toggle two times during each wave period. Once when the wave/signal == HIGH and again when wave/signal == LOW. If it toggles on ONLY a Rising or Falling edge, that would equate to only ONCE each wave period effectively cutting the Gate frequency in half by doubling the period. Actually I could make this scenario work by doubling the Gate frequency from the get-go, but then my programed min/max duty cycles and periods would have to modified accordingly also…

Triggering the toggle on BOTH Rising & Falling edges would work equally as well, but I can’t find any examples of that for an ATtiny85.

I have tried the same approach with:

void loop() {
  
   GATE();
   carrierwave();
 
 if (bitRead(PORTB,PB1)== 1) {                
     PORTB ^= (1 << PB0);           // toggle outPin PB0, PP5; 
  }
}   
//

This code will toggle PB0, pp#5 to HIGH, but does not allow toggling of the -carrierwave()- through PB0. Just gives a HIGH signal.

I will change your code to: (hope I got it right…bit(0) == PB0?)

ISR (PCINT0_vect) 
{
  if (PINB & bit (1))            // if pin 1 now HIGH
  {
    PINB = bit (0);             // toggle PB0, pp #5 (carrierwave())
  }
}

I will try your suggestions as soon as I get a chance and report back with the results. (just got back home from work today…)

take care, peace
mjd

Triggering the toggle on BOTH Rising & Falling edges would work equally as well, but I can't find any examples of that for an ATtiny85.

What do you mean? The pin-change interrupts fire on rise and fall, so all you have to do is toggle the other pin then.

Hello Nick G Thanks for the answer, OK.

'CHANGE, RISING, and FALLING from a pin change interrupt..."

So CHANGE will trigger on both conditions: RISING & FALLING.

I was under the mistaken impression that CHANGE would read the change between HIGH & LOW states.

Well, between the HIGH and LOW state we have a FALLING edge and between a LOW and HIGH state we have a RISING edge. So I guess it is the same thing, triggering on both RISING & FALLING edges.

Thanks for clearing that up.....

OK, so will : PINB = bit (0); toggle or switch the state of PB0 to and from output / input? Is this the same as toggling PB0 on and off?

I guess what I want to know is if I am barking up the wrong tree with this line of thought concerning gating of the carrierwave()?

As soon as I test the last code I will report back. Thanks and have a great evening. take care, peace mjd

Look at the datasheet. Writing to PINx (not PORTx) toggles it.

Hello Nick G & all

Well I have remade the code according the suggestions and have posted it below:

int maxontime = 2000;          // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 73;            // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.30;             // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;         // Max Gating Duty Cycle

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;
// Create other variables

float gperiod;          // us
float gateontime ;      // always us
int critfreq = (1000000 * duty) / maxontime; // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ; // Hertz
float ontime = 0;      // always us
float offtime = 0;     // ms or us
float gateofftime = 0; // ms or us
float freq;               // BPS Hertz
float period;           // us
float gating;           // BPS Hertz

// Define pins for ATTiny85

int outPin = 0;     // PhysicalPin 5; P0
int ledPin = 1;     // PP 6; P1   
int gatePin = 3;   // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))  // if pin 1 now HIGH
     {
     PINB = bit (0);   // toggle PB0
     }
 }
 

void setup() 
{ // initialize the digital pins as an output:
  pinMode(outPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  DDRB = _BV(PB0);               // PB0 is an output. 
  GIMSK |= 1<<PCIE;            // Enable pin change interrupts
  PCMSK |= 1<<PCINT1;        // Enable pin change interrupt on pin 1
  GIFR   |= bit (PCIF);            // clear Pin Change interrupt Flag
  
}
///////////////////////Main()loop/////////////////////////
void loop() 
{
   GATE();
   carrierwave();
}   
//////////////////////GATE()loop////////////////////////  
 void GATE() 
 {
  
  vpw = analogRead(pwPin);               // read pw voltage
  vbps = analogRead(bpsPin);             // read bps voltage and calc T and f.
  vgate = analogRead(gatePin)-offThresh; // read gate voltage

  /*
  Turn off the coil completely when the voltage
  to the pulse-width is below some threshold (0.02volts)
  */

  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
    }

  else {

    gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depnding on offThresh
    

    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
    */


    if (gating < 31) {

      gperiod = (1.0 / gating) * 1000;      // ms

      // Since 31 is a very low frequency, it will not exceed our
      // pulse width at 10% duty cycle, so we just calc ontime in us.

               gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
     
      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime / 1000; // period in ms
      
      /*
         Now send the output signals  
     */    
      
      // digitalWrite(outPin, HIGH );    // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);       // On
       delayMicroseconds(gateontime);    // delay in us

      // digitalWrite(outPin, LOW);      // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);        // Off
       delay(gateofftime);               // delay in ms
       
   

    }

    else {
      gperiod = (1.0 / gating) * 1000000; // us

      if (gating > gcritfreq) {
        gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
      }

      else {

        gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
      }

      // Calculate gateofftime, capping the on-time to some max

      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime;  // period in us
      
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);       // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);         // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);        // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);          // Off
      delayMicroseconds(gateofftime);     // delay in us
    }
  }
}

////////////carrierwave()LOOP///////////////

 void carrierwave() {
  
   vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
  }

  else {

  freq = 1 + (vbps + 2) /2; // frequency varies from 1-290Hz depnding on offThresh
  // This is also why we divide by 3 (from 1023)
  if (freq < 31) {
    period = (1.0 / freq) * 1000;       // ms
    
   
    ontime = 1 + (vpw / 1023.0) * maxontime; // us

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime / 1000; // period in ms

    // Now send the output signals

    digitalWrite(outPin, HIGH);     // On
  // digitalWrite(ledPin, HIGH);     // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);      // Off
  // digitalWrite(ledPin, LOW);      // Off
    delay(offtime);                 // delay in ms

  }

  else {

    period = (1.0 / freq) * 1000000; // us

    if (freq > critfreq) {
      ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
    }
    else {
      ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
    }

    // Calculate off-times, capping the on-time to some max

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime;      // period in us

    // Now send the output signals in microseconds

    digitalWrite(outPin, HIGH);     // On
   // digitalWrite(ledPin, HIGH);     // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);      // Off
   // digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(offtime);     // delay in us
    } 
  }
} 
/////////////////////END///////////////////////////

The ISR vect. interrupt is toggling on the ledPin as expected.

But is only running the carrierwave() function ONE TIME per cycle.

Now I need to make the carrierwave() function run for the ENTIRE period of Marktime (time when the gate signal is HIGH). As of now it triggers and runs ONCE only and then WAITS until the next ISR vect. interrupt to trigger again and so on…

Running the carrierwave() function only once does NOT effectively gate the signal. It only serves to fire ONE pulse each period INSTEAD of a series of pulses. ( a series of pulses each period would constitute one gate cycle’s MarkTime).

Apparently the code is NOT structured correctly to do this.

Is there a command as such to do this, or is it that the sequence is wrong with the code?

I have tried many variations now, and the best I can do is Run Once each Marktime.

How do I code with the ISR vect. interrupt:

If Gate() function signal == HIGH then continually re-run carrierwave() until Gate() == LOW;?

This seems to me that Timer0 and Timer1 must be setup independently to pull this off.

I would appreciate pointers as I really want to understand what is happening here.

Thanks
take care, peace.
mjd

I have posts about modulating 38 kHz on my timers page:

http://www.gammon.com.au/timers

Good day Nick G

Thanks for posting the link:

Yes, It was your website that started this thread:

"Good day all;

I have tried to port ‘Modulating a 38 kHz carrier with a 500 Hz signal’ (from the Gammon Forum) to the ATtiny85.
Needless to say I failed. The timers are different between the Atmega328p and the ATtiny85.
My reason for attempting this code port was to experiment with variable gating of a variable carrier wave…"

My original idea was to adapt your code for ‘Modulating a 38 kHz carrier with a 500 Hz signal’ to use on my ATtiny85. I was going to use your code as a template for my project. But I couldn’t make the code run on the ATTiny85.

In my code, the carrierwave() function has adjustable and pre programmed features that make it variable. Likewise the GATE() function also has adjustable features that I don’t want to lose.

Here is my attempt to use your template with my functions:

int maxontime = 2000;             // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 83;                   // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.30;                    // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;            // Max Gating Duty Cycle

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;
// Create other variables

float gperiod;          // us
float gateontime ;      // always us
int critfreq = (1000000 * duty) / maxontime; // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ; // Hertz
float ontime = 0;      // always us
float offtime = 0;     // ms or us
float gateofftime = 0; // ms or us
float freq;            // BPS Hertz
float period;          // us
float gating;          // BPS Hertz

// Define pins for ATTiny85

int outPin = 0;    // PhysicalPin 5; P0
int ledPin = 1;    // PP 6; P1
int gatePin = 3;   // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

ISR (PCINT0_vect) 
 {
                                                   // if pin 1 now high, turn on toggling of OC1A on compare
   if (PINB & bit (1))                      //MAKE LOW not HIGH!!!!!
     {
     TCCR1 |= bit (0) ;               // Toggle OC1A on Compare Match
     }    
   else
     {
     TCCR1 &= ~bit (0) ;           // DO NOT Toggle OC1A on Compare Match
       digitalWrite (outPin, LOW);   // ensure off
     }  
 }
 

void setup() {
                                         // initialize the digital pins as an output:
  pinMode(outPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
   
                                        // pin change interrupt (example for D1)
  PCMSK  |= bit (PCINT1);  // want pin D1 / PP 6
  GIFR   |= bit (PCIF);        // clear any outstanding interrupts
  GIMSK  |= bit (PCIE);      // enable pin change interrupts 
 
}
///////////////////////Mainloop/////////////////////////
void loop() {
  
   GATE();
   carrierwave();
  
}   
//////////////////////GATE()loop////////////////////////  
 void GATE() {
  
  vpw = analogRead(pwPin);               // read pw voltage
  vbps = analogRead(bpsPin);             // read bps voltage and calc T and f.
  vgate = analogRead(gatePin)-offThresh; // read gate voltage

  /*
   Turn of the coil completely when the voltage
  to the pulse-width is below some threshold.
  */

  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
    }

  else {

    gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depending on offThresh
    

    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
    */


    if (gating < 31) {

      gperiod = (1.0 / gating) * 1000;      // ms

      // Since 31 is a very low frequency, it will not exceed our
      // pulse width at 10% duty cycle, so we just calc ontime in us.

      gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime / 1000; // period in ms
      
      /*
         Now send the output signals  
     */    
      
       //digitalWrite(outPin, HIGH );    // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);       // On
       delayMicroseconds(gateontime);    // delay in us

       //digitalWrite(outPin, LOW);      // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);        // Off
       delay(gateofftime);               // delay in ms
       
   

    }

    else {
      gperiod = (1.0 / gating) * 1000000; // us

      if (gating > gcritfreq) {
        gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
      }

      else {

        gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
      }

      // Calculate gateofftime, capping the on-time to some max

      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime;  // period in us
      
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);       // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);         // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);        // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);          // Off
      delayMicroseconds(gateofftime);     // delay in us
      

    }
  }

 }

////////////carrierwave()LOOP///////////////

 void carrierwave() {
 
 vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
  }

  else {

  freq = 1 + (vbps + 2) /2; // frequency varies from 1-290Hz depnding on offThresh
  // This is also why we divide by 3 (from 1023)
  if (freq < 31) {
    period = (1.0 / freq) * 1000;       // ms
    
   
    ontime = 1 + (vpw / 1023.0) * maxontime; // us

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime / 1000; // period in ms

    // Now send the output signals

    digitalWrite(outPin, HIGH);     // On
  // digitalWrite(ledPin, HIGH);     // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);      // Off
  // digitalWrite(ledPin, LOW);      // Off
    delay(offtime);                 // delay in ms

  }

  else {

    period = (1.0 / freq) * 1000000; // us

    if (freq > critfreq) {
      ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
    }
    else {
      ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
    }

    // Calculate off-times, capping the on-time to some max

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime;      // period in us

    // Now send the output signals in microseconds

    digitalWrite(outPin, HIGH);     // On
   // digitalWrite(ledPin, HIGH);     // On
    delayMicroseconds(ontime);      // delay in us

    digitalWrite(outPin, LOW);      // Off
   // digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(offtime);     // delay in us
  }
  }
}

I still get the same result… One pulse per period.

I would really appreciate if any pointers can be given related to the posted code.

I know that is most probably a stupid mistake on my part, and really want to understand what this mistake is.

I mean I could have already finished this project with a simple AND gate and another $1.00 ATtiny85…
But that would defeat the point of posting all this code and spending almost two weeks on this.

Open to any and all comments/suggestions.

Thanks
take care, peace
mjd

Hello All

OK, finally found one of the problems with the code:

PINx is only to READ a value; NOT to write a bit…
PORTx is used to write or change or set the bit.

*/
#include <avr/io.h>
#include <avr/interrupt.h>
/*
User definable variables here - this is all you need to adjust!
*/

int maxontime = 2000;          // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 73;            // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.50;             // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;         // Max Gating Duty Cycle

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;
// Create other variables

float gperiod;          // us
float gateontime ;      // always us
int critfreq = (1000000 * duty) / maxontime; // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ; // Hertz
float ontime = 0;      // always us
float offtime = 0;     // ms or us
float gateofftime = 0; // ms or us
float freq;            // BPS Hertz
float period;          // us
float gating;          // BPS Hertz

// Define pins for ATTiny85

int outPin = 0;    // PhysicalPin 5; P0
int ledPin = 1;    // PP 6; P1   //int gatePin = 3;   // PP 2; P3
int gatePin = 3;   // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))  // if pin 1 now HIGH
     {
     PORTB |= (1<<0);  // set bit 0 in PORTD to 1// DDRB |= (1<<0);
     }
   else 
     {
     PORTB &= ~(1<<0); //  set bit 0 in PORTD to 0// DDRB &= ~(1<<0);
     }
 }
 

void setup() 
{ 
  // initialize the digital pins as an output:
  pinMode(outPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  GIMSK |=bit(PCIE);          // Enable pin change interrupts
  PCMSK |=bit(PCINT1);        // Enable pin change interrupt on pin 1
  GIFR  |=bit(PCIF);          // clear Pin Change interrupt Flag
}
///////////////////////Main()loop/////////////////////////
void loop() 
{
  GATE();
  carrierwave();
}   
//////////////////////GATE()loop////////////////////////  
 void GATE() 
{
    vpw = analogRead(pwPin);               // read pw voltage
    vbps = analogRead(bpsPin);             // read bps voltage and calc T and f.
    vgate = analogRead(gatePin)-offThresh; // read gate voltage

  /*
  Turn off the coil completely when the voltage
  to vgate is below threshold.
  */
  

  if (vgate < 0) 
    {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
    }
  
    else 
      {
      gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depnding on offThresh
    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
      */
     if (gating < 31) \
     {
       gperiod = (1.0 / gating) * 1000;      // ms
        // Since 31 is a very low frequency, it will not exceed our
        // pulse width at 10% duty cycle, so we just calc ontime in us.
       gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
       
        if (gateontime < gateminontime) 
        {
          gateontime = gateminontime;
        }
          gateofftime = gperiod - gateontime / 1000; // period in ms
      /*
         Now send the output signals  
     */    
       // digitalWrite(outPin, HIGH );    // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);       // On
       delayMicroseconds(gateontime);    // delay in us

      // digitalWrite(outPin, LOW);      // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);        // Off
       delay(gateofftime);               // delay in ms
    }
    
        else 
        {
          gperiod = (1.0 / gating) * 1000000; // us
    
          if (gating > gcritfreq) 
          {
           gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
          }
      
            else 
            {
             gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
            }
      
            // Calculate gateofftime, capping the on-time to some max
        
              if (gateontime < gateminontime)
              {
               gateontime = gateminontime;
              }
               gateofftime = gperiod - gateontime;  // period in us
              
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);       // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);         // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);        // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);          // Off
      delayMicroseconds(gateofftime);     // delay in us
    }
  }
}

////////////carrierwave()LOOP///////////////

 void carrierwave() 
{
  vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0) 
  {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
  }

    else 
      {
        freq = 1 + (vbps + 2) /2; // frequency varies from 1-290Hz depnding on offThresh
      // This is also why we divide by 3 (from 1023)
       if (freq < 31) 
       {
         period = (1.0 / freq) * 1000;       // ms
         ontime = 1 + (vpw / 1023.0) * maxontime; // us
    
         if (ontime > maxontime) 
         {
          ontime = maxontime;
         }
          offtime = period - ontime / 1000; // period in ms
    
        // Now send the output signals
    
        digitalWrite(outPin, HIGH);     // On
      // digitalWrite(ledPin, HIGH);     // On
        delayMicroseconds(ontime);      // delay in us
    
        digitalWrite(outPin, LOW);      // Off
      // digitalWrite(ledPin, LOW);      // Off
        delay(offtime);                 // delay in ms
       }
    
      else
      {
        period = (1.0 / freq) * 1000000; // us
        if (freq > critfreq) 
        {
          ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
        }
          else 
          {
            ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
          }
    
        // Calculate off-times, capping the on-time to some max
      
          if (ontime > maxontime)
          {
            ontime = maxontime;
          }
            offtime = period - ontime;      // period in us
      
        // Now send the output signals in microseconds
    
        digitalWrite(outPin, HIGH);     // On
       // digitalWrite(ledPin, HIGH);     // On
        delayMicroseconds(ontime);      // delay in us
    
        digitalWrite(outPin, LOW);      // Off
       // digitalWrite(ledPin, LOW);      // Off
        delayMicroseconds(offtime);     // delay in us
      } 
    }
  } 
/////////////////////END///

By making those changes in the code I now have the following results. Please see attached o-scope shots;

We can clearly see the desired effect beginning to happen. The GATE() function is now controlling the ouput PB0 of the carrierwave() function. The output is precisely following GATE() function signal, but…

My question is :

Why is it only letting the carrierwave() function pass through the output of PB0 for ONLY one to 4 cycles and then for the remainder of the period, the output from PB0 goes HIGH, ie; with carrier modulation.

When the output on PB0 is enabled, it should allow the carrierwave() function waveform to modulate the ENTIRE Marktime (HIGH) period.

This can be seen from the attached 0-scope shots.

I still am missing a crucial part to the puzzle.

I hope someone with more experience can point me in the correct direction with this.

Thanks in advance

take care, peace
mjd

lost_bro: OK, finally found one of the problems with the code:

PINx is only to READ a value; NOT to write a bit............... PORTx is used to write or change or set the bit.

I wouldn't have suggested using PINx if it didn't change the bit. See the datasheet:

10.2.2 Toggling the Pin

Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.

It's there in black and white. Writing (a one bit) to the PINx pin toggles it.

Writing zero does nothing. So for example:

PINB = 0b00110001;

That toggles 3 bits, and leaves the others alone.

Hello Nick G

You are correct, and I stand corrected.
There is a lot of bogus information on the net also… you can’t believe everything you Google.

OK< with this code the ISR triggers on PB1 and gives a LOW on the output pin PB0.
And this is exactly what the code says it will do , correct?

ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))  // if pin 1 now HIGH
     {
     PINB = 0b00000001;;  // toggle PB0
     }
 }

But I do not want a simple HIGH or LOW on PB0, I need for it to turn on / off the carrierwave() signal that is running through PB0.

Apparently the above code as I have it configured overides the carrier wave with a HIGH signal. This is what I see on the o-scope.

What am I doing wrong with this code?

Thanks in advance.
take care, peace
mjd

Hello Nick G & All;

OK; I have re written the ISR code to run the carrierwave() function upon interrupt:

ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))                                        // if pin 1 now HIGH (during GATE() Marktime)
   {
     for (int x = 0; x <carrierwaveCount; x++) // run carrierwave() loop funtion 
     {                                                            // until carrierwavecount reached
      carrierwave();
     } 
   }
 }

I have made carrierwavecount a user changeable variable, so the final number of carrierwave pulses within the GATE() function are controlled.

This is not how I envisioned the ISR to function.
I originally wanted to just use the ISR to gate the carrierwave() function, the analogy of an AND logic gate function instead of having to run another function.
When both GATE() & carrierwave() are (1) then output PB0 will be (1), but modulated at the frequency of the carrierwave() function.

I now have the ATtiny85 taking analogRead from 3 potentiometers and outputing a highly user definable gated output signal.

But I still would like to understand what I am doing wrong with the code regarding directly gating a port/pin PB0 on the ATtiny85? Any suggestions as to what is wrong?

thanks

take care, peace
mjd

Your code does not resemble what I referred you to in my earlier post. (Here for reference):

// Example of modulating a 38 kHz carrier frequency at 500 Hz with a variable duty cycle
// Author: Nick Gammon
// Date: 24 September 2012


const byte POTENTIOMETER = A0;
const byte LED = 9;  // Timer 1 "A" output: OC1A

// Clock frequency divided by 500 Hz frequency desired (allowing for prescaler of 128)
const long timer2_OCR2A_Setting = F_CPU / 500L / 128L;

ISR (PCINT2_vect)
   {
    
   // if pin 3 now high, turn on toggling of OC1A on compare
   if (PIND & bit (3))
     {
     TCCR1A |= bit (COM1A0) ;  // Toggle OC1A on Compare Match
     }
   else
     {
     TCCR1A &= ~bit (COM1A0) ;  // DO NOT Toggle OC1A on Compare Match
     digitalWrite (LED, LOW);  // ensure off
     }  // end of if
     
   }  // end of PCINT2_vect


void setup() {
  pinMode (LED, OUTPUT);
  pinMode (3, OUTPUT);  // OC2B
  
  // set up Timer 1 - gives us 38.095 kHz
  TCCR1A = 0; 
  TCCR1B = bit(WGM12) | bit (CS10);   // CTC, No prescaler
  OCR1A =  (F_CPU / 38000L / 2) - 1;  // zero relative
  
  // Timer 2 - gives us our 1 mS counting interval
  // 16 MHz clock (62.5 nS per tick) - prescaled by 128
  //  counter increments every 8 uS. 
  // So we count 250 of them, giving exactly 2000 uS (2 mS period = 500 Hz frequency)
  TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1);   // Fast PWM mode
  TCCR2B = bit (WGM22) | bit (CS20) | bit (CS22) ;  // prescaler of 128
  OCR2A  = timer2_OCR2A_Setting - 1;                // count up to 250  (zero relative!!!!)
  
  // pin change interrupt
  PCMSK2 |= bit (PCINT19);  // want pin 3
  PCIFR  |= bit (PCIF2);    // clear any outstanding interrupts
  PCICR  |= bit (PCIE2);    // enable pin change interrupts for D0 to D7
  
}  // end of setup

void loop()
  {
  // alter Timer 2 duty cycle in accordance with pot reading
  OCR2B = (((long) (analogRead (POTENTIOMETER) + 1) * timer2_OCR2A_Setting) / 1024L) - 1;

  // other stuff here
  }  // end of loop

In that I used a hardware timer to generate the 38 kHz and merely switched the output of the hardware on and off in the ISR. Now this isn't for an ATtiny85, but I would expect only minor modifications to allow for the different registers.

Good Evening Nick G

Thanks for taking the time to assist sorting out this code.

OK, I have re-written the ISR to follow your code example:

) 
ISR (PCINT0_vect) 
 {
   if (PINB & bit (1))  // if pin 1 now HIGH
     {
     TCCR1 |= bit (COM1A0) ;  // Toggle OC1A on Compare Match
     }
   else 
     {
     TCCR1 &= ~bit (COM1A0) ;  // DO NOT Toggle OC1A on Compare Match
     }
 }

This runs the interrupt and only gives ONE pulse/period and then runs a group of pulses @ 145kHz. In other words it appears that the carrierwave() function is only running once per/ interrupt followed by a faster 145kHz PWM square wave. This fast pwm squarewave is NOT part of the carrierwave() function. This is probably related to the fact that your code uses hardware timer pwm and my code is software driven pwm. Your hardware timer pwm is constantly running in the background and my software pwm only runs when called?

I need to know which timer is running my software pwm, that is not specified in my code. Just to experiment, I tried to interrupt the other timer accordingly to no result.

I am open for further suggestions. thanks

take care, peace mjd