2011-10-13 05:18 AM
Hi all,
Iwant to run
a
servo
using the
STM32
Discovery
,if
you
have a
suggestion
program to
run
the
servo
?or
you have a
simple
code to
run the
servo
on the
STM32
Discovery
Thank you
Regards,Endy2011-10-13 07:38 AM
What kind of signal does the servo need? There have been several examples posted showing how to set up the timers to generate PWM signals, and to sweep the duty cycle.
2011-10-13 08:56 AM
my servo need a square signals with 20ms, I have tried a timer with interrupt but does can run
this my program:#include ''stm32f10x.h''#include ''stm32f10x_tim.h''#include ''STM32vldiscovery.h'' u16 period; u16 scale; u16 width; u16 count; u16 angle;void TIM3_IRQChannel(void){}void TIM3_IRQHandler(void){ count=count+1; if (count == 200) { count = 0x00; } if (count <= angle) { GPIO_SetBits(GPIOC,GPIO_Pin_7); } if (count >= angle) { GPIO_ResetBits(GPIOC,GPIO_Pin_7); }}int main(void){ GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; //RCC_Config(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // Permit ReMap GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // clock to 50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // alternate function pull GPIO_Init(GPIOC, &GPIO_InitStructure);// Configuration for GPIOB assume GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); scale = 101; period = 2501; width = period/2; TIM_TimeBaseStructure.TIM_Period = (period - 1); TIM_TimeBaseStructure.TIM_Prescaler = (scale - 1); TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQHandler; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = width; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_ClearFlag(TIM3, TIM_FLAG_Update); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); TIM_Cmd(TIM3,ENABLE); while (1) { angle = 20; }}void Delay(__IO uint32_t nCount){ for(; nCount != 0; nCount--);}#ifdef USE_FULL_ASSERTvoid assert_failed(uint8_t* file, uint32_t line){ while (1) { }}#endif2011-10-13 09:27 AM
Presumably not truly square (50/50) because you need to pull the duty in/out to achieve the ''angle'' you want. What's the specification for that? ie min/max high time.
PC.7 is being driven by the TIM3_CH2 output, you don't control it by writing to the GPIO pin directly. The values for scale and period are nonsensical, it will generate a ~95Hz signal (10.525 ms) on the pin, and call your update interrupt at that periodicity. Whereas scale = 48; // Assuming a 24 MHz TIMCLK, gives 500 KHz timebase period = 10000; Would give you 50 Hz (20 ms period), and provide a duty cycle sweepable from 0 to 100% in 0.01% increments (2 us tick units), which you could program in interrupt using the TIM3 CCR2 register (with 0 .. 10000). Your timer interrupt will also need to actually clear the source of the interrupt, otherwise it will continually tail chain.2011-10-13 10:16 AM
I
want to make a
signal
to drive the
servo
to the
control
signal
high
and signal
low
as
I included
this
picture
, how to makethe signal
,I
can control
with a
logic
high
Thanks clive12011-10-13 10:25 AM
2011-10-13 10:49 AM
Ok, I don't see a horizontal scale, but I'll assume you have a 20 ms period.
With PWM you control the ''width'' of the high portion with the CCR register for the channel. It's referred to as the duty cycle, 10/90 would spend 2 ms high, 18 ms low, using my suggested settings you'd be programming in 1000 into the CCR Again, what is the minimum and maximum width of the high portion? I don't have the specifications for *your* servo.With that information you could convert a fractional angle, 0-360 degrees, into a setting written into the CCR.
Some typical ones rotate 180 degrees and expect a 600 to 2400 us width to achieve that range, ie 1800 us or 900 tick units at 500 KHz (2 us) TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degrees So perhaps something like : void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_UP) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_UP); // minimum high of 600 us, with 180 degrees at 2400 us TIM3->CCR2 = 300 + (u16)(angle * 5.0); // where angle is a float 0.0-180.0 degrees } } If I changed scale/period to something like 8/60000 I could achieve even better resolution/granularity. If you have 4 servos, you could use the same TIM3, and all 4 PWM channels. Edit: fixed scaling to 5.02011-10-13 12:34 PM
Sorry
clive
, I reallydo not
understand
with
this
program
,if
you
can
give
me an example of
a simple
program
to
carry out
the servo
program
,because
I am a
newbie
programmer
,I
'vetried
the program
to
run the
servo
on the
AVR
and the
servo
can run,
and I want to
make a
program
on
STM32_Discovery
as
logic
programs on the
AVR
Servo
that I use
is the
Hitec
HS
-325HB
.Spesefikasi
what
you need
to
be
about providing
simple
program to
run
the
servo
?or
you have
another way to run
the
servo
?The following
is
my
AVR
program
:
#include <avr/io.h>#include <avr/iom8535.h>#include <avr/interrupt.h>#include <util/delay.h> #define count _SFR_IO8 (0x60)#define angle _SFR_IO8 (0x61)void delay_ms(uint16_t ms)//program delay{while (ms){ _delay_ms(1); ms--;//ms=ms-1}}ISR(TIMER0_OVF_vect){TCNT0 = 0xcd;count = count+1;if (count == 200) { count = 0x00; }if (count <= angle) { PORTB |= _BV(7);//servo } if (count >= angle) { PORTB &= ~_BV(7); }}int main (void){ DDRB = 0xff; PORTB = 0x00; TCCR0 = 0x02;//prescaller 8 TCNT0 = 0xcd;//0xff-0x9b=64(100) //xtall=8MHz, 8M/(8x100)=10kHz //t=1/10k=0.1ms OCR0=0X00; TIMSK = 0x01; count = 0x00; sei(); while (1) { angle=30;//min: 11 , max: 47; servo run 180 degree }}From: clive1Posted: Thursday, October 13, 2011 8:07 PMSubject: Servo control using STM32VLDiscoveryOk, I don't see a horizontal scale, but I'll assume you have a 20 ms period.
With PWM you control the ''width'' of the high portion with the CCR register for the channel. It's referred to as the duty cycle, 10/90 would spend 2 ms high, 18 ms low, using my suggested settings you'd be programming in 1000 into the CCRAgain, what is the minimum and maximum width of the high portion? I don't have the specifications for *your* servo.With that information you could convert a fractional angle, 0-360 degrees, into a setting written into the CCR.
Some typical ones rotate 180 degrees and expect a 600 to 2400 us width to achieve that range, ie 1800 us or 900 tick units at 500 KHz (2 us)TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degreesSo perhaps something like :void TIM3_IRQHandler(void){ if (TIM_GetITStatus(TIM3, TIM_IT_UP) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_UP); // minimum high of 600 us, with 180 degrees at 2400 us TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degrees }}If I changed scale/period to something like 8/60000 I could achieve even better resolution/granularity.If you have 4 servos, you could use the same TIM3, and all 4 PWM channels.2011-10-13 01:00 PM
Sorry
clive
, I reallydo not
understand
with
this
program
,if
you
can
give
me an example of
a simple
program
to
carry out
the servo
program
,because
I am a
newbie
programmer
,I
'vetried
the program
to
run the
servo
on the
AVR
and the
servo
can run,
and I want to
make a
program
on
STM32_Discovery
as
logic
programs on the
AVR
Servo
that I use
is the
Hitec
HS
-325HB
.Spesefikasi
what
you need
to
be
about providing
simple
program to
run
the
servo
?or
you have
another way to run
the
servo
?Your AVR code manually drives the pin, the STM32 timers are capable of generating the signal directly. You set up the timers, then you program a register with a value based on the angle you want the servo to attain. Here's a specification for the signalling.
http://www.servocity.com/html/hs-325hb_bb_deluxe.html
2011-10-13 01:50 PM
// STM32 Servo Demo for 24 MHz VL Discovery - sourcer32@gmail.com
#include ''stm32F10x.h'' #include ''STM32vldiscovery.h'' void RCC_Configuration(void); void GPIO_Configuration(void); void NVIC_Configuration(void); void TIM3_Configuration(void); float servo_angle = 0.0; // +/- 90 float angle_delta = (1.0 / 50.0); // slew 1 degree per second void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // minimum high of 600 us for -90 degrees, with +90 degrees at 2400 us, 10 us per degree // timer timebase set to us units to simplify the configuration/math TIM3->CCR2 = 600 + (u16)((servo_angle + 90.0) * 10.0); // where angle is a float -90.0 to +90.0 degrees // a quick hack to get the servo to stroke back and forth servo_angle += angle_delta; if ((servo_angle >= 90.0) || (servo_angle <= -90.0)) { angle_delta = -angle_delta; // reverse servo_angle += angle_delta; } } } int main(void) { RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); TIM3_Configuration(); while(1); } void RCC_Configuration(void) { // clock for GPIO and AFIO (Remap) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); // clock for TIM3 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); } void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); /* Enable the TIM3 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; // PC.07 TIM3_CH2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); // Remap to get signal on PC.07 } void TIM3_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // Simplify the math here so TIM_Pulse has 1 us units TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1; // 24 MHz / 24 = 1 MHz TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20 ms) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // Channel 2 configuration = PC.07 TIM3_CH2 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 600 + 900; // 1500 us - Servo Top Centre TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); // turning on TIM3 and PWM outputs TIM_Cmd(TIM3, ENABLE); TIM_CtrlPWMOutputs(TIM3, ENABLE); // TIM IT enable TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); }