Pages: [1] 2   Go Down
Author Topic: Attiny 45 38khz flash  (Read 3027 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all

I am new to Arduino and the forum.
I am trying to make a virtual wall for my Roomba robot.
It requires a 38kHz pulse with an IR led.
I managed this with my Arduino uno but I am having problems with my Attiny 45.
I have sucessfully downloaded the LED blink sketch to the Attiny 45 and it is blinking at 1Hz.
When I use the delayMicroseconds function it doesn't flash faster than approximately 100 ms.

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delayMicroseconds(13)               // wait for 13 ms
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delayMicroseconds(13)               // wait for 13 ms
}

Could the problem be that I haven't been able to set the clock frequency to 8 MHz?
Thanks

Logged

Valencia, Spain
Online Online
Faraday Member
**
Karma: 150
Posts: 5668
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could the problem be that I haven't been able to set the clock frequency to 8 MHz?
Thanks

Maybe.

The "Burn bootloader" option in the Tools menu will sets the clock frequency of the chip to whatever's selected as the current board.

Select "Tiny45 8MHz" then do that and you should be running at 8mHz.


OTOH I don't think your program will ever work like that. The loop(), the digitalWrite()s, even the delayMicroseconds(), they all take time to execute.
« Last Edit: December 29, 2012, 03:34:37 pm by fungus » Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

SE USA
Offline Offline
Faraday Member
**
Karma: 41
Posts: 3783
@ssh0le
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

your going from a arduino clocked at 16Mhz to a tiny clocked at 1Mhz, yes that would have an effect on timers, though if you were at 1Mhz it should be more like 200ms
Logged


United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

To generate 38KHz it's better to use one of the timer/counters. I use timer 1 so that timer 0 is still available for supporting the micros() function. This is the code I use:

Code:
void setup()
{
  PORTB = 0;
  DDRB =  0b00000010; // set PB1 (= OCR1A) to be an output
}

// Set the frequency that we will get on pin OCR1A but don't turn it on
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  while ((requiredDivisor + prescalerVal/2)/prescalerVal > 256)
  {
    ++prescalerBits;
    prescalerVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1C = top;
}

// Turn the frequency on
void on()
{
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
}

// Turn the frequency off and turn off the IR LED.
// We let the counter continue running, we just turn off the OCR1A pin.
void off()
{
  TCCR1 &= ~(1 << COM1A0);
}
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Valencia, Spain
Online Online
Faraday Member
**
Karma: 150
Posts: 5668
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe the "tone()" function will work, though I don't know its limitations...

Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

Thanks for all your suggestions, I will try this.

Happy new year!

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

Thanks for the help!
I used the Timer that dc 42 suggested an it worked fine.
I added 1 ms delay in the loop function as below:

void loop() {
 on ();
delay (1);
off ();
delay (1);
}

It worked like a charm as a virtual wall for my Roomba robot.

Thanks again!
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 76
Youtube _Domino SixO
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Can anyone post a Arduino code ???
I need to light up a IR led at 38Khz
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use the code I posted in reply #3. Call setFrequency(38000) to select 38kHz. After that, call on() to start a burst of IR, and off() to stop it.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi All ,

I am trying to port my daikin AC remote control application to Attiny85 , but currently stuck as I am not expert at all.
To switch on AC I need to send the following sequence

Code:
unsigned int power_ON[] ={ 3420 , 1660 , 460 , 1220 , 460 , 380 , 480 , 360 , 500 , 340 , 500 , 1200 , 460 , 380 , 480 , 360 , 460 , 380 , 480 , 360 , 460 , 1240 , 460 , 380 , 460 , 1220 , 460 , 1240 , 480 , 360 , 480 , 1200 , 460 , 1240 , 480 , 1200 , 460 , 1220 , 500 , 1200 , 480 , 360 , 460 , 380 , 500 , 1180 , 500 , 360 , 480 , 360 , 460 , 380 , 480 , 360 , 460 , 380 , 460 , 380 , 460 , 1240 , 460 , 1220 , 480 , 1200 , 500 , 1200 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 480 , 360 , 500 , 360 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , .. , 460 , 1240 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 1220 , 460 , 1240 , 460 , 380 , 460 , 1220 , 460 , 400 , 440 , 400 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , 460 , 380 , ..};

I am using the following code available

// This procedure sends a 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(long microsecs) {
  // we'll count down from the number of microseconds we are told to wait

  cli();  // this turns off any background interrupts

  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
   digitalWrite(IRledPin, HIGH);  // this takes about 3 microseconds to happen
   delayMicroseconds(10);         // hang out for 10 microseconds
   digitalWrite(IRledPin, LOW);   // this also takes about 3 microseconds
   delayMicroseconds(10);         // hang out for 10 microseconds

   // so 26 microseconds altogether
   microsecs -= 26;
  }

  sei();  // this turns them back on
}

void sendDaikinOn()
{

 int i1;
for (i1 = 0; i1 < size_off; i1++)
 {
        pulseIR(power_ON[i1]);
        i1++;
        delayMicroseconds(power_ON[i1]);
 }  
 
}

As per the advice from , dc42 using the following code ,

void setup()
{
  PORTB = 0;
  DDRB =  0b00000010; // set PB1 (= OCR1A) to be an output
  setFrequency(38000) ;
}

// Set the frequency that we will get on pin OCR1A but don't turn it on
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  while ((requiredDivisor + prescalerVal/2)/prescalerVal > 256)
  {
    ++prescalerBits;
    prescalerVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1C = top;
}

// Turn the frequency on
void on()
{
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
}

// Turn the frequency off and turn off the IR LED.
// We let the counter continue running, we just turn off the OCR1A pin.
void off()
{
  TCCR1 &= ~(1 << COM1A0);
}

void loop() {
delay(10000);
sendDaikinOn();
delay(10000);

}


void sendDaikinOn()
{

 int i1;
for (i1 = 0; i1 < size_on; i1++)
 {
      on ();
       delayMicroseconds(power_ON[i1]);
    //    pulseIR(power_ON[i1]);
        i1++;
        off ();
        delayMicroseconds(power_ON[i1]);
 }  
}

But this is not working , can some one please help me on this.

Moderator edit: [code] [/code] tags added.
« Last Edit: February 19, 2014, 01:14:24 pm by Coding Badly » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What clock frequency are running the attiny45 at? Did you set F_CPU in the board definition entry to match that frequency? If you are using the internal 8MHz clock, did you clear the CLKDIV8 fuse in the attiny?
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using external crysal 16mhz and in board definition i set the frquency as 1600000. I could see this clock vlaue when trying to compile the program. I am using arduini editor to compile and load the program.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So have you programmed the fuses in the attiny to use the external crystal and clear the CLKDIV8 fuse?

I normally use the 8MHz internal clock on the attiny. The frequency doesn't need to be precise for 38kHz IR.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you very much for the reply , dc42.  I have programmed the fuses in the attiny to use the external crystal and cleared the CLKDIV8 fuse. Somewhere I read that internal clock is not very precise so that's the reason I have a 16mHx external clock.

In my case I have to send the pulses for 3420 and sleep 1660 and again send pulses for 460 and sleep for 1220 micro seconds.

What is the logic I need to use to send this kind of data using IR transmitter with attiny85.

I used the code available in
http://learn.adafruit.com/ir-sensor?view=all for the arduino , but the same is working for attimy85.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In case it helps, here is code I am using to turn 3 devices on or off when a button is pressed. I build it in AVR Studio, so it doesn't use the Arduino libraries (although I borrowed some code from them), and I use the internal 8MHz oscillator.

Code:
/*
 * RemoteControl.cpp
 *
 * Created: 25/11/2012 12:41:35
 *  Author: David
 */


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define F_CPU (8000000UL) // 8MHz

// Class to hold the data for the IR on/off signal for a particular device
class RemoteData
{
uint16_t headerMarkLength;
uint16_t headerNormalLength;
uint16_t headerRepLength;
uint16_t frequency;
uint16_t bitLength;
uint16_t bitPeriod;
uint32_t burstPeriod;
uint8_t numRepeats;
uint8_t numCycles;
const uint8_t *normalData;
const uint8_t *repeatData;

void generateBurst(bool isRepeat) const;

public:
RemoteData(uint16_t hml, uint16_t hnl, uint16_t hrl, uint16_t f, uint16_t bl, uint16_t bp, uint32_t up,
uint8_t nr, uint8_t nc, const uint8_t* nd, const uint8_t* rd)
: headerMarkLength(hml), headerNormalLength(hnl), headerRepLength(hrl), frequency(f), bitLength(bl), bitPeriod(bp), burstPeriod(up),
numRepeats(nr), numCycles(nc), normalData(nd), repeatData(rd)
{ }

void activate() const;
};

// Data for PVR on/off signal
const uint8_t pvrNormalData[] = {0b11111111, 0b11111011, 0b11111111, 0b11010101, 0b01010101, 0b01000000, 0};
const uint8_t pvrRepeatData[] = {0b10000000, 0};

const RemoteData pvr(9000, 13500, 11100, 38000, 555, 1110, 108000UL, 2, 1, pvrNormalData, pvrRepeatData);

// Data for TV on/off signal
const uint8_t tvNormalData[] = {0b10111111, 0b01011011, 0b11011000, 0};
const uint8_t tvRepeatData[] = {0b10111110, 0b01110110, 0b10101101, 0};

const RemoteData tv(0, 0, 0, 38000, 250, 1060, 66200UL, 1, 3, tvNormalData, tvRepeatData);

// Data for hifi on/off signal
const uint8_t hifiNormalData[] = {0b11110111, 0b01111111, 0b01010110, 0b10110101, 0b01010101, 0b11011111, 0b10101101, 0b01010101, 0};
const uint8_t hifiRepeatData[] = {0b10000000, 0};

const RemoteData hifi(9000, 13500, 13500, 38000, 555, 1120, 108000UL, 2, 1, hifiNormalData, hifiRepeatData);

// Set the frequency that we will get on pin OCR1A but don't turn it on
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  while ((requiredDivisor + prescalerVal/2)/prescalerVal > 256)
  {
    ++prescalerBits;
    prescalerVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1C = top;
}

// Turn the frequency on
void on()
{
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
}

// Turn the frequency off and turn off the IR LED.
// We let the counter continue running, we just turn off the OCR1A pin.
void off()
{
  TCCR1 &= ~(1 << COM1A0);
}

volatile uint32_t timer0_overflow_count = 0; // microseconds timer

// ISR for timer 0, counts microseconds
ISR(TIMER0_OVF_vect)
{
timer0_overflow_count++;
//TIFR |= _BV(TOV0);
}

// ISR for INT0, wakes up from sleep mode when button is pressed
ISR(INT0_vect)
{
GIMSK = 0; // disable INT0
}

// Return the number of microseconds from start
uint32_t micros()
{
uint8_t oldSREG = SREG;
cli();
uint32_t m = timer0_overflow_count;
uint8_t t = TCNT0;

if ((TIFR & (1 << TOV0)) && (t < 255))
{
m++;
}
SREG = oldSREG;

return (m << 8) | t;
}

void RemoteData::generateBurst(bool repeat) const
{
  setFrequency(frequency);
  uint32_t start = micros();
  if (headerMarkLength != 0)
  {
    on();
    while (micros() - start < headerMarkLength) {}
    off();
    uint32_t headerLength = repeat ? headerRepLength : headerNormalLength;
    while (micros() - start < headerLength) {}
  }

  const uint8_t* p = (repeat ? repeatData : normalData);
  uint32_t bitStart = micros();
  for(;;)
  {
    uint8_t b = *p++;
    if (b == 0) break;
    for (uint8_t i = 0; i < 8; ++i)
    {
      if (b & 0x80)
      {
        on();
        while (micros() - bitStart < bitLength) {}
        off();
      }
      while (micros() - bitStart < bitPeriod) {}
      b <<= 1;
      bitStart += bitPeriod;
    }
  }
  while (micros() - start < burstPeriod) {};
}

void RemoteData::activate() const
{
  for (uint8_t c = 0; c < numCycles; ++c)
  {
    generateBurst(false);
    for (uint8_t i = 0; i < numRepeats; ++i)
    {
      generateBurst(true);
    }
  }
}

void setup()
{
PORTB = 0b00011100; // pullup resistor on PB2/3/4 enabled, outputs PB0 and PB1 low
DDRB =  0b00000011; // PB0 and PB1 are outputs, rest are inputs

TCCR0A = 0;
TCCR0B = _BV(CS01); // prescaler = 8 so 1MHz count rate

TIMSK = _BV(TOIE0); // enable timer 0 overflow interrupt
GIMSK = 0;
PCMSK = 0;
}

int main(void)
{
setup();
sei();
for (uint8_t i = 0; i < 6; ++i)
{
uint32_t start = micros();
PORTB ^= 0b00000001; // toggle visible LED
while (micros() - start < 250000UL) {} // wait 0.25 secs before toggling it again
}

    for (;;)
    {
// Wait for button to be pressed
do
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
if (PINB & 0b00000100)
{
GIMSK = _BV(INT0);
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
sei();
uint32_t now = micros();
while ((micros() - now) < 5000) {}
} while (PINB & 0b00000100);

PORTB |= 0b00000001; // turn on visible LED
uint32_t start = micros();

// The TV doesn't always respond to the PVR HDMI signal up unless we activate it a short while before the PVR. So start the TV first and PVR last.
tv.activate();
while (micros() - start < 250000UL) {} // wait until 200ms after we started
hifi.activate();
while (micros() - start < 500000UL) {} // wait until 500ms after we started
pvr.activate();

while (micros() - start < 1000000UL) {} // keep LED on for at least a second

PORTB &= 0b11111110; // turn LED off

// Wait for button to be released
start = micros();
for (;;)
{
uint32_t now = micros();
if (!(PINB & 0b00000100))
{
start = now;
}
else if (now - start >= 5000)
{
break;
}
}
    }
}
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Pages: [1] 2   Go Up
Jump to: