/////////////////////////////////////////////////////////////////////////
////                          main01.c                                 ////
////                                                                 ////
////  Copyright 2007 by James K Beard and Rowan University.          ////
////                                                                 ////
////  This program reads two A to D converters and uses them as      ////
////  inputs for two PWM outputs.  Two pushbuttons are used to       ////
////  toggle outputs of the PWM between I/O pins, so that motor      ////
////  direction can be reversed.  An additional pushbutton is passed ////
////  through to an I/O pin as a magnet driver.                      ////
////                                                                 ////
////  I/O Pins:                                                      ////
////  Pin   No. Function                                             ////
////  A0    2   INPUT  Speed thumbwheel input                        ////
////  A1    3   INPUT  Lift thumbwheel input                         ////
////  B1    22  INPUT  Auxiliary pushbutton, 0 => down               ////
////  B2    23  INPUT  Auxiliary toggle, intially 0                  ////
////  C0    11  OUTPUT  Lifft up-down, 0 => down (initially down)    ////
////  C1    12  OUTPUT  Lift PWM output                              ////
////  C2    13  OUTPUT  Propulsion PWM output                        ////
////  C3    14  OUTPUT  Propulsion fwd-bk, 0 => backw (init. fwd.)   ////
////  C4    15  OUTPUT  Magnet drive, 0 => off (initially off)       ////
////  C5    16  INPUT  Magnet toggle, 0 => down (initially off)      ////
////  C6    17  INPUT  Lift toggle, 0 => down (initially off)        ////
////  C7    18  INPUT  Propulsion drctn toggle 0 => dwn (init off)   ////
////                                                                 ////
////  April 5, 2007:  deleted output to bus B, added delay in loop   ////
////  and added a fourth pushbutton on bus B1, output on B2          ////
/////////////////////////////////////////////////////////////////////////

#include <16F876A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device ADC=10 //10 bits right justified in a 16 bit word
#use delay(clock=4000000) //Put your clock rate here; 4 MHz == 4000000
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //RS-232 not used
#define scale_shift 4 //log2(T2_Ticks/2^(ADC bits)); see below
#define speedpos 0 //Propulsion is bottom 4 bits
#define liftpos 4 //Lift is top 4 bits
void main() {
   long int speed, lift, adc_out; //long int is 16 bits in CCS PIC C MCU compiler
   int lsb;//speed_Hbridge, lift_Hbridge, Hbridge, lsb; //8 bits
   short forward, lift_up, magnet_on, aux_function; //One bit
   short pbp, pbp_state, pbl, pbl_state, pbm, pbm_state, pbx, pbx_state; //Anti-bounce logic
//SETUP
   SET_TRIS_B(0b00000010); //All outputs except pushbutton on B1; use only output on B2
   SET_TRIS_C(0b11100000); //Buttons input on C7, C6, C5, magnet drive on C4
//   setup_port_a( ALL_ANALOG );  //Inputs are A0 A1 A2 A3 A5, ref is 5 V
   setup_adc_ports( ALL_ANALOG );  //Inputs are A0 A1 A2 A3 A5, ref is 5 V
   
   setup_adc( ADC_CLOCK_INTERNAL ); //Internal clock, or box crystal if there
//Set up PWM clock, which is always timer 2
//Minimum Frequency:
//The resolution is the number of ticks in a PWM period, and we want 10 bits
//A period is 1/(PWM frequency)
//The number of ticks in Timer 2 is
//  T2_Ticks = 4*T2_DIV*(period+1)
//We will use a period (second counter) of 255
//T2_DIV can be 1, 4 or 16
//This gives us 1024 (10 bits), 4096 (12 bits), or 16385 (14 bits)
//PWM frequency determination
//PWM frequency is divided down from master clock
//  PWM frequency = Clock/T2_Ticks)
//We have a 4 MHz clock.
//This gives us a choice of 3906 Hz, 977 Hz or 244 Hz
//We will try 244 Hz.  If it is too low and motor buzzes, try 977 Hz
   setup_timer_2(T2_DIV_BY_16, 255, 1);
//The ADC output must be scaled so that 2^10=1024 is scaled to the PWM period
//See "#define scale_shift 4" above
   setup_ccp1(CCP_PWM); //Configure CCP1 as a PWM
   setup_ccp2(CCP_PWM); //Configure CCP2 as a PWM
//VARIABLE INITIALIZATIONS
   pbp=1;  //Initialize all pushbuttons as off, with pullups
   pbl=1;
   pbm=1;
   pbx=1;
   pbp_state=1;
   pbl_state=1;
   pbm_state=1;
   pbx_state=1;
   forward=1; //Initially, move forward
   lift_up=0; //Initially, hook moves down
   magnet_on=0; //Initially, magnet is off
   aux_function=0; //Initially, auxiliary function is off
   do {
//Read speed thumbwheel
      set_adc_channel(0); //Propulsion thumbwheel is port A0
      delay_us(10);   //A small delay is required before a read
      adc_out=Read_ADC();
      lsb=bit_test(adc_out,0); //Extend LSB on scaling shift
      speed = ((adc_out+lsb)<<scale_shift)-lsb;
      set_pwm1_duty(speed); //Output thumbwheel data to PWM for propulsion
//      speed_Hbridge=input_state(PIN_C2); //Set drive for first MOSFET
//      speed_Hbridge|=(speed_Hbridge)<<1; //Second MOSFET
//Read lift thumbwheel
      set_adc_channel(1); //Crane lift thumbwheel is port A1
      delay_us(10);   //A small delay is required before a read
      adc_out=Read_ADC();
      lsb=bit_test(adc_out,0); //Extend LSB on scaling shift
      lift = ((adc_out+lsb)<<scale_shift)-lsb;
      set_pwm2_duty(lift); //Output thumbwheel data to PWM for lift motor
//      lift_Hbridge=input_state(PIN_C1);;//Set drive for first MOSFET
//      lift_Hbridge|=(lift_Hbridge)<<1; //Second MOSFET
//Check push button for propulsion direction reversal
      pbp=input_state(PIN_C7);  //Read propulsion pushbutton (0 == pushed)
      forward^=(!pbp & pbp_state); //Toggle if transition from 1 to 0
      pbp_state=pbp;
      output_bit(PIN_C3,forward);  //Put propulsion toggle on pin C3
//Check push button for crane lift direction reversal
      pbl=input_state(PIN_C6);
      lift_up^=(!pbl & pbl_state);
      pbl_state=pbl;
      output_bit(PIN_C0,lift_up);  //Put lift toggle on pin C0
//Check magnet push-on, push-off button
      pbm=input_state(PIN_C5);
      magnet_on^=(!pbm & pbm_state);
      pbm_state=pbm;
      output_bit(PIN_C4,magnet_on); //Put magnet toggle on pin C4
//Check extra, push button
      pbx=input_state(PIN_B1);
      aux_function^=(!pbm & pbm_state); //Put push button action here
      pbx_state=pbx;
      output_bit(PIN_B2,aux_function); //Put auxiliary function on pin B2
//Build and output H-bridge output word on port B
//This is probably too slow for smooth motor speed control
//because the waveform update granularity is the loop time,
//not the Timer 2 comparator, so a hardware solution is best.
//      speed_Hbridge = (!forward) ? speed_Hbridge : speed_Hbridge<<2;
//      lift_Hbridge = (!lift_up) ? lift_Hbridge : lift_Hbridge<<2;
//      Hbridge = (speed_Hbridge << speedpos)  | (lift_Hbridge << liftpos);
//      output_B(Hbridge); //Output the H-bridge bits to bus B
      delay_ms(20);  //Delay to avoid multiple spurious pushbutton toggles
   } while (TRUE);
}

