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

📄 motorctrl.c

📁 This isThe program of AVR microchip controling motor using PWM and PID.
💻 C
字号:
//*****************************************************************************
// File Name	: pid.c
// 
// Title		: test pid implementation
// Revision		: 1.1
// Notes		:
// Target MCU	: Atmel AVR series
// Editor Tabs	: 4
// 
// Revision History:
// When			Who			Description of change
// -----------	-----------	-----------------------
// 05-Feb-2003	pstang		Created the program
//*****************************************************************************

 
//----- Include Files ---------------------------------------------------------
#include <avr/io.h>		// include I/O definitions (port names, pin names, etc)
#include <avr/signal.h>	// include "signal" names (interrupt names)
#include <avr/interrupt.h>	// include interrupt support

#include "global.h"		// include our global settings
#include "uart.h"		// include uart function library
#include "rprintf.h"	// include printf function library
#include "timer.h"		// include timer function library (timing, PWM, etc)
#include "vt100.h"		// include VT100 terminal support
#include "a2d.h"		// include A2D converter support
#include "encoder.h"	// include encoder driver
#include "fixedpt.h"	// fixed-point math support
#include "cmdline.h"

// motor connection defines
#define MOTOR_BRAKE_PORT	PORTC
#define MOTOR_BRAKE_DDR		DDRC
#define MOTOR0_BRAKE		PC2
#define MOTOR1_BRAKE		PC3

#define MOTOR_PWM_PORT		PORTD
#define MOTOR_PWM_DDR		DDRD
#define MOTOR0_PWM			PD4
#define MOTOR1_PWM			PD5

#define MOTOR_DIR_PORT		PORTD
#define MOTOR_DIR_DDR		DDRD
#define MOTOR0_DIR			PD6
#define MOTOR1_DIR			PD7

// motor controller mode defines
#define CONTROLMODE_POS		0
#define CONTROLMODE_VEL		1

volatile s32 EncoderLastPos=0;
volatile u32 Counts=0;
volatile u32 Cycles=0;
volatile u08 TimerIncs=0;
volatile u08 ServiceFlag=FALSE;
volatile struct Controller_struct
{
	// controls coefficients
	s32 Kp;				// proportional gain
	s32 Ki;				// integral gain
	s32 Kd;				// derivative gain
	// state variables
	s32 error;			// error (input-feedback)
	s32 error_last;		// previous error
	s32 error_integ;	// integral of error
	s32 error_diff;		// derivative of error
	// limits
	s32 windupMax;		// integral wind-up limit
	s32 outputMax;		// motor output clamp (limit)
	// input and output
	s32 output;			// motor output
	s32 input;			// user input
	s32 feedback;		// motor feedback
	// counters
	u32 counts;
	// mode
	u08 mode;			// control mode
} Controller;

// motor command system
void motorCommand(void);
// motor command functions
void motorPosGo(void);
void motorGetCoeffs(void);
void motorSetCoeffs(void);
void motorSetMode(void);
void motorShowPID(void);
void motorHelp(void);

// motor control functions
void motorInit(void);
void motorSetPower(s32 power);

// PID controller algorithm
void pidService(void);
void timerService(void);

// testing functions
void motorTest(void);
void encoderTest(void);

//----- Begin Code ------------------------------------------------------------
int main(void)
{
	// initialize our libraries
	// initialize the UART (serial port)
	uartInit();
	// set the baud rate of the UART for our debug/reporting output
	uartSetBaudRate(115200);
	// initialize the timer system
	timerInit();
	// init A2D
	a2dInit();
	// initialize rprintf system
	rprintfInit(uartSendByte);
	// initialize vt100 library
	vt100Init();

	// clear the terminal screen
	vt100ClearScreen();
	
	// run the encoder test
	//encoderTest();

	// run the motor test
	//motorTest();

	// command system
	motorCommand();

	return 0;
}

void motorCommand(void)
{
	u08 c;

	// print welcome
	rprintf("Motor Controller V1.0\r\n");

	// initialize cmdline system
	cmdlineInit();

	// direct cmdline output to uart (serial port)
	cmdlineSetOutputFunc(uartSendByte);

	// add commands to the command database
	cmdlineAddCommand("go",			motorPosGo);
	cmdlineAddCommand("getcoeff",	motorGetCoeffs);
	cmdlineAddCommand("setcoeff",	motorSetCoeffs);
	cmdlineAddCommand("mode",		motorSetMode);
	cmdlineAddCommand("piddump",	motorShowPID);
	cmdlineAddCommand("help",		motorHelp);
	cmdlineAddCommand("enctest",	encoderTest);
	cmdlineAddCommand("motortest",	motorTest);
	// send a CR to cmdline input to stimulate a prompt
	cmdlineInputFunc('\r');


	// initialize Controller structure
	// mode
	Controller.mode			= CONTROLMODE_POS;
	// controls coefficients
	Controller.Kp			= 4000;
	Controller.Ki			= 0;
	Controller.Kd			= 4000;
	// limits
	Controller.windupMax	= 200<<8;
	Controller.outputMax	= 700;
	// state variables
	Controller.error		= 0;
	Controller.error_last	= 0;
	Controller.error_integ	= 0;
	Controller.error_diff	= 0;
	// input and output
	Controller.output		= 0;
	Controller.input		= 0;
	Controller.feedback		= 0;

	// initialize motor control lines
	motorInit();

	// set up LEDs
	outb(DDRB, 0xFF);
	// set up a2d converter
	a2dSetPrescaler(ADC_PRESCALE_DIV8);
	
	// initialize encoder
	encoderInit();

	// setup PWM on timer1
	timer1SetPrescaler(TIMER_CLK_DIV8);
	timer1PWMInit(10);
	timer1PWMAOn();
	timer1PWMBOn();
	// attach pid service
	timerAttach(TIMER1OVERFLOW_INT, pidService);

	// ***** this part currently unused *****
	// setup metering timer
	// count with 32.768KHz/8
	//timer2SetPrescaler(TIMERRTC_CLK_DIV8);
	timer2SetPrescaler(TIMERRTC_CLK_DIV1024);
	// switch to asynchronous input (32KHz crystal)
	//sbi(ASSR, AS2);
	// attach service
	//timerAttach(TIMER2OVERFLOW_INT, timerService);
	// **************************************
	
	while(1)
	{
		// pass characters received on the uart (serial port)
		// into the cmdline processor
		while(uartReceiveByte(&c)) cmdlineInputFunc(c);

		// run the cmdline execution functions
		cmdlineMainLoop();

		// print debug messages
		if(ServiceFlag)
		{
			rprintf("Cyc=");
			rprintfNum(10, 6, FALSE, ' ', Cycles);
			rprintf("  Pos=");
			rprintfNum(10, 7, TRUE, ' ', Controller.feedback);
			rprintf("  Ep=");
			rprintfNum(10, 7, TRUE, ' ', Controller.error);
			rprintf("  Ei=");
			rprintfNum(10, 7, TRUE, ' ', Controller.error_integ);
			rprintf("  Ed=");
			rprintfNum(10, 7, TRUE, ' ', Controller.error_diff);
			rprintf("  out=");
			rprintfNum(10, 7, TRUE, ' ', Controller.output);
			rprintfCRLF();
			ServiceFlag=FALSE;
		}
	}

}

void motorPosGo(void)
{
	Controller.input = cmdlineGetArgInt(1);
	rprintf("Set control input to: %d\r\n", Controller.input);
}

void motorGetCoeffs(void)
{
	rprintf("Control coeffs set to:\r\n");
	rprintfProgStrM("Kp="); rprintfNum(10, 6, TRUE, ' ', Controller.Kp); rprintfCRLF();
	rprintfProgStrM("Ki="); rprintfNum(10, 6, TRUE, ' ', Controller.Ki); rprintfCRLF();
	rprintfProgStrM("Kd="); rprintfNum(10, 6, TRUE, ' ', Controller.Kd); rprintfCRLF();
}

void motorSetCoeffs(void)
{
	Controller.Kp = cmdlineGetArgInt(1);
	Controller.Ki = cmdlineGetArgInt(2);
	Controller.Kd = cmdlineGetArgInt(3);

	motorGetCoeffs();
}

void motorSetMode(void)
{
	Controller.mode = cmdlineGetArgInt(1);
	rprintf("Control Mode set to: %d\r\n", Controller.mode);
}

void motorShowPID(void)
{
	if(cmdlineGetArgInt(1))
		timerAttach(TIMER2OVERFLOW_INT, timerService);
	else
		timerDetach(TIMER2OVERFLOW_INT);
}

void motorHelp(void)
{
	rprintfCRLF();

	rprintf("Available commands are:\r\n");
	rprintf("help                     - displays available commands\r\n");
	rprintf("go [x]                   - set controller input\r\n");
	rprintf("getcoeffs                - show controller coeffs\r\n");
	rprintf("setcoeffs [kp] [ki] [kd] - set controller coeffs\r\n");
	rprintf("mode [m]                 - set motor control mode\r\n");
	rprintf("                           m=0: position control\r\n");
	rprintf("                           m=1: velocity control\r\n");
	rprintf("enctest                  - encoder hardware test\r\n");
	rprintf("motortest                - motor hardware and driver test\r\n");

	rprintfCRLF();

}

void motorInit(void)
{
	// configure ports
	// initial state
	cbi(MOTOR_BRAKE_PORT, MOTOR0_BRAKE);
	cbi(MOTOR_BRAKE_PORT, MOTOR1_BRAKE);
	cbi(MOTOR_PWM_PORT,	MOTOR0_PWM);
	cbi(MOTOR_PWM_PORT,	MOTOR1_PWM);
	cbi(MOTOR_DIR_PORT, MOTOR0_DIR);
	cbi(MOTOR_DIR_PORT, MOTOR1_DIR);
	// I/O direction
	sbi(MOTOR_BRAKE_DDR, MOTOR0_BRAKE);
	sbi(MOTOR_BRAKE_DDR, MOTOR1_BRAKE);
	sbi(MOTOR_PWM_DDR, MOTOR0_PWM);
	sbi(MOTOR_PWM_DDR, MOTOR1_PWM);
	sbi(MOTOR_DIR_DDR, MOTOR0_DIR);
	sbi(MOTOR_DIR_DDR, MOTOR1_DIR);
}

void motorSetPower(s32 power)
{
	// set direction
	if(power > 0)
	{
		sbi(MOTOR_DIR_PORT, MOTOR0_DIR);
		sbi(MOTOR_DIR_PORT, MOTOR1_DIR);
	}
	else
	{
		cbi(MOTOR_DIR_PORT, MOTOR0_DIR);
		cbi(MOTOR_DIR_PORT, MOTOR1_DIR);
	}

	// clamp power level
	power = MIN(ABS(power),Controller.outputMax);

	// set power
	if(power < 15) power = 0;

	timer1PWMASet(power);
	timer1PWMBSet(power);

	// led debug
	outb(PORTB, (~power)>>6);
}

void pidService(void)
{
	s32 EncoderCurrentPos;
	
	// get setpoint
	// **** set by user via commands
	//Controller.input = 0;
	
	// get motor feedback
	if(Controller.mode == CONTROLMODE_POS)
	{
		// position feedback
		Controller.feedback = encoderGetPosition(0);
	}
	else
	{
		// velocity feedback
		EncoderCurrentPos = encoderGetPosition(0);
		Controller.feedback = EncoderCurrentPos-EncoderLastPos;
		EncoderLastPos = EncoderCurrentPos;
	}

	// calculate error
	Controller.error = Controller.input-Controller.feedback;
	// calculate integral error
	Controller.error_integ += Controller.error;
	// clamp integral error (anti-windup)
	//Controller.error_integ = MAX(Controller.error_integ, -Controller.windupMax);
	//Controller.error_integ = MIN(Controller.error_integ,  Controller.windupMax);
	// calculate differential error
	Controller.error_diff = Controller.error - Controller.error_last;
	Controller.error_last = Controller.error;
	// do PID
	Controller.output =	 ((Controller.Kp*Controller.error)>>8)
						+((Controller.Ki*Controller.error_integ)>>8)
						+((Controller.Kd*Controller.error_diff)>>8);
	// output value
	motorSetPower(Controller.output);
	// counters
	Controller.counts++;
}

void timerService(void)
{	
	if(!TimerIncs)
	{
		Cycles = Controller.counts;
		Controller.counts=0;
		ServiceFlag=TRUE;
		TimerIncs=3;
	}
	TimerIncs--;
}

void motorTest(void)
{
	s16 i;
	s16 dir = 1;
	u16 waitRamp = 1000;
	u16 waitConstant = 1000;

	// initialize motor control lines
	motorInit();
	
	// set maximum motor output
	Controller.outputMax = 255;
	
	// setup LEDs
	outb(DDRB, 0xFF);

	// setup PWM on timer1
	timer1SetPrescaler(TIMER_CLK_DIV64);
	// 8-bit PWM
	timer1PWMInit(8);
	// both PWM channels on
	timer1PWMAOn();
	timer1PWMBOn();

	// do speed triangle
	while(1)
	{
		// ramp speed up
		rprintfProgStrM("Ramp Up\r\n");
		for(i=0; i<256; i++)
		{
			motorSetPower(dir*i);
			timerPause(waitRamp>>8);
			outb(PORTB, ~i);
		}
		// constant speed
		rprintfProgStrM("Constant\r\n");
		timerPause(waitConstant);
		// ramp speed down
		rprintfProgStrM("Ramp Down\r\n");
		for(i=255; i>=0; i--)
		{
			motorSetPower(dir*i);
			timerPause(waitRamp>>8);
			outb(PORTB, ~i);
		}
		// stop
		rprintfProgStrM("Stop\r\n");
		timerPause(waitConstant);
		// toggle direction
		dir = -dir;
	}
}

void encoderTest(void)
{
	// initialize the encoders
	encoderInit();
	//cbi(GIMSK, INT1);

	// print a little intro message so we know things are working
	rprintf("\r\nWelcome to the encoder test!\r\n");

	// report encoder position continuously
	while(1)
	{
		rprintfProgStrM("Encoder0: ");
		// print encoder0 position
		// use base-10, 10 chars, signed, pad with spaces
		rprintfNum(10, 10, TRUE, ' ', encoderGetPosition(0));

		rprintfProgStrM("  Encoder1: ");
		// print encoder1 position
		// use base-10, 10 chars, signed, pad with spaces
		rprintfNum(10, 10, TRUE, ' ', encoderGetPosition(1));

		// print carriage return and line feed
		rprintfCRLF();

		// pause so we don't flood the host computer
		timerPause(25);
	}
}

⌨️ 快捷键说明

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