⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cerebv2.c

📁 a zipped example of communication between the Cerebellum 16f877 pic board and the CMUcam. There are
💻 C
字号:
/* Version Information:
This is Version 2, so it's for the new Cerebellum in which Btn1 is connected to B0
and the motor direction is now B1 instead of B0.

*/

/* Cereb.c is the main helper file for Cerebellum Programming. 
   See the API for details of how to use this stuff.
	Much of original code is courtesy of Kwanjee Ng
	Illah Nourbakhsh 2002 
*/

/* things to add later -illah- :

1 Add CMUcam communication functionality in the form of a cmucam.c include.

*/

// API provided for cerebv2 //////////////////////
//
// call init_cerebellum() first in your main
// turn on an led with set_bit(PORTB, (GREEN|YELLOW)); turn off with clear_bit
// (PORTB & BTNn) is true if button n is depressed and false otherwise
//
// To output on a digital pin on portD, use set_bit(PORTD, n); where n is 0-7 (and clear_bit)
// These are the pins to generally use for digital output.
// But if you're using the Servoes, you will have to set the mask for the servoes
// appropriately so that you can preserve some of the pins for your own digital out
// purposes.  Read the Servoes section below.
// 
// call ser_init(SER_115200) to set up hardware serial port
// ser_tx(char c) sends a character out over the serial line
// ser_putstring(const char *text) writes a CONST string out the serial line
// ser_writechar(char c) writes out a character in decimal (good for debugging!)
// ser_rcv() is a blocking receive char call that returns a char
//		note that if the input buffer has overflowed it dumps the buffer
//		and continues waiting for a new character to return!
// ser_rcv_nb() is a nonblocking receive char call that returns a char
//          or if there is nothing waiting, returns a 0. Does NOT check for
//		frame error and overflow conditions!!!
// to save memory, if not using the serial port, don't call ser_init() and then
// don't use any of the above functions.
// 
// to use servoes, begin by calling servo_init() in your main.
// then before expecting servoes to get used make servo_state=1;
// servoes use interrupts, so make sure you're starting interrupts:
//		set_bit(INTCON, GIE);
// then command a servo by commanding servo_pos[n]=p. This will drive
// the servo on port Dn to position p.  If p is zero, it deactivates the servo.
// to save memory, if not using servoes don't call servo_init(), do not
// put "set_bit(INTCON, GIE);" in your code, and also
// go to cereb.c and find void interrupt(void) and comment out the line that
// calls do_servo().
//
// to use some servoes and other portD lines for direct digital outputs, note
// the variable servo_mask.  This defaults to 11111111b, which means all pins
// on portD are configured for servo output use.  If you want to have D0,D1
// and D3 be servo pins and the rest controlled directly by you, using set_bit,
// then in Main() you would include the line: "servo_mask = 00000111b;"
// Then the servo controller would ignore pins D3 - D7 and you can set them
// as desired. For example you could set pin3 to be high: "set_bit(PORTD,3);"
// Note the tristate is still configuring ALL of portD for digital output (not input).
//
// to use the analog-digital input lines, first in main you must initialize
// with the command: ADCON1=0;
// to read analog input channel ch, use adc_read(ch) which returns a char
// ch should be 0-7 inclusive. numbering on cerebellum goes from A0 as channel
// zero, left-to-right and top-to-bottom, so that E2 is analog channel 7
//
// to use the motor PWM outputs, first call pwm_init() in your code.
// if both commands are in there, call ser_init() first. The motor command
// is pwm_setvel8(n,dir,duty) where n=0 or 1 (0 means Motor1 on Cerebellum
// and 1 means Motor2 on Cerebellum). dir is direction (0 or 1) and duty is
// a char, with 0 meaning off and 255 meaning full-on.
// To save memory, if you are not using motor PWM then comment out pwm_init() in
// main().
// // 
////////////////////
// 

// Below code is for implementing the hardware serial port //
char ser_tmp;
char SSPCON@0x14;
char PIR1@0x0c;
char PIE1@0x8c;
char TRISC@0x87;
char TRISD@0x88;
char TXSTA@0x98;
char RCSTA@0x18;
char SPBRG@0x99;
char RCREG@0x1a;
char TXREG@0x19;
char PORTD@0x08;
char myOption_Reg@0x81;

// call ser_init to initial hardware serial as: ser_init(SER_115200) //
void ser_init(char spbrg_val) {
	
	SSPCON = 0;
	PIR1 = 0;  // this ensures also RCIF = TXIF = 0;
	clear_bit(PIE1,5); //RCIE = 0;
	clear_bit(PIE1,4); //TXIE = 0;
	TRISC = TRISC | 0xC0; // setup TRISC for USART use
	SPBRG = spbrg_val;
    	TXSTA = 000100100b; // txen, brgh
	RCSTA = 010010000b; // spen and cren, the rest all off
	ser_tmp = RCREG; // flush the rx buffer
	ser_tmp = RCREG;
	ser_tmp = RCREG;
}

// low-level call to send a character serially.
void ser_tx(char c) {

	//wait for txif to go hi
	while (!(PIR1 & 16)) ; //while (!TXIF);
	//disable_interrupt(GIE); //?
	TXREG = c;
	//enable_interrupt(GIE);  //?
}

void ser_putstring(const char* text) {
    char i = 0;
    while( text[i] != 0 )
        ser_tx( text[i++] ); 
}

// writes a character out the serial port as a 3 digit number
void ser_writechar(char data) {
    ser_tx( '0' + data/100 );
    ser_tx( '0' + (data%100)/10 );
    ser_tx( '0' + data%10 );
}

// this is a blocking receive //
char ser_rcv(void) {
	while (1) {
		if (RCSTA & 2) { // RCSTA bit 1 is overflow error
			// overflow error
			clear_bit(RCSTA,CREN); // CREN is RCStatus bit 4 //
			ser_tmp = RCREG; // flush the rx buffer
			ser_tmp = RCREG;
			ser_tmp = RCREG;
			set_bit(RCSTA,CREN); // CREN = 1;
		}
		else if (RCSTA & 4) { // RCSTA bit 2 is framing error
			// framing error
			ser_tmp = RCREG;
		}
		else if (PIR1 & 32) { // PIR1 bit 5 is RCIF
			ser_tmp = RCREG;
			return ser_tmp;
		}
	}
}

// nonblocking receive returns 0 for any error, including nothing to read
char ser_rcv_nb(void) {
	if (PIR1 & 32) {
		ser_tmp = RCREG;
		return ser_tmp;
	} else {
		return 0;
	}
}

// this next section is for servo control /////////////

char servo_state = 0;
char servo_curr = 0;
char servo_mask = 11111111b; // default that all of portD will be
					// used for servo operations rather 
					// than direct digital output twiddling
char servo_switch = 1;
char servo_pos[8] = {0,0,0,0,0,0,0,0};
char _servo_free = 0;

void servo_init(void) {
    OPTION_REG = 132; // bit 7 = 1 for portB pull-up and bit2 is for prescaler
				// TMR0 @ 1:32, prescaler to timer0 (for servo control)
    TRISD = 0; // port D as outputs	for servo commands!
	// in fact we already do this in init_cerebellum(); we do it again for //
	// redundancy only here //
    set_bit(INTCON, T0IE); //T0IE = 1 ie enable TMR0 overflow bit - T0IE is bit 5
    delay_ms(1);   
}

void do_servo(void) {
	clear_bit(_servo_free,0); // the bit 0 of servo_free = 0;
	if (servo_state == 1) {
		// next intr in 0.6 ms
		TMR0 = 153;
		//TMR0 = 145;
		if ((servo_pos[servo_curr] != 0) && ((servo_mask & servo_switch) != 0))
			PORTD |= servo_switch; // output hi to specific servo pin out
		servo_state = 2;
                set_bit(_servo_free,0); // the bit servo_free = 1;
	}
	else if (servo_state == 2) {
		TMR0 = 255 - servo_pos[servo_curr];
		servo_state = 3;
	}
	else if (servo_state == 3) {
		if ((servo_mask & servo_switch) != 0)
			PORTD &= ~servo_switch; // output lo to this servo bit, but
							// preserve all other digital hi's on port D
		TMR0 = servo_pos[servo_curr];
		servo_curr = servo_curr + 1;
		servo_curr = servo_curr & 0x07; // increment to next servo, mod 8 //
		servo_switch = servo_switch << 1;
		if (servo_switch == 0) servo_switch = 1; // increment to next servo port bit //
		servo_state = 1;
	}
	clear_bit(INTCON, 2); // clear T0IF = 0;
}

// end of servo control

// Analog-digital converter code //////////////////

char ADCON0@0x1f;
char ADRESH@0x1e;
char ADCON1@0x9f;

// this is called with a character 0 through 7 and returns 
// an analog-digital reading
char adc_read(char ch) {
	ADCON0 = (ch << 3) & 56; // shift ch to correct bit position
	ADCON0 |= 0x81; // Tad = Fosc/32, ADC on.
	delay_us(12); // wait for Tacq
    	ADCON0 |= 4; // acquire go!	
      while (ADCON0 & 4); // wait for AD to complete
      delay_us(4); // wait for 2Tad
      return ADRESH; // return captured value
}

// End of Analog-Digital conversion code //////////////

// PWM Motor code //////////////
//globals for motor PWM control//
char ccpcon;
char CCP1CON@0x17;
char CCP2CON@0x1d;
char TMR2@0x11;
char PR2@0x92;
char CCPR1L@0x15;
char CCPR2L@0x1b;
char T2CON@0x12;
char PORTC@0x07;

void pwm_init(void) {
	// init hardware PWM
	CCP1CON = 0; // CCP off
	CCP2CON = 0;
	TMR2 = 0;
	PR2 = 0xff; // 0x3f: 78kHz, 0xff: 19.5kHz
	CCPR1L = 0; // actually, I don't think the output is inverted! 0 = stop.
	CCPR2L = 0;
	TRISC = TRISC & 11011000b; // set DC motor pins to output
	clear_bit(TRISB,1); // clear for motor direction output lines - chnged 0 to 1 illah 1/16/03
	clear_bit(TRISA,4); // clear for motor direction output lines	
	ccpcon = 00111100b; // setup reg mask
	CCP1CON = ccpcon; // CCP module to PWM mode
	CCP2CON = ccpcon;
	set_bit(T2CON,TMR2ON);
}

// parameters are motor number (0 or 1), direction (0 or 1) and speed //
// presumes that port c, bits 5 and 0 are being used for this.
void pwm_setvel8(char n, char d, char c) {
	if (n == 0) {
		if (d == 0) { //set_bit(PORTC,5);
			set_bit(PORTC,5);
			clear_bit(PORTB,1); // changed 0 to 1 illah 1/16/2003
		}
		else { //clear_bit(PORTC,5);
			clear_bit(PORTC,5);
			set_bit(PORTB,1); // changed 0 to 1 illah 1/16/2003
		}
		CCPR1L = c;
	}
	else if (n==1) {
		if (d == 0) { //set_bit(PORTC,0);
			set_bit(PORTC,0);
			clear_bit(PORTA,4);
		}
		else { //clear_bit(PORTC,0);
			clear_bit(PORTC,0);
			set_bit(PORTA,4);
		}
		CCPR2L = c;
	}
}
// END of PWM Motor Code ///////////////////////

// interrupt handler code

// variables for saving state during interrupt handling
int save_w;
int save_status;

//the actual interrupt handler function itself.
void interrupt(void) {
      //store current state of processor
	asm {
   	movwf _save_w
   	swapf STATUS,W
   	bcf   STATUS,5
   	bcf   STATUS,6
   	movwf _save_status
	} // end asm

	if (INTCON & 36) do_servo();
      // in other words if (TOIE & TOIF) then do_servo() //
	
	// restore processor state
	asm {
   	swapf _save_status,W
   	movwf STATUS
   	swapf _save_w,F
   	swapf _save_w,W
	} // end asm
}

// this initializes the buttons and leds on cerebellum //
// this also initializes PortD digital as outputs, for servoes and digital outs //
void init_cerebellum(void)
{
	TRISB &= 207; // make port B pins 4 and 5 write-out able for LED's by setting
			  // tristate bits 4 and 5 to zero
	PORTB &= 207; // turn off yellow and green LED's   
      TRISD = 0; // port D as outputs for Servo cmds and digital output settings    	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -