bits van input in een byte zetten.

trix

Golden Member

hallo,

ik heb hier een stukje code dat ik probeer te doorgronden, ik heb dat niet zelf bedacht, maar dekees heeft dat voor mij gemaakt.
ik kan de topic waarin hij dat heeft gepost niet meer terug vinden, vandaar een nieuw topic.
prog. draait in een atmega32.

wat is de bedoeling v/d code:
- ik heb 24x een input verdeeld over 3 poorten (A B & C).
- iedere 4 mS word er naar 1 input gekeken.
- de status ("1" of "0") word in een byte geschreven.
- op het eind van die "scan" zijn er dus 3 bytes gevuld.

dat is het eigenlijk, later worden die 3 bytes verstuurd over RS485 naar een andere controller (atmega2560).

c code:


ISR(TIMER1_COMPA_vect)
{	
	static uint8_t PulseCounter = 150;
	static uint8_t BitCounter   = 0;
		
	if(PulseCounter == 0)
	{
		PulseCounter = 150;			
			
	switch(BitCounter++)
	{
	case 0 : { byte_1 |= (PINC & 0x80);  PORTD |= (1 << PIND3); break;}
	case 1 : { byte_1 |= (PINC & 0x40);  break; }
	case 2 : { byte_1 |= (PINC & 0x20);  break; }
	case 3 : { byte_1 |= (PINC & 0x10);  break; }
	case 4 : { byte_1 |= (PINC & 0x08);  break; }
	case 5 : { byte_1 |= (PINC & 0x04);  break; }
	case 6 : { byte_1 |= (PINC & 0x02);  break; }
	case 7 : { byte_1 |= (PINC & 0x01);
	columns_byte_1 [column_counter_byte_1] = byte_1;  
	column_counter_byte_1 += 1;
	break;
	}

	case 8 : { byte_2 |= (PINA & 0x80); PORTD |= (1 << PIND4); PORTD &= ~(1 << PIND3); break; }
	case 9 : { byte_2 |= (PINA & 0x40);  break; }
	case 10: { byte_2 |= (PINA & 0x20);  break; }
	case 11: { byte_2 |= (PINA & 0x10);  break; }
	case 12: { byte_2 |= (PINA & 0x08);  break; }
	case 13: { byte_2 |= (PINA & 0x04);  break; }
	case 14: { byte_2 |= (PINA & 0x02);  break; }
	case 15: { byte_2 |= (PINA & 0x01);
	columns_byte_2 [column_counter_byte_2] = byte_2;  
        column_counter_byte_2 += 1;
	break;
	}

	case 16: { byte_3 |= (PINB & 0x80); PORTD |= (1 << PIND7); PORTD &= ~(1 << PIND4); break; }
	case 17: { byte_3 |= (PINB & 0x40);  break; }
	case 18: { byte_3 |= (PINB & 0x20);  break; }
	case 19: { byte_3 |= (PINB & 0x10);  break; }
	case 20: { byte_3 |= (PINB & 0x08);  break; }
	case 21: { byte_3 |= (PINB & 0x04);  break; }
	case 22: { byte_3 |= (PINB & 0x02);  break; }
	case 23: { byte_3 |= (PINB & 0x01);  
	columns_byte_3 [column_counter_byte_3] = byte_3; 
	column_counter_byte_3 += 1;
	break;
	}
// below: pulse counter = 0; needed so that TSAL & TSOP number 1 start on the same time.
	case 24:
	{
	 PORTD &= ~(1 << PIND7);
	 BitCounter = 0;
	 PulseCounter = 0;
   	 start_scan = 0;				   
	 break;
	}
	} // from: switch
	} // from: if(PulseCounter == 0)

	else
	{
		PulseCounter -= 1;
	}
				
	} // from: ISR

	ISR(TIMER1_COMPB_vect) // 38 khz
	{
		PORTB = 0;
		PORTA = 0;
		PORTC = 0;
	}

welk deel begrijp ik dan o.a. niet goed:

c code:

case 1 : { byte_1 |= (PINC & 0x40);  break; }

hier moet de status van een specifieke input pin in byte_1 worden gezet, zonder de overige bits te veranderen, gebeurt dat ook ?

eigenwijs = ook wijs
buckfast_beekeeper

Golden Member

|= Bitwise inclusive OR and assignment operator. je mask is hier 0x40 = 64 of 0b0100 0000. Waardoor je dus alleen bit 7 gaat aanpassen.

Van Lambiek wordt goede geuze gemaakt.
trix

Golden Member

dus dat is dan goed.

vervolgens is het dan de bedoeling dat die byte_1, byte_2 en byte_3 ieder in een apparte array word gezet.
de plaats in de array word opgehoogd met:

c code:

column_counter_byte_1 += 1;

dit is toch het zelfde als:

c code:

column_counter_byte_1 = column_counter_byte_1 + 1;

vraag is dan, hoef je niet ergens aan te geven hoe groot die array is ?

[Bericht gewijzigd door trix op maandag 27 juli 2020 11:25:23 (90%)

eigenwijs = ook wijs
buckfast_beekeeper

Golden Member

Op 27 juli 2020 10:52:28 schreef trix:
[...]
vervolgens is het dan de bedoeling dat die byte_1, byte_2 en byte_3 ieder in een apparte array word gezet.

Nu volg ik even niet.

de plaats in de array word opgehoogd met:

c code:

column_counter_byte_1 += 1;

dit is toch het zelfde als:

c code:

column_counter_byte_1 = column_counter_byte_1 + 1;

[...]

Beiden zijn identiek. Alleen is de bovenste een verkorte schrijfwijze.

Normaal kan je voor +=1 ook nog ++ gebruiken. met +=2 is dat dan weer niet meer mogelijk.

Van Lambiek wordt goede geuze gemaakt.

vraag is dan, hoef je niet ergens aan te geven hoe groot die array is ?

Ja inderdaad, die moet je altijd bewaken.
Hier zal de column_counter_xxx wel ergens anders in het programma bewaakt worden maar dan nog kun je beter ook hier op zeker spelen. Dus met iets als:

code:


      columns_byte_1 [column_counter_byte_1] = byte_1;  
      column_counter_byte_1 += 1;

Bewaken met

code:


      if(column_counter_byte_1 < sizeof(columns_byte_1) )
      {  columns_byte_1 [column_counter_byte_1] = byte_1;  
         column_counter_byte_1 += 1;
      }

En zo ook de andere 2 column's natuurlijk.

trix

Golden Member

Op 27 juli 2020 11:54:38 schreef buckfast_beekeeper:
[...]
Nu volg ik even niet.

byte_1 komt in de array: columns_byte_1
byte_2 komt in de array: columns_byte_2
byte_3 komt in de array: columns_byte_3

eigenwijs = ook wijs

Je had toch 24 receivers (vertikaal) direct aan de pins van een controller hangen?
Dan kun je toch direct de 3 poorten uitlezen en heb je 3 bytes = 24 bits, niks te shiften/decoderen.
Misshien dat de bits niet helemaal exact mappen op je poorten en moet je misschien wat bits omwisselen maar dat is ook niet zo schokkend.

In je ISR lees je eerst alle 3 poorten direct achter elkaar (om geen timeshift te krijgen) in 3 lokale variablen, daarna stop je die 3 bytes in een array die de horizontale as voorstelt. Als je hele scan van tig meter gedaan is stuur je de bytes op naar je andere CPU. Of je doet dat parallel (in je main loop) op een getimede trigger van de CPU waar het naar toe moet.

Je hebt dan een horizontale baan van alle pixels.
Voor elk bordje van 24 pixels heb je dan een baantje die je later in je "hoofd" CPU weer aan elkaar plakt.

-edit- Ach, crap: Je wilde die dingen vertikaal scannen om geen strooilicht te kijgen.

Dan zou ik gewoon een teller maken van 0-23 en het bit/byte uitrekenen wat je in moet vullen.

Ik ga er even vanuit dat het bovenste bit 0 is en byte ook
Wat pseudo code:

code:



// Globale variablen
// Tabel met poortnummers
uint8_t portname[3] = { portA, portB, portC};


// main loop die iedere scan triggerd
// Erase bytes, moet voor elke scan van 24 bits
for (int i= 0; i < 3; i++ ) {
    array[0] = 0;
}
int row = 0;


ISR(TIMER1_COMPA_vect)
{
  bytenum = row % 3; // Hier komt 0,1,2 uit als index van de poorten.
  bit = row & 0x07; // Hier komt 0-7 uit voor het bit uit de betreffende poort.

  port = portname[row]; // haal het poort nummer op.

  // Lees de hardware port en maskeer het juiste bitje 
  uint8_t readmask = readport(port) & (1 << bit);
  // Voeg bitje samen met al eerder gelezen bits
  array[bytenum] |= readmask;

  // Volgende row
  row++;
}

Zit er ergens wat gespiegeld moet je misschien de poort assignment in de tabellen omdraaien of het bitmask omdraaien maar dat is simpel.

Er moet ergens nog wat synchronisatie worden toegevoegd om iedere scan de boel te triggeren.

Maar eigenlijk heb je geen ISR nodig. In jouw geval is er een tegenoverliggende print die de IR leds van boven naar beneden aanstuurt daarmee moet de ontvanger precies gesynchroniseerd worden.
Welke controller doet dat aansturen? Ik neem aan je hoofprocessor die alle borden straks leest?

Trigger je nu maar 1-malig ieder bord (per 24 bits) en laat je dan de zender en ontvanger op vrijloop de boel inlezen?
Als je dat doet krijg je straks wat fading effecten en moet je een kleine dode tijd tussen het zenden/inlezen bouwen. Of in het midden van de IR zenderpuls een sample nemen. DWZ als de zender 4ms de led aanzet moet je op de ontvanger na 2ms beginnen te lezen en dan de intervallen 4ms maken.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
trix

Golden Member

Op 27 juli 2020 20:54:53 schreef henri62:
Trigger je nu maar 1-malig ieder bord (per 24 bits) en laat je dan de zender en ontvanger op vrijloop de boel inlezen?
Als je dat doet krijg je straks wat fading effecten en moet je een kleine dode tijd tussen het zenden/inlezen bouwen. Of in het midden van de IR zenderpuls een sample nemen. DWZ als de zender 4ms de led aanzet moet je op de ontvanger na 2ms beginnen te lezen en dan de intervallen 4ms maken.

nog niet alles volledig en begrijpend gelezen, maar dit hierboven is exact
hoe het nu gaat.
ik zal morgen eens de volledige code posten.

eigenwijs = ook wijs
trix

Golden Member

volledige code:
onderstaande is getest met 3x array waar vaste waardes in stonden, dus het verzenden van de atmega 32 naar de atmega 2560 gaat wel goed.
lukt nu alleen niet om de status v/d input pinnen over te sturen.

edit: net nog eens getest met een array met vaste waardes daar in, en dit werkt correct.
probleem volgens mij is dat de byte_1 byte_2 en byte_3 niet goed in de array worden gezet.

c code:


//*** 28-7-2020 ******************************************************************************************
// TESTING THE RS485 UART TSOP ***************************************************************************

// fuse: ext. crystal/resonater medium freq. start up 16 64
// fuse: J-tag uitvinken

#define F_CPU 8000000UL // 8 MHz clock speed

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

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

	int receivedbyte	= 0;
	int bytetosend	    = 0;
	int column_counter_byte_1	= 0;
	int column_counter_byte_2	= 0;
	int column_counter_byte_3	= 0;	
	
	int byte_1          = 0;
	int byte_2          = 0;
	int byte_3          = 0;
			
	uint8_t PulseCounter = 150;
	uint8_t BitCounter   = 0;		
	
	volatile start_scan = 0;
	int start_send_data_byte_1 = 0;
	int start_send_data_byte_2 = 0;
	int start_send_data_byte_3 = 0;
	int shift_byte_out  = 0;
	 
	uint8_t columns_byte_1 [300]; 
	uint8_t columns_byte_2 [300]; 
	uint8_t columns_byte_3 [300]; 
	 
	ISR(TIMER1_COMPA_vect)
	{	
		static uint8_t PulseCounter = 150;
		static uint8_t BitCounter   = 0;
		
	if(PulseCounter == 0)
	{

        PulseCounter = 150;			
			
			
	switch(BitCounter++)
	{
	case 0 : { byte_1 |= (PINC & 0x80);  PORTD |= (1 << PIND3); break;}
	case 1 : { byte_1 |= (PINC & 0x40);  break; }
	case 2 : { byte_1 |= (PINC & 0x20);  break; }
	case 3 : { byte_1 |= (PINC & 0x10);  break; }
	case 4 : { byte_1 |= (PINC & 0x08);  break; }
	case 5 : { byte_1 |= (PINC & 0x04);  break; }
	case 6 : { byte_1 |= (PINC & 0x02);  break; }
	case 7 : { byte_1 |= (PINC & 0x01);
	if(column_counter_byte_1 < sizeof(columns_byte_1) )
	{					
		columns_byte_1 [column_counter_byte_1] = byte_1; 
		column_counter_byte_1 += 1;
	}
	break;
        }				

	case 8 : { byte_2 |= (PINA & 0x80); PORTD |= (1 << PIND4); PORTD &= ~(1 << PIND3); break; }
	case 9 : { byte_2 |= (PINA & 0x40);  break; }
	case 10: { byte_2 |= (PINA & 0x20);  break; }
	case 11: { byte_2 |= (PINA & 0x10);  break; }
	case 12: { byte_2 |= (PINA & 0x08);  break; }
	case 13: { byte_2 |= (PINA & 0x04);  break; }
	case 14: { byte_2 |= (PINA & 0x02);  break; }
	case 15: { byte_2 |= (PINA & 0x01);
	if(column_counter_byte_2 < sizeof(columns_byte_2) )
	{
		columns_byte_2 [column_counter_byte_2] = byte_2; 
		column_counter_byte_2 += 1;
	}
	break;
	}

	case 16: { byte_3 |= (PINB & 0x80); PORTD |= (1 << PIND7); PORTD &= ~(1 << PIND4); break; }
	case 17: { byte_3 |= (PINB & 0x40);  break; }
	case 18: { byte_3 |= (PINB & 0x20);  break; }
	case 19: { byte_3 |= (PINB & 0x10);  break; }
	case 20: { byte_3 |= (PINB & 0x08);  break; }
	case 21: { byte_3 |= (PINB & 0x04);  break; }
	case 22: { byte_3 |= (PINB & 0x02);  break; }
	case 23: { byte_3 |= (PINB & 0x01);
	if(column_counter_byte_3 < sizeof(columns_byte_3) )
	{					  
		columns_byte_3 [column_counter_byte_3] = byte_3; 
		column_counter_byte_3 += 1;
	}
	break;
	}
// below: pulse counter = 0; needed so that TSAL & TSOP number 1 start on the same time.
	case 24:
	{
	PORTD &= ~(1 << PIND7);
	BitCounter = 0;
	PulseCounter = 0;
   	start_scan = 0;				   
	break;
	}
	} // from: switch
	} // from: if(PulseCounter == 0)

	else
	{
		PulseCounter -= 1;
	}
				
	} // from: ISR

	ISR(TIMER1_COMPB_vect) // 38 khz
	{
		PORTB = 0;
		PORTA = 0;
		PORTC = 0;
	}	

int main(void)
{
		DDRA = 0b00000000;
		PORTA = 0b11111111;
		
		DDRB = 0b00000000;
		PORTB = 0b11111111;
		
		DDRC = 0b00000000;
		PORTC = 0b11111111;
		
		DDRD = 0b11111110; // PD0 = RXD
//		PORTD = 0b00000001;		
		
		sei();
		
		TCCR1B |= (1 << WGM12); // CTC-mode,
		TIMSK  |= (1 << OCIE1A)	| (1 << OCIE1B) ; // timer1 A & B compare match interrupt enabled

		OCR1A = 209;
		OCR1B = 100;		
		
		UCSRA = (1 << MPCM); // enable: multi processor communication mode
		UCSRB = (1 << RXEN) | (1 << TXEN)| (1 << UCSZ2);   // Turn on the transmission and reception circuit
		UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // 9-bit mode, URSEL bit for selecting UCSRC
						
		UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
		UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
						
	for(;;)
	{									
		while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
		receivedbyte = UDR; // Fetch the received byte value into the variable "ReceivedByte"

//*** adress numbering: TSAL 1-20 and TSOP 21-40 *******************************************************				
	if (receivedbyte == 21) // adress byte
	{					
		UCSRA  &=~(1 << MPCM); // make MPCM "0"
				
		while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
		receivedbyte = UDR; // Fetch the received byte value into the variable "ReceivedByte"
					
		if (receivedbyte == 0b11110000) // is the data byte: start your scan
		{										
				_delay_ms(3); // to make we look in the middle off the TSAL pulse
			start_scan = 1;
			column_counter_byte_1	= 0; // 0, so that the first saved byte comes on 0 in the array
			column_counter_byte_2	= 0;
			column_counter_byte_3	= 0; 					
		}
					
		if (receivedbyte == 0b00000001) // is the data byte: send the data 1e byte to the master
		{
			_delay_ms(5);
			start_send_data_byte_1 = 1;
		}
					
		if (receivedbyte == 0b00000010) // is the data byte: send the data 2e byte to the master
		{
												
			_delay_ms(5);
			start_send_data_byte_2 = 1;
		}
					
		if (receivedbyte == 0b00000011) // is the data byte: send the data 3e byte to the master
		{
			_delay_ms(5);
			start_send_data_byte_3 = 1;
		}
										
		while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
		receivedbyte = UDR; // Fetch the received byte value into the variable "ReceivedByte"
					
		if (receivedbyte == 0b11111111) // is the stop byte
		{						
			UCSRA = (1 << MPCM); // enable: multi processor communication mode
		}										
	}
				
//********** TSOP ****************************************************************************************				
				
	while (start_scan == 1)
	{					
		TCCR1B |= (1 << CS10); // start timer with prescaler = 0
//		PORTA = byte_1;	// for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
								
	}
				
	if (start_scan == 0)
	{									    
		TCCR1B &= ~(1 << CS10); // stop timer with prescaler = 0
		byte_1 = 0;	// waarschijnlijk alleen voor testen^^^^^^^^^^^^^^^^^^				
	}				
					
	while (start_send_data_byte_1 == 1)
	{															
		PORTD |= (1 << PIND3); // for checking rood  = "1" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^					
						
		PORTD |= (1 << PIND2); // switch MAX485 as transmitter pin 2 & 3 = "1"
			
		for (shift_byte_out = 0; shift_byte_out < 302; shift_byte_out ++) //test ^^^^^^^^^^^^^^
		{
			while ((UCSRA & (1 << UDRE)) == 0) {}; // do nothing till the UDR is ready to receive
						
			bytetosend = columns_byte_1[shift_byte_out]; 
						
			UDR = bytetosend;
		}
					
		start_send_data_byte_1 = 0;
		PORTD &= ~(1 << PIND3); // for checking rood  = "0" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	}					
	 			
	while (start_send_data_byte_2 == 1)
	{															
		PORTD |= (1 << PIND4); // // for checking geel  = "1" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^					
					
		PORTD |= (1 << PIND2); // switch MAX485 as transmitter pin 2 & 3 = "1"
										
		for (shift_byte_out = 0; shift_byte_out < 302; shift_byte_out ++)
		{
			while ((UCSRA & (1 << UDRE)) == 0) {}; // do nothing till the UDR is ready to receive
						
			bytetosend = columns_byte_2[shift_byte_out]; 
						
			UDR = bytetosend;
		}
					
		start_send_data_byte_2 = 0;
		PORTD &= ~(1 << PIND4); // for checking geel  = "0" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	}			
					
	while (start_send_data_byte_3 == 1)
	{									
		PORTD |= (1 << PIND7);	// for checking groen  = "1" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^					
					
		PORTD |= (1 << PIND2); // switch MAX485 as transmitter pin 2 & 3 = "1"
								
		for (shift_byte_out = 0; shift_byte_out < 302; shift_byte_out ++)
		{
			while ((UCSRA & (1 << UDRE)) == 0) {}; // do nothing till the UDR is ready to receive
						
			bytetosend = columns_byte_3[shift_byte_out]; 
						
			UDR = bytetosend;
		}
					
		start_send_data_byte_3 = 0;
		PORTD &= ~(1 << PIND7); // for checking groen  = "0" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	}				
					
	if (start_send_data_byte_3 == 0)
	{
		PORTD &= ~(1 << PIND2); // switch MAX485 as receiver pin 2 & 3 = "0"					
					
	}				
				
	} // from: for (;;)
} // from: main	
eigenwijs = ook wijs

Zo te zien is er niets die de werkelijke scan loop start?
Hoe had je dat in gedachten hoe dat zou moeten werken?

Maak eerst eens een simpel diagram of wat eisen wat elk systeem/cpu board precies zou moeten doen, want zo ga je er niet uit komen.

Ik stel me dit voor:

Je hebt N zender borden die ieder 24 IR zenders hebben.
Je hebt N ontvanger borden die ieder 24 IR ontvangers hebben.

Elk zender board moet synchroon lopen met zijn ontvanger (of andersom).
Elk zender board zal van beneden naar boven elke van de 24 leds aansturen en de ontvanger moet die bits synchroon inlezen (dit om strooilicht te voorkomen).

Als je een complete vertikale scan doet wil je dat ieder board 24 pixels inleest en dat dit parallel/tegelijk gebeurd.

Na een scan van 24 pixels per board heb je een complete scan van N x 24 pixels en die wil je in een centrale processor ontvangen.

Afgaande uit de gegevens van vorige posts kom ik tot de conclusie dat een led uitlezen ca 4ms duurt, dus een complete scan van EEN bordje (en dus in totaal ALLE vertikale borden) zal dus ca 24*4ms = 96 ms duren.

Hieruit kun je dus afleiden dat de hoofd processor alle borden dus op een tick van minimaal 96 ms moet triggeren om alles te scannen.

Om alle data over te sturen van N borden moet je dus N x 24/8 bytes ruim binnen het budget van 96 ms moeten kunnen versturen.

Stel N=10 geeft dit jouw 300 bytes.

Als je uitgaat van een mechanisme dat elk board zijn eigen request binnen krijgt om zijn data te sturen (vanuit de hoofdprocessor) heb je snel minimaal 2 bytes voor de request nodig (adres, commando) + wat delay, zeg maar 3 bytes * 10 bits => 30 bits. (10 bits=start bit, 8 data bits, stop bit)

De data moet dan terug gestuurd worden ook nog eens minimaal 4 bytes. => 40 bits.
Dus totaal voor alle borden 10 *(30+40) = 700 bits.
Dus je baudrate moet dan minimaal 96 ms / 700 = 137 us => 7300 baud moeten zijn en dan moet echt alles perfect op elkaar afgestemd zijn. Ik zou dan minimaal op 19200 baud of hoger gaan zitten.

Wil je dus volcontinue scannen kun je de data die je opstuurd in een ISR versturen en "tegelijk" je volgende row scannen.

Je hebt ook nog die trigger vanuit je hoofdprocessor nodig om de scan's van ieder board te triggeren, dat kun je doen door een commando naar het RS485 broadcast adres te sturen, dat is "by convention" adres 0. Dit is vaak in een CPU configureerbaar dat je ook via je UART data binnen krijgt op adres 0 naast wat je zelf in je adres match register zet. Alle borden starten dat exact gelijk met je scan opdracht.

Ik schrijf dit verhaal boven omdat de clou van het verhaal is dat je in de main loop eigenlijk alleen moet wachten op ontvangst van de trigger van de hoofdprocessor: Je zet wat variabelen klaar en wacht op het START-SCAN commando (op het broadcast adres). Dan start je de juiste timers en die doen de rest.

Dit doe je in beide borden zowel de ontvanger as de zender. Alleen zit er in de zender de code die de leds aanstuurt en in de ontvanger code die de ontvangers uitleest.

In je main loop wacht je dan tot de 24 scan pulsen gemaakt zijn en het feestje begint opnieuw voor de volgende trigger vanuit je hoofdprocessor.

Het verhaal wordt complexer als je echt het onderste uit de kan wilt halen.
In de ontvanger kun je het best ook een double buffer mechanisme inbouwen: Terwijl je de ene rij leds inleest heb je een ander buffertje die je verzend naar de hoofdprocessor die het vorige "sample" uitleest in de 96 ms die het duurt om een nieuwe scan te maken. Vandaar dat ik ook uitgelegd heb wat je tijds-budget is om een hele rij van leds uit te lezen.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
trix

Golden Member

bovenstaande is wanneer je meteen de data naar de hoofd controller stuurt tijdens het scannen, maar dat doe ik niet, ik sla alle data v/d scans eerst op in de atmega 32.
en later als alle scans klaar zijn vraagt de hoofd controller aan iedere atmega 32 om zijn data naar de hoofdcontroller te sturen, op deze manier word het allemaal niet zo tijd kritisch, nadeel is dat het later versturen wel extra tijd kost.

- hoofd controller stuurt alleen een start comando naar de zend en de ontvang PCB. (0b11110000 in mijn prog) vanaf daar gebeurt de scan in de zend & ontvang controller.
- vervolgens gaan de zend & ontvang PCB de 24 led's 1 voor 1 af. (over 24 led's zal de synchronisatie niet verlopen).
- werkstuk schuift 10 mm op en de hoofdcontroller stuurt weer enkel en alleen een start comando naar de zend & ontvanger.(werkstuk beweegt continu)
- dat doet ie in totaal 300x en de scan is klaar. zo zit er in elke atmega32 v/d ontvanger 3x300 = 900 bytes,
- tenslotte vraagt de hoofd controller aan elke atmega 32 v/d ontvanger, stuur mij je data. in het geval van 10 borden is dat dus 10 x 900 = 9000 byte.

dit is denk ik de meest simpele manier om dit te doen, wat wel voor verbetering vatbaar is natuurlijk, vooral in tijdswinst.

eigenwijs = ook wijs
Shiptronic

Overleden

Op 27 juli 2020 10:39:04 schreef trix:
hallo,

ik heb hier een stukje code dat ik probeer te doorgronden, ik heb dat niet zelf bedacht, maar dekees heeft dat voor mij gemaakt.
ik kan de topic waarin hij dat heeft gepost niet meer terug vinden, vandaar een nieuw topic.

Deze ? : https://www.circuitsonline.net/forum/view/150417?query=dekees&mode…

Wie de vraag stelt, zal met het antwoord moeten leren leven.

Zowiezo lijkt hier ook iets niet pluis:

code:


    while (start_scan == 1)
    {					
	TCCR1B |= (1 << CS10); // start timer with prescaler = 0
//		PORTA = byte_1;	// for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    }

Hier wordt continue de prescaler gezet, dat wil je maar een keer doen en dan wachten op het einde van de 24 scan pulsen.
Die while() hoort iets later te zitten en triggeren op een conditie die ergens in de ISR hoort te zitten.

PS Wat doet dit hier?:

code:


	ISR(TIMER1_COMPB_vect) // 38 khz
	{
		PORTB = 0;
		PORTA = 0;
		PORTC = 0;
	}

[Bericht gewijzigd door henri62 op dinsdag 28 juli 2020 21:20:41 (12%)

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
trix

Golden Member

moet ik nog eens bekijken, de scan in het zender gedeelt is hetzelfde qua opbouw, en dat werkt 100 % zeker.

@shiptronic, nee dat is een andere topic.

eigenwijs = ook wijs
trix

Golden Member

Op 28 juli 2020 20:47:23 schreef henri62:

code:

    
PS Wat doet dit hier?:
[code]
	ISR(TIMER1_COMPB_vect) // 38 khz
	{
		PORTB = 0;
		PORTA = 0;
		PORTC = 0;
	}

timer1 staat in CTC mode (clear to compare match).

met: ISR(TIMER1_COMPA_vect) word de freqentie v/d "draag freq."
OCR1A = 209 (clk = 8 MHz) dit geeft ong. 38kHz.

met: ISR(TIMER1_COMPB_vect) word de puls lengt bepaald. is ong. de helft (50% duty cycle).

eigenwijs = ook wijs
trix

Golden Member

ik heb nu een software fout ontdekt in mijn op zet waardoor een en ander niet goed kan werken.

voor het voorbeeld neem ik 1x IR zender (TSAL) en 1x IR ontvanger (TSOP) die fysiek tegen over elkaar staan.

hoe het nu is:
- de zender stuurt 4mS lang de TSAL aan.
- de ontvanger kijk 4mS lang of hij licht of donker is (1 of 0)
daar begint hij mee op het midden v/d TSAL puls (heb ik zo geprogd)
maar dat betekent dat hij na het einde v/d TSAL pulse nog steeds 2 mS
kijkt of hij licht of donker is. dit geeft foutieve waardes.

hoe het moet zijn:
- de zender stuurt 4mS lang de TSAL aan.
- de ontvanger kijkt dan van 1 tot 3 mS of hij licht of donker is.

maar ik zie even niet hoe ik dit in de geposte code moet aanpassen ? het start moment op 1mS is geen probleem (heb ik nu ook al (op 2mS)) maar het stop moment bij 3 mS is wel een probleem.
kan iemand mij hier mee op weg helpen ?
bedankt.

eigenwijs = ook wijs
trix

Golden Member

even een plaatje bij gevoegd ter verduidelijking.
ik moet dat stop moment in mijn code zien te verwerken (groene lijn)

eigenwijs = ook wijs
trix

Golden Member

Op 28 juli 2020 20:47:23 schreef henri62:
PS Wat doet dit hier?:

code:


	ISR(TIMER1_COMPB_vect) // 38 khz
	{
		PORTB = 0;
		PORTA = 0;
		PORTC = 0;
	}

ik denk dat je hier gelijk had, en dat dit hier niet thuis hoort (in tegenstelling tot wat ik later beweerde)

klopt nog meer niet inde code, ben zoekende :)

eigenwijs = ook wijs
trix

Golden Member

de getrapte blokken onder zijn de IR diode (TSAL).
de grijze blokken zijn de "kijk" momenten, nu mooi in het midden v/d TSAL puls.
code komt nog.

eigenwijs = ook wijs
trix

Golden Member

in de code test ik alleen met poort C. poort A misbruik ik om de LA aant te sturen.
ondanks dat nu mijn "kijk" moment in de IR ontvanger (TSOP) goed is, krijg ik nog steeds niet de data in de array.
nog even zoeken/testen dus.

dit is een deel v/d code.

c code:


	uint8_t columns_byte_1 [300]; // geblokt voor te testen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	uint8_t columns_byte_2 [300]; // geblokt voor te testen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	uint8_t columns_byte_3 [300]; // geblokt voor te testen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	 
ISR(TIMER1_COMPA_vect)
{	
	static uint8_t PulseCounter = 150;
	static uint8_t BitCounter   = 0;
		
	if(PulseCounter == 0)
	{
		PulseCounter = 150;						
			
			// - Lokale variabelen zijn weer weg als de ISR is afgelopen
			// - Of je moet ze static declareren zoals de PulseCounter hierboven
			
		TCNT0 = 0; // is the start moment from the 2 mS (length of puls) 
		PORTA |= (1 << PINA0);
		check_bit = 1;
			
		switch(BitCounter++)
		{
				
		case 0 : { byte_1 |= ((PINC & 0x80) & (check_bit == 1)); PORTA |= (1 << PINA7); PORTD |= (1 << PIND3); break;}
		case 1 : { byte_1 |= ((PINC & 0x40) & (check_bit == 1)); PORTA |= (1 << PINA6); break; }
		case 2 : { byte_1 |= ((PINC & 0x20) & (check_bit == 1)); PORTA |= (1 << PINA5); break; }
		case 3 : { byte_1 |= ((PINC & 0x10) & (check_bit == 1)); PORTA |= (1 << PINA4); break; }
		case 4 : { byte_1 |= ((PINC & 0x08) & (check_bit == 1)); PORTA |= (1 << PINA3); break; }
		case 5 : { byte_1 |= ((PINC & 0x04) & (check_bit == 1)); PORTA |= (1 << PINA2); break; }
		case 6 : { byte_1 |= ((PINC & 0x02) & (check_bit == 1)); PORTA |= (1 << PINA1); break; }
		case 7 : { byte_1 |= ((PINC & 0x01) & (check_bit == 1)); 
			if(column_counter_byte_1 < sizeof(columns_byte_1) )
			{					
				columns_byte_1 [column_counter_byte_1] = byte_1; 
				column_counter_byte_1 += 1;
			}
			break;
		}							

		
// below: pulse counter = 0; needed so that TSAL & TSOP number 1 start on the same time.
			case 24:
			{
			   PORTD &= ~(1 << PIND7);
			   BitCounter = 0;
				  PulseCounter = 0;
   			   start_scan = 0;				   
			      break;
			}
		} // from: switch
	} // from: if(PulseCounter == 0)
	else
	{
		PulseCounter -= 1;
	}
				
} // from: ISR

ISR(TIMER1_COMPB_vect) // 38 khz
{
	PORTB = 0;
//	PORTA = 0; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA7); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA6); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA5); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA4); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA3); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA2); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTA &= ~(1 << PINA1); // for testing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	PORTC = 0;
}
	
ISR(TIMER0_COMP_vect) // needed for making the TSOP looking for 2 mS
{
	PORTA &= ~(1 << PINA0);
	check_bit = 0;
}

[Bericht gewijzigd door trix op zondag 2 augustus 2020 16:43:55 (16%)

eigenwijs = ook wijs
trix

Golden Member

hallo,

ik heb hetgeen wat niet werkt terug gebracht tot het stukje code wat niet werkt.

c code:


case 7 : { byte_1 |= ((PINC & 0x01) & (check_bit == 1));

check_bit is het moment dat ik naar de IR ontvanger (TSOP) kijk of deze "1" of "0" is. (in mijn getekend plaatje (paar posts terug) de 2mS die ik nu terug gebracht heb naar 0,5 mS).
de status moet in byte_1 worden geplaatst, zonder de overige bits te veranderen. die doe ik uiteindelijk 8x zodat de byte_1 volledig gevuld is.

dit werkt niet, nu had ik een paar vragen:
- PINC & 0x01 moet dat niet PORTC & 0x01
- is & juist of moet dat && zijn tussen (PINC & 0x01) en (check_bit == 1)

ik heb bovenstaande al wel getest maar zonder resultaat.
wie ziet er wat er wellicht niet goed is, mijn dank is groot, want ik zie het voorlopig niet :(

eigenwijs = ook wijs
trix

Golden Member

nog even getest, en dit werkt wel:

c code:


case 7 : { byte_1 |= ((0b11111111) & (check_bit == 1));

er komt keurig 00000001 in mijn ext. RAM terecht.
probleem lijkt dan toch in dit stukje te zitten:

c code:


(PINC & 0x01)
eigenwijs = ook wijs

Alle code die je laat zien doet dingen die m.i. zou moeten werken met iets als:

code:


    byte = PINC;

als je alle bits moet doen, waarom dan per bit overzetten als het in 1x kan?

Of als het per bit echt apart moet:

code:


   byte = 0;
   for (i=0;i<7;i++) 
      byte |= PINC & ( 1<<i);

Wat dan precies hetzelfde doet als bovenstaande maar mogelijk heb je nog meer code die dan moet gebeuren in de loop.

Zomaar een stuk code dumpen en zeggen: "ik krijg het niet aan het werk" betekent dat we om te helpen jou code moeten gaan zitten lezen en dan daaruit zien te halen, niet wat het DOET, maar wat het HAD MOETEN DOEN en dan omschrijven naar iets wat wel werkt.

Als je nou eens begint met een voor-mensen-leesbaare omschrijving van het probleem.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
trix

Golden Member

het is niet zomaar een stuk code, de volledige code staat hier een stukje boven in dezelfde topic. maar 98 % daarvan werkt goed op 1 stukje na.
dat ene stukje is dus die regel (wat ik heb gepost) die niet werkt, daar zit het probleem.
ik heb het probleem terug gebracht naar dat ene stukje. als dat werkt is het klaar.

ik zal straks (moet nu weg) nog eens beschrijven wat de bedoeling v/d code is, maar dan komen er allemaal suggesties over hoe het ook kan, terwijl het al werkt. en dwalen we af.....ben ik bang.
al word alle hulp door mij enorm gewardeerd _/-\o_

eigenwijs = ook wijs

code:


(PINC & 0x01)

Dit leest de status van alle pinnen van PORTC en doet vervolgens een bitwise and met 0b00000001. Het resultaat is 1 (0b00000001) als de pin PC0 hoog is. En anders is het resultaat 0 (0b00000000).

Niks mis mee dus.

code:


(PORTC & 0x01)

Hier gebeurt hetzelfde, alleen dan niet met de status van de pinnen, maar met de waarde in het PORTC register. Dat is de waarde die je daar zelf in hebt geschreven, en hoeft niet overeen te komen met de status van de pinnen. Als de pinnen op 'ingang' staan (DDRC=0), dan kun je zo testen of de pullup weerstand van PC0 aan staat.

code:


(check_bit == 1)

Hier vergelijk je de waarde van check_bit met 1. Als check_bit de waarde 0b00000001 heeft dan krijg je true, en anders false. Alle 8 bits moeten juist zijn. Als check_bit bijv 0b01000001 heeft dan krijg je ook false. De compiler garandeert dat false gelijk is aan 0, maar true kan in principe van alles zijn. Hier krijg je een 1 terug voor true, maar ik zou daar nooit zo op rekenen.

code:


   (PINC & 0b00000001)

Doet een AND operatie tussen overeenkomstige bits van beide kanten.
Het resultaat is 0b0000001 of 0b00000000, afhankelijk van PINC.0 Omdat in de tweede operand alle andere bits op 0 staan worden die in het resultaat ook 0.

code:


   (PINC && 0b00000001)

Met een dubbele & wordt er ook een AND operatie uitgevoerd, maar dan worden beide operands eerst als geheel omgezet naar true of false. Het resultaat is ook true of false, true als eender welk bit in PINC hoog is, want dan wordt PINC als geheel ook true, en de andere operand (0b00000001)is ook altijd true.