Programeringsfrågor C++ radiostyrd båt

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Tack så mycket! Funkade galant :)
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Icecap »

Som ie skriver ska du deklarera den som volatile. Det betyder - för kompilern - "denna får du INTE rensa bort för att minska koden!"

En del kompilers kan nämligen optimera och om man t.ex. skriver:
Sequence_Timer = 300;
while(Sequence_Timer > 10);

Detta kommer kompilern i vanligt fall att optimera till:
while(true);
Den kan ju "se" att Sequence_Timer blir > 10 från start.

Men vid att deklarera Sequence_Timer som volatile säger man till kompilern "denna kan ändra sig bortom din kontroll så den SKA kollas!"

Tänk en I/O-port eller liknande - men även värden som ändras i någon ISR eller liknande.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Tack för förklaringen Icecap :)

Nu har jag kört fast igen. Jag har en magnetometer(kompass)-sensor HMC5883 som jag kopplat in via I2C. Det verkar som att det funkar när jag kopplar in oscilloskopet samtidigt. AVR:en skickar rätt adress och sensorn svarar tillbaka. Men värdet som kommer tillbaka ändras inte utan är fast(det borde ju ändras när man rör sensorn).
Datablad: https://cdn-shop.adafruit.com/datasheet ... ass_IC.pdf
Jag har inte hållit på så mycket med att läsa via I2C men det jag inte fattar är att det står:
Send 0x3D 0x06 (Read all 6 bytes. If gain is changed then this data set is using previous gain) Convert three 16-bit 2’s compliment hex values to decimal values and assign to X, Z, Y, respectively.
Send 0x3C 0x03 (point to first data register 03) Wait about 67 ms (if 15 Hz rate) or monitor status register or DRDY hardware interrupt pin
Varför just 0x06(adressen för det som ska läsas ligger ju på 03-08)? Och dom menar väl att man att man ska göra 6st läsningar i rad eller vad menar dom?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Icecap »

Det är två kommandon. Den första är att du vill läsa 6 bytes och den andra är att läsningen ska börja från adress 3. Det kan vara att man ska kasta om på följden, har inte kollat så noga.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Jaha, jag trodde att 0x06 var adressen man ville läsa, men det är alltså hur många byte man vill läsa?

Oavsett hur jag testar så verkar det inte vilja komma tillbaka några värden som ändrar sig när jag vrider sensorn. Det verkar komma tillbaka värden men dom rör sig inte. Jag börjar vädra nått nybörjar-fel igen. Jag har hittat en kod för att läsa in ett 16-bitars värde och försöker att läsa in 2 byte. Jag använder likadana start, stop och send_byte funktioner på den andra I2C-porten som går till en OLED-display och den funkar så det borde inte vara det som felar. Alla funktioner(t.ex. wait_for_completion) pollar så loopen kan inte vara för snabb.
Såhär initierar jag I2C1 och det görs 500ms efter att systemet fått spänning:

Kod: Markera allt

void I2C1_Init(void){
	TWBR1 = 72; //TwoWireBitRate-register, selects the division factor for the SCL clock in Master mode 100KHz((16 000 000 / 100 000) – 16) / 2
	
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x00); //Config register A
	I2C1_Send_Byte(0x70); //8-avarage, 15Hz dafault, normal measurement
	I2C1_Stop_condition();
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x01); //Config register B
	I2C1_Send_Byte(0xA0); //Gain =5
	I2C1_Stop_condition();
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x02); //Mode register
	I2C1_Send_Byte(0x00); //Continuous mode
	I2C1_Stop_condition();
}
Såhär läser två stycken byte från address 0x03-0x04 och det görs varje loop:

Kod: Markera allt

void I2C1_Read(void){
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS+1); //Slave adress + 1 for read
		TWDR1 = 0x02;
		// perform first read to get the MSB
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA)); // with ACK set
		wait_for_completion;
		// the received byte is now in the TWDR data register
		register_value = (TWDR1 << 8);                     // put value in top half of variable
		// second read to get LSB
		TWCR1 = ((1 << TWINT) | (1 << TWEN));              // no acknowledge bit set, NOT ACK
		wait_for_completion;
		// the second byte is now in TWDR
		register_value += TWDR1;		
		I2C1_Stop_condition();
		
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS);
		I2C1_Send_Byte(0x03); //Move adress-pointer
		I2C1_Stop_condition();
}
Det intressanta är att om jag startar om systemet så får jag ett värde från magnetometern, startar jag om den igen så får jag ett värde som är antingen samma eller väldigt nära det första. Vrider jag den och startar om så får jag ett nytt värde. Så det verkar som att den faktiskt skickar rätt värde en gång men sen antingen inte läser in ett nytt värde från sensorn eller också att sensorn skickar samma hela tiden.
Någon som har någon teori om detta?
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Jag insåg att jag kanske hade för kort loop-time eftersom det även står "wait 67 ms(if 15 Hz rate)" så jag gjorde en rutin som läser med ca 200 ms mellanrum men resultatet blev samma.
Däremot om jag ändrar detta:

Kod: Markera allt

		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS);
		I2C1_Send_Byte(0x03); //Move adress-pointer
		I2C1_Stop_condition();
...till detta:

Kod: Markera allt

		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS);
		I2C1_Send_Byte(0x02); //Move adress-pointer
		I2C1_Send_Byte(0x00); //Continuous mode
		I2C1_Stop_condition();
...så funkar det, men varför :humm: Det funkar då även utan att vänta 67 ms. Det är ju konstigt för det står ju "send 0x3C 0x03 (point to first register 0x03)" men det funkar inte, däremot att skicka 0x02 och skriva en gång så pekaren ökas till 0x03 funkar :humm:
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Mr Andersson »

Det står ju under operational examples som du postade att alla 6 register måste läsas innan de uppdateras.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Det är sant, men om 0x06 var hur många byte man vill läsa från minnet så har jag ju ändrat till 0x02 och då borde det ju funka :humm: Fast kanske man MÅSTE läsa 6 byte? :humm:
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Mr Andersson: Tack för att du pekade mig i rätt riktning, hittade detta:
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Förlåt om jag är trög men jag får det fortfarande inte att funka bra. Och jag är ännu förbryllad över vad 0x06 betyder, det står ingenstans(som jag hittar) att man ska skicka vilket antal byte man vill läsa, det verkar även lite konstigt att det kommer direkt efter att man skickat kommandot för att läsa(det borde ju starta en läsning och att just då ladda TWDR med 0x06 verkar ju lite konstigt), borde inte det snarare starta en transmission från slaven?

Eller är det underförstått att I2C funkar så jämt, att man efter kommandot för läsning skickar antal byte man vill läsa?

Edit: "clock out the new data", vad menas med det? Det ska alltså inte vara 6 st läsningar utan man "klockar ut" alla bitar på rad eller vadå?
Och "automatically re-point back to register 3", sen står det att man ska sända kommando för att peka på 0x03. Är det "automatically" eller inte?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Icecap »

Du ska läsa alla 6 bytes i en läsning.
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Jag vete tusan vad jag gör för fel. Har läst detta och trodde att jag förstod hyffsat: https://mansfield-devine.com/speculatri ... iving-data

Likväl förstår jag inte hur 0x06 ska skickas och hur man läser 6 byte i sekvens samt när man ska skicka ACK och inte. Detta rullar ett tag men ger inte rätt värden och sedan låser sig programmet helt(och om jag kommenterar ut denna läsning så låser det sig inte så det är ju nått som inte blir rätt).
Rullar med 100ms interval:

Kod: Markera allt

void I2C1_Read(void){
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS+1);
		TWDR1 = 0x06;
		I2C1_Stop_condition();
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS+1);
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagX = (TWDR1 << 8); 
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagX += TWDR1;
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagZ = (TWDR1 << 8); 
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagZ += TWDR1;
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagY = (TWDR1 << 8);
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagY += TWDR1;
		TWCR1 = ((1 << TWINT) | (1 << TWEN));
		I2C1_Stop_condition();
		
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS);
		I2C1_Send_Byte(0x03); //Move adress-pointer
		I2C1_Stop_condition();
}
Övrig kod:

Kod: Markera allt

#define SLAVE_ADRESS 0x3C
#define wait_for_completion while(!(TWCR1 & (1 << TWINT)));

int MagX;
int MagZ;
int MagY;

void I2C1_Start_condition(void){
	TWCR1 = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
	wait_for_completion;
}

void I2C1_Stop_condition(void){
	TWCR1 = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}
void I2C1_Send_Byte(uint8_t byte){
	TWDR1 = byte;
	TWCR1 = (1<<TWINT) | (1<<TWEN);
	wait_for_completion;
}
Initieringen:

Kod: Markera allt

void I2C1_Init(void){
	TWBR1 = 72; //TwoWireBitRate-register, selects the division factor for the SCL clock in Master mode 100KHz((16 000 000 / 100 000) – 16) / 2
	
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x00); //Config register A
	I2C1_Send_Byte(0x70); //8-avarage, 15Hz dafault, normal measurement
	I2C1_Stop_condition();
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x01); //Config register B
	I2C1_Send_Byte(0xA0); //Gain =5
	I2C1_Stop_condition();
	I2C1_Start_condition();
	I2C1_Send_Byte(SLAVE_ADRESS);
	I2C1_Send_Byte(0x02); //Mode register
	I2C1_Send_Byte(0x00); //Continuous mode
	I2C1_Stop_condition();
}
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Nu kanske jag fått det att funka:

Kod: Markera allt

void I2C1_Read(void){
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS);
		I2C1_Send_Byte(0x03); //Move adress-pointer			
		I2C1_Start_condition();
		I2C1_Send_Byte(SLAVE_ADRESS+1);
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagX = (TWDR1 << 8); 
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagX += TWDR1;
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagZ = (TWDR1 << 8); 
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagZ += TWDR1;
		TWCR1 = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA));
		wait_for_completion;
		MagY = (TWDR1 << 8);
		TWCR1 = ((1 << TWINT) | (1 << TWEN));
		wait_for_completion;
		MagY += TWDR1;
		I2C1_Stop_condition();
}
Ger alla värden rätt och har inte hängt sig ännu men det kan ju fortfarande vara fel. Känns dock mycket mer logiskt att sätta adressen innan man ska läsa den än att sätta den i slutet för att den ska stå rätt nästa gång man läser(eller hur dom nu tänkte i databladet). Sen har jag skippat 0x06 helt, jag fattade ändå aldrig varför den skulle vara där och det verkar funka bättre utan.
Om nån vet hur man egentligen ska göra så förklara gärna :)
Glattnos
Inlägg: 2972
Blev medlem: 29 oktober 2009, 20:01:18

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Glattnos »

Finns det något smart sätt att använda X och Y från sensorn för att få en ungefärlig ritktning? I princip så räcker det i min applikation att använda värdet från X eftersom jag bara behöver mäta om kursen ändras mycket åt något håll. Problemet med att ta värdet enbart från en axel är ju att i princip alla värden har två riktningar, vilket kan vara ett problem vid "topparna på kurvan".
Jag tänkte om man på nått enkelt sätt kan kombinera X och Y. Det behövs ingen tilt kompensering eller rättvisande kurs utan bara så att den kan känna av åt vilket håll den ska kompensera.

Här är kurvorna lite grovt, dom är nog lite snyggare med exaktare mätning.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programeringsfrågor C++ radiostyrd båt

Inlägg av Icecap »

Det du behöver är att räkna om till en vektor, alltså "nord"s vinkel i förhållande till sensorn.

Det du har är ju resultatet av enhetsvinkeln så det är bara att skala värden rätt och räkna baklänges.
Skriv svar