Search |
 |
|
 |
| Author |
Message |
|
|
Posted: May 18, 2006 - 10:20 AM |
|


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)
********************************
|
| |
|
|
|
|
|
Posted: May 18, 2006 - 05:34 PM |
|


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. |
|
|
| |
|
|
|
|
|
Posted: May 18, 2006 - 05:56 PM |
|

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... |
|
|
| |
|
|
|
|
|
Posted: May 18, 2006 - 09:06 PM |
|

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
|
|
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 08:56 AM |
|


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;
}
|
|
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 10:31 AM |
|

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
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 02:18 PM |
|

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
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 04:24 PM |
|


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 |
|
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 04:57 PM |
|


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!!!
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 05:44 PM |
|

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? |
|
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 07:59 PM |
|


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
@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 |
|
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 08:08 PM |
|


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!!!
|
| |
|
|
|
|
|
Posted: May 20, 2006 - 10:38 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: May 21, 2006 - 03:40 AM |
|

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? |
|
|
| |
|
|
|
|
|
Posted: May 21, 2006 - 09:20 AM |
|


Joined: Mar 12, 2004
Posts: 1113
Location: Linköping, Sweden
|
|
|
|
|
|
|
Posted: Aug 24, 2007 - 01:56 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Aug 24, 2007 - 02:40 PM |
|


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. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 24, 2007 - 04:45 PM |
|


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
|
| |
|
|
|
|
|
Posted: Aug 25, 2007 - 03:41 AM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Aug 25, 2007 - 09:13 AM |
|


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 |
|
|
| |
|
|
|
|
|
|
|
|