Very basic question: Variable to port

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys

This is a really simple question, I know, but it's driving me nuts.
In my small program, I want to generate some reasonably random numbers and store them in a variable. Later in the code, I want to output that variable on PORTD (7 bits) on an ATTiny2313, but when I get to the part where the variable is supposed to be outputted, my board goes nuts. I'm sure it's a matter of data types.
The problem arises in the function "sendtelegram".
Can you spot my mistake and help me output the variable "tele"?

/*
 * ttrandomizer.c
 *
 * Created: 17-10-2012 09:52:20
 *  Author: mmk
 */ 

#define F_CPU 3686400UL  // 3,6864 MHz
   //#define F_CPU 14.7456E6
   

//Includes
#include 
#include 
#include 
#include 

//Defines
#define ON 1
#define OFF 0

//Function prototyping
void init(void);
void selspeed(void);
void seltime(void);
void selaction(void);
void sendtelegram(uint8_t);
//void t1start(int);

uint8_t static volatile randspeed=20;
int static volatile randhold=39;
int static volatile randaction=3;
int static volatile speed=0;
int static volatile time=0;


int main(void)
{
	
	init();
	
    while(1)
    {
     randspeed=(randspeed*109+89)%23; 
	 randhold=(randhold*109+89)%20;
	 randaction=(randaction*109+89)%10; 
	 
	 selspeed();
	 
	 sendtelegram(randspeed);

	 seltime();
	 
	 selaction();


    }
}

void init(void){
	//Port init
	DDRD=0xFF; //Port D is set as an output
	PORTD=0x00; //Port D is driven low.
	
	DDRB=0x41; //PB.0 and PB.6 (LED) is set to be an output.
	PORTB=0x00; //All pins on Port B driven low (Hi-Z for all other than PB.0/6).

}

void selspeed(void){
	/*
	Possible speeds
	1.3 m/s = 0x04
	to 
	3.5 m/s = 0x1A
	13 possibilities
	*/
	randspeed+=4; //The telegrams start at 0x04 or just 4. Thus the random result is added with 4 to get a valid telegram.
	}

void seltime(void){
	
}

void selaction(void){
	
}

void sendtelegram(uint8_t tele){
	
	
	PORTD=tele;
    _delay_ms(50);
	PORTD=0x00;
}

EDIT: Silly typo corrected :)

Last Edited: Thu. Oct 18, 2012 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

PORTB (7 bits)

Quote:

PORTD=tele;

Perhaps check over the post again, and edit/correct.

What does "go nuts" mean?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, go nuts was a little... inaccurate, I agree.
Since the board is very simple, I have attaced an LED to PB.6, which is active low, so I can see when the processor is running.
As soon as I include the "sendtelegram"-routine, the LED starts blinking at a high frequency, so I assume the processor resets or something like that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Assuming this is outputting to a line of LEDs is 50ms really long enough to see what you are looking for anyway? That's only 1/20th second.

BTW your random number generator like all PRNGs will not appear THAT random. Every time you run the program it will appear to outptu the same sequence as your initial seed is hard-coded. In that case you might as well just use C's own rand()/srand() rather than implementing your own PRNG.

The real trick to using PRNGs is to inject some entropy when you start. One possible source if the device has a user interface is to time from power on until the first button press. This is unlikely ever to be the same and gives you a value to use as the seed to start at a different point in the PRNG sequence each time. Another idea is to store the seed into EEPROM from time to time. Next time you switch on use the stored seed from last time to start the sequence at an apparently random place.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The 50 ms are supposed to be adjusted later. However, the port doesn't drive LEDs, but communicate with another processor, so probably 50-100 ms will suffice.
Otherwise a good point.
As for the random number generator, it's ok that it's not very random, because it runs on a whack-a-mole-like machine, and I doubt people using it will hang around long enough to figure out the pattern :)
Still, good input. I might implement the EEPROM-feature when I get everything else to work, just for the exercise (and provided I have enough code space).

The original question stands, though: How do I output a variable to a port?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

How do I output a variable to a port?

Exactly as you are already doing it:

DDRD = 0xFF; // somewhere in the init

..

PORTD = value;

If you use test values of 0x00 then 0xFF then something like 0x55 do you see (a) all outputs low, (b) all outputs high, (c) alternate high-low outputs ? If so it's working. Maybe delay longer (like 2000ms) to give you a chance to probe it with a meter, scope or logic probe and just cycle through those 3 values.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Strange...
So what types of variable can I output to a port?

int
uint8_t
char
byte

Any 8-bit type?

And if I try to output a type longer than 8 bit?

I know that these are probably lame questions, but I'm wondering, and I haven't been able to find a clear answer.

EDIT: I changed the code at bit, so that in "sendtelegram", I set PORTB=0xFF; instead of the variable.
Same thing happens, the LED starts blinking erratically.

Then I commented out the call for the "sendtelegram" routine entirely and the LED stays on...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So what types of variable can I output to a port?

int
uint8_t
char
byte

Any 8-bit type?

And if I try to output a type longer than 8 bit?


You can output absolutely any C type you like. All that happens i that if the thing is too wide to fit the lower 8 bits will be used. So if you use:

uint32_t longval = 0xBABEFACE;

PORTD = longval;

that would write 0xCE to the port. The same happens if you forget PORTs and just use:

uint32_t longval = 0xBABEFACE;
uint8_t byteval;

byteval = longval;

byteval then contains 0xCE. You can even do things like:

byteval = longval >> 16;

and byteval will get the 0xBE in the middle of the dword. In fact it doesn't stop there:

byteval = longval >> 20;

and it gets 0xAB - part of the first byte and part of the second (in a big endian view).

Similarly:

float f = 1234.5678;
PORTD = f;

this converts f to integer (1234 - the fractional part is lost) then 1234 & 0xFF is 210 so 210 (0xD2) is written to the port.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the clarification, Clawson, that was a major help.

Well, I found the problem and it wasn't in the code, but in the hardware.
I couldn't upload the schematic, but if I had, you guys would have been laughing at me (and I deserve it).
The board I'm using is used with a PLC which provides 24V signals. The input is divided down to around 4.5V with a set of resistors and protected by external 4V7 zeners going to ground.
I, of course, forgot about those still sitting on the board, so every time I tried to put the port high, the tiny power supply would fail and pull the reset pin on the processor.

Silly or not, I found the problem. Thank you for guiding me with some critical questions :)