CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

R2R Ladder SIN wave

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
SteveAustin
Guest







R2R Ladder SIN wave
PostPosted: Sun May 20, 2007 4:00 am     Reply with quote

Hi all, i have searched all over he site and didn`t find a clear example. I have a 16f917 and a r2r ladder(8 bit resolution) used for DAC.
I must generate a Sin wave, if anybody can give me an example code I`ll be very greatfull.

I`ll wait for you`re posts impatiently.
Best Wishes,
Austin
SteveAustin
Guest







PostPosted: Sun May 20, 2007 4:12 am     Reply with quote

Sin is at 50Hz
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Sun May 20, 2007 5:25 am     Reply with quote

For a sine wave creation you have many choices:

- a full lookup table
- a quadrant lookup table (with some logic)
- a lookup table with linear interpolation between the elements to increase resolution
- a mix of the above two
- no lookup table, use the built-in sin() function (worst choice I think: to much code, hassle with floating poin, etc.)
- look for the CORDIC algorithm
SteveAustin
Guest







PostPosted: Sun May 20, 2007 5:47 am     Reply with quote

i would like a full lookup table,......or any method that you have the code
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Sun May 20, 2007 7:02 am     Reply with quote

I found a quarter lookup table I wrote some time:
Code:
const int sintable[] = {0x00,0x03,0x06,0x09,0x0c,0x10,0x13,0x16,
   0x19,0x1c,0x1f,0x22,0x25,0x28,0x2b,0x2e,
   0x31,0x33,0x36,0x39,0x3c,0x3f,0x41,0x44,
   0x47,0x49,0x4c,0x4e,0x51,0x53,0x55,0x58,
   0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,
   0x6a,0x6b,0x6d,0x6f,0x70,0x71,0x73,0x74,
   0x75,0x76,0x78,0x79,0x7a,0x7a,0x7b,0x7c,
   0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f, 0x7f
};

int my_sin(int deg) {
   if (deg<64) return (sintable[deg]+128);  //first quarter
   if (deg<128) return (sintable[128-deg]+128); //second
   if (deg<192) return (128-sintable[deg-128]); //third
   return (128-sintable[~deg]); //fourth
}

I use 1/256th of a circle as a parameter, the function returns 128 as the zero level.
It can be optimized further to use bit_tests and complementing values.

All you have to do is to add a timer interrupt to inc a counter 256values = 1 cycle 50 cycles/sec and to output the result to the resistor ladder.
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Sun May 20, 2007 7:25 am     Reply with quote

Since you talk about sine waves I assume you need the sines in sequence

Tables and built in functions look up random sines with equal efficiency.

The CORDIC however since it is rotational can be modified to to produce sines in sequence.

Another approach is finite differences. Look at Bresenham's algorithm for a circle. Set the center at 0,0 and the radius at 1 ( the unit circle) the x,y position of a point on the circle is cosx,siny. A few add and subtracts and a multiplication and you move from x,y to x1,y1 where x1-x is your bit resolution. Looking at the y value you went from sin(y) to sin(y1) in sequence
So suppose you resolution was 16 bits then your unit radius is 65535...its like you have a screen 65536 x 65536 pixels and your are drawing a circle that touches the edges using Bresenham's algorithm. Again this is only useful if you can take advantage of the fact you need sines in sequence ...if this is true than you can gain great efficiency.
below is a breshenham adaption for a screen with a rectangular pixel size
aka aspect ration. I have comments to show the math involved.
You would need to go to 16 or 32 bit resolution so modify the code accordingly.

The key to note is the next sine is just

if (delta<0) delta=delta+2*x+3;
else {delta=delta+2*(x-y)+5;y=y-1;}
x=x+1;
the code uses the 8 fold symmetry of a circle and traces through 45 degrees. You sine wave also has this symmetry

Code:
void circle(int x_ctr,int y_ctr,int radius,int pen_size,int set)
{
int x,y,r,x1,y1;

signed long delta;


// y axis is shrunk to reflect the aspect ratio
// this uses bresenham's algorithm
// theory
// 0=x^2+y^2-r^2 is true circle centered at 0,0
// error is x^2+y^2-r^2
// looking at north to north east octant
// pixels are * 0
//              0
// algorithm chooses pixel due east or south east
// * has the coord (x,y) both 0 pixels have an x coord of x+1
//   mid pt has coord of (x+1,y+1/2)
//   error is (x+1)^2+(y+1/2)^2 -r^2
//   error >0 draw south east ( x+1,y-1)  pixel   else draw east pixel (x+1,y)
//   now we can compute the error in advance for the next iteration
//   change in error from (x+1,y-1/2) to (x+2,y-1/2) is 2x+3
//                        (x+1,y-1/2) to  (x+2,y-3/2)  2x+3 -2y+2
//   Note: delta is the error in the code below
//         if delta is <0 then we decrement y
r=70;
if (radius<70) r=radius;  // max radius is 70 pixels
for (r=radius-pen_size;r<=radius;r++)
{
x=0;
y=r;

// assume last step was to south east pixel from (0,r)  or 2*0-2*r+5
  delta=(long)5-(long)2*(long)r;
loop:

    y1=(long)y*(long)11/(long)14; /// aspect ratio
    x1=(long)x*(long)11/(long)14; /// aspect ratio

    plot(x_ctr+x,y_ctr+y1,set);
    plot(x_ctr+x,y_ctr-y1,set);
    plot(x_ctr-x,y_ctr+y1,set);
    plot(x_ctr-x,y_ctr-y1,set);

    plot(x_ctr+y,y_ctr+x1,set);
    plot(x_ctr+y,y_ctr-x1,set);
    plot(x_ctr-y,y_ctr+x1,set);
    plot(x_ctr-y,y_ctr-x1,set);


    if (delta<0) delta=delta+(long)2*(long)x+(long)3;
    else          {delta=delta+(long)2*((long)x-(long)y)+(long)5;y=y-1;}


    x=x+1;
 if (x<=y) goto loop;
 }
 }
SteveAustin
Guest







PostPosted: Sun May 20, 2007 7:27 am     Reply with quote

I thank you very much for the code libor, but you see i`m a little noob in lookup tables. I have 8 ports which i need to combine to get an analogic result (from 0 to 5V; first are MSB and least are LSB).
Now the big question is how to command them, because the lookup table gives me just some numbers.
I`ll wait you`re answer
Thanx very much
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Sun May 20, 2007 7:49 am     Reply with quote

The easiest if you would use continous ports (bits) of one port register (B port for example) in their original bit order. Then you could use a simple output_b(value) instruction.
If your ports are mixed over various addresses, then you can remap them using #bit
#bit LADDER_0BIT PORTB.5
#bit LADDER_1BIT PORTB.2
..etc

and set them directly
LADDER_0BIT = bit_test(value,0);
LADDER_1BIT = bit_test(value,1);
etc.

Though I would suggest to prepare all output byte(s) first in a temp register and write it to the output at once to avoid the short mismatched values from the sinewave during port update.
Guest








PostPosted: Sun May 20, 2007 1:44 pm     Reply with quote

If you only need to generate sine waves with your R-2R ladder, then you could change the resistor weighting from R-2R to give you a sine wave by incrementing/decrementing the output linearly and using the resistor weighting to remove the need for any clever calculations.
SteveAustin
Guest







PostPosted: Mon May 21, 2007 12:19 am     Reply with quote

Thank you for you`re nice replay libour, i allmost done it but i still have some difficultys.
My testing code is:
Quote:

#include "16F917.h"
#include <stdio.h>
#include <stdlib.h>
#fuses INTRC_IO,NOPROTECT,NOWDT,PUT
#use delay(clock=4000000)
#define INT_PERIPHERAL 0x0B40 // 2864

#byte T1CON = 0x10 // timer 1
#byte INTCON = 0x0B // Intcon
#byte PIE1 = 0x8C // PIE
#byte PORTE = 0x09
#byte PORTC = 0x07

#bit TMR1ON = T1CON.0 // 0 Bit --> Timer1 - 1/8
#bit PEIE = INTCON.6 // PEIE
#bit GIE = INTCON.7 // GIE
#bit TMR1IE = PIE1.0 // TMR1IE
//===============================
#bit LADDER_0BIT = PORTE.0
#bit LADDER_1BIT = PORTE.1
#bit LADDER_2BIT = PORTE.2
#bit LADDER_3BIT = PORTC.3
#bit LADDER_4BIT = PORTC.4
#bit LADDER_5BIT = PORTC.5
#bit LADDER_6BIT = PORTC.6
#bit LADDER_7BIT = PORTC.7

#define enable PIN_B0 //input line from host
int c=1,place,o,value,i;
const int sintable[] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
0x100
};

void main()
{
setup_oscillator(OSC_4MHZ);
TMR1IE = 1;
GIE = 1;
PEIE = 1;
SETUP_TIMER_0(RTCC_INTERNAL | RTCC_8_BIT|RTCC_DIV_32);
ENABLE_INTERRUPTS(GLOBAL); // enable interrupts in general to be active
ENABLE_INTERRUPTS(INT_RTCC); // enable the interrupt for Timer 0
//--------------------------------------------------------------------------------



while(1){ // Prevent PIC from going to sleep.
if(c==1){ //case 1
for(i=0;i<257;i++){
if(i==256){
i=0;
}
sintable[i]=value;
LADDER_0BIT = bit_test(value,0);
LADDER_1BIT = bit_test(value,1);
LADDER_2BIT = bit_test(value,2);
LADDER_3BIT = bit_test(value,3);
LADDER_4BIT = bit_test(value,4);
LADDER_5BIT = bit_test(value,5);
LADDER_6BIT = bit_test(value,6);
LADDER_7BIT = bit_test(value,7);
delay_us(39);
}
LADDER_0BIT = bit_test(value,0);
output_high(PIN_D3);
if(!input(enable)){
c=2;
delay_ms(300);
}
}
if(c==2){ //case 2

output_low(PIN_D3);
if(!input(enable)){
c=1;
delay_ms(300);
}
}
}
/*setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);

setup_timer_2(T2_DIV_BY_1, 128, 1);

pwm_l = 128;
pwm_r = 128;

set_pwm1_duty(pwm_l);
set_pwm2_duty(pwm_r);
*/

}

#INT_RTCC // This function will be called on a Timer0 interrupt
void timer0_interrupt_service()
{


}


Well my pins stay to 0 logic mo mater i do.
I tried something easyer like making a port an output and 1 logic:
Quote:

value = 0xFF;
LADDER_0BIT = bit_test(value,0); //ladder_0bit = pinE0

It`s staying to 0 logic too.
Soo what am i doing wrong??????

If you`ll be so kind enough to guide me, I`ll be very happy
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Mon May 21, 2007 2:27 am     Reply with quote

Just a few thoughts now for beginning:
- I see no instruction you set the ports to output, if you use variable mapping to set their level, the compiler does not know about it and does not set the TRIS register automatically as with the output_high, ..low commands. All ports are inputs as default after reset. I suggest to use #USE FAST_IO() -s (manual direction setting mode) and set the ones you use as output with set_c_tris() instruction.

...or as another option, stick to output_low, output_high instructions:

if bit_test(value,0) output_high(PIN_E0);
else output_low(PIN_E0);
...
...so the compiler cares for port directions. (STANDARD_IO setting)


for(i=0;i<257;i++){
if(i==256){
this makes no sense, the i is an int type, its value range is 0-255, however you can take use of this 'feature': just increment it, it will roll over from 255 to 0 automatically.
SteveAustin
Guest







PostPosted: Mon May 21, 2007 9:43 am     Reply with quote

Thanx very much libor, everything is working fine now :D
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Mon May 21, 2007 2:25 pm     Reply with quote

I know you have already done this with a lookup table
but I had some spare time and wanted to do some mathematics.
The few lines of code below will generate sines to 8 bit precision for all for 0 to 255

Code:

#include <18F2320.h>
#fuses NOWDT,NOLVP,INTRC_IO
                    //Internal RC Osc

#use delay(clock=4000000)

#use rs232(debugger)
/// the sum of the first n numbers=n(n+1)/2
/// sum(n+1)=sum(n)+n+1
/// the sum of every pt on the y axis is y(y+1)/2=sum(y)
///     or y^2=2sum(y)-y
/// the sum of every pt on the x axis is x(x+1)/2=sum(x)
///     or x^2=2sum(x)-x
/// for a circle x^2+y^2=R^2
/// so 2sum(x)-x+2sum(y)-y=r^2 for the true circle
/// if we set x=0 and y=r then 2sum(r)-r=r^2
/// Now consider the increase in x^2 as x moves from pt x to pt x+1
/// (x+1)^2 -x^2
/// substituting sum we get
/// 2(sum(x+1))-(x+1) -( 2sum(x)-x)
/// 2(sum(x)+x+1) -(x+1) -2sum(x)+x
/// x+1+x or 2x+1
/// but since x^2+y^2 =r^2 that means y^2 must decrease by the same amount 2x+1
/// the goal is to find the change in y value that most closely matches
///
/// the initial y^2 value is r^2 so the initial 2sum(r)+r=r^2
/// so first available move from pt y to pt y-1  value
/// generates a decrease in y^2
/// of 2sum(y)-y -( 2sum(y-1)-y-1)
/// or 2(sum(y-1)+y)-y -( 2sum(y-1)-y-1) or 2y+1
/// 2x+1 and 2y+1 will only match when x=y so there are always errors deltax deltay
/// acumulating between the movements of x and y
///
/// on a circle of radius 255 we have x =255*cos(theta) y=255*sin(theta)
/// where theta is arctan(y/x)  x is stepped in unit increments
/// theta decreases from 90 to 0
/// y represents the sine 1/4 wave from 90 to zero in 255 increments of dx
///
// for testing
//#include "c:\Program files\PICC\drivers\MATH.H"

void main()
{
//float a,sina;
int8 x,y,r;

signed int16 deltax,deltay;

setup_oscillator(OSC_4MHZ);
r=255;
x=0;
y=r;
deltax=0;
deltay=(long)2*(long)r+(long)1;

loop:
x=x+1;
deltax=deltax+(long)2*(long)x+(long)1;

if ( deltax>deltay )
  {
   /// we can move y
 
   deltay=deltay-deltax;
    deltax=0;
    y=y-1;
    deltay=deltay+(long)2*(long)y+(long)1;
   while (deltay<0)
   {
    y=y-1;
    deltay=deltay+(long)2*(long)y+(long)1;
   }
 
   
  }
  // a=atan((float)y/(float)x);
  // sina=255L*sin(a);
  // printf("\n\r x=%u y=%u sin=%f",x,y,sina);
    printf("\n\r x=%u y=%u ",x,y);
  if (x<255) goto loop;
 
while(1);
   
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group