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