//  Differential input to fixed point number +/-127 mVolts 
// echoed to the PWM with a gain of 10
// The PWM runs at 62,500 Hz for lower audio noise.
// The ADC sampling and PWM update run at 7812 Hz.
// The ADC input uses a UNION to avoid a multiply.
// NOTE -- You MUST MOUNT the Aref jumper  

#include <Mega32.h>
#include <stdio.h> 
#include <stdlib.h> 
#include <delay.h>
//I like these definitions
#define begin {
#define end   } 

#define int2fix(a)   (((int)(a))<<8)            //Convert char to fix. a is a char
#define float2fix(a) ((int)((a)*256.0))         //float to fix 
#define fix2int(a)   ((signed char)((a)>>8))    //Convert fix to char. a is an int

//Union avoids shifting when merging ADC output bytes
union ADtype begin 
    signed int vv ;  // temp membrane voltage 
    char Ain[2];
end AD ;
signed int v ;   // ADC voltage

//=============================================================
//read ADC 7812 scamples/sec  
// total time in isr must be less than 2048 cycles
interrupt [TIM1_COMPA] void ADCread(void)
begin 
    // read the voltage x10, but     
    // actual voltage = ADCH/128.0*Vcc/gain = ADCH>>8   since Vcc/10 = 1/2
    // We want the voltage in the upper byte to be in millivolts 
    // Convert to millivolts (ADC>>8)*1000, or very nearly ADC<<2
    AD.Ain[0] = ADCL;
    AD.Ain[1] = ADCH;
    v = (AD.vv)<<2 ;   // convert to millivolts in fixed 8:8 notation
    // start the next conversion
    ADCSR.6 = 1 ;  
    
   // update PWM output 
   // PWM is 0 to 5 volts in 256 counts
   // If we call 2.5 volt offset "zero" output (OCR0=128)
   // and we want a gain of 10 so that 100 mV input yields
   // 1 volt above zero out (3.5 volts) then we need to
   // scale v. Now for the PWM, 256/5=51.2 couts/volt output so if we 
   // divide v by 2 and add 128
   // (v/2)+128 we get approximately the right number
   // (within 2%).
	OCR0 = (fix2int(v)>>1) + 128 ; 
	  
end //ISR

//===============================================================
void main(void)
begin 
    //set up the A port
    //for analog inputs
    DDRA =  0 ; 
    PORTA = 0;
     
    //set up the B.3 port for PWM output
    DDRB.3 = 1 ; 
    
   //init the A to D converter 
   // left adj /EXTERNAL Aref
   //!!!CONNECT Aref jumper!!!! 
   // 10*(chan1 - chan0)
   ADMUX = 0b00101001;   
   //enable ADC and set prescaler to 1/128*16MHz=125,000
   //and clear interupt enable
   //and start a conversion
   ADCSR = 0b11000111; 
   
   //turn on timer0 pwm with period= 256 cycles  
    // (62,500 samples/sec) in fast PWM mode.
    TCNT0 = 0; 
    TCCR0 = 0b01101001 ;   //bit 4 inverts the PWM
    
    // timer 1 interrupt every 2048 cycles to update potential 
    // and update OCR0
    TCCR1B = 0b00001001 ;
    TCNT1 = 0; 
    OCR1A = 2047;
    TIMSK = 0b00010000 ;  
   #asm("sei") ;
   
   //init the UART
   UCSRB = 0x18;
   UBRRL = 103;
   printf("starting...\n\r"); 
   
  
   // just spins and prints voltages
   while (1)
   begin
    printf("%d\n\r",fix2int(v))  ;
	delay_ms(200) ;
  end
end