freakone | strona domowa

freakone.pl

14 Sierpnia

Atmega, Bluetooth i Android

Badając temat taniej komunikacji bezprzewodowej nieodzownym rozwiązaniem do sprawdzenia jest Bluetooth.
Swój moduł bluetooth w zestawie z kluczem USB kupiłem w serwisie dealextreme. Jest tam mnóstwo tanich, chińskich rzeczy i co najlepsze wysyłka do Polski jest za darmo. Wireless Bluetooth RS232 TTL Transceiver kosztował mnie 6.6$, a Super Mini Bluetooth 2.0 Adapter Dongle 1.8$ co razem dało śmieszne 25zł. Niestety nie miałem szczęścia i dostałem wersję z uboższym firmware - płytka mogła służyć tylko jako host (sama nie mogła się podłączać do innych urządzeń).

Samo podłączenie i uruchomienie urządzenia jest banalne. 2 piny zasilające (3.3V), 2 piny komunikacji szeregowej i opcjonalny pin na diodę sygnalizacyjną. Schemat i specyfikację można odnaleźć w tym datasheecie.



Konfiguracja urządzenia odbywa się poprzez wysyłanie komend AT+ przez UARTA. Domyślnie połączenie szeregowe ma parametry: baud 9600, brak parzystości, 8 bitów danych, 1 bit stopu. Po podłączeniu na początku wysyłamy samą komendę "AT", jeśli wszystko jest w porządku urządzenie odpowie nam "OK". Lista wszystkich komend jest dostępna w tym pliku. Możemy zmieniać: szybkość połączenia, nazwę urządzenia i pin. Należy pamiętać, że komendy działają jedynie, gdy moduł nie jest połączony z innym urządzeniem.

Komunikacja z komputerem

Tutaj nie będę się rozpisywał, rozwiązanie najbardziej oczywiste, banalne i najszybsze do skonfigurowania. Podłączamy zakupionego dongla (na windowsie 7 wszystkie sterowniki instalują się same), przez windowsowego managera odnajdujemy nasze urządzenie.
Po podaniu PINu zostaniemy zapytani o stworzenie portu COM, oczywiście się zgadzamy. To wszystko, mamy teraz dostęp do naszego urządzenia przez port komunikacyjny, możemy podłączyć się terminalem, czy łatwo zaimplementować funkcję w programie.
Oczywiście jeśli komuś nie pasuje windowsowa obsługa bluetootha może użyć np. BlueSoleila.

Komunikacja z telefonem

Idąc dalej stwierdziłem, że moduł można sprzęgnąć z telefonem. Smartfon jest dużo bardziej mobilny od laptopa co może się przydać w testach np. LineFollowera (którego aktualnie konstruuje kolega Łukasz). Bieganie za robotem z laptopem nie jest tak wygodne jak z telefonem :) Jako, że posiadam telefon z Androidem oczywistym wyborem było napisanie samemu aplikacji. W markecie są dostępne terminale bluetooth, jednak nie posiadają funkcjonalności, którą chciałem osiągnąć.

Moja aplikacja umożliwia nam pełną, dwukierunkową komunikację z danym układem - możemy zarówno wysyłać polecenia jak i odbierać informacje (czy to debugujące, czy interfejsowe). Idąc za ciosem można rozbudować program tak, że dostaniemy pełne, wielostopniowe menu dla danego układu. Jest to jednocześnie mój "Hello World" na androida - apka ma kilka niedociągnięć (zwiechy przy przywracaniu ze stanu uśpienia lub gdy starci połączenie) ale da się jej używać. Wszelkie nowe wersje będę publikował na blogu.

Zaimplementowane są: przesyłanie informacji z czujnika położenia (możemy np. użyć telefonu jako kierownicy i sterować torem jazdy robota), przycisków typu włącz-wyłącz i zwykłych. To jedynie ułamek tego co możemy zrobić - wszystko zależy od naszych potrzeb i pomysłu. Dostępne jest mnóstwo czujników: akcelerometr, czujnik pola magnetycznego, oświetlenia itp, itp.


Kod źródłowy
Skompilowana aplikacja

Układ testowy

Mikroprocesor AVR ATiny2313(8MHz RC) połączony z modułem BT i parę diodek.

Działanie aplikacji na androida i układu testowego:


Kod źródłowy dla AVR:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define F_OSC 8000000
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_OSC / (USART_BAUDRATE * 16UL))) - 1) 

void USART_Init()
{		
	UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);	
	UCSRC = (3<<UCSZ0);
	
	UBRRL = BAUD_PRESCALE; 	// Load lower 8-bits of the baud rate value into the low byte of the UBRR register
	UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR registe
}

void uart_put(unsigned char data )
{
	while ( !(UCSRA & (1<<UDRE)) )
		; 			                

	UDR = data; 			        
}

volatile char accelero[3];
volatile unsigned char i = 0;
ISR(USART_RX_vect)
{
	if(i > 0)
	{
		accelero[i - 1] = UDR;
		
		if(i == 3) 
			i = 0;
		else
			i++;
	}
	else
	{	
		switch(UDR)
		{					
			case 0x01: // button1
			PORTB ^= (1 << PB0);
			break;
			
			case 0x02: // button2
			PORTB ^= (1 << PB2);
			break;

			case 0x04: //pozycja
			i++;
			break;
		}
	}
}

int main()
{
	DDRB = 0xff;
	PORTB = 0;	
	
	sei();	//rejestr przerwań 
	USART_Init(); //inicjalizacja uarta
	
	uart_put('T'); // mozemy sobie cos wyslac do telefonu
	
	while(1)
	{
		// w zaleznosci od polozenia gasimy lub zapalamy diody
		if(accelero[2] > 30)
			PORTB |= (1 << PB3);
		else if(accelero[2] < -30)
			PORTB &= ~(1 << PB3);
		
		if(accelero[1] > 30)
			PORTB |= (1 << PB2);
		else if(accelero[1] < -30)
			PORTB &= ~(1 << PB2);
	}

}

10 Sierpnia

Obsługa modułu RFM70 za pomocą mikrokontrolerów AVR

Moduł RFM70 zamówiłem ze względu na cenę - 12 złotych 8 złotych na transreciver to naprawdę mało. Niestety przed zakupem nie spojrzałem do datasheeta (a może i stety, wtedy bym go zapewne nie kupił :)) - tak fatalnie napisanej dokumentacji nie widziałem nigdy.

Nie było by w tym nic złego ale fakt, że biblioteka do obsługi modułu, którą zaraz przedstawię ma ponad 600 linii kodu (same definicje komend, adresów i nie wiadomo czego jeszcze zajmują około 200) skutecznie zniechęciła mnie do napisania jej samemu od podstaw.
Z pomocą wujka google udało mi się znaleźć kilka gotowców żadnego jednak nie udało mi się uruchomić. Na stronie voti.nl odnalazłem implementację obsługi modułu w C - wersja pod Arduino była zaprojektowana dla mikrokontrolera Atmega 128, wystarczyło ją przerobić – wyrzucić te wszystkie funkcje wysokiego poziomu z Arduino IDE. Pracę zacząłem, jednak w trakcie natknąłem na stronę, której autor już dokonał tego co ja chciałem zrobić. Po małych przeróbkach RFM ruszył bez problemów.

Przerobiłem bibliotekę na bardziej user-friendly oraz uporządkowałem i częściowo okomentowałem cały kod. Teraz wystarczy odwiedzić plik rfm70-config.h oraz opcjonalnie uart.h i dokonać konfiguracji. RFM70 powinien ruszyć od strzała :)
Biblioteka posiada zaimplementowaną diodę informacyjną - mruga gdy dane są wysyłane lub odbierane. Gdy moduł RFM nie zostanie poprawnie zainicjalizowany dioda mruga w nieskończoność wedle schematu 10100011. W pliku rfm70-config.h możemy włączyć tryb debugu - komunikaty przesyłane są przez port szeregowy (zaimplemetowałem 3, można dodać więcej).

Układy testowe zmontowałem na AVRach Atmega8 (odbiornik) i Atmega16 (nadajnik), moc nadawania została ustawiona na maksymalną, mikrokontrolery były taktowane wewnętrzym zegarem 8MHz. Pobór prądu nadajnika to około 6.4 mA, odbiornika około 26 mA. Pakiet miał długość 5 bajtów, wysyłany co 20ms.

Zasięg testowałem zarówno na otwartym terenie (po około 30 metrach zaczęły się sporadyczne dropy pakietów przy poruszaniu, po 40 przy bezruchu), jak i w domu (nadajnik umieszczony na piętrze, po zejściu na parter i przejściu przez 3 pomieszczenia stracił sygnał).


Kod obsługujący bibliotekę jest banalny.

Przykład odbiornika:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>

#include "rfm70.h"	

int main()
{
	uint8_t test[]={'t', 'e', 's', 't','y'};	
	initRFM(); //inicjalizacja RFM70
	
	setModeTX(); //tryb nadawania
	setChannel(8); // kanał 8
	setPower(3); // maksymalna moc (0: -10dBm | 1: -5dBm | 2: 0dBm | 3: 5dBm)
	
	while (1)
	{	
		sendPayload(test, 5, 0); //tablica, dlugosc, 0 - bez potwierdzenia | 1 - z potwierdzeniem
		_delay_ms(20);	
	}
}

Przykład nadajnika:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>

#include "rfm70.h"	

int main()
{
	uint8_t bufor[32];	
	initRFM(); //inicjalizacja RFM70
	
	setModeRX(); //tryb odbioru
	setChannel(8); // kanał 8
	
	while (1)
	{	
		if (receivePayload(bufor)) // odbieramy dane i przesyłamy je dalej za pomocą uarta
		{
			uart_puts((char*)bufor);
			uart_puts("\n");
		}	
	}
}

Pobierz bibliotekę modułu RFM70 dla mikrokontrolerów AVR

04 Lipca

Driver LED MBI5168 w połączeniu z Atmegą i MSP430

Biorąc się za projekt LED-CUBE'a chciałem wykorzystać driver MBI5168 do sterowania diodami, jednak jak się okazało nie mogę tego zrobić z 2 prostych powodów:

  • Driver posiada tylko 8 wyjść - ja potrzebuję 9ciu (to jeszcze dałoby się jakoś obejść)
  • W driverze wyjścia są katodami, ja katody mam połączone jako warstwy (3) więc driver lekko by się marnował, a kostki przelutowywać mi się nie chce. Wygodniejsze i bardziej ekonomicznie będzie zastosowanie tranzystorów.


Podłączenie:


  • pin 1 - GND: masa
  • pin 2 - SDI: wejście danych
  • pin 3 - CLK: wejście zegara taktującego
  • pin 4 - sygnalizacja początku (stan wysoki) i końca (stan niski) transmisji
  • piny 5-12: wyjścia prądowe diód, tutaj podpinamy katodę diody
  • pin 13 - OE: pin służący do włączania (stan niski) i wyłączania (stan wysoki) układu
  • pin 14 - SDO: wyjście danych, używane przy łączeniu kilku driverów
  • pin 15 - R-EXT: między ten pin, a masę (pin 1) włączamy rezystor ograniczający prąd wysyłany do diód, ja zastosowałem 200omów, co daje około 15mA na diodę
  • pin 16 - VDD: +5V, tutaj podłączamy anody


Atmega 8

W przypadku atmegi zarówno driver MBI5168 jak i atmega były zasilane z jednego źródłą zasilania. SPI zostało wykonane w sposób programowy, w nagłówku pliku wpisujemy porty, do których zostały podłączone odpowiednie piny.

Program zapala wszystkie diody (jeśli mamy je podłączone), a następnie po kolei je gasi. Dane co do aktywności diód przekazujemy funkcją transmit_byte(), która jako parametr przyjmóje bajt infromacji. Każdy bit odpowiada jednemu wyjściu, OUT7 to pierwszy bit z prawej strony. Przekazując 0b00001001 otrzymamy aktywne wyjście 7 i 4.

#include <avr/io.h> 
#include <util/delay.h>

// CMD - wyjście, dane transmisji
#define CMD_SET PORTC |= (1<<4)
#define CMD_CLR PORTC &= ~(1<<4)
#define CMD_DIR DDRC |= (1<<4)

// CLK - wyjście, zegar transmisji
#define CLK_SET PORTC |= (1<<3)
#define CLK_CLR PORTC &= ~(1<<3)
#define CLK_DIR DDRC |= (1<<3)

// LE - wyjście, sygnalizacja początku transmisji
#define T_START PORTC |= (1<<2)
#define T_END PORTC &= ~(1<<2)
#define T_DIR DDRC |= (1<<2)

// OE - wyjście, włączenie i wyłączenie układu
#define MBI_OFF PORTC |= (1<<1)
#define MBI_ON PORTC &= ~(1<<1)
#define MBI_DIR DDRC |= (1<<1)

//opóźnienie
#define _NOP_ asm volatile("nop\n\t""nop\n\t" "nop\n\t" "nop\n\t" ::)

void transmit_byte(unsigned char byte)
{
	T_START;
	
   for(int i = 0; i < 8; i++, byte>>=1)
   {
       CLK_CLR;
       if(byte& 0x01) CMD_SET; else CMD_CLR;
       _NOP_;
	   _NOP_;
       CLK_SET;
   }
   CMD_SET;
   
   T_END;
}

int main()
{	
	T_DIR;
	CLK_DIR;
	CMD_DIR;
	MBI_DIR; // ustawiamy kierunki transmisji	
	
	MBI_ON; // włączamy wyświetlanie

	char dane = 0xff;
	
	while(1)
	{
		transmit_byte(dane); 
		
		for(int i = 0; i <8; i++)
		{
			dane &= ~(1 << i);
			transmit_byte(dane);
			_delay_ms(500);
		} // gasimy diody po kolei
		
		dane = 0xff; //zapalamy wszystkie diody
	}
	
	return 0;
}


LanuchPad - MSP430G2553

W tym przypadku zastosowany został sprzętowy interfejs SPI - USCI A. CLK podłączamy pod P1.4, SDI pod P1.2, a LE pod P1.6. Pin OE został na stałe podpięty do masy, co skutkuje ciągłą pracą układu. W programie wykorzystujemy programowalny przycisk Lanuchpada do gaszenia diód.
Funkcja transmit_byte, działa prawie tak samo jak w przypadku atmegi, różnica polega na tym, że bity są odwrócone (OUT0 to pierwszy bit z prawej strony).

LanuchPad i układ MBI były zasilane z osobnych źródeł - MSP pobierał prąd z USB (3.3V) natomiast MBI z zewnętrznego zasilacza ze stabilizatorem LM317.

#include <msp430.h>

void transmit_byte(unsigned char byte)
{
	P1OUT |= BIT6; // dajemy znak na rozpoczęcie transmisji

	UCA0TXBUF = byte; //umieszczemy dane w buforze
	while (!(IFG2 & UCA0TXIFG)); // czekamy na zakońćzenie transmisji

	P1OUT &= ~BIT6; // dajemy znak na koniec transmisji
}

void hw_init()
{
	WDTCTL = WDTPW + WDTHOLD;		// watchdog off
	P1DIR |= BIT6; // P1.6 - flaga rozpoczęcia/ zakończenia transmisji

	P1SEL = BIT2 + BIT4;
	P1SEL2 = BIT2 + BIT4; // P1.2 i P1.4 przełączamy na HW CLK i MOSI

	UCA0CTL0 |= UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master
	UCA0CTL1 |= UCSSEL_2;                     // SMCLK
	UCA0MCTL = 0;                             // No modulation
	UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

	P1DIR &= ~BIT3; //P1.3 jako wyjscie
	P1REN |= BIT3; // ustawiamy podciągnięcie do vcc
	P1OUT |= BIT3; // aktywujemy podciągnięćie do vcc


}

int main(void) {

	unsigned int i;

	hw_init();
	
	unsigned char dane = 0xff;
	while(1)
	{

		transmit_byte(dane);
		_delay_cycles(200000);

		for(i = 0; i < 8; i++)
		{
			while(P1IN & BIT3);
			while(!(P1IN & BIT3)); //czekamy na przycisniecie przycisku

			dane &= ~(1 << i);
			transmit_byte(dane);
		} // gasimy diody po kolei

		dane = 0xff; //zapalamy wszystkie diody
	}
}

03 Lipca

Naklejki na mikrokontrolery AVR

Szperając po internecie natrafiłem na bardzo przydatną rzecz, mianowicie naklejki z opisem portów na mikrokontrolery Atmela.

Przy budowaniu układów bez płytki prototypowej jest to strasznie przydatne - nie trzeba co chwilę zaglądać do datasheeta.

Wygląda to tak:


Naklejki są dostępne na atmegi 8,48,88,168,328,16 i 32 oraz attiny 2313 i 26.

Wszystkie wersje można zdobyć TUTAJ.

03 Lipca

Wakacje

Przez ostatnie 2 miesiące z powodu braku czasu nie udało mi się dodać żadnego posta, przez wakacje mam nadzieję nadrobić zaległości :)

W kolejce mam kilka projektów, które czekają na opisanie (m.in. konwerter USB-232, LED-CUBE), jak zrobię jakąś sensowną dokumentację to na pewno je tu zamieszczę.

18 Kwietnia

Intruder 1 - powoli do przodu

Aktualizacja na dole strony.

Parę fotek + filmik z pierwszego przejazdu. Całość sklecona na szybko, ale pierwszy crashtest zaliczony :)

13 Kwietnia

Przesyłka z LanuchPadem

Przyznam, że lekko się zdziwiłem, ale dziś przyszła paczka z LaunchPadem. 4 dni po złożeniu zamówienia - czasami nawet paczki z allegro dłużej przychodzą.

Poniżej kilka fotek, wieczorem jak mi starczy czasu to go uruchomię.



13 Kwietnia

Intruder 1 - aktualizacja

Dodane nowe fotki. Jak Pawełek mi wyśle to będzie więcej.

11 Kwietnia

Nowe sprawozdania

Dodałem nowe sprawozdania, które dostałem od kolegi miszlena :)

Numery: 20, 29, 30, 33, 44, 64, 77

10 Kwietnia

Lutowanie jest łatwe

Komiks po polsku: FullSolderComic_PL

Oryginał

Ogólnie polecam całego bloga: MightyOhm