Ovladanie krokoveho motora joystickom + uvod displej
Zo stránky SensorWiki
Záverečný projekt predmetu MIPS / LS2023 - Matej Ledecky
Zadanie
- 1. Preštudovanie datasheetov k daným komponentom
- Joystick
- LCD/I2C
- Krokový motor + driver
- 2.Návrh zapojenia a funkčnosti komponentov
- 3. Zapojenie
- 4. Návrh programového riešenia
- Čítanie hodnôt z joysticku a vhodná interpretácia pre ďalšie použitie
- Pohyb krokového motora v oboch smeroch
- Rýchlosť krokového motora
- Prepojenie joystick - motor
- Ovládanie joystickom smer/rychlosť otáčania
- Úvodná obrazovka
- Výpis privítania a čo robí daný projekt na LCD
- Výpis smeru otáčania na LCD
- 5. Otestovanie funkčnosti (videodokumentácia)
Hardware:
- 1.Arduino uno R3
- 2.Joystick
- 3.LED display 16×2 I2C
- 4.Krokový motor 28BYJ-48 modul ULN2003
Schéma zapojenia zariadenia:
Literatúra:
Analýza a opis riešenia
- 1.Najprv som pripojil joystick a vyhotovil jeho programové riešenie. Joystick je súčiastka, ktorá funguje štandardne na báze potenciometra, variabilného rezistora, ktorý mení odpor pri zmene polohy. Tento konkrétny joystick má dve osi pohybu (x a y) a tlačidlo. Na toto zariadenie použijeme jednu os pohybu, ktorú pripojíme na A/D prevodník s použitím knižnice, ktorú sme používali na cvičeniach.
- 2.Ďalej som zapojil krokový motor spolu s driverom a vyhotovil programový systém, pri ktorom je možné motorom otáčať a aj meniť jeho rýchlosť. Krokový motor 28BYJ-48 s modulom ULN2003 funguje na princípe rozdelenia celého otáčania na kroky. Každý krok zodpovedá určitému uhlu otáčania. ULN2003 je ovládač, ktorý prijíma signály z mikrokontroléra a riadi cievky motora. Postupným napájaním cievok v správnom poradí sa motor pohybuje o jeden krok. Tento spôsob umožňuje presné riadenie pozície a rýchlosti motora. Jednoducho povedané, motor sa otáča v malých krokoch riadených elektrickými impulzmi z ovládača ULN2003.
- 3.Pokračoval som prepojením týchto dvoch funkcií s výsledným cieľom, aby som vedel podľa smeru otočenia páčky (buď vľavo alebo vpravo) riadiť smer krokového motora a intenzitou ohybu v danom smere riadiť rýchlosť. Smer je riešený podľa výstupných parametrov systému: pri hodnotách v nižšej polovici možných výstupných hodnôt je jeden smer a pri vyššej druhý, pričom program ráta aj s takzvaným mŕtvym stredom (stav, kedy sa nič nedeje). Funkcia rýchlosti vychádza z úpravy delayu medzi jednotlivými krokmi motora, pričom hodnota pre úpravu vychádza z hodnoty výstupu joysticka.
- 4.V poslednom programovom kroku som vyhotovil jednoduchú úvodnú obrazovku (info k zariadeniu vid video) spolu s výpisom smeru otáčania. Realizácia spočívala v pripojení LCD LED displeja 16×2 s I2C modulom, s ktorým sa pracuje podobne ako na cvičení, s rozdielom, že tu sa používa aj I2C, s ktorým sme sa stretli tiež na cvičení.
- 5.Na záver som všetko odskúšal a po overení funkčnosti vyhotovil jednoduchú inštalačnú dosku pre dané zariadenie, ktorá bola z dreva a mosadzných úchytov, a vytvorila celistvé zariadenie s jednoduchým ovládaním.
Algoritmus a program
#include "main.h" // vlozenie potrebnych includeov prepojeni
#define X_PIN 0 //definovanie pinov joysticku
#define Y_PIN 1
void delay(int delay) // klasicky delay
{
for (int i=1; i<=delay; i++)
_delay_ms(1);
}
void delayus(int delay) //us delay pre pozitie v rotacii ako regulacia rychlosti
{
for (int i=1; i<=delay; i++)
_delay_us(1);
}
void left(char Pole[],int Speed){ //tocenie doprava
for (int L=0;L<10;L++)
for(int i = 0; i < 4; i++){
PORTD = Pole[i];
delayus(4250 - Speed*20);
}
PORTD = 0b00000000;
}
void right(char Pole[], int Speed){ // tocenie dolava
for (int L=0;L<10;L++)
for(int i = 3; i >= 0; i--){
PORTD = Pole[i];
delayus(4000 - Speed*20);
}
PORTD = 0b00000000;
}
int main(void)
{
MCUCR &= ~(1<<PUD);
DDRD |= 0b00111100; //paramatre pre otacanie
char Pole[] = {0b00100000, 0b00010000, 0b00001000, 0b00000100};
int Speed = 0;
unsigned int Valuex; // premenne pre nacitanie s AD prevodnika
unsigned int Valuey;
unsigned int Value;
int x = 0b00001110; // premenna pre mod LCD cursor on/OFF
int y = 0b00001100;
char *num;
TWI_Init(); //inicializacie TWI LCD ADC + uvodne texty
delay(500);
LCD_Init(y);
delay(500);
LCD_clear();
delay(500);
LCD_sendString("Vitajte");
delay(2000);
LCD_clear();
delay(500);
LCD_sendString("Riadenie Motora ");
LCD_setPosition(0,1);
LCD_sendString("Joystickom");
delay(2000);
LCD_clear();
delay(500);
LCD_sendString("Smer otacania");
LCD_setPosition(0,1);
delay(500);
adc_init();
delay(500);
while(1){
Valuex = adc_read(X_PIN)/4; //Citanie s AD do valuex
if(Valuex > 125){ //pobyb packy po osi x dolava
Speed=Valuex-123; //vypocet konstatny rychlosti
left(Pole,Speed); // rotacia dolava
LCD_setPosition(0,1); // pozicia kurzora LCD
LCD_sendString("<--"); // vypis na LCD
}
else if(Valuex < 124){ //to iste len do druhej strany s mensimi upravami kvoli rozdielnym hodnotam s AD
Speed=127-Valuex;
right(Pole, Speed);
LCD_setPosition(0,1);
LCD_sendString("-->");
}
else{
LCD_setPosition(0,1); // KED nic
LCD_sendString("<->");
}
/* num = (char *)malloc(snprintf(NULL, 0, "%d", o) + 1);
LCD_sendString(num);
free(num); */
}
return(0);
}
#ifndef MAIN_H_
#define MAIN_H_
#define BAUD 9600
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include "adc.h"
#include "twi.h"
#include "lcd.h"
#endif /* MAIN_H_ */
</source></tab>
#ifndef LCD_H_
#define LCD_H_
void LCD_Init(int);
void sendHalfByte(unsigned char);
void sendByte(unsigned char, unsigned char);
void LCD_setPosition(unsigned char, unsigned char);
void LCD_sendString(char[]);
void LCD_clear(void);
void LCD_BackLight(unsigned char);
#endif /* LCD_H_ */
</tabs>
</source></tab>
#include "main.h"
unsigned char portlcd = 0;
void LCD_Init(int X) {
sendHalfByte(0b00000011);
_delay_ms(5);
sendHalfByte(0b00000011);
_delay_us(100);
sendHalfByte(0b00000011);
_delay_ms(1);
sendHalfByte(0b00000010);
_delay_ms(1);
sendByte(0b00101000, 0); // Data 4bit, Line 2, Font 5x8
_delay_ms(1);
sendByte(X, 0); //Display ON, Blink OFF CUrsor ON/OFF vramci premennej
_delay_ms(1);
TWI_TransmitByAddr(portlcd |= 0x08, 0x4E); //BackLight ON
TWI_TransmitByAddr(portlcd &= ~0x02, 0x4E); //LCD Write ON
}
void LCD_BackLight(unsigned char mode) {
switch(mode) {
case 0:
TWI_TransmitByAddr(portlcd &= ~0x08, 0x4E); //BackLight OFF
break;
case 1:
TWI_TransmitByAddr(portlcd |= 0x08, 0x4E); //BackLight ON
break;
}
}
void sendHalfByte(unsigned char c) {
c <<= 4;
TWI_TransmitByAddr(portlcd |= 0x04, 0x4E); // Enable E
_delay_us(50);
TWI_TransmitByAddr(portlcd | c, 0x4E);
TWI_TransmitByAddr(portlcd &= ~0x04, 0x4E); // Disable E
_delay_us(50);
}
void sendByte(unsigned char c, unsigned char mode) {
if(mode == 0) TWI_TransmitByAddr(portlcd &= ~0x01, 0x4E);
else TWI_TransmitByAddr(portlcd |= 0x01, 0x4E);
unsigned char hc = 0;
hc = c >> 4;
sendHalfByte(hc);
sendHalfByte(c);
}
void LCD_sendString(char s[]) {
char n;
for(n=0; s[n]!='\0'; n++)
sendByte(s[n], 1);
}
void LCD_setPosition(unsigned char x, unsigned char y) {
switch(y) {
case 0:
sendByte(x | 0x80, 0);
break;
case 1:
sendByte((0x40+ x) | 0x80, 0);
break;
case 2:
sendByte((0x10+ x) | 0x80, 0);
break;
case 3:
sendByte((0x50+ x) | 0x80, 0);
break;
}
}
void LCD_clear(void) {
sendByte(0x01, 0);
_delay_ms(5);
}
</tabs>
</source></tab>
#include <avr/io.h>
#ifndef ADC_H_
#define ADC_H_
void adc_init(void); // A/D converter initialization
unsigned int adc_read(char a_pin);
#endif /* ADC_H_ */
</tabs>
</source></tab>
#include "main.h"
void adc_init(void){
ADMUX = (1<<REFS0);
ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
unsigned int adc_read(char a_pin){
a_pin &= 0x07;
ADMUX = (ADMUX & 0xF8)|a_pin;
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));
return(ADC);
}
</tabs>
</source></tab>
#ifndef TWI_H_
#define TWI_H_
void TWI_Start(void);
void TWI_Init(void);
void TWI_Stop(void);
void TWI_Transmit(unsigned char);
void TWI_TransmitByAddr(unsigned char, unsigned char);
#endif /* TWI_H_ */
</tabs>
</source></tab>
#include "main.h"
void TWI_Init(void) {
TWBR = 0x48;
}
void TWI_Start(void) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
}
void TWI_Transmit(unsigned char data) {
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
}
void TWI_TransmitByAddr(unsigned char data, unsigned char addr) {
TWI_Start();
TWI_Transmit(addr);
TWI_Transmit(data);
TWI_Stop();
}
void TWI_Stop(void) {
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}
</tabs>
Ukážka zariadenia
Video s prezentáciou funkcie