Table of Contents

CAN windscreen wiper

Requirements: [HW] 2 x Controller, [HW] Servo-motor

Windscreen wiper in different modes

This project demonstrates how to use CAN interface to transfer commands from one device to other. Two ARM-CAN contollers are need of which one acts as a lever on the steering wheel of a car and another one as a windscreen wiper controller. When buttons is pressed on lever controller, next wiping mode is selected and wiper is notified. Servo-motor is used for simulating the wiper. There are three modes:

windscreen_wiper_control.c

//*****************************************************************************
//
// Windscreen wiper control
//
// Program is entirely interrupts based.
//
// Copyright (c) 2009 TUT Department of Mechatronics
//
//*****************************************************************************
 
#include <inc/hw_ints.h>
#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <driverlib/sysctl.h>
#include <driverlib/interrupt.h>
#include <driverlib/gpio.h>
#include <driverlib/timer.h>
#include <driverlib/can.h>
#include <drivers/general.h>
#include <drivers/rgb_led.h>
 
//*****************************************************************************
//
// Configuration.
//
//*****************************************************************************
#define CAN_BITRATE           250000
#define CAN_ACTUATOR_MSG_ID   0x01
#define CAN_ACTUATOR_MSG_BOX  1
 
//*****************************************************************************
//
// Global variables.
//
//*****************************************************************************
unsigned char g_ucMode = 0;
 
//*****************************************************************************
//
// The interrupt handler for the port B interrupt.
//
//*****************************************************************************
void PortBIntHandler(void)
{
	tCANMsgObject psCommandMsg;
 
	//
	// Clear the port interrupt.
	//
	GPIOPinIntClear(GPIO_PORTB_BASE, GPIO_PIN_7);	
 
	//
	// Next wiper mode of 3 modes.
	//
	g_ucMode = (g_ucMode + 1) % 3;
 
	//
	// Create message.
	//			
	psCommandMsg.ulMsgID    = CAN_ACTUATOR_MSG_ID;	
	psCommandMsg.ulFlags    = MSG_OBJ_NO_FLAGS;
	psCommandMsg.ulMsgLen   = 1;
	psCommandMsg.pucMsgData = &g_ucMode;
 
	//
	// Set message.
	//
	CANMessageSet(CAN0_BASE, CAN_ACTUATOR_MSG_BOX,
	              &psCommandMsg, MSG_OBJ_TYPE_TX);
 
	//
	// Turn on the appropriate LED.
	//			
	RGBLEDSetRGB((g_ucMode == 0 ? 255 : 0),
	             (g_ucMode == 1 ? 255 : 0),
	             (g_ucMode == 2 ? 255 : 0));
}
 
//*****************************************************************************
//
// Main function.
//
//*****************************************************************************
int main(void)
{	
	//
	// Set the clocking to run from the PLL at 50MHz
	//
	SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
	SYSCTL_XTAL_8MHZ);
 
	//
	// Enable peripherals.
	//	
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);		
	SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);		
 
	//
	// Enable the peripherals that should continue to run when the processor
	// is sleeping.
	//		
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOC);    
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOE);	
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_CAN0);
 
	//
	// Drivers configuring.
	//
	DeviceConfigure();	
	RGBLEDConfigure();
 
	// 
	// Configure button to generate interrupt on press.
	//		
	GPIOIntTypeSet(GPIO_PORTB_BASE, GPIO_PIN_7, GPIO_FALLING_EDGE);
	GPIOPinIntEnable(GPIO_PORTB_BASE, GPIO_PIN_7);
	IntEnable(INT_GPIOB);
 
	//
	// Configure CAN pins.
	//    
	GPIOPinTypeCAN(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1);	
 
	//
	// Enable the CAN controller.
	//	    
	CANInit(CAN0_BASE);
	CANBitRateSet(CAN0_BASE, SysCtlClockGet(), CAN_BITRATE);
	CANEnable(CAN0_BASE);	
 
	//
	// Enable processor interrupts.
	//
	IntMasterEnable();	
 
	//
	// Loop forever.
	//
	while (1)
	{	
		//
		// Save power - turn off CPU.
		//
		SysCtlSleep();
	}
}

windscreen_wiper_actuator.c

//*****************************************************************************
//
// Windscreen wiper actuator
//
// Program is entirely interrupts based.
//
// Copyright (c) 2009 TUT Department of Mechatronics
//
//*****************************************************************************
 
#include <inc/hw_ints.h>
#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <driverlib/sysctl.h>
#include <driverlib/interrupt.h>
#include <driverlib/gpio.h>
#include <driverlib/timer.h>
#include <driverlib/can.h>
#include <drivers/general.h>
#include <drivers/rgb_led.h>
#include <drivers/servo_motor.h>
 
//*****************************************************************************
//
// Configuration.
//
//*****************************************************************************
#define SERVO_INDEX                0
#define CAN_BITRATE                250000
#define CAN_ACTUATOR_MSG_ID        0x01
#define CAN_ACTUATOR_MSG_BOX       1
#define CAN_ACTUATOR_MSG_BOX_FLAG  (1 << (CAN_ACTUATOR_MSG_BOX - 1))
 
//*****************************************************************************
//
// Global variables.
//
//*****************************************************************************
signed long g_slWiperDirection = 1;
 
//*****************************************************************************
//
// The interrupt handler for the timer2 interrupt.
//
//*****************************************************************************
void Timer2IntHandler(void)
{
	//
	// Clear the timer interrupt.
	//
	TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT);	
 
	//
	// Set servo position.
	//
	ServoSetPulseWidth(SERVO_INDEX, 100 * g_slWiperDirection);
 
	//
	// Reverse wiper direction.
	//
	g_slWiperDirection = -g_slWiperDirection;
}
 
//*****************************************************************************
//
// Wiper mode setting.
//
//*****************************************************************************
void WiperModeSet(unsigned char ucMode)
{	
	unsigned long ulPeriod = 0;
 
	//
	// Turn on the appropriate LED.
	//			
	RGBLEDSetRGB((ucMode == 0 ? 255 : 0),
	             (ucMode == 1 ? 255 : 0),
	             (ucMode == 2 ? 255 : 0));	
 
	//
	// Mode 0 ?
	//	
	if (ucMode == 0)
	{	
		//
		// Disable wiper timer.
		//
		TimerDisable(TIMER2_BASE, TIMER_A);
 
		//
		// Stop servo motor.
		//
		ServoSetPulseWidth(SERVO_INDEX, 0);				
	}
	//
	// Mode 1 or 2 ?
	//
	else if (ucMode <= 2)
	{
		//
		// Set period according to the mode.
		//
		switch (ucMode)
		{
			case 1:
				ulPeriod = SysCtlClockGet() * 2; // 2 s
				break;
 
			case 2:
				ulPeriod = SysCtlClockGet() / 2; // 500 ms
				break;
		}
 
		//
		// Configure periodic timer to generate interrupt.		
		//
		TimerLoadSet(TIMER2_BASE, TIMER_A, ulPeriod);
		TimerEnable(TIMER2_BASE, TIMER_A);
	}
}
 
//*****************************************************************************
//
// The interrupt handler for the CAN interrupt.
//
//*****************************************************************************
void CAN0IntHandler(void)
{
	tCANMsgObject psCommandMsg;
	unsigned char pucRxData[8];
	unsigned char ucMode = 0;
 
	//
	// Set pointer to data.
	//
	psCommandMsg.pucMsgData = pucRxData;	
 
	//
	// New CAN message received ?
	//
	if (CANStatusGet(CAN0_BASE, CAN_STS_NEWDAT) & CAN_ACTUATOR_MSG_BOX_FLAG)
	{
		//
		// Get the message.
		//
		CANMessageGet(CAN0_BASE, CAN_ACTUATOR_MSG_BOX_FLAG, &psCommandMsg, true);
 
		//
		// Check message length.
		//
		if (psCommandMsg.ulMsgLen == 1)
		{
			//
			// Get mode from data.
			//
			ucMode = *psCommandMsg.pucMsgData;
 
			//
			// Set wiper mode.
			//				
			WiperModeSet(ucMode);		
		}
	}	
}
 
//*****************************************************************************
//
// Main function.
//
//*****************************************************************************
int main(void)
{		
	tCANMsgObject psCommandMsg;	
 
	//
	// Set the clocking to run from the PLL at 50MHz
	//
	SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
	   SYSCTL_XTAL_8MHZ);
 
	//
	// Enable peripherals.
	//	
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);	
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);		
 
	//
	// Enable the peripherals that should continue to run when the processor
	// is sleeping.
	//		
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOC);    
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOE);    
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER0);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER2);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_CAN0);
 
	//
	// Drivers configuring.
	//
	DeviceConfigure();
	RGBLEDConfigure();
	ServoConfigure(SERVO_INDEX);
 
	//
	// Configure timer 2 as periodic wiper timer.
	//	
	TimerConfigure(TIMER2_BASE, TIMER_CFG_32_BIT_PER);		
 
	//
	// Enable timer 2 interrupt.
	//	
	TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT);
	IntEnable(INT_TIMER2A);	
 
	//
	// Configure CAN pins.
	//    
	GPIOPinTypeCAN(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1);	
 
	//
	// Enable the CAN controller.
	//	    
	CANInit(CAN0_BASE);
	CANBitRateSet(CAN0_BASE, SysCtlClockGet(), CAN_BITRATE);
	CANEnable(CAN0_BASE);	
 
	//
	// Enable CAN interrupts.
	//
	CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_STATUS);
	IntEnable(INT_CAN0);    
 
	//
	// Create receive command message object.
	//	
	psCommandMsg.ulMsgID     = CAN_ACTUATOR_MSG_ID;
	psCommandMsg.ulMsgIDMask = CAN_ACTUATOR_MSG_ID;
	psCommandMsg.ulFlags     = MSG_OBJ_RX_INT_ENABLE;
 
	//
	// Set message object.
	//
	CANMessageSet(CAN0_BASE, CAN_ACTUATOR_MSG_BOX, &psCommandMsg, MSG_OBJ_TYPE_RX);
 
	//
	// Enable processor interrupts.
	//
	IntMasterEnable();	
 
	//
	// Loop forever.
	//
	while (1)
	{
		//
		// Save power - turn off CPU.
		//
		SysCtlSleep();
	}
}