This code is from project: OpenWrt antenna rotator , Android tablet controlling stepper motor
delay.h
#ifndef _H_DELAY_
#define _H_DELAY_
#define nop() __asm__ __volatile__("nop")
void delay_ms(unsigned short ms);
void delay_us(unsigned short us);
#endif
delay.c
#include "main.h"
#include <util/delay.h>
#include "delay.h"
/****************************************************************************/
/* It is better to put a delay in the loop than provide high value to */
/* standard function, because the code will be smaller, */
/****************************************************************************/
void delay_ms(unsigned short ms) {
while ( ms ) {
ms--;
_delay_ms(1);
}
}
void delay_us(unsigned short us) {
while ( us ) {
us--;
_delay_us(1);
}
}
main.h
#ifndef _H_MAIN_H #define _H_MAIN_H // define CPU speed, in our case is 1MHz from internal oscilator (default) #define F_CPU 1000000L // some usefeuul macros #define H(a,b) a |=(1<<(b)) #define L(a,b) a &=~(1<<(b)) #define IS(a,b) bit_is_set(a,b) #define BS(a,b) (a & (1<<(b))) #endif
main.c
#include "main.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"
#include "motor.h"
#include "delay.h"
/****************************************************************************/
/* This is the interrupt generated from RS232. */
/* This funtion will be run always after some data can be recived from */
/* attiny's USART port. */
/****************************************************************************/
SIGNAL(SIG_USART0_RECV) {
uint8_t chr;
static uint8_t nDataCnt = 0;
static uint8_t nData = 0;
// data counter
nDataCnt++;
// get one character from USART (RS232)
chr = RxByte();
/*
* If it is a 'R' it means that we want to begin propper data
* transmission.
* 'R" aslo resets already recived data
*/
if (chr == 'R') {
nData = 0;
nDataCnt = 0;
// send reset confirm
TxString("R");
return;
}
/* Switch is used to merge recieved data from port.
* Message is 3 characters long, it's begin with a
* two digit number and followed by one char that was
* added as a future. Maybe someday it would be
* driven also in vertical way by another motor.
*/
switch(nDataCnt)
{
case 1:
// getting first byte -> it must be a number
nData = nData + ((chr -48) * 10);
break;
case 2:
// getting second byte -> it must be a number
nData = nData + ((chr -48) * 1);
break;
case 3:
// getting lasat byte -> it must be char 'H'
switch(chr)
{
case 'H':
if(nData >= 0 && nData <= 90) {
// nData after merge is a number from 0 to 90
// we can now set motor position
setPos(nData);
// after change motor position, we can send
// confirmation of propper behaviour.
TxString("O");
nData = 0;
nDataCnt = 0;
return;
}
else
// something went wrong, sending 'E' as a ERROR
TxString("E");
default:
// like above 'E' -> ERROR
nData = 0;
nDataCnt = 0;
TxString("E");
return;
};
};
}
/****************************************************************************/
/* This is the main loop, it's not comlicated, because we work on */
/* interrupts. */
/****************************************************************************/
int main()
{
// init serial communication, interrupts etc.
InitUart();
// init output port for motor control
DDRB = 0x0F;
PORTB = 0x00;
// set zero position (we already at 0 after restart, so 'do nothing'
setPos(0);
// enable global interrupts
sei();
// infinite loop
while(1) {
}
}
motor.h
#ifndef _H_MOTOR_H #define _H_MOTOR_H void left(); void right(); void setPos(unsigned short); void step(); #endif
motor.c
#include "main.h"
#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include "motor.h"
#include "delay.h"
// global variables for stepper motor position
static signed short stepPos;
static signed short pos;
/****************************************************************************/
/* This function is used to make one step left. */
/****************************************************************************/
void left() {
stepPos++;
if (stepPos > 3)
stepPos = 0;
step();
}
/****************************************************************************/
/* This function is used to make one step right. */
/****************************************************************************/
void right() {
stepPos--;
if (stepPos < 0)
stepPos = 3;
step();
}
/****************************************************************************/
/* setPos function is calculating how many time we have to run 'left()' or */
/* 'right()' to get propper position. */
/****************************************************************************/
void setPos(unsigned short newPos) {
unsigned short ammount;
// 'pos' is current position
if (newPos > pos) {
// calculating distance
ammount = newPos - pos;
while(ammount--)
right();
// stop
PORTB = 0;
}
if (newPos < pos) {
ammount = pos - newPos;
while(ammount--)
left();
// stop
PORTB = 0;
}
PORTB = 0;
// remember new position as actual position (we already there)
pos = newPos;
}
/****************************************************************************/
/* Stepper motor has 4 positions. By 'step' function we send accurate */
/* value to port and motor is changing position to required. */
/****************************************************************************/
void step() {
switch(stepPos) {
case 0:
// one
PORTB = 5;
break;
case 1:
// two
PORTB = 6;
break;
case 2:
// three
PORTB = 10;
break;
case 3:
// four
PORTB = 9;
break;
};
/* Delay needs to be done here, because changing position
* last some time and motor need time to react.
*/
delay_ms(50);
}
uart.h
#ifndef _H_UART_H #define _H_UART_H //#define USART_BAUDRATE 9600 //#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL ) )) -1 ) unsigned char RxByte(void); void TxByte(unsigned char ); void TxString(const char *); void InitUart(void); #endif
uart.c
#include "main.h"
#include <avr/io.h>
#include "uart.h"
/****************************************************************************/
/* At the beginnig, we should init the uasrt port on our MCU. */
/****************************************************************************/
void InitUart (void) {
// 1mhz 9600 U2X
UBRRH = 0;
UBRRL = 12;
// x 2
UCSRA = (1<<U2X);
// enable receiving, sending and receive innterrupt.
UCSRB = (1<<RXEN) | (1<<TXEN) | (0<<TXCIE) | (1<<RXCIE);
// 8N1
UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
}
unsigned char RxByte(void) {
// wait to complete receive
while (!(UCSRA & (1 << RXC)));
// return register in which is recieved byte
return UDR;
}
void TxByte(unsigned char data) {
// wait for green light for transmit
while (!(UCSRA & (1 << UDRE)));
// send byte to port
UDR = data;
}
void TxString (const char *str) {
int n = '\0';
// send whole string to port
while ( str[n] != '\0') {
while (!(UCSRA & (1 << UDRE)));
UDR = str[n++];
}
}
Makefile
CPU=attiny2313 GCC=avr-gcc CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min INCLUDES= LIBS= OBJCPY=avr-objcopy OBJECTS=main.o uart.o delay.o motor.o PROJECT_NAME=antenaDriver HEX_FILE=$(PROJECT_NAME).hex HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex # this line shoud be replaced by your programmator # I use simplest ISP by parallel port and bunch of # wires and resistors. PROG=uisp PROG_FLAGS=-dprog=dapa -dpart=attiny26 all: cls $(PROJECT_NAME) obj size #upload $(PROJECT_NAME): $(OBJECTS) $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES) main.o: main.c main.h $(GCC) $(CFLAGS) $(INCLUDES) -c main.c uart.o: uart.c uart.h $(GCC) $(CFLAGS) $(INCLUDES) -c uart.c delay.o: delay.c delay.h $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c motor.o: motor.c motor.h $(GCC) $(CFLAGS) $(INCLUDES) -c motor.c obj: $(OBJECTS) $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE) clean: rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE) cls: clear size: du -b $(HEX_FILE) upload: all $(HEX_FILE) $(PROG) $(PROG_FLAGS) --erase --upload if=$(HEX_FILE) download: $(PROG) $(PROG_FLAGS) --download of=$(HEX_FILE_DUMP)
wonderful
ReplyDelete