Atmega8 USART servo control problem???

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everybody!!!
i'm trying to control 2 servos and 2 DC motors (to be used in a small electric helicopter)using the atmega8. the problem is i have two microcontrollers, one as a transmitter which converts 3 analogue signals to digital and send them through the USART by wire to the receiver. the receiver uses the other atmega8 and i managed to get the digital signals on the receiver but so far i have not been able to generate the PWM signals for controlling the servos and motors using the digital signals received from the transmitter.both microcontrollers operate at 8MHz, 9600 baud rate, and i'm using the stk500 and avrstudio4 to program them in assembly language. Can anybody help me???

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We'll be happy to help, but we'll need to see some code. When you post it, be sure to use the code tags (the "Code" button) so it will be readable.

It sounds like a fun project.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the rreceiver code below only receives the digital signals and display them on the LEDs on the stk500.

.include "m8def.inc"
;##### ATMEGA8 SLAVE RECEIVER #####;

.equ CLOCK = 8000000
.equ BAUD = 9600
.equ UBRRVAL = CLOCK/(BAUD*16)-1

.org 0x000
rjmp reset

reset:	
	; init stack pointer
	ldi r16, LOW(RAMEND)
	out SPL, r16
	ldi r16, HIGH(RAMEND)
	out SPH, r16

; configure Port B to ouput
	ldi temp, 0xFF
	out DDRB, temp

; configure Port D to ouput
	ldi temp, 0xFF
	out DDRD, temp

; init UART
	ldi temp, LOW(UBRRVAL)	; set baud rate
	out UBRRL, temp
	ldi temp, HIGH(UBRRVAL)
	out UBRRH, temp


	ldi temp, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)		; Frame-Format: 8 Bit
	out UCSRC, temp

	sbi UCSRB, RXEN		; activate RX (receive)



USART_Receive:

	; Wait for data to be received
	sbis UCSRA, RXC
	rjmp USART_Receive
	; Get and return received data from buffer
	in temp, UDR
	out PORTD, temp

	ret

loop:
rjmp loop

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But where is the PWM code? Show us what you have tried so far.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

ret


??? After init, you fall through to the receive code, and then ret -- to where? (As written, I suspect you code is restarting everytime it sees a character.)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mbianji wrote:
Hi everybody!!!
the problem is i have two microcontrollers, one as a transmitter which converts 3 analogue signals to digital and send them through the USART by wire to the receiver.... Can anybody help me???

I have done a similar project...i controlled a RC helicopter using (2) Atmega16 micros [one of the micros was onboard the RC helicopter, the other was on the ground...it communicated via wireless) I am guessing the next step in your project is to go wireless?

If so, you will have a difficult time sending wireless data with your current code if you don't upgrade to wireless communication first..RX TX module = physical wire

This will save you a week of troubleshooting.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that is the code i have tried to first control one servo.

.include "m8def.inc"
;##### ATMEGA8 SLAVE RECEIVER #####;

.def regs = R15
.def temp = R16
.def flag = R17
.def pos = R18
.def result = R19			; contains the bit pattern to trigger the servo lines
.def past = R20

.equ cycle = 20000		; 20000us. Servo operates from 12 to 40 ms but the cycle 
				; time has influence on the servo position
.equ smid = 1500		; servo neutral 1500 us
.equ smin =  700		; servo min
.equ smax = 2500		; servo max

.equ CLOCK = 8000000
.equ BAUD = 9600
.equ UBRRVAL = CLOCK/(BAUD*16)-1

intvect:
	rjmp reset		; RESET	
	reti			; INT0
	reti			; INT1
	reti			; T2 Compare
	reti			; T2 Overflow
	reti			; T1 Capture
	rjmp intoca		; T1 Compare A
	rjmp intocb		; T1 Compare B
	reti			; T1 Overflow
	reti			; T0 Overflow
	reti			; SPI Transfer complete
	rjmp USART_Receive	; UART RX Complete
	reti			; UDR Empty
	reti			; UART TX Complete
	reti			; ADC complete
	reti			; EEPROM Ready
	reti			; Analog Comparator
	reti			; TWM
	reti			; SPM_RDY

reset:   
   ; init stack pointer
   ldi r16, LOW(RAMEND)
   out SPL, r16
   ldi r16, HIGH(RAMEND)
   out SPH, r16

; configure Port B to ouput
   ldi temp, 0xFF
   out DDRB, temp

; configure Port D to ouput
   ldi temp, 0xFF
   out DDRD, temp

	ldi R24, LOW(cycle)	; OCR1A cycle
	ldi R25, HIGH(cycle)
	out OCR1AH, R25
	out OCR1AL, R24	

	ldi R24, LOW(smid)	; OCR1B middle position
	ldi R25, HIGH(smid)
	out OCR1BH, R25
	out OCR1BL, R24


	in temp, TIMSK
	ori temp, (1<<OCIE1A) | (1<<OCIE1B)	; enable interrupt on OCR1B and OCR1A
	out TIMSK, temp

	;;ldi temp, 0b00001001	; no Prescaler
	ldi temp, 0b00001010	; Timer Prescaler 8
				; WGM13:2 = 01 -> CTC Mode
	out TCCR1B, temp


; init UART
   ldi temp, LOW(UBRRVAL)   ; set baud rate
   out UBRRL, temp
   ldi temp, HIGH(UBRRVAL)
   out UBRRH, temp


   ldi temp, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)      ; Frame-Format: 8 Bit
   out UCSRC, temp
   sbi UCSRB, RXCIE	; Interrupt on receive
   sbi UCSRB, RXEN      ; activate RX (receive)

   sei

loop:

	ldi temp, HIGH(smax)	
	cp temp, patn		 
	brne down

        out OCR1BH, patn		
	out OCR1BL, patn
	rcall delay	

down:

	ldi temp, HIGH(smin)	
	cp temp, patn		 
	brne loop
  
        out OCR1BH, patn		
	out OCR1BL, patn

rjmp loop


USART_Receive:
    push temp
   ; Wait for data to be received
   sbis UCSRA, RXC
   rjmp USART_Receive
   ; Get and return received data from buffer
   in temp, UDR
   out PORTD, temp

   rcall convert    ;conversion routine
   pop temp
   reti

 intoca:	
	sbi PORTB, 1		; servo High
	reti
intocb:	
	cbi PORTB, 1		; servo Low
	reti
convert:

	clr past
	;1st bit
    mov r3, temp
	ldi pos, 0b00000001
	and pos, r3
	cpi pos, 0b00000001
	breq conv1bit

	;2nd bit
	ldi pos, 0b00000010
	and pos, r3
	cpi pos, 0b00000010
	breq conv2bit

	;3rd bit
	ldi pos, 0b00000100
	and pos, r3
	cpi pos, 0b00000100
	breq conv3bit

	;4th bit
	ldi pos, 0b00001000
	and pos, r3
	cpi pos, 0b00001000
	breq conv4bit

	;5th bit
	ldi pos, 0b00010000
	and pos, r3
	cpi pos, 0b00010000
	breq conv5bit

	;6th bit
	ldi pos, 0b00100000
	and pos, r3
	cpi pos, 0b00100000
	breq conv6bit

	;7th bit
	ldi pos, 0b01000000
	and pos, r3
	cpi pos, 0b01000000
	breq conv7bit

	;8th bit
	ldi pos, 0b10000000
	and pos, r3
	cpi pos, 0b10000000
	breq conv8bit

	ret ; all done

conv1bit:
	ldi past, 1
	ret
conv2bit:
	ldi result, 2
	add result, past
	ret
conv3bit:
	ldi past, 4
	add result, past
	ret
conv4bit:
	ldi past, 8
	add result, past
	ret
conv5bit:
	ldi past, 16
	add result, past
	ret
conv6bit:
	ldi past, 32
	add result, past
	ret
conv7bit:
	ldi past, 64
	add result, past
	ret
conv8bit:
	ldi past, 128
	add result, past
	ret

;;;;delay routine;;;
;;;;;;;;;;;;;;;;;;;;

delay:
	ldi temp, 0xFF
dls:	
	nop
	nop
	nop
	dec temp
	brne dls
	ret


  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Mbianji,

The ATMega8 has two easy ways of generating PWM for servos, FAST PWM and CTC based. Here is an outline for generating a single channel PWM that will for for almost any AVR controller.

Here is a recipie for the CTC approach.

Use the 16 bit couter timer (TIMER1).
Internal R/C fuse set to 8MHz(sloppy but workable) or a crystal clock (10MHz prefered).
Select divide by 8 clock.
Set WGM = 4 (CTC mode)
OCR1A will define the top value for the counter.
Set up and enable the interrupt routine. This code should turn on the pulse and write in the current OCR1B value.
OCR1B is the current pulse on time. This should vary between 1ms to 2ms depending upon your servo position.
Set up and enable OCR1B interrupt. This routine should turn off the servo pulse.
Your main routine or other code can decode the servo position. Just remember that the minimum servo pulse corresponds to one extreme of position, the maximum to the other. For most hobby servos this is 1ms to 2ms respectively.

I have deliberately not supplied working code or more specific values. Working out what the above means will help cement youir understanding or both the servo process and how the controller's hardware works.

You will need a routine to calculate OCR1B given a specific servo position. This is where you might put code to adjust for your specific servo's pulse range.

Have fun and send pictures!

"It's easier to ask forgiveness than it is to get permission" - Admiral "Amazing" Grace Hopper.