The Godfather talking
This is god damn my place! Capisci?
Welcome, Guest. Please login or register.
Did you miss your activation email?
October 23, 2016, 11:39:35 11:39

Login with username, password and session length

Pages: [1]
Author Topic: Help Req.: 50Hz sine wave with Atmel (51 or AVR) or PIC  (Read 4120 times)
0 Members and 1 Guest are viewing this topic.
Junior Member
Offline Offline

Posts: 91

Thank You
-Given: 87
-Receive: 9

« on: February 22, 2008, 04:00:45 16:00 »

I request a help to our friends gurus on Atmel and/or Microchip for a asm file to create a 50Hz sinus wave...
Thank you.
Active Member
Offline Offline

Posts: 130

Thank You
-Given: 44
-Receive: 19

« Reply #1 on: February 22, 2008, 05:14:05 17:14 »

Check out microchip website, there is a application note to create sinewave


Never Never Never giveup
Junior Member
Offline Offline

Posts: 41

Thank You
-Given: 12
-Receive: 6

READ, REAd, REad, Read

« Reply #2 on: February 23, 2008, 08:40:34 20:40 »


I have done a lot of this stuff, but it was a while ago.  Let me try to explain the basics.

You first need to read and understand how the hardware in the PIC for PWM works.

You will have to write to the control registers to set the mode to PWM and get the period set to what you want to use.

Here is some code that I wrote, this is not all complete, but should give some insight for the set-up:

; PWM period definition  (25KHz is 40uS, 20KHz would be 50uS)
; The period of the PWM is Given by the following formula:
; PWM period = (PR2 + 1) * 4 * Tosc * TMR2 prescaler

;PR2_VAL EQU 61 ; 20 Mhz 50 uSec frame
PR2_VAL EQU 49 ; 20 Mhz 40 uSec frame

The next step is to set up an interrupt routine to reload the period register


ORG 0x00 ; Reset Vector
GOTO Main ; go to main program

ORG 0x04

movwf   isr_save_w ; save off current W register contents
movf STATUS,w ; move status register into W register
bcf     STATUS,RP0 ; ensure file register bank set to 0
movwf isr_save_status ; save off contents of STATUS register

btfss PIR1,TMR2IF ; check TMR2 as source of interrupt
goto ISR_NO_SOURCE ; NO, unexpected interrupt
call PWMInterruptService ; yes, handle timer 2 interrupt
goto ISR_OUT

; test for additional interrupt sources here

ISR_NO_SOURCE goto $ ; Source of the interrupt unknown

bcf     STATUS,RP0 ; ensure file register bank set to 0
movf    isr_save_status,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf   isr_save_w,f
swapf   isr_save_w,w ; restore pre-isr W register contents
retfie ; return from interrupt

; Function: PWMInterruptService
; Date: 02/19/00
; Purpose: Handle the PWM interrupt
; Inputs: next_duty = duty cycle during next time slice
; Outputs:
; Notes: Set flag to indicate a PWM time slice is complete
; clear HW flag indicating that TMR2 was the source of the interrupt
; write next_duty to HW reg that controls the duty cycle


bsf flag_PWM_UPDATE ; 1 = a time slice of the PWM is complete, get the next duty cycle

bcf PIR1,TMR2IF ; clear flag for timer 2 as interrupt source

movfw next_duty ; get the next duty cycle

movwf CCPR1L ; write next duty cycle to HW register


OK, got all of that back-ground stuff done, now, all you need to do is reload
'next_duty' each time it is used, I timed things using the flag_PWM_UPDATE.
Consider this type of thing to define your variables and bits within a byte to
be used as flags:

;flag_byte_1 bit definitions
UNUSED_6 EQU     6 ;
UNUSED_5 EQU     5 ;
UNUSED_4 EQU     4 ;
UNUSED_3 EQU     3 ;
PWM_UPDATE EQU     1 ; 1 = a time slice of the PWM is complete, get the next duty cycle
FREQ_60 EQU 0 ; 1 = 60Hz selected, 0 = 50Hz selected

#define flag_BRIDGE_SEL flag_byte_1, BRIDGE_SEL
#define flag_PWM_UPDATE flag_byte_1, PWM_UPDATE
#define flag_FREQ_60 flag_byte_1, FREQ_60

; RAM location allocation
CBLOCK RAM_START ; start ram location
max_tbl_offset ; max value the offset into the table being used
next_duty ; next duty cycle value to put in CCPR1L during ISR
pwm_period ; Value to determine PWM period
quadrant ; current quadrant of output waveform [0..3]
tbl_offset ; current position within look-up table
flag_byte_1 ; General boolean flag bits
isr_save_w ; save W in ISR
isr_save_status ; save STATUS in ISR
start_delay ; number of quadrant 0 to 1 rollovers before power enable
temp_1 ; general temp var
RAM_END ; Not really used as RAM, only to get last used RAM address
ENDC ; end of the constant block

Getting all of this??

Now you just need to wait for flag_PWM_UPDATE to be set.  Then clear it and do
a table look-up to set next_duty.  Sorta like this:

call InitCpuRam ; Initialize CPU control registers and RAM

bsf PIE1, TMR2IE ; Enable interrupt from TMR2

BSF T2CON,TMR2ON ; Turn on timer 2
BSF INTCON,PEIE ; Enable peripheral interrupts
BSF INTCON,GIE ; Enable all un-masked interrupts


btfss flag_PWM_UPDATE ; 1 = a time slice of the PWM is complete, get the next duty cycle
goto LOOP
bcf flag_PWM_UPDATE ; Clear the flag

call GetNextDuty
movfw next_duty
goto LOOP

Almost done now, you need two more pieces,
1. A "controller" for the table look-up.  ( I called it GetNextDuty )
2. The table look-up itself.  ( I called it GetTable )

Let's do the table lookup first.  This routine returns the table value based
on tbl_offset.  A few things to understand about a table look-up:

Make sure the value of tbl_offset is always a valid number, that is, it never
gets too big.  Look at my example, there are 64 entries in this table, so tbl_offset
must always be 63 to 0.  If it gets any bigger, this code will go into the
weeds and fail.  So in your controller, you will want to use
TBL_END - TBL_START to check when to reset tbl_offset back to zero.

The table length can not exceed 250 entries with this simple example.

The table addresses can not change pages in memory.  That is, the upper
bits of the address can not change.  Consider that the address of GetTable is
0x05FB, so in 4 more instructions, the address will be 0x0600.  This also will
break this code, so make sure that you check the listing file to make sure the
whole table in in the same page.

GetTable ORG BLK_500
movlw high $
movwf PCLATH
movfw tbl_offset
addwf PCL, F

DT 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6
DT 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14
DT 14, 14, 15, 15, 16, 16, 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24
DT 25

Finally, you will need to write the "controller" routine that actually does
the call to 'GetTable'  I will let you work on this, but here are the basics:

increment tbl_offset
test if tbl_offset > ( TBL_END - TBL_START )
   if true, then tbl_offset = 0.
call GetTable

write W to with 'movfw   next_duty'

I used Excel to do the math in order to generate the values in the table.

This is a fairly small and easy program to do just looking at it, but there is
alot to get right.  Once you have a working asm program, the next effort is to
come up with a spreadsheet to generate the table values.

I will watch for your reply, and will help you do this and make it work.

Get started on a complete program and post it, we will all be here to get it

Best wishes,

Offline Offline

Posts: 12

Thank You
-Given: 11
-Receive: 0

« Reply #3 on: March 01, 2008, 10:03:06 22:03 »

Caveman wrote a good sample. But if you want to use picbasic and you have a DAC, you can use direct Picbasic's sinus command in order to produce sinus wave.
Junior Member
Offline Offline

Posts: 41

Thank You
-Given: 12
-Receive: 6

READ, REAd, REad, Read

« Reply #4 on: March 02, 2008, 04:46:33 04:46 »


I don't know PicBasic very well, but I have used it.

But if you want to use picbasic and you have a DAC, you can use direct Picbasic's sinus command in order to produce sinus wave.

I assume that PicBasic has a function for sine(30) to return 0.500

The question was to produce a 50Hz sine wave output.........

Could you show us how to do this in PicBasic? 

I would like to see a shorter example than my home-grown solution in ASM.

After you post your solution, maybe we can all work together and do a solution in C also, or maybe others.

Always remember, give a task to 10 people, you will get 10 different answers.  All may work, all have something to learn from.  Some may be better, but remember, all came from different sources and backgrounds.  Mine may not be the best, but it fit my purposes, and it works. 

When a person asks a question, answer it, or do your best to give a clear insight to the aspects of the subject.

I purposely left out some of the work, but I though I was thorough enough to generate more detailed questions.

Just looking for solutions,

Let's keep on helping, but, please be specific.

Junior Member
Offline Offline

Posts: 35

Thank You
-Given: 59
-Receive: 16

« Reply #5 on: March 02, 2008, 07:37:54 07:37 »

Use almost any Atmel and DDS synthesis  : )  a 2313 can give you the 50hz sine, or square, triangle it depends onthe table you load...

Take a look here:

« Last Edit: March 02, 2008, 07:41:12 07:41 by Matrixx » Logged
Junior Member
Offline Offline

Posts: 91

Thank You
-Given: 87
-Receive: 9

« Reply #6 on: March 02, 2008, 07:37:30 19:37 »

Hi Caveman an Friends...

Please take a look at this interesting thesis about a intertied inverter based on our "old" 16F84.

I´ve generated the HEX file, tranfered to MCU, building a PCB with the PIC and DAC...  ...genrating a 50HZ external

interrupt for RB0...  ...but the PORTB (1 to 7) outputs remains at 0's...

Please, take a look on ASM and explain me what are wrong.

I supose the PORTA conected to TTL buffers have some kind of control on work...

I' beguining on PIC's and my head are burning...  The PDF have good details...

I hope your help. Please!
Pages: [1]
Jump to:  


... Copyright 2003-2999 ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC