USART Üzerinden Struct Göndermek

Başlatan kimlenbu, 04 Haziran 2014, 17:06:18

kimlenbu

Selamlar,

İki adet STM32F407 arasında seri olarak veri alışverişi olması gerekiyor. Veriler iki işlemcide de struct tipinde.

typedef struct MyTestStruct
{
	uint8_t  a;
	uint16_t b;
	uint32_t c
}MyTestStruct;

MyTestStruct TestStruct[] = {
	{0xAA,0xBBBB,0xCCCCCCCC},
	{0x2A,0x2BBB,0x2CCCCCCC},
};


USART veri gönderme fonksiyonum şu şekilde :

void USART_puts(USART_TypeDef* USARTx, volatile char *s){

	while(*s){
		// wait until data register is empty
		while( !(USARTx->SR & 0x00000040) );
		USART_SendData(USARTx, *s);
		*s++;
	}
}


Bu struct'ı tek seferde gönderme şansım var mı ? Araştırdığımda "Type Casting" önermişler, aşağıdaki şekilde denedim çalışmadı.

Struct içinden bir değişken göndermeyi denedim olmadı :

USART_puts(USART6, (uint8_t *) TestStruct[0].a );


Struct'ı göndermeyi denedim olmadı :
USART_puts(USART6, (uint8_t *) TestStruct );


Bu struct'ı usart üzerinden tek seferde nasıl göndeririz ? (iki tarftaki işlemci de aynı, derleyici de aynı)


Klein

C pointer ile çalışırken biraz tutucudur.  işaretinin gösterdiği büyüklük aynı bile olsa  , birebir tip uyumu ister. Bu sebeple casting yaparız. 
eğer USART_Puts(..) fonksiyonu 
veri işaretçisi olarak "*char " parametre alıyorsa,  casting şu şekilde olmalı   "(char *) mystruct"
eğer *uint8_t   şeklinde parametre alıyorsa yaptığınız casting doğru. Hata vermemelidir.

kimlenbu

#2
Hata vermiyor, derleniyor ama veriler hatalı gönderiliyor (PC'de kontrol ediyorum)

Bu şekilde gönderiyorum :

USART_puts(USART6, (volatile char *) TestStruct );


Karşı tarafa şu şekilde ulaşıyor :

47 6F 6E 64 65 72 69 79 6F 6D AA


Düzeltme : Pardon verilerde hata var, veri göndermeden önce "Gonderiyom" mesaji gidiyordu, onun hex değerleriymiş :)

aslında AA gönderiyormuş sadece

G47 o6F n6E d64 e65 r72 i69 y79 o6F m6D  AA 



Klein

#3
typedef volatile struct  __attribute__ ((__packed__))
{
	struct{
		TBroadCastRegisters BroadCastRegisters;						//	10
		TSTSRegisters StsRegisters;					// 	6
		Alarmflags_TypeDef ActiveAlarms;						//	2
		Alarmflags_TypeDef AlarmHistory;						//	2
		uint16_t Reserve[2];
		Param_TypeDef Params;// 	78
		TFunctions Function;								//2
		int16_t Anin[4];//16
		int16_t AdcRaw[4];//16
		int16_t Adc[4];//16

	};
}IOMap_Typedef; // 120


Paketleme  GCC'de böyle. Keil kullanıyorsan farklı olabilir. 
Ayrıca  structların boyunu mümkün olduğunca 32 bitin katlarına denk getirirsen iyi olur.

Neden paketlemen gerekiyor?
CPU 32 bit.  Eğer struct paketlenmemişse derleyici  değişkenleri yerleştirirken  adresleri 32 bitin katları olacak şeklide yerleştirir.

kimlenbu

Sağolun cevaplar için, ekipmanlar iş yerinde yarın ilk iş deneyip yazarım sonucu. "packed" olayını bilmiyordum ne yalan söyleyeyim.

CLR

#5
Keil'de struct için __packed keywordu yeterli.

Blok olarak packed yapacaksan

#pragma pack(push, x)  ve #pragma pack(pop) kullanabilirsin. Burada x byte sayısıdır mesela 1 ise __packed ile aynı.

typedef __packed struct{
	u8	LcdCmdFlag;				
	u16	LcdCmd;					
	u32	LcdCmdTimeout;			
}LcdCmdRegs_Typedef;

#pragma pack(push, 1)  

typedef struct...

typedef struct...

typedef struct...

#pragma pack(pop)


Ayrıca yerinde olsam bu şekilde interface yapmazdım. Struct'ları packed tanımladıktan sonra , usart RX ve TX DMA'ya ilgili structların'ın start adreslerini girerdim hem herşeyi dma yapardı hemde gelen veya giden struct registerlerin otomatik update olur. Mesela peryodik flag tanımlayabilirsin, flag set olunca dma gönderir, diğeride alır gibi.

Knowledge and Experience are Power

kimlenbu

Struct'ı "packed" yapınca düzeldi :) ekstra bytelar'da gönderiyor ve byte sıralamalarına dikkat etmem gerekiyor ama usart kodlarımı düzenlerim ona göre.

AA BB BB CC CC CC CC 2A BB 2B CC CC CC 2C



@CLR hocam, öneriniz için teşekkür ederim. "kara düzen" bi çalıştırayım, DMA'yı süsleme kısmında hallederim :)

Elektroemre

Konunun biraz dışında ama böyle bir struct'u gönderirken paket başı sonunu nasıl tespit ediyorsunuz, bu sorun olmuyor mu?
Paket içinde null dahil 0...255 aralığındaki tüm değerlerin olma ihtimali var.

kimlenbu

Alıntı yapılan: Elektroemre - 05 Haziran 2014, 12:11:46
Konunun biraz dışında ama böyle bir struct'u gönderirken paket başı sonunu nasıl tespit ediyorsunuz, bu sorun olmuyor mu?
Paket içinde null dahil 0...255 aralığındaki tüm değerlerin olma ihtimali var.

"$Gonderiyom" ile baslayip "$Bitti" ile sonlandiriyorum :) eger bu kadar karakterin arka arka gelecegi tutarsa da gidip bi sayisal oynarim :)

Elektroemre

#9
Haha  :D Yinede benim içime sinmiyor hocam. Profesyonel uygulamlarda da bu şekilde mi?
Kendi uygulamalarımda '$' karakteri ile başlayıp sonra tün dataları ascii'ye dönüştürüp gönderiyorum. Haliyle özellik sayılarda baya bir hız kaybı yaşanıyor.
Sayıları hexdecimal gönderince normalin 2 katı (1byte için 2 ascii karakter) band genişliği harcıyorum. en sonda \n ile bitiriyorum.
Uygulamayı terminalden elle test etmekte kolaylaşıyor ama dediğim gibi fazla band genişliği harcıyorum.

Klein

Paket sonunda 1-2Byte  boşluk verirseniz, karşı taraf bunun paket sonu olduğunu anlar. Binary haberleşen bir  çok ( hatta benim gördüklerimin tamamı) ve kendi kullandığım yöntem bu.
Modbus RTu böyle çalışır. 3Byte boşluk paket sonu kabul ediir.

Eğer paket içeriğinde kaç byte veri göndereceğinizi belirttiyseniz ve de CRC ,LRC benzeri bir kontrol mekanizmanız varsa , sonlandırma olmadan da paketi işleyebilirsiniz. Ancak tek başına önermem.

Klein

Alıntı yapılan: gerbay - 05 Haziran 2014, 13:29:52
bu işler için uygulanması gereken yöntem structure göndermek. structure içine gerekli senkronizasyon alanlarını ve ortamına göre gerekiyorsa checksum ı vs. koyup göndermek.

ben normal tam sayılar dışında float, double da gönderdim. çok gönderenini de gördüm. çok gönderen derken Türkiye anlamında değil.

LN270 - INS,  bu zımbırtının protocol struct ında tam sayı da var, float da var, double da var.

stucture gönderin/alın.. doğru yöntem bu..
Türkiye'de neden olmasın hocam. Yıllardır struct gönderirim.  Modbus çalışırken de , Kendi protokolümle de. Bence çok kişi vardır bu şekilde çalışan.

Elektroemre

Hocam UART ile 3.5 byte süresini tespit edip frameleri ayrıştırma olayı açıkçası sıkıntılı olur.

Bu bahsettiğiniz senkronizasyon byte'ları ve sonrasında gelen 0 değerleri, gönderdiğiniz içerikle tesadüf olarak denk gelince ne yapılıyor?

Sistem gelen data buffer'ında senkronizasyon byte'larını arıyor,
daha sonra senkronizasyon byte'ından sonraki diğer parametrelere bakıp değerler tutarlıysa "tamam abi burası paketin başı" kararı veriyor,
yok tutarlı değilse "paketin başı zannettik ama değilmiş normal data galiba" deyip diğer senkronizasyon byte'larını aramaya devam ediyor.

Durum bu mudur hocam?

muhittin_kaplan

Konu Güzel. yeni bir öğrenme Kaynağı,
Hocam Kullandığım Yöntemden bahsedeyim
bilgileri sprintf ile bir katar yapıp usart tan yolluyorum. tabiki ardına CR LF ekliyorum.

bu struct göndermek arasında ne gibi bir iyilik/kötülük oluşturur ? Sonuçta usart ByteByte Göndermeyecek mi ?

muhittin_kaplan

Siz Anltın ben Öğrneym Hcam Yntemi mmknse.