<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl-pl">
<link rel="self" type="application/atom+xml" href="https://forum.atnel.pl/feed.php?f=8&amp;t=5736&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2014-01-29T22:13:06+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=8&amp;t=5736&amp;mode</id>
<entry>
<author><name><![CDATA[danielos]]></name></author>
<updated>2014-01-29T22:13:06+01:00</updated>
<published>2014-01-29T22:13:06+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=5736&amp;p=67336#p67336</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=5736&amp;p=67336#p67336"/>
<title type="html"><![CDATA[AVR jako urządzenie SLAVE dla TWI - obsługa]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=5736&amp;p=67336#p67336"><![CDATA[
Witam.<br /><br />Krótki wstęp dlaczego wykonałem komunikację między uC wykorzystując magistralę TWI.<br /><br />Na potrzeby swojej pracy dyplomowej potrzebowałem wykonać komunikację między mikrokontrolerami AVR po TWI (UART już miałem zajęty do komunikacji z komputerem). Jeden uC odpowiedzialny był za obsługę RFM12B oraz komunikację z komputerem. Natomiast drugi stanowił interfejs użytkownika z klawiaturą oraz wyświetlaczem LED. <br />Dlaczego użyłem pojęć &quot;JEDEN&quot; oraz &quot;DRUGI&quot; zamiast MASTER i SLAVE - ponieważ podczas pracy programu zmieniałem konfigurację danego uC w zależności od potrzeby.<br />Pracę dyplomową obroniłem już jakiś czas temu, ale dopiero teraz udało mi się znaleźć trochę czasu, żeby poprawić biblioteki. Udostępniam je z tego względu, gdyż w sieci nie znalazłem w naszym języku prostych bibliotek - na czas kiedy pisałem pracę dyplomową, w chwili obecnej mogło się to zmienić.<br /><br />Pisząc biblioteki wzorowałem się w pewnym stopniu na bibliotekach zawartych na stronie <a href="http://www.ermicro.com/blog/?p=1239"  class="postlink">http://www.ermicro.com/blog/?p=1239</a>, oraz książkach Mirka (za które bardzo dziękuję).<br /><br />Na początku umieszczę pliki biblioteki, a następnie krótko opiszę najważniejsze fragmenty kodu. Całość jest do pobrania w załączniku wraz z przykładowym programem do testowania.<br /><br /><span style="text-decoration: underline"><strong>ds_twi.c</strong></span><br /><br />[syntax=csharp]/*<br /> * ds_twi.c<br /> *<br /> *  Created on: 04-01-2014<br /> * Edited on: 29-01-2014<br /> *      Author: Daniel (danielo$)<br /> *<br /> *<br /> *Na podstawie (Based on):<br /> *http://www.ermicro.com<br /> *http://www.ermicro.com/blog/?p=1239<br /> *<br /> *http://www.atnel.pl<br /> *książka:<br /> *Mikrokontrolery AVR Język C - podstawy programowania<br /> *Mirosław Kardaś<br /> *<br /> *Język C. Pasja programowania mikrokontrolerów 8-bitowych )<br /> *Mirosław Kardaś<br /> *<br /> *All rights reserved.<br /> */<br /><br />#include &lt;avr/io.h&gt;<br />#include &lt;avr/pgmspace.h&gt;<br />#include &lt;avr/interrupt.h&gt;<br />#include &lt;util/twi.h&gt;<br />#include &lt;util/delay.h&gt;<br />#include &lt;string.h&gt;<br />#include &lt;stdlib.h&gt;<br /><br />#include &quot;ds_twi.h&quot;<br />//#include &quot;../LCD/HD44780.h&quot;<br />//#include &quot;../DS_uart/uart.h&quot;<br /><br />//definicje zmiennych<br /><br />char TWI_TX_BUF&#91;TWI_TX_SIZE&#93;;//bufor w którym znajdują się dane do wysyłki<br />volatile char TWI_RX_BUF&#91;TWI_RX_SIZE&#93;;//bufor odbioru danych<br />volatile uint8_t i_send;//zmienna, która przechowuje numer wysyłanego bajtu<br />volatile uint8_t Twi_Rx_head=0;//głowa bufora<br />uint8_t Twi_Rx_t=0;//zmienna pomocnicza - przepisywanie do bufora odbioru<br />volatile TTWI_STATUS twi_status_slave;//własnna zmienna - status TWI<br /><br />//-----definicje funkcji<br /><br />//!!--!!WSPOLNE dla Master i Slave<br /><br />void twi_init(uint8_t adr){<br />/*<br /> * Tylko adres 7bit. najmłodszy określa czy odbiór (0) czy wysyłania (1)<br /> * Gdy adr ma wartość 0, to urządzenie pracuje jako Master. W przeciwnym wypadku jako Slave<br /> */<br /><br />if(!adr){<br />//Master<br /><br />/*<br /> * TWSR = 0x00;preskaler<br /> * TWBR = 12;wartość bit rate<br /> *<br /> */<br /><br />#if F_CPU&lt;=2000000<br />TWSR = 0x00;<br />TWBR = 2;<br />/*<br /> * dla 1MHz:SCL_freq = 1000000 / (16 + 2 * 2 * 1) = 50kHz<br /> * dla 2MHz:SCL_freq = 2000000 / (16 + 2 * 2 * 1) = 100kHz<br /> */<br />#elif F_CPU==4000000<br />TWSR = 0x00;<br />TWBR = 12;//100kHz<br />#elif F_CPU==6000000<br />TWSR = 0x00;<br />TWBR = 22;//100kHz<br />#elif F_CPU==8000000<br />TWSR = 0x00;<br />TWBR = 32;//100kHz<br />#elif F_CPU==10000000<br />TWSR = 0x00;<br />TWBR = 42;//100kHz<br />#elif F_CPU&lt;=12000000<br />TWSR = 0x00;<br />TWBR = 52;//100kHz<br />#elif F_CPU==14000000<br />TWSR = 0x00;<br />TWBR = 62;//100kHz<br />#elif F_CPU&lt;=16000000<br />TWSR = 0x00;<br />TWBR = 72;//100kHz<br />#elif F_CPU==18000000<br />TWSR = 0x00;<br />TWBR = 82;//100kHz<br />#endif<br /><br />}else{<br />//Slave<br />TWAR = adr &amp; 0xFE;//wpisanie adresu<br />TWDR = 0x00;//rejestr danych wypełniamy 0<br /><br />TWCR |= (1&lt;&lt;TWINT) | (1&lt;&lt;TWEA) | (1&lt;&lt;TWEN) | (1&lt;&lt;TWIE);// Włączenie przerwania od TWI (TWINT, TWIE), włączenie potwierdzenia (TWEA), włączeni TWI (TWEN)<br /><br /><br />#if TWI_GCALL<br />//gdy ma reagować na adres 0x00<br />TWAR |= (1&lt;&lt;TWGCE);<br />#endif<br /><br />}<br /><br />}<br /><br />//!!--!!dla MASTER<br /><br />void twi_start(void){//sprzętowa sekwencja start<br /><br />TWCR = (1&lt;&lt;TWINT) | (1&lt;&lt;TWSTA) | (1&lt;&lt;TWEN);<br /><br />while(!(TWCR &amp; (1&lt;&lt;TWINT)));<br /><br />}<br /><br />void twi_stop(void){//sprzętowa sekwencja stop<br /><br />TWCR = (1&lt;&lt;TWINT) | (1&lt;&lt;TWSTO) | (1&lt;&lt;TWEN);<br /><br />while(!(TWCR &amp; (1&lt;&lt;TWSTO)));<br /><br />}<br /><br />void twi_send(uint8_t data){<br />//wysłanie pojedyńczego bajtu<br /><br />TWDR = data;<br />TWCR = (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN);<br /><br />while(!(TWCR &amp; (1&lt;&lt;TWINT)));<br /><br />}<br /><br />uint8_t twi_read(uint8_t ack){<br />//odebranie pojedyńczego bajtu<br /><br />TWCR = (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN) | (ack&lt;&lt;TWEA);<br />while(!(TWCR &amp; (1&lt;&lt;TWINT)));<br /><br />return TWDR;<br />}<br /><br />uint8_t twi_send_to_device(uint8_t address, uint8_t registry, char *send_data){<br />//pod wskazany adres urządzenia wysyłany jest ciąg znaków do podanego rejestru<br /><br />uint8_t twi_stat = 0;//zmienna w której przechowywany jest aktualny status TWI<br /><br />// sekwencja start<br />twi_start();<br />twi_stat = TW_STATUS;//zapisanie statusu TWI do zmiennej twi_start<br /><br />if( (twi_stat != TW_START) &amp;&amp; (twi_stat != TW_REP_START) )<br />return twi_stat | 0x04;<br /><br />//wywołanie urządzenia z ustawionym zapisem (najmłodszy bit adresu ustawiony na 0)<br />twi_send(address &amp; 0xFE);<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat ==  TW_MT_SLA_NACK) || (twi_stat == TW_MT_ARB_LOST) || (twi_stat != TW_MT_SLA_ACK) )//0x20, 0x38, 0x18<br />return twi_stat | 0x04;<br /><br />//wysłanie do urządzenia bitu kontrolnego bądź rejestr - informacje potrzebne do odbioru danych<br /><br />twi_send(registry);<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat == TW_MT_ARB_LOST) || (twi_stat != TW_MT_DATA_ACK)) // 0x38, 0x28<br />return twi_stat | 0x04;<br /><br />else if (twi_stat == TW_MT_DATA_NACK){//0x30<br /><br />twi_stop();<br />twi_stat = TW_STATUS;<br />return twi_stat | TW_MT_DATA_NACK | 0x04;<br />}<br /><br /><br />//wysyłanie danych<br /><br />while(*send_data){<br />twi_send(*send_data++);<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat == TW_MT_DATA_NACK) || (twi_stat == TW_MT_ARB_LOST) || (twi_stat != TW_MT_DATA_ACK)) //0x30, 0x38, 0x28<br />return twi_stat | 0x04;<br /><br />else if (twi_stat == TW_MT_DATA_NACK){//0x30<br /><br />twi_stop();<br />twi_stat = TW_STATUS;<br />return twi_stat | TW_MT_DATA_NACK | 0x04;<br />}<br /><br />}<br /><br />twi_stop();<br /><br />return 0;<br />}<br /><br />uint8_t twi_read_from_device(uint8_t address, uint8_t registry, uint8_t nr_data, char *read_data){<br />/* z wskazanego adresu urządzenia oraz rejestru odczytywany jest okreslony ciąg znaków<br /> * address - adres urządzeniaXXXX XXX0<br /> * registry - rejestr, ramka kontrolna<br /> * nr_data - ilosc odczytywanych danych// 0 - jesli ilosc danych przesyłana jest jako tekst w 2 pierwszych bajtach<br /> * read_data - odczytane dane<br /> */<br /><br />char len_data&#91;&#93; = {&quot;00&quot;};//dlugosc odbieranej ramki<br />uint8_t twi_stat=0;//status magistrali twi<br /><br />twi_start();<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat != TW_START) &amp;&amp; (twi_stat != TW_REP_START) )<br />return twi_stat | 0x04;<br /><br />//wywołanie urządzenia z ustawionym zapisem (najmłodszy ustawiony na 0)<br />twi_send(address &amp; 0xFE);<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat == TW_MT_DATA_NACK) || (twi_stat == TW_MT_ARB_LOST) || (twi_stat != TW_MT_SLA_ACK) )//0x20, 0x38, 0x18<br />return twi_stat | 0x04;<br /><br />//wysłanie do urządzenia bitu kontrolnego bądź rejestr - informacje potrzebne do odbioru danych<br />twi_send(registry);<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat == TW_MT_DATA_NACK)  || (twi_stat == TW_MT_ARB_LOST) || (twi_stat != TW_MT_DATA_ACK) )//0x30, 0x38, 0x28<br />return twi_stat | 0x04;<br /><br />//stop<br /><br />twi_stop();<br />twi_stat = TW_STATUS;<br /><br />#if TWI_DELAY_REP_START//jeżeli wartość została wpisana<br />//opóźnienie wywołania startu<br />_delay_ms(TWI_DELAY_REP_START);<br /><br />#endif<br /><br /><br />//powtórzenie startu<br />twi_start();<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat != TW_START) &amp;&amp; (twi_stat != TW_REP_START) )<br />return twi_stat | 0x04;<br /><br />//powtórne wywołanie urzadzenia, lecz z zamiarem odczytu danych<br /><br />twi_send( (address &amp; 0xFE) | 0x01 );<br />twi_stat = TW_STATUS;<br /><br />if( (twi_stat == TW_MR_SLA_NACK) || (twi_stat == TW_MR_ARB_LOST) || (twi_stat != TW_MR_SLA_ACK) ) //0x48, 0x38, 0x40<br />return twi_stat | 0x04;<br /><br />//ilość odbieranych danych<br /><br />if(nr_data){<br />//stała zdefiniowana wartość<br />while(--nr_data){<br />*read_data++ = twi_read(ACK);<br />twi_stat = TW_STATUS;<br />if( (twi_stat == TW_MR_ARB_LOST) || (twi_stat != TW_MR_DATA_ACK) )//0x38, 0x50<br />return twi_stat | 0x04;<br />}<br /><br />*read_data++ = twi_read(NACK);<br />twi_stat = TW_STATUS;<br />if( twi_stat != TW_MR_DATA_NACK)<br />return twi_stat | 0x04;<br /><br />}else{<br />//pierwsze dwa bajty danych zawierają ilość odbieranych danych<br />uint8_t i=0;<br />for( i=0 ; i &lt; 2 ; i++){<br />len_data&#91;i&#93; = twi_read(ACK);<br />twi_stat = TW_STATUS;<br />if( (twi_stat == TW_MR_ARB_LOST) || (twi_stat != TW_MR_DATA_ACK) )//0x38, 0x50<br />return twi_stat | 0x04;<br />}<br /><br />//konwersja z ANSI na typ uint8_t<br />nr_data = atoi(len_data);<br /><br />//odbieranie określonej ilości danych<br />while(--nr_data){<br />//odbiór z potwierdzeniem<br />*read_data++ = twi_read(ACK);<br />twi_stat = TW_STATUS;<br />if( (twi_stat == TW_MR_ARB_LOST) || (twi_stat != TW_MR_DATA_ACK) )//0x38, 0x50<br />return twi_stat | 0x04;<br />}<br /><br />//odbiór bez potwierdzenia<br />*read_data++ = twi_read(NACK);<br />twi_stat = TW_STATUS;<br />if( twi_stat != TW_MR_DATA_NACK)<br />return twi_stat | 0x04;<br />}<br /><br />//stop<br />twi_stop();<br /><br />return 0;<br />}<br /><br /><br />//!!--!!dla SLAVE<br /><br />//przerwanie od TWI<br /><br />ISR(TWI_vect){<br /><br />switch(TW_STATUS){<br /><br />//wysyłanie danych<br />case TW_ST_SLA_ACK://0xA8Own SLA+R has been received, ACK has been returned<br />case TW_ST_ARB_LOST_SLA_ACK://0xB0Arbitration lost in SLA+R/W, own SLA+R has been received, ACK has been returned<br />case TW_ST_DATA_ACK://0xB8Data byte in TWDR has been transmitted, ACK has been received<br /><br />//wpisanie do rejestru danych z bufora wysyłania<br />TWDR = TWI_TX_BUF&#91;i_send++&#93;;<br />TWCR |= (1&lt;&lt;TWINT);<br />if(i_send == TWI_TX_SIZE) i_send=0;//jeżeli skończyły się dane w buforze, a master dalej odbiera, slave wysyła dane od początku<br />break;<br /><br />case TW_ST_DATA_NACK://0xC0Data byte in TWDR has been transmitted, NOT ACK has been received<br /><br />//odebrano NACK - koniec odbierania danych<br />i_send = 0;<br />twi_status_slave.twi_ss_end_send=1;//zakończono wysyłanie danych<br />TWCR |= (1&lt;&lt;TWINT);<br /><br />break;<br /><br />//odbiór danych<br />//własny adres<br />case TW_SR_SLA_ACK://0x60SLA+W received, ACK has been returned<br />case TW_SR_ARB_LOST_SLA_ACK://0x68Arbitration lost in SLA+R/W<br /><br />//odebrano własny adres<br />twi_status_slave.twi_sr_own_adr=1;<br />TWCR |= (1&lt;&lt;TWINT);<br />break;<br /><br />//general call-adres 0x00<br />#if TWI_GCALL<br />case TW_SR_GCALL_ACK://0x70general call address has been received , ACK has been returned<br />twi_status_slave.twi_sr_gen_call=1;//odebrano GC<br />TWCR |= (1&lt;&lt;TWINT)<br />break;<br />#endif<br />case TW_SR_DATA_ACK://0x80address witn own SLA+w, data has been received, ACK has been returned<br />case TW_SR_GCALL_DATA_ACK://0x90address - general call, data has been returned, ack has been returned<br />if(!twi_status_slave.twi_sr_rec_data)//jeżeli nie jest jeszcze ustawiona zmienna<br />twi_status_slave.twi_sr_rec_data=1;//odbiór danych<br /><br />TWI_RX_BUF&#91;Twi_Rx_head++&#93; = TWDR;//zapis odebranych danych do bufora<br /><br />if(Twi_Rx_head == TWI_RX_SIZE-1) {//sprawdzenie czy odebrane dane będą nadpisywane w buforze. o 1 mniejszy bo jeszcze znak końca linii (13)<br />twi_status_slave.twi_sr_overwrite=1;//nadpisywanie danych<br />Twi_Rx_head = 0;//ustawienie początku bufora<br />}<br /><br />TWCR |= (1&lt;&lt;TWINT);<br />break;<br /><br />case TW_SR_STOP://0xA0STOP or repeated start has been received<br /><br />twi_status_slave.twi_sr_end_received=1;//zakończono odbiór<br /><br />TWCR |= (1&lt;&lt;TWINT);<br /><br />TWI_RX_BUF&#91;Twi_Rx_head++&#93; = 13;//koniec linii<br />Twi_Rx_head = 0;//ustawienie początku bufora<br />break;<br /><br />default:<br />TWCR |= (1&lt;&lt;TWINT);//clear twint flag<br /><br />}<br /><br />}<br /><br />uint16_t twi_status_sl(void){<br />//funkcja zwracająca status obsługi TWI dla slave<br />return twi_status_slave.bool;<br />}<br /><br />uint8_t twi_status(void){<br />//funkcja zwracająca status TWI - sprzętowe procedury. Rejestr TWSR<br />return TW_STATUS;<br />}<br /><br />inline int get_char(void){//pobieranie bajtu z bufora cyklicznego<br />return TWI_RX_BUF&#91;Twi_Rx_t++&#93;;//zwrócenie danych znajdujących się w komórce<br />}<br /><br />char *twi_get_data(char *s){//pobieranie ramki danych z bufora cyklicznego<br />char c;<br />char *wsk = s;//kopia zapasowa wskaźnika przekazanych danych (początku bufora)<br /><br />while((c=get_char())){//pobranie pojedyńczego znaku, wpisanie do c i sprawdzenie czy jest różna od 0<br />if(c == 13 || c &lt; 0)break;//jeżeli jest znak CR lub -1 (brak danych w buforze) koniec pętli<br />*s++ = c;//wpisanie do bufora pod adres wskaźnika danych 'c' i inkrementacja wskaźnika - następny adrs<br />}//while<br /><br />*s = 0;//zakończenie odczytanej linijki poprzez znak 0 - NULL- bo to C-string<br /><br />Twi_Rx_t=0;<br /><br />return wsk;//odczytane dane są w s i zwracane poprzez wsk<br />}<br /><br />void insert_data(char *s){//wpisanie danych do bufora nadawczego z twi. Dane wysyłające muszą posiadać na końcu wartosc 0x00<br /><br />#if TWI_SLAVE_SEND_LENGTH//w zależności czy w pierwszych dwóch bajtach danych wysyłanych ma znajdować się ilość wysyłanych danych<br />uint16_t i_insert=2;<br />#else//czy nie<br />uint16_t i_insert=0;<br />#endif<br />char c= *s;<br /><br />//przepisywanie danych do bufora wysyłania<br />while(c){<br />if( c==13 || c &lt; 0 ) break;<br />TWI_TX_BUF&#91;i_insert++&#93; = c;<br />c = *++s;<br />if(i_insert == TWI_TX_SIZE-1) break;<br />}<br /><br />TWI_TX_BUF&#91;i_insert&#93; = 13;//koniec danych w buforze oznaczony jako znak CR<br /><br />#if TWI_SLAVE_SEND_LENGTH//wpisanie do dwóch pierwszych bajtów bufora ilości wysyłanych danych<br />i_insert=-2;<br />TWI_TX_BUF&#91;0&#93; = i_insert/10 + 0x30;<br />TWI_TX_BUF&#91;1&#93; = i_insert%10 + 0x30;<br />#endif<br />}<br /><br />//Zdarzenia dotyczace obsługi TWI<br /><br />//wskaźnik do funkcji zwrotnej dla odbioru danych w TWI_event<br />static void (*twi_event_received_callback)(char *received_bufor);<br /><br />//rejestracja funkcji zwrotnej dla odbioru danych<br />void register_twi_event_received(void (*callback)(char *received_bufor)){<br />twi_event_received_callback = callback;<br />}<br /><br />//zdarzenie obsługi TWI<br />void TWI_EVENT(char *twi_event_bufor){<br /><br />//odbiór<br />if(twi_status_slave.twi_sr_end_received){//jeżeli skończono odbiór<br />if(twi_event_received_callback){//jeżeli funkcja została zarejestrowana<br />twi_get_data(twi_event_bufor);//pobranie danych z bufora i wpisanie do twi_even_bufor<br />(*twi_event_received_callback)(twi_event_bufor);//wywołanie funkcji obsługi zdarzenia<br />twi_status_slave.bool &amp;= 0xFF00;//wyzerowanie statusów informujących o odbiorze danych<br />}//received callback<br />//end received<br /><br />}else if(twi_status_slave.twi_ss_end_send){//zakończono wysyłanie danych<br />twi_status_slave.bool &amp;= 0x00FF;//wyzerowanie statusów informujących o wysyłaniu danych<br />//funkcja która reaguje na zakończenie wysyłania danych&lt;- można ją tutaj dodać<br />}<br /><br /><br />}<br /><br />void twi_send_data(char *twi_send_data){//zewnętrzna funkcja do wpisywania danych które mają zostać odesłane do MASTER<br />insert_data(twi_send_data);<br />}<br /><br /><br />//ostrzeżenie w przypadku gdy ustawiona ilość danych rejestru jest większa od bufora odbioru<br />#if TWI_REC_REG_DATA &gt;= TWI_RX_SIZE<br /><br />#error &quot;Za mała wielkość bufora odbioru TWI. Zwiększ wartość TWI_RX_SIZE&quot;<br /><br />#endif[/syntax]<br /><br /><br /><span style="text-decoration: underline"><strong>ds_twi.h</strong></span><br /><br />[syntax=csharp]/*<br /> * ds_twi.h<br /> *<br /> *  Created on: 04-01-2014<br /> * Edited on: 29-01-2014<br /> *      Author: Daniel (danielo$)<br /> *<br /> *<br /> *Na podstawie (Based on):<br /> *http://www.ermicro.com<br /> *http://www.ermicro.com/blog/?p=1239<br /> *http://www.atnel.pl<br /> *książka:<br /> *Mikrokontrolery AVR Język C - podstawy programowania<br /> *Mirosław Kardaś<br /> *<br /> *Język C. Pasja programowania mikrokontrolerów 8-bitowych<br /> *Mirosław Kardaś<br /> *<br /> *All rights reserved.<br /> */<br /><br />#ifndef DS_TWI_H_<br />#define DS_TWI_H_<br /><br />#define TWI_SLAVE_ADDRESS0x42//litera B<br /><br />//#define TWI_TIMEOUT1//do wykorzystania w przyszłości<br />#define TWI_DELAY_REP_START 10//czas w ms, po którym następuje powtórzenie startu dla odbierania danych. UWAGA!! opóźnienie realizowane przy pomocy funkcji _delay_ms<br /><br />#define TWI_GCALL0//Czy mikrokontroler ma reagować na General Call - adres 0x00. TYLKO dla pracy jako Slave<br /><br />#define TWI_TX_SIZE32//rozmiar tablicy wysyłanych danych<br />#define TWI_RX_SIZE16//rozmiar bufora odbioru-najlepiej wielokrotnosci dwojki<br /><br />#define TWI_SLAVE_SEND_LENGTH 1//układ slave wysyła w pierwszych dwóch bajtach długość danych do odebrania przez MASTER<br /><br />#define TWI_REC_REG_DATA 1//ilość danych w buforze to adres rejestru<br /><br />//-----!!Nie zmieniać<br /><br />#define ACK 1<br />#define NACK 0<br />//#define MAX_TRY 50//do wykorzystania w przyszłości<br /><br />#define TWI_WRITE1<br />#define TWI_READ0<br /><br />#define MASTER 1<br />#define SLAVE 0<br /><br />//definicja własnej zmiennej<br />typedef union{<br />uint16_t bool;<br />struct{<br />//--odbiór<br />uint16_t twi_sr_own_adr:1;//1 - odebrano własny adres<br />uint16_t twi_sr_gen_call:1;//2- odebrano general call -0x00<br />uint16_t twi_sr_rec_data:1;//3- odbiór danych<br />uint16_t twi_sr_end_received:1;//4- zakończono odbiór<br />uint16_t twi_sr_overwrite:1;//5- występuje nadpisywanie danych<br />uint16_t twi_sr_rec_error:1;//6- błędny odbiór<br />//7<br />//8<br /><br />//--wysyłanie<br />uint16_t twi_ss_end_send:1;//9- wysłano dane<br />//10<br />//11<br />//12<br />//13<br />//14<br />//15<br />//16<br />};<br />}TTWI_STATUS;<br /><br />//-----deklaracje zmiennych<br />extern volatile TTWI_STATUS twi_status_slave;//status twi<br />extern volatile char TWI_RX_BUF&#91;TWI_RX_SIZE&#93;;//bufor odbioru<br /><br />//-----deklaracje funkcji<br />void twi_init(uint8_t adr);//Tylko 7bit. Gdy adr jest 0, to urządzenie pracuje jako Master. W przeciwnym wypadku jako Slave<br />void twi_start(void);//sekwencja start<br />void twi_stop(void);//sekwencja stop<br />void twi_send(uint8_t data);//wysłanie pojedyńczego bajtu<br />uint8_t twi_read(uint8_t ack);//odebranie pojedyńczego bajtu<br />uint8_t twi_send_to_device(uint8_t address, uint8_t registry, char *send_data);//pod wskazany adres urządzenia wysyłany jest ciąg znaków do podanego rejestru<br />uint8_t twi_read_from_device(uint8_t address, uint8_t registry, uint8_t nr_data, char *read_data);//z wskazanego adresu urządzenia oraz rejestru odczytywany jest ciąg znaków<br /><br />uint16_t twi_status_sl(void);//funkcja zwracająca status obsługi TWI dla slave<br />uint8_t twi_status(void);//funkcja zwracająca status TWI - sprzętowe procedury. Rejestr TWSR<br /><br />char *twi_get_data(char *s);//pobieranie ramki danych z bufora cyklicznego<br /><br />//Zdarzenia dotyczące obsługi TWI<br /><br />void TWI_EVENT(char *twi_event_bufor);//zdarzenie TWI<br />void register_twi_event_received(void (*callback)(char *received_bufor));//rejestracja funkcji obsługi zdarzenia TWI<br /><br />void twi_send_data(char *twi_send_data);//wpisanie danych które mają zostać wysłane przez TWI do bufora TWI_TX_BUF<br /><br />#endif /* DS_TWI_H_ */[/syntax]<br /><br />Bibliotekę starałem wykonać się tak, aby była ona uniwersalna. Dlatego też, ramkę danych wykonałem na podstawie not katalogowych urządzeń komunikujących się za pomocą I2C.<br /><br />Ramka danych ma następujący format:<br />- dla zapisu w urządzeniu Slave<br /><br /><a href="http://forum.atnel.pl/_obrazki/o/898/e2faf69b639dfcc85f4ac4c33cecfbb0.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/thumb/898/e2faf69b639dfcc85f4ac4c33cecfbb0.jpg" alt="Obrazek" /></a><br /><br />- dla odczytu z urządzenia Slave<br /><br /><a href="http://forum.atnel.pl/_obrazki/o/898/8e7dd5614cc6530c775069f2530effe5.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/thumb/898/8e7dd5614cc6530c775069f2530effe5.jpg" alt="Obrazek" /></a><br /><br />Podczas odczytu danych z urządzenia SLAVE, nie jest konieczne wysyłanie do SLAVE rejestru. Można od razu rozpocząć odbiór danych.<br />W przypadku wysłania rejestru, należy ustawić czas opóźnienia T wysłania ponownego startu. Czas T powinien być na tyle długi, aby program zdążył przygotować dane.<br /><br /><br /><br /><span style="text-decoration: underline">Konfiguracja.</span><br /><br />Konfiguracji dokonujemy w pliku <strong>ds_twi.h</strong> do komentarza &quot;<span style="text-decoration: underline">nie zmieniać</span>&quot;.<br /><br />Adres jaki nasze urządzenie SLAVE będzie posiadało. Ja wykorzystywałem litery jako adres z tą uwagą, aby najmłodszy bit miał wartość 0. Na najmłodszym bicie przesyłana jest informacja czy następuje odczyt czy zapis do SLAVE.<br />[syntax=csharp]#define TWI_SLAVE_ADDRESS0x42//litera B[/syntax]<br /><br />Podczas odczytu z urządzenia SLAVE może występować opóźnienie w celu przygotowania danych do odesłania (np. w celu wykonania pomiarów, bądź odczytu danych z innych urządzeń) - czas podawany jest w ms.<br />[syntax=csharp]#define TWI_DELAY_REP_START 10//czas w ms, po którym następuje powtórzenie startu dla odbierania danych. UWAGA!! opóźnienie realizowane przy pomocy funkcji _delay_ms[/syntax]<br /><br />Układ może również reagować na ogólne wywołanie za pomocą adresu 0x00 (General Call)<br />[syntax=csharp]#define TWI_GCALL0//Czy mikrokontroler ma reagować na General Call - adres 0x00. TYLKO dla pracy jako Slave[/syntax]<br /><br />Rozmiary bufora obioru, oraz wysyłania.<br />[syntax=csharp]#define TWI_TX_SIZE32//rozmiar tablicy wysyłanych danych<br />#define TWI_RX_SIZE16//rozmiar bufora odbioru-najlepiej wielokrotnosci dwojki[/syntax]<br /><br />Dane odbierane przez układ Master mogą mieć różną długość - w takim przypadku w pierwszych 2 bajtach przesyłana jest liczba w kodzie ASCII informująca o ilości danych. Gdy ilość danych jest stała, TWI_SLAVE_SEND_LENGTH należy ustawić na 0, w przeciwnym razie 1.<br />[syntax=csharp]#define TWI_SLAVE_SEND_LENGTH 1//układ slave wysyła w pierwszych dwóch bajtach długość danych do odebrania przez MASTER[/syntax]<br /><br />Funkcje, dla użytkownika:<br /><br />Inicjalizacja TWI. Gdy układ ma pracować jako MASTER, argument przesyłany do funkcji powinien mieć wartość 0. Natomiast gdy urządzenie ma pracować jako SLAVE, argumentem jest adres tego urządzenia.<br />[syntax=csharp]void twi_init(uint8_t adr);//Tylko 7bit. Gdy adr jest 0, to urządzenie pracuje jako Master. W przeciwnym wypadku jako Slave[/syntax]<br /><br />Funkcje do wykorzystania w przypadku, gdy ramka danych zdefiniowana w następnych funkcjach nie pokrywa się z ramką danych obsługiwanego urządzenia.<br />[syntax=csharp]void twi_start(void);//sekwencja start<br />void twi_stop(void);//sekwencja stop<br />void twi_send(uint8_t data);//wysłanie pojedyńczego bajtu<br />uint8_t twi_read(uint8_t ack);//odebranie pojedyńczego bajtu[/syntax]<br /><br />Wysyłanie danych z MASTER do SLAVE. Pod wskazany adres (address) urządzenia wysyłany jest ciąg znaków (send_data) do podanego rejestru (registry).<br />[syntax=csharp]uint8_t twi_send_to_device(uint8_t address, uint8_t registry, char *send_data);//pod wskazany adres urządzenia wysyłany jest ciąg znaków do podanego rejestru[/syntax]<br /><br />Odczyt danych z SLAVE przez MASTER. Z podanego adresu urządzenia (address), oraz rejestru (registry) odczytywana jest odpowiednia ilość danych (nr_data)  i zapisywana do bufora read_data. W przypadku gdy ilość odczytywanych danych jest zmienna argument nr_data musi mieć wartość 0.<br />[syntax=csharp]uint8_t twi_read_from_device(uint8_t address, uint8_t registry, uint8_t nr_data, char *read_data);//z wskazanego adresu urządzenia oraz rejestru odczytywany jest ciąg znaków[/syntax]<br /><br />Funkcje umożliwiające odczytanie statusu magistrali TWI oraz obsługi TWI dla SLAVE<br />[syntax=csharp]uint16_t twi_status_sl(void);//funkcja zwracająca status obsługi TWI dla slave<br />uint8_t twi_status(void);//funkcja zwracająca status TWI - sprzętowe procedury. Rejestr TWSR[/syntax]<br /><br />Obsługa zdarzeń TWI, oraz rejestracja odpowiednich funkcji do obsługi tego zdarzenia.<br />[syntax=csharp]void TWI_EVENT(char *twi_event_bufor);//zdarzenie TWI<br />void register_twi_event_received(void (*callback)(char *received_bufor));//rejestracja funkcji obsługi zdarzenia TWI[/syntax]<br /><br />Dane które mają zostać przygotowane do wysyłania są przesyłane jako argument funkcji:<br />[syntax=csharp]void twi_send_data(char *twi_send_data);//wpisanie danych które mają zostać wysłane przez TWI do bufora TWI_TX_BUF[/syntax]<br /><br />Odebrany rejestr przechowywany jest w pierwszych komórkach bufora odbioru. Przygotowanie danych do wysłania można wykonać po odebraniu rejestru w zdarzeniu do obsługi TWI, bądź gdziekolwiek w programie gdy jest taka potrzeba.<br /><br />Przykładowe zastosowanie zdarzenia TWI dla układu SLAVE:<br /><br />[syntax=csharp]#include &quot;DS_TWI/ds_twi.h&quot;<br />void reakcja_odbior(char *buffor);<br /><br />int main(void)<br />{<br />LCD_init();<br />twi_init(TWI_SLAVE_ADDRESS);<br />register_twi_event_received(reakcja_odbior);<br /><br />sei();//globalne odblokowanie przerwań<br />while (1)<br />{<br />TWI_EVENT(bufor);<br />}<br />}<br /><br />// ----- definicje funkcji<br />void reakcja_odbior(char *buffor){<br />switch (buffor&#91;0&#93;)<br />{<br />case 'o'://odbiór<br />LCD_local(0,0);<br />LCD_text(buffor);<br />break;<br /><br />case 'w'://wysyłanie<br />twi_send_data(&quot;wyslano przez TWI&quot;);<br />break;<br /><br />default:<br />break;<br />}<br />}[/syntax]<br /><br />Poszczególne fragmenty kodu opatrzone są komentarzami.<br />W przypadku jakichkolwiek pytań, należy pytać!<br /><br />Jeżeli w jakimś miejscu pojawiły się jakieś błędy - też pisać. Każdy może się pomylić.<br /><br />W przyszłości mam zamiar wykonać timeout w celu zabezpieczenia programu tam gdzie zostały zastosowane pętle while(), oraz wykonać szerszą obsługę magistrali TWI w układzie SLAVE (np. w przypadku nie odebrania danych, bądź powtórne wysłania danych).<br /><br />Proszę o wyrozumiałość;)<br /><br />P.S.<br /><br />Przykład zastosowania obejmuje dwa mikrokontrolera pierwszy MASTER - ATmega 8 połączona z komputerem przez uart. Wysyłając wartość &quot;1&quot; przez terminal (19200 bps) wysyłane jest polecenie odbioru danych. Natomiast wpisanie dowolnego krótkiego tekstu (około 8 znaków) do terminala i wciśnięcie enter zapisuje dane w SLAVE. Układ taktowany wewnętrznym kwarcem 4MHz.<br />Układ Slave to Atmega32 taktowana zewnętrznym kwarcem 4MHz. Podłączony jest do niej wyświetlacz lcd 2 wierszowy. Odebrane dane z Master są wyświetlane na LCD.<br /><br />Rezystory podciągające magistralę o wartości 4,7k znajdują się przy Master.<br /><br />Jeżeli ktoś mógłby przetestować działanie tych bibliotek na innych AVR byłbym wdzięczny.<br /><br />P.S. 2<br /><br />Jeżeli znajdę trochę więcej czasu to postaram się dokładniej opisać sposób komunikacji oraz działania tych bibliotek i umieścić w jakimś pdf - w bliżej nieokreślonym czasie.<br /><br />Pozdrawiam<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=898">danielos</a> — 29 sty 2014, o 22:13</p><hr />
]]></content>
</entry>
</feed>