Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
MegaUSBFreak
PostPosted: May 18, 2006 - 10:20 AM
Raving lunatic


Joined: Aug 21, 2004
Posts: 2226
Location: germany

Hi,

never though of that - but you´re right.

Just thinking how to workaround this. Maybe checking the timer´s counter value and output to port when it changes the state the next time.
Or setting the AVR to sleep BEFORE the interrupt...

_________________
Klaus
********************************
Look at: www.megausb.de (German)
********************************
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
bobgardner
PostPosted: May 18, 2006 - 05:34 PM
10k+ Postman


Joined: Sep 04, 2002
Posts: 13610
Location: Orlando Florida

Everyone always tries to use hw timers and interrupts. Its soooo easy to just turn on the output, delay desired usec, turn off the output, delay 20ms, repeat. There it is. 4 lines of code. Sheesh.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
intx13
PostPosted: May 18, 2006 - 05:56 PM
Newbie


Joined: May 14, 2006
Posts: 15


Bobgardner... it can be that easy, but that's not really usable for 8 channels with other code running to generate the outputs on those pins. The goal, I think, it to come up with some configurable code that can be plugged into a program to use software PWMs. That means the user (in a perfect world) provides the code with the desired base frequency, the desired pulse widths of each pin, and the code sets up the timer, converts the pulse width (in terms of hte users chosen resolution) into an actual timer count, and manages turning the pin on and off. If you can do that in four lines...
 
 View user's profile Send private message  
Reply with quote Back to top
Powersoft
PostPosted: May 18, 2006 - 09:06 PM
Rookie


Joined: Mar 31, 2006
Posts: 23


Here is an example of a three channel PWM in software. The code is a PWM-loop that call a subroutine in between the delays at "special" time. Also the PWM loop must run at constant frequency.

The subroutine is calculating all necessary data for the PWM, like the delays T2, T3, the pin output data and so on. But the whole idea is that the subroutine also "know" (based on the calculations) the greatest delays in the pulse that make room for calling the next subroutine.

Code:

PWM:      OUT PORTB,D0

Dly1:        INC T1

      BRNE Dly1

      OUT PORTB,D1

      SBRC STE_Cpy,1

      RCALL PROC

Dly2:   DEC T2_Cpy

      BRNE Dly2

      OUT PORTB,D2_Cpy

      SBRC STE_Cpy,2

      RCALL PROC

Dly3:   DEC T3_Cpy

      BRNE Dly3

      OUT PORTB,D3

      SBRS STE_Cpy,0

      RCALL PROC

Dly4:   INC T4_Cpy

      BRNE Dly4



      MOV T2_Cpy,T2

      MOV T3_Cpy,T3

      MOV T4_Cpy,T4

      MOV D2_Cpy,D2

      MOV STE_Cpy,STE



      RJMP PWM
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: May 20, 2006 - 08:56 AM
Posting Freak


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden

Here some code (avr-gcc) I have used for servos (not generic PWM). It does need a 16-bit timer output compare but the timer is free running and can be used for other tasks (like input capture). I have run it as shown here on mega16, mega128 and tiny2313.

Jitter will depend on how much cli/sei is needed and what other interrupts are doing. I have also noticed there is a lot more jitter when using the internal RC Oscillator on some avr models e.g., this test program on a tiny2313 has ~1µs jitter with a 8MHz crystal and ~5µs with the internal oscillator at 8Mhz.

/Lars

Code:
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>


#define SERVO_PORT  PORTB
#define SERVO_DDR   DDRB

// Upto 8 servos (since pulses are generated in
// sequence + only one port is used).
#define N_SERVOS    8

// Servo times (this is Futaba timing).
#define SERVO_MIN    920 // µs
#define SERVO_MAX   2120 // µs
#define SERVO_MID   (SERVO_MIN + SERVO_MAX) / 2

// Time between servo pulses. 
#define SERVO_FRAME 20000 // µs (50Hz)

// Time slot available for each servo.
#define SERVO_TIME_DIV (SERVO_FRAME / N_SERVOS)

#if (SERVO_TIME_DIV < SERVO_MAX + 50)
#warning "Output fewer servo signals or increase SERVO_FRAME"
#endif
#if ((SERVO_TIME_DIV * (F_CPU / 1000000UL)) >= 0xFF00)
#warning "Output more servo signals or decrease SERVO_FRAME (or use the prescaler)"
#endif

// Computing timer ticks given µs.
// Note, this version works out ok with even MHz F_CPU (e.g., 1, 2, 4, 8, 16 MHz).
// (Not a good idea to have this end up as a floating point operation)
#define US2TIMER1(us) ((us) * (uint16_t)(F_CPU / 1E6))

// Servo times - to be entered as timer1 ticks (using US2TIMER1).
// This must be updated with interrupts disabled.
volatile uint16_t servoTime[N_SERVOS];

// Servo output allocation (on a single port currently).
const static uint8_t servoOutMask[N_SERVOS] = {
    0b00000001, // PX0
    0b00000010, // PX1
    0b00000100, // PX2
    0b00001000, // PX3
    0b00010000, // PX4
    0b00100000, // PX5
    0b01000000, // PX6
    0b10000000, // PX7
};
// Servo mask is just the above masks ored.
#define SERVO_MASK 0xff

void servoStart(void)
{
    // Outputs
    SERVO_DDR |= SERVO_MASK;
    // Setupt a first compare match
    OCR1A = TCNT1 + US2TIMER1(100);
    // start timer 1 with no prescaler
    TCCR1B = (1 << CS10);      
    // Enable interrupt
    TIMSK |= (1 << OCIE1A);
}

void servoSet(uint8_t servo, uint16_t time /* µs */)
{
    uint16_t ticks = US2TIMER1(time);
    cli();
    servoTime[servo] = ticks;
    sei();
}

int main(void)
{
    // Some test times
    uint8_t i;
    for(i = 0; i < N_SERVOS; i++) {
        servoTime[i] = US2TIMER1(SERVO_MID);
    }
#if N_SERVOS > 2   
    servoTime[2] = US2TIMER1(SERVO_MIN);
#endif
    servoTime[N_SERVOS-1] = US2TIMER1(SERVO_MAX);
   
    servoStart();
    sei();
   
    while(1) {
        uint16_t time;
        uint8_t w;
       
        // Test update of servo 0
        for(time = 1000; time <= 2000; time += 50) {
            servoSet(0, time);
            for(w = 0; w < 25; w++) {
                _delay_ms(10);
            }
        }
    }
}

ISR(TIMER1_COMPA_vect)
{
    static uint16_t nextStart;
    static uint8_t servo;
    static bool outputHigh = true;
    uint16_t currentTime = OCR1A;
    uint8_t mask = servoOutMask[servo];
   
    if (outputHigh) {
        SERVO_PORT |= mask;
        // Set the end time for the servo pulse
        OCR1A = currentTime + servoTime[servo];
        nextStart = currentTime + US2TIMER1(SERVO_TIME_DIV);
    } else {
        SERVO_PORT &= ~mask;
        if (++servo == N_SERVOS) {
            servo = 0;
        }
        OCR1A = nextStart;
    }
    outputHigh = !outputHigh;
}
 
 View user's profile Send private message  
Reply with quote Back to top
heguli
PostPosted: May 20, 2006 - 10:31 AM
Hangaround


Joined: Oct 04, 2004
Posts: 442
Location: Turku, Finland

Also this is my first microcontroller project, so you need to modify it for sure.
AT90S1200 gives 3,9kHz pwm out and it is controlled with three buttons.

Code:



; ***** DEVICE USE INTERNAL 1MHz OSCILLATOR ******************************

; ***** SPECIFY DEVICE ***************************************************
.device AT90S1200
.equ   SIGNATURE_000   = 0x1e
.equ   SIGNATURE_001   = 0x90
.equ   SIGNATURE_002   = 0x01

; ****** SPECIFY SREG   **************************************************
.equ   SREG   = 0x3F

; ****** SPECIFY TIMER  **************************************************
.equ   TCNT0   = 0x32   ;timer & counter register
.equ   TCCR0   = 0x33   ;timer & counter control register
.equ   TIMSK   = 0x39   ;timer & counter interrupt mask register
.equ   TIFR   = 0x38   ;timer & counter interrupt flag register
.equ   TOV0   = 1      ;timer & counter overflow bit
.equ   OVF0addr= $002   ;Overflow0 Interrupt Vector Address

; ****** SPECIFY PORT B **************************************************
.equ   PORTB   = 0x18
.equ   DDRB   = 0x17
.equ   PINB   = 0x16
.equ   PINB7   =7
.equ   PINB6   =6
.equ   PINB5   =5
.equ   PINB4   =4
.equ   PINB3   =3
.equ   PINB2   =2
.equ   PINB1   =1
.equ   PINB0   =0

; ****** SPECIFY PORT D **************************************************
.equ   PORTD   = 0x12
.equ   DDRD   = 0x11
.equ   PIND   = 0x10
.equ   PIND6   =6
.equ   PIND5   =5
.equ   PIND4   =4
.equ   PIND3   =3
.equ   PIND2   =2
.equ   PIND1   =1
.equ   PIND0   =0

; ***** SPECIFY EEPROM REG ***********************************************
.equ   EEAR   = 0x1E  ;address register
.equ   EEDR   = 0x1D  ;data register
.equ   EECR   = 0x1C  ;control register
.equ   EEWE   =1
.equ   EERE   =0

; ***** SPECIFY GENERAL INT MASK REG *************************************
.equ   GIMSK   = 0x3B

; ***** SPECIFY MCU CONTROL REG ******************************************
.equ   MCUCR   = 0x35

; ***** SPECIFY WATCHDOG TIMER REG ***************************************
.equ   WDTCR   = 0x21

; ***** SPECIFY ANALOG COMPARATOR CONTROL AND STATUS REG *****************
.equ   ACSR   = 0x08

; ***** GENERAL PURPOSE REG **********************************************
; ***** R0-R31, R16-R31 IMMEDIATE, R30 (Z-REGISTER) **********************
.def user_reg2=r16
.def monitor=r17
.def mode_sta=r18   ;mode button status
.def mode_dis=r19   ;mode button disable
.def int_mem=r20
.def memuser1=r21
.def memuser2=r22
.def memuser3=r23
.def memuser4=r24
.def temp=r25
.def temp2=r26
.def user_reg=r27
.def div1=r28
.def div2=r29
.def div3=r31

.org 0x0000
   rjmp INIT


.org 0x0002         ; ***** counter overflow interrupt *****
   rjmp coi

INIT:
cli               ; DISABLE INTERRUPT FOR INIT SECTION
;**** B PORT TO OUT&INPUT ***************
   ldi temp, 0x1f
   out DDRB, temp
;**** D PORT TO OUT&INPUT ***************
   ldi temp, 0x0F
   out DDRD, temp
   ldi temp, 0xf0
   out portd, temp
;**** TIMER *****************************
   ldi temp, 0x01   ; PRESCALE TIMER NO DIV
   out TCCR0, temp
   ldi temp, 0x02   ; ENABLE TIMER INTERRUPT MASK REG
   out TIMSK, temp
;**** SREG ******************************
   ldi temp, 0x80   ; ENABLE GLOBAL INTERRUPT
   out SREG, temp
;**** ANALOG COMPARATOR *****************
   ldi temp, 0x90   ; COMPARATOR DISABLE, INT FLAG CLEAR,
   out ACSR, temp
;**** CLEAR DIV 1,2,3 *******************
   ldi temp, 0x00
   mov div1, temp
   mov div2, temp
   mov div3, temp
;**** CLEAR USER_REGS *******************
   mov user_reg, temp
   mov user_reg2, temp
   mov mode_sta, temp
   mov mode_dis, temp
;**** CLEAR MEMUSER *********************
   mov memuser1, temp
   mov memuser2, temp
   mov memuser3, temp
   mov memuser4, temp


start:
; **************** READ USER EEPROM TO GENERAL PURPOSE REGISTER **********
   ldi temp, 0x01    ; ADDRESS USER EEPROM1
   out EEAR, temp
   sbi   EECR, 0      ; READ ENABLE
promld1:
   sbic EECR, 0   ; SKIP NEXT IF READ IS DONE
   rjmp promld1
   in memuser1, EEDR ; MOVE DATA FROM EEDR TO MEMUSER1


   ldi temp, 0x02
   out EEAR, temp
   sbi   EECR, 0      
promld2:
   sbic EECR, 0
   rjmp promld2
   in memuser2, EEDR
   
   
   ldi temp, 0x03
   out EEAR, temp
   sbi   EECR, 0   
promld3:
   sbic EECR, 0
   rjmp promld3
   in memuser3, EEDR


   ldi temp, 0x04
   out EEAR, temp
   sbi   EECR, 0   
promld4:
   sbic EECR, 0
   rjmp promld4
   in memuser4, EEDR
   
   sei               ; ENABLE INTERRUPT
   
; ************************************************************************
; ******************* NORMAL USE START HERE ******************************
; ************************************************************************



motor1:               ; COMPARE TIMER AND MEMUSER, IF EQUAL WRITE LOW TO PORT PIN
   in temp, TCNT0      ; AS LONG AS TIMER HAS A LOWER VALUE THEN MEMUSER, PORTB HIGH
   cp temp, memuser1
   brlo motor2         ; CLEAR PORT IF SAME OR HIGHER
   cbi portb, 4

motor2:
   in temp, TCNT0
   cp temp, memuser2
   brlo motor3
   cbi portb, 3

motor3:
   in temp, TCNT0
   cp temp, memuser3
   brlo motor4
   cbi portb, 2

motor4:
   in temp, TCNT0
   cp temp, memuser4
   brlo pollsw
   cbi portb, 1
   
pollsw:
   
   cpi mode_sta, 0x00
   brne prog_mode
   in temp, pind      ; POLL MODE BUTTON, IF PUSHED => PROGRAM MODE
   sbrc temp, 4      ; READ PIND TO TEMP AND IF PD4 LOW JUM
   rjmp motor1
   inc mode_sta
   rjmp m_user1

; ************************************************************************
; ******************* PROGRAM MODE START HERE ****************************
; ************************************************************************



prog_mode:
   
; ************************ 2 sek. puls ***********************************
   cpi div1, 0xff      ; DIV div1 WITH 255
   brne continue1
   clr div1
   clr monitor
   inc div2

continue1:
   cpi div2, 0x07      ; DIV div2 WITH 7
   brne continue2   
   clr div2
   inc div3

continue2:
   cpi div3, 0x02      ; DIV div3 WITH 2 (DIV2 T= ~2 sec)
   brne m_user1
   clr div3
   in temp, pind      ; IF MODE RELEASED CONTINUE
   sbic pind, 4
   rjmp m_user1   
   inc mode_sta
   

; ************************ 1 READ "+" AND "-" -BUTTON ********************
m_user1:
   cpi mode_sta, 0x01
   brne m_user2
   sbi portd, 0      ; SET LED #1, MEANING CHANGES ARE MADE TO MEMUSER1

   cpi memuser1, 0xff   ; IF MEMUSER1 FULL, DISABLE "+" -BUTTON
   breq min1button
plus1button:         ; CHECK + BUTTON
   sbic pind, 6      ; SKIP IF BIT IS CLEAR
   rjmp min1button
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user2
   cpi monitor, 0x01
   brsh m_user2
   inc monitor         ; END SLOW DOWN
   inc memuser1
   
min1button:
   cpi memuser1, 0x00    ; IF MEMUSER1 "NULL" OUTPUT, DISABLE "-" -BUTTON
   breq m_user2
   sbic pind, 5
   rjmp m_user2
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user2
   cpi monitor, 0x01
   brsh m_user2
   inc monitor         ; END SLOW DOWN
   dec memuser1
; ************************************************************************

; ************************ 2 READ "+" AND "-" -BUTTON ********************
m_user2:
   cpi mode_sta, 0x02
   brne m_user3
   sbi portd, 1      ; SET LED #2, MEANING CHANGES ARE MADE TO MEMUSER1
   cbi portd, 0      ; CLEAR PREVIOUS STATE

   cpi memuser2, 0xff    ; IF MEMUSER1 FULL, DISABLE "+" -BUTTON
   breq min2button
plus2button:         ; CHECK + BUTTON
   sbic pind, 6
   rjmp min2button
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user3
   cpi monitor, 0x01
   brsh m_user3
   inc monitor         ; END SLOW DOWN
   inc memuser2
   
min2button:
   cpi memuser2, 0x00    ; IF MEMUSER1 "NULL" OUTPUT, DISABLE "-" -BUTTON
   breq m_user3
   sbic pind, 5
   rjmp m_user3
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user3
   cpi monitor, 0x01
   brsh m_user3
   inc monitor         ; END SLOW DOWN
   dec memuser2
; ************************************************************************

; ************************ 3 READ "+" AND "-" -BUTTON ********************
m_user3:
   cpi mode_sta, 0x03
   brne m_user4
   sbi portd, 2      ; SET LED #3, MEANING CHANGES ARE MADE TO MEMUSER1
   cbi portd, 1      ; CLEAR PREVIOUS STATE

   cpi memuser3, 0xff    ; IF MEMUSER1 FULL, DISABLE "+" -BUTTON
   breq min3button
plus3button:         ; CHECK + BUTTON
   sbic pind, 6
   rjmp min3button
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user4
   cpi monitor, 0x01
   brsh m_user4
   inc monitor         ; END SLOW DOWN
   inc memuser3
   
min3button:
   cpi memuser3, 0x00    ; IF MEMUSER1 "NULL" OUTPUT, DISABLE "-" -BUTTON
   breq m_user4
   sbic pind, 5
   rjmp m_user4
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne m_user4
   cpi monitor, 0x01
   brsh m_user4
   inc monitor         ; END SLOW DOWN
   dec memuser3
; ************************************************************************

; ************************ 4 READ "+" AND "-" -BUTTON ********************
m_user4:
   cpi mode_sta, 0x04
   brne endbut
   sbi portd, 3      ; SET LED #4, MEANING CHANGES ARE MADE TO MEMUSER1
   cbi portd, 2      ; CLEAR PREVIOUS STATE

   cpi memuser4, 0xff   ; IF MEMUSER1 FULL, DISABLE "+" -BUTTON
   breq min4button
plusbutton:            ; CHECK + BUTTON
   sbic pind, 6
   rjmp min4button
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne endbut
   cpi monitor, 0x01
   brsh endbut
   inc monitor         ; END SLOW DOWN
   inc memuser4
   
min4button:
   cpi memuser4, 0x00    ; IF MEMUSER1 "NULL" OUTPUT, DISABLE "-" -BUTTON
   breq endbut
   
   sbic pind, 5
   rjmp endbut
   cpi div1, 0x0f      ; SLOW DOWN INC MEMUSER
   brne endbut
   cpi monitor, 0x01
   brsh endbut
   inc monitor         ; END SLOW DOWN
   dec memuser4
; ************************************************************************
endbut:
   cpi mode_sta, 0x05
   brsh clear_mode      ; BRANCH IF SAME OR HIGHER
rjmp motor1
clear_mode:
   clr mode_sta
   cbi portd, 3      ; CLEAR PREVIOUS STATE
   ldi temp, 0xff      ; SET ALL LED'S FOR A SIGN OF EEPROM WRITE
   out portd, temp
; *********************************** WRITE EEPROM ***********************
   cli               ; DISABLE GLOBAL INTERRUPT
   clr temp

   mov temp2, memuser1
   rcall saveprom
   mov memuser1, temp2
   
   mov temp2, memuser2
   rcall saveprom
   mov memuser2, temp2

   mov temp2, memuser3
   rcall saveprom
   mov memuser3, temp2

   mov temp2, memuser4
   rcall saveprom
   mov memuser4, temp2

release:            ; WAIT TO MODE BUTTON RELEASED
   sbis pind, 4
   rjmp release
   sei               ; GLOBAL INTERRUPT ON
   ldi temp, 0xf0
   out portd, temp
   rjmp motor1




saveprom:
   inc temp
   out EEAR, temp      ; EEPROM ADDRESS FOR MEMUSER
   out EEDR, temp2      ; EEPROM DATA
   sbi   EECR, 1         ; WRITE ENABLE
againprom:
   sbic EECR, 1
   rjmp againprom
   ret


coi:
   inc div1
   ldi int_mem, 0xff    ; ***** ALL MOTOR ACTIVE *****
   out portb, int_mem
   reti


_________________
Regards
heguli
 
 View user's profile Send private message  
Reply with quote Back to top
jgrunt
PostPosted: May 20, 2006 - 02:18 PM
Hangaround


Joined: Mar 14, 2005
Posts: 485


Hardware PWM. Listen to Ron. Set it and forget it!
Code:

#include   <avr/io.h>   //gcc
void init_servo_driver(void);   
int main(void)         //8MHz
{
   unsigned int servo_a = 1500;
   unsigned int servo_b = 1500;

   init_servo_driver();
   while(1)
   {
      OCR1A = servo_a;
      OCR1B = servo_b;
   }
   return 0;
}
void init_servo_driver(void)
{
   TCCR1B   =   0x00;   //stop timer
   DDRD   =   0xFF;   //set pins for output
   TCNT1H   =   0xB1;   //setup
   TCNT1L   =   0xE1;
   ICR1   =   20000;   // used for TOP, makes for 50 hz
   OCR1A   =   1500;   // servo at center (1.5ms pulse)
   OCR1B   =   1500;   // servo at center (1.5ms pulse)
   TCCR1A   =   0xA2;
   TCCR1B   =   0x1A;   //start timer
}

_________________
-Chris
Illinois
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: May 20, 2006 - 04:24 PM
Posting Freak


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden

Nothing wrong with HW pwm if you are happy with two servos (well, upto 6 on a mega128). But you can't use the timer(s) for much else (e.g., input capture).
/Lars
 
 View user's profile Send private message  
Reply with quote Back to top
microcarl
PostPosted: May 20, 2006 - 04:57 PM
Raving lunatic


Joined: May 30, 2004
Posts: 7801
Location: Cincinnati, Ohio

Lajon wrote:
Nothing wrong with HW pwm if you are happy with two servos (well, upto 6 on a mega128). But you can't use the timer(s) for much else (e.g., input capture).
/Lars


If you go to Lynxmotion.com at: http://www.lynxmotion.com/Product.aspx? ... egoryID=52

they sell a 32 channel PWM servo controller that uses a Mega8 AVR. The source code is available for download. I have two SSC-32 servo controllers and they work very well.

You could download the code from their web-site and get a good example of how they accomplisned a seemingly impossible feat!

_________________
Carl W. Livingston, KC5OTL
microcarl@roadrunner.com

It's a fundamental law of nature... All things gravitate toward total chaos!!!

The original Dragon Slayer !

Long live the AVR!!!
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Someguy22
PostPosted: May 20, 2006 - 05:44 PM
Hangaround


Joined: Mar 14, 2006
Posts: 473


What is so hard about running 10 PWM servos with one timer? A servo requires a 1 to 2 ms pulse every 20 ms. Set a pin high, set the timer interrupt to the length of the pulse. when the interrupt hits, set the pin low and the timer to (2ms - pulse length), when the interrupt hits, move on to the next pin where you set it high, set the timer........

You get 10 PWM signals with 1 timer, low software overhead and plenty of CPU time left to do other stuff.

If you care to eat up your CPU time, use software to time the high pulses every 2 ms. I bet you could time 4 pulses cleanly in software easy. Hmm... 40 servos at once. Who would have thunk it?
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: May 20, 2006 - 07:59 PM
Posting Freak


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden

@microcarl
Can't say I felt the need to run 32 servos but who knows Very Happy

@Someguy22
Quote:
What is so hard about running 10 PWM servos with one timer?

Who said it is hard? Look at my post above, the code is there for 8 servos (works similar to what you describe). Use the OC1B interrupt also for upto 16 servos.

/Lars
 
 View user's profile Send private message  
Reply with quote Back to top
microcarl
PostPosted: May 20, 2006 - 08:08 PM
Raving lunatic


Joined: May 30, 2004
Posts: 7801
Location: Cincinnati, Ohio

Lajion wrote:
Quote:
Can't say I felt the need to run 32 servos but who knows


Well, you don't have to employ all 32 servo control functions. The whole point of providing the link was to give you an opportunity to see how someone else has emplemented servo control in radical numbers with a minimum of software and hardware.

And I also thought that you probably wouldn't want to re-invent the wheel!

_________________
Carl W. Livingston, KC5OTL
microcarl@roadrunner.com

It's a fundamental law of nature... All things gravitate toward total chaos!!!

The original Dragon Slayer !

Long live the AVR!!!
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Someguy22
PostPosted: May 20, 2006 - 10:38 PM
Hangaround


Joined: Mar 14, 2006
Posts: 473


Lajon wrote:
@Someguy22
Quote:
What is so hard about running 10 PWM servos with one timer?

Who said it is hard? Look at my post above, the code is there for 8 servos (works similar to what you describe). Use the OC1B interrupt also for upto 16 servos.

/Lars


I read your post, but not your code. OK it's not hard.
 
 View user's profile Send private message  
Reply with quote Back to top
John_Gutmann
PostPosted: May 21, 2006 - 03:40 AM
Hangaround


Joined: Apr 15, 2006
Posts: 254


Ok, sorry for my absence i have been busy. Basically what I am trying to do is run normal hobby servos off of an avr. it would be nice if I could do it all on one chip but if not it is ok. I do not know much sbout programming PWM or even much about timers, just the basics so all of this is helping me alot. I will look at the lynx motion link. If I use that as an off board system, I have no idea how to communicate with it so starting with control of one servo would be nice so i can see how it is done and all.

I thank you all for writing this code and doing ossi's contest but what I really need right now is a code for one servo.

I just saw jgrunts code and omg you did it pefectly for me!!! that is exactly what I am looking for. Could you maybe add more comments to explain things and explain your dreaded magic numbers?
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: May 21, 2006 - 09:20 AM
Posting Freak


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden

You will find HW PWM for servos discussed in many threads. For example here:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=32907
In the data sheet you should have a look at timer 1 fast PWM (mode 14)
/Lars
 
 View user's profile Send private message  
Reply with quote Back to top
avcaveman
PostPosted: Aug 24, 2007 - 01:56 PM
Wannabe


Joined: May 21, 2007
Posts: 61


Lars,

Sorry for my ignorance, but what does this bit do?

Code:
 for(w = 0; w < 25; w++) {
   _delay_ms(10);
 }


Does it have any effect on the frequency or the duty cycle?

Thinking about this more -- I guess frequency isn't much important for PWM, is it? I mean if you run 100Hz vs. 200Hz, and the duty cycle is 50%, the motor still gets half of the voltage, and should generally run the same speed, correct, or am I way off? I know the frequency will have some effect, but I am not sure how everything plays together to know what that effect might be.

My application is a very simple DC motor that I have a very simple H-bridge for (with enable/direction and PWM inputs).

Oh, and I just saw that this is for servos, not regular PWM. I will have to look closer at it to see what is going on, and how I might modify it for my use. I need at least 4 servos for my project, and I am using one of the timer on my ATMega128 for reading inputs (thanks for that again, BTW).

Thanks,

-Kevin
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 24, 2007 - 02:40 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 34710
Location: (using avr-gcc in) Finchingfield, Essex, England

The code you posted delays for 25 lots of 10 milliseconds. In other words 250ms or 1/4 of one second.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
bobgardner
PostPosted: Aug 24, 2007 - 04:45 PM
10k+ Postman


Joined: Sep 04, 2002
Posts: 13610
Location: Orlando Florida

When someone asks about PWM, you cant assume they mean motor speed control or lamp dimming with a mosfet. They might mean hobby rc servo control. One or the other needs a better name to describe it.

_________________
Imagecraft compiler user
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
avcaveman
PostPosted: Aug 25, 2007 - 03:41 AM
Wannabe


Joined: May 21, 2007
Posts: 61


Yes, but why not just call a delay of 250ms and be done with it? Does the register for delaying not hold a value so large, or what? What does the purpose of the delay do, at any rate? Just prevent calling the servoSet() call too rapidly, I suppose?

Anyway, I am in need of a tutorial to explain the difference in PWM approaches. I suppose I shall go searching for them tomorrow.

Thanks for the feedback,

-Kevin
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: Aug 25, 2007 - 09:13 AM
Posting Freak


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden

Quote:
Yes, but why not just call a delay of 250ms and be done with it?
From the avr-libc manual:
Quote:
The maximal possible delay is 262.14 ms / F_CPU in MHz.

Quote:
Just prevent calling the servoSet() call too rapidly, I suppose?
Yes.
/Lars
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits