State Machine ile Gelen Veri Kontrolü

Başlatan vitruvius, 11 Haziran 2014, 19:05:28

vitruvius

Merhaba, Atmega644P'den başka bir Atmega644P'ye seri veri yollamaya çalışıyorum. İlk başta sırasıyla 0x16, 0x10, 0x02 gönderiyorum. Bunları okumak için bir state machine kurdum. Her durumda birini kontrol edip sıradaki duruma geçiyorum.

Burada şöyle bir sorun var her durum başında yaptığım kontrol sanırım çok hızlı olduğundan program else satırına girip çıkıyordu. Ben de o yüzden veri gelene kadar beklemek için başa bir if komutu daha ekledim. Önce veri geliyor mu diye bakıyorum, sonra gelen veri aradığım değere eşit mi diye bakıyorum. Hala mantıksız geliyor ama işe de yarıyor. Bunu tek satırda yapabileceğim bir mantık nasıl olur?

Bir de gelen verilerin içinde 0x00 gelme durumu var. Proteus'ta osiloskoptan bakıp start ve stop bit arasında 8 bit 0 geldiğini görüyorum ama program else'e giriyor. 0x01 geldiği zaman bir sorun yok. Bunu nasıl aşarım?

İlgili kod parçası:
while(1)
    {
		rec_char=uart_getc();		
		
		switch(state)	
		{
			case SYN_s:
				if ((unsigned char) rec_char) // Ek if, veri geldi mi diye kontrol.
				{
					if ((unsigned char) rec_char == 0x16)
					{
						state=DLE_1_s;
					}
					else
					{
						state=SYN_s;
					}
				}
				
				break;
				
			case DLE_1_s:
				if ((unsigned char) rec_char) // Ek if, veri geldi mi diye kontrol.
				{
					if ((unsigned char) rec_char == 0x10)
					{
						state=STX_s;
					}
					else
					{
						state=SYN_s;
					}
				}
				
				break;

//Diğer state'ler.

            case TARGET_NO_4_s:
				if ((unsigned char) rec_char) // Ek if, veri geldi mi diye kontrol.
				{
					if((unsigned char) rec_char == 0x00) // Burada 0x00 alınca else'e geçiyor.
					{
						state=PACKET_NO_s;
					}
					else
					{
						state=SYN_s;
					}
				}
				
				break;


Teşekkürler.

Tagli

Bana biraz garip göründü, veya olayı tam anlayamadım. Gelen veri yoksa zaten state machine kısmına girmemeli bence.

Ben XC16'da state machine'i RX kesmesi içine gömdüm. Address detect ile 9 bit iletişim yapıyorum. Kodlarım şöyle:
void __interrupt(auto_psv) _U1RXInterrupt(void) {
    unsigned int temp = U1RXREG;
    char data = temp;
    char bit8 = temp >> 8;
    _U1RXIF = 0;

    if (bit8 == 1) { /* Address detection */
        if (data == devAddr) {
            state = 1;
            U1STAbits.ADDEN = 0;
            /* blink(); */
        }
        else { /* RX interrupted */
            state = 0;
            U1STAbits.ADDEN = 1;
            bufferKillGhost(&rxBuffer);
        }
    }
    else if (state == 1) { /* Size determination state */
        state = 2;
        rxCounter = 0;
        checksum = (unsigned char) data;
        payloadSize = (unsigned char) data;
    }
    else if (state == 2) { /* Payload receive state */
        if (rxCounter++ < payloadSize) {
            checksum += (unsigned char) data;
            /* TODO: Implement error checking for buffer overflow. */
            bufferGhostEnqueue(&rxBuffer, data);
        }
        else {
            state = 0;
            U1STAbits.ADDEN = 1;
            if (checksum == (unsigned char) data) {
                bufferAcceptGhost(&rxBuffer);
                /* blink(); */
            }
            else {
                bufferKillGhost(&rxBuffer); /* Checksum failure */
                /* blink(); */
            }
        }
    }
}

Veri paketim, mark parity ile gelen bir adres ile başlıyor. Bu aynı zamanda state machine'i herhangi bir noktada sıfırlama etkisine de sahip. Diğer tüm byte'lar space parity ile gidiyor. Daha sonra paket boyutunu yolluyorum. Arada paket verisinin kendisi gidiyor. Sonunda da basit bir checksum var. Checksum kontrolü yapılmadan önce, gelen veri bir dairesel tampon belleğe atılıyor ama kesin kabul edilmediği için "hayalet" olarak tanımlıyorum onu. Kontrolden olumlu geçerse, veri kesinleşiyor. Geçmezse yok sayılıyor.
Gökçe Tağlıoğlu

vitruvius

Structure şu şekilde:



Bu aynı zamanda cihazın seri numarasını oluşturuyor, o yüzden kontrol etmek istiyorum. Bahsi geçen byte "Byte 4". Seq. Number her zaman 0. 7 numaralı bit ise güne göre değişip ya 1 yada 0 oluyor. 0 olduğu zamansa Byte 4 0x00 oluyor.

Tagli

#3
Veri 0x00 gelirse dışta bulunan if ((unsigned char) rec_char) bloğundan içeri giremezsin ki.
Gökçe Tağlıoğlu

vitruvius

İşte zaten onun yolunu arıyorum =) O satırı kullanmayınca mesela DLE'yi kontrol ederken şöyle yazınca direkt else'e girip çıkıyor.

case DLE_1_s:
                if ((unsigned char) rec_char == 0x10)
                    {
                        state=STX_s;
                    }
                    else
                    {
                        state=SYN_s;
                    }
                
                break;


Neden o satıra ihtiyacım olduğunu yada o satırdan nasıl kurtulabileceğimi anlamaya çalışıyorum. Benim mantığıma göre önce veri var mı diye bakıp sonra gelen veriyi bir değerle kıyaslamanın bir manası yok. Direkt gelen veriyi istediğim değerle kıyaslarsam ve bu doğruysa zaten veri gelmiş demektir. Ama bir sebepten bu şekilde yapınca direkt olarak else'e giriyor.

Tagli

uart_getc(); fonksiyonu nasıl çalışıyor? Veri yoksa 0x00 mı döndürüyor - ki bence böyle olmaması lazım - yoksa beklemede mi kalıyor? Veri olup olmadığını anlamanın başka bir yolu olmalı. Veri varsa uart_getc(); çağrılmalı sadece. PIC'te böyle yapılıyordu. Atmel'de de mantığın benzer olduğunu sanıyorum. Mutlaka kontrol edebileceğin bir kesme bayrağı falan vardır.
Gökçe Tağlıoğlu

Kabil ATICI

#6
RX ile ilgili iki tane kesmesi var,(iki seri port için)
USART1 RX Complete
USART0 RX Complete --Veri geldi
USART1,UDR Empty
USART0,UDR Empty --veri hattı boş

USART1 RX Complete veya USART0 RX Complete çoğunlukla iş görür. Kesme bayrak kullanılmazsa, bazen 0x00'da bir veri olarak gelebilir.

bayrağı da
Receive Complete (RXCn)  olması lazım. (n kullanılan seri port numarası)


ek:
http://www.atmel.com/images/AVR307.zip
adresinden UART  kesme ile ilgili örneklere ulaşılabilir. (Kendi işlemcinize göre uyarlamanız gerekebilir)
ambar7

vitruvius

Ondan önce kafama başka bir şey takıldı onu düşünüyorum. Data telegram şu şekilde:



Şimdi diyelim ki SYN'i aldım. DLE'yi kontrol ederken 0x10'dan başka bir şey geldi. Bu durumda ne yapmalıyım? Tekrar başa dönüp SYN'i mi kontrol etmeliyim, yoksa DLE state'i içinde mi kalmalıyım?

Tagli

Ben olsam bir şeylerin yanlış olduğu sonucuna varıp state machine'i sıfırlardım. Ama tabi o iletişim protokolünün (data telegram) standartı başka bir şey söylüyor olabilir. Protokolde ne şekilde tanımlanmışsa ona göre hareket edilmeli.
Gökçe Tağlıoğlu

vitruvius

Data telegram kısmı gördüğünüzden 3 cümle fazlası, onlar da konuyla bağlantılı değil. Peki başa dönüp SYN beklersem ve şu şekilde bir veriyle karşılaşırsam data'yı kaçırmam mı? "SYN SYN DLE STX".

İlk SYN'den sonra DLE'yi kontrol edecek ancak ikinci veri de SYN, bu yüzden yanlış deyip başa dönüp tekrar SYN bekleyecek. Halbuki ilk SYN'den sonra data doğru bir şekilde geliyor. Bu kafamı karıştırdı, state machine'i tam olarak kuramadım.

Protokolü incelemek isteyenler için (Sayfa 8): http://www.4shared.com/office/KVNCGnvpba/Protocolspecification_EIA-485_.html

Tagli

Dediğim gibi, SYN geldiğinde state machine resetlenecek. Benzer durumu benim verdiğim kodda da görebilirsin. Benim kodda adres biti olan byte SYN gibi davranıyor. O geldiğinde her şey sıfırdan başlıyor.
Gökçe Tağlıoğlu

mehmet

AT Mega644 pdf 182. sayfa
UCSRnA – USART Control and Status Register AUCSRnA – USART Control and Status Register A
Bit 4 – FEn: Frame Error
Bunu inceleyiniz. Geçerli veri gilip gelmediğini bununla tespit edebilirsiniz...
Olan olmuştur,
olacak olan da olmuştur.
Olacak bir şey yoktur.
---------------------------------------------
http://www.mehmetbilgi.net.tr