Transfering integer via rs232 without converting to string.

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View


Hi all,

I would like to transfer an integer (4bytes) from a vb program running on my
main computer to an ATmega8 microcontroller without having to convert it to
a string and sending every char of the number.
Is this at all possible? Haven't found out how to get to the 4bytes
represending the integer in vb yet..

It's not transfer of the bytes that is the problem but how to get to the 4
bytes in vb, and how to tell the microcontroller that the 4 bytes is to
represent an integer?!

Hope someone out there knows a solution to this "small" problem, as this
would simplify my microcontroller code a lot...

Thanks



Re: Transfering integer via rs232 without converting to string.


On Sun, 1 Apr 2007 09:35:50 +0200, "Henning Mortensen"

Quoted text here. Click to load it

Which version of VB are you using, VB6 or VB.NET?

Hmm, since you are mentioning a 4 byte integer, I'll assume you mean
VB.NET, as ints are 16 bit in VB6 by default. (and if memory serves)

Probably the simplest way to do this (if you are determined to do it
at all - is the overhead really that big resp. converting back from a
string representation really that difficult?) is to send the value
byte by byte - e.g. like so:

Imports System.Runtime.InteropServices

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
      Dim theInteger As Int32
      theInteger = Convert.ToInt32(TextBox1.Text)

      ListBox1.Items.Clear()
      For i As Integer = 1 To Marshal.SizeOf(theInteger)
         Dim byteToSend As Byte
         byteToSend = theInteger And &HFF
         ' Here, you would send your byte instead of adding it to the
listbox
         ListBox1.Items.Add(byteToSend)
         theInteger >>= 8
      Next

   End Sub
End Class

This is a quick hack with a form containing a button, a textbox and a
listbox. (I left the default names so you can easily reconstruct the
sample)

Enter your int to be sent in the textbox - pressing the button will
disassemble it into bytes and add them to the listbox.

Instead of adding the bytes to the listbox you would send them to the
AVR, in whichever way this happens in your setup (you didn't mention).

On the AVR side (assuming you are using some higher-level language, I
am not familiar with BASCOM here, only gcc), you'd initialize a 32 bit
integer variable (a long) with zero, shift the first byte 0 times and
add (or "OR") it to the total, left-shift the second byte by 8 bits
and "add", the third one 16 bits and the fourth one 24 bits and add
again.

Of course, you'll have to KNOW that you expect an int to be sent at
that time, that it is exactly four bytes wide, and that it comes in
lower-valued bytes first.

Things are trickier in VB6 since there is no bit shift operator there,
when replacing it with integer division you have to be careful with
the handling of negative numbers.

   Regards,
   Gilles.


Re: Transfering integer via rs232 without converting to string.


Quoted text here. Click to load it

Hi Gilles.

Thanks for the quick responds, and solution :) (Why didn't I think of
that??!! It's so simpel when you got the >>= operator..!!)
I found something else that will also do the trick @
http://www.codeproject.com/vb/net/CopyMemory_in_Net.asp . and yes it's Vb.net
and gcc..

I like your solution tho, nice and simple and no creapy memcopy (that could
create caos...).

Thanks again, now I can finally get the last programming done...

Best Regards,
 - Henning





Re: Transfering integer via rs232 without converting to string.


Hi again,

Now the project is almost done, I find myself in a bit of Debugging
HELL......
I have spent hours trying to figure out that I'm doing wrong..

Here is the Microcontroller rs232 interrupt reciving data.. (I have
rewritten it many times, so maybe it's a bit explicit.. )

ISR(USART_RXC_vect)
{
 Letter=UDR;
 Buffer[BufferPointer]=Letter;

 if (++BufferPointer=12%)
 {
  BufferPointer=0;

  LongIntTemp = 0;
  LongIntTemp = Buffer[3];
  Rxcord = LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[2];
  LongIntTemp = LongIntTemp << 8;
  Rxcord = Rxcord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[1];
  LongIntTemp = LongIntTemp << 16;
  Rxcord = Rxcord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[0];
  LongIntTemp = LongIntTemp << 24;
  Rxcord = Rxcord | LongIntTemp;

  LongIntTemp = 0;
  LongIntTemp = Buffer[7];
  Rycord = LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[6];
  LongIntTemp = LongIntTemp << 8;
  Rycord = Rycord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[5];
  LongIntTemp = LongIntTemp << 16;
  Rycord = Rycord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[4];
  LongIntTemp = LongIntTemp << 24;
  Rycord = Rycord | LongIntTemp;

  LongIntTemp = 0;
  LongIntTemp = Buffer[11];
  Rzcord = LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[10];
  LongIntTemp = LongIntTemp << 8;
  Rzcord = Rzcord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[9];
  LongIntTemp = LongIntTemp << 16;
  Rzcord = Rzcord | LongIntTemp;
  LongIntTemp = 0;
  LongIntTemp = Buffer[8];
  LongIntTemp = LongIntTemp << 24;
  Rzcord = Rzcord | LongIntTemp;

  moveto(Rxcord,Rycord,Rzcord);        // This is where the 3 Uint32_t are
used.

  Flash();            //Flash LED on the controller board
  print(0);
 }
}

All definitions used:

uint32_t LongIntTemp=0;
uint32_t Rxcord = 0;
uint32_t Rycord = 0;
uint32_t Rzcord = 0;

An now the VB.net code sending the 12 Bytes represending the 3 Uint32

UInt32Temp =
(Convert.ToUInt32(arrlistShapes.Item(intShapecounter).item(intLinecounter).item(intPointcounter).X
* CNCScale))
strOutBuffer(3) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(2) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(1) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(0) = UInt32Temp And 255
'Y
UInt32Temp =
Convert.ToInt32(arrlistShapes.Item(intShapecounter).item(intLinecounter).item(intPointcounter).Y
* CNCScale)
strOutBuffer(7) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(6) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(5) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(4) = UInt32Temp And 255
'Z
UInt32Temp =
Convert.ToInt32(arrlistShapes.Item(intShapecounter).item(intLinecounter).item(intPointcounter).Z
* CNCScale)
strOutBuffer(11) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(10) = UInt32Temp And 255
UInt32Temp >>= 8
strOutBuffer(9) = UInt32Temp And 255
uInt32Temp >>= 8
strOutBuffer(8) = uInt32Temp And 255
SerialPort.Write(strOutBuffer, 0, 12)     ' send x,y,z coordinat
strInBuffer = SerialPort.ReadByte() ' Wait for the Microcontroller to 0

If I programmes the microcontroller with coordinates at "boot/reset" to
moveto(x,y,z); everything works fine.
So I pretty sure that the problem is in the convertion some where..?
I have tryed to ecco the send bytes back to the main program, and that looks
ok as well.
I have also tryed to convert the recived bytes using the
"Buffer[3]+Buffer[2]*256+Buffer[1]*256*256+Buffer[0]*256*256*256" methode
but with same result at the above code..

I hope it's some thing simpel I have missed..

 - Henning

Quoted text here. Click to load it




k



Re: Transfering integer via rs232 without converting to string.


On Mon, 23 Apr 2007 17:30:41 +0200, "Henning Mortensen"

Quoted text here. Click to load it

What is happening - wrong behaviour, no response at all, lockups?

Of what type are the elements of Buffer - make sure it is unsigned
(uint8_t), otherwise you will get sign extension for values over 0x7f
when copying them into your long.

What C compiler are you using for the AVR side, does it give any
warnings?

Oh, one more thing: is the "moveto()" a time-consuming operation? You
want to avoid those in an ISR. (Usually, the ISR just handles
receiving and storing the characters e.g. in a ring buffer, the main
program handles processing them)

Let's get the basic communication to work first in principle, then
make your code a bit more compact :-)

   Regards,
   Gilles.


Quoted text here. Click to load it


Re: Transfering integer via rs232 without converting to string.


Hi Gilles,

You did it with nothing more than "make sure it is unsigned (uint8_t)"
I used a char as i was 110% sure that was equal to an unsigned 8 bit byte...
I have used char a billion times without problems.
But here it was what gave all the problems..

Thanks for all your help.

Now my homemade CNC cutter (plotter for now, still need Z-axes hardware) can
draw nice shapes :)

 - Henning




Quoted text here. Click to load it



Re: Transfering integer via rs232 without converting to string.


On Tue, 24 Apr 2007 09:08:28 +0200, "Henning Mortensen"

Quoted text here. Click to load it

You're welcome, glad that I was able to help :-)

Here's a suggestion for an alternate coordinate reading function:

uint32_t ReadCoordinate(void)
{
   uint32_t receivedValue = 0L;

   for(int i=0; i < 4; i++) {
      receivedValue |= (long)GetSerialByte() << i*8;
   }
  
   return receivedValue;
}

You could use something like this to send received coordinates (in
readable hex) back to the PC (your VB program or e.g. Hyperterminal):

void EchoCoordinate(uint32_t coordinate)
{
   SendSerialString("Received: 0x");

   for(int bitStart = 28; bitStart >= 0; bitStart -= 4)
   {
      TransmitSerialByte("0123456789ABCDEF"[(coordinate >> bitStart) &
0x0F]);
   }
   SendSerialString("\r\n");
}


This is a test routine that uses the above functions:

void CoordinateTest(void)
{
   uint32_t coordinate;
   while(1) {
      SendSerialString("Waiting for coordinate\r\n");
      coordinate = ReadCoordinate();
      EchoCoordinate(coordinate);
   }
}

I quickly tested that in Hyperterminal - you can e.g. press Ctrl-A,
Ctrl-B, Ctrl-C, Ctrl-D, and should get back "Received: 0x04030201"

I'm appending excerpts from the routines used in the above - take
these with a grain of salt though:

- they may not be complete (pasted, not tested :-)
- they are from an Atmega128 project of mine, so you'll have to adapt
the hardware specific stuff (e.g. register names) for your Atmega8
- I'm an AVR noob although I've been programming in C for some while
:-)
- your newsreader (or mine) may have messed up line wraps.
- this is using gcc in gnu99 mode which may not be compatible with
your makefile / remaining code.

   Regards,
   Gilles.

serialcomm.c:
------------------------------

#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>

#include "serialcomm.h"

/// Size of ring buffer for reception (RINGBUFFER-1 bytes may be
received without being processed)
#define RINGBUFFER_SIZE 64

static volatile uint8_t ringBuffer[RINGBUFFER_SIZE];
static volatile uint8_t bufferHead; ///< incoming bytes will be stored
here
static volatile uint8_t bufferTail; ///< Retrieved bytes will be
delivered from here

/// Set up serial hardware
/// @param divisor divisor to set up baudrate - use BAUDDIVISOR macro
void InitializeSerialPort(uint16_t divisor)
{
   cli(); // don't disturb while we're setting up
  
   // Set baud rate
   UBRR1H = (uint8_t)(divisor>>8);
   UBRR1L = (uint8_t)divisor;
  
   // Enable receiver, transmitter, and received character interrupt
   UCSR1B = _BV(RXEN)|_BV(TXEN)|_BV(RXCIE);
  
   // Set frame format: 8 data, 1 stop bit
   UCSR1C = _BV(USBS)|(3<<UCSZ0);
  
   // Initialize ring buffer
   bufferHead = bufferTail = 0;
  
   sei(); // allow interrupts
}

void TransmitSerialByte(uint8_t byte)
{
   /* Wait for empty transmit buffer */
   loop_until_bit_is_set(UCSR1A, UDRE);

   /* Put byte into buffer, sends the byte */
   UDR1 = byte;
}

uint8_t IsSerialByteAvailable(void)
{
   return bufferTail != bufferHead;
}

uint8_t GetSerialByte(void)
{
   while(!IsSerialByteAvailable())
   {
      // Wait
   }
 
   cli();
   uint8_t byte = ringBuffer[bufferTail];
   bufferTail = (bufferTail + 1) % RINGBUFFER_SIZE;
   sei();
  
   return byte;
}

void SendSerialString(char *s)
{
   uint8_t c;
   while((c = (uint8_t)(*s++)))
   {
      TransmitSerialByte(c);
   }
}

SIGNAL(SIG_UART1_RECV)
{
   if(UCSR1A & _BV(RXC))
   {
      uint8_t receivedChar = UDR1;

      uint8_t tmpHead = (bufferHead + 1) % RINGBUFFER_SIZE;
      if(tmpHead == bufferTail) {
         return; // buffer full, ignore additional bytes
      }
        
      ringBuffer[bufferHead] = receivedChar;
      bufferHead = tmpHead;            
   }
}

Serialcomm.h:
--------------------
#ifndef _SERIALCOMM_H
#define _SERIALCOMM_H

#define BAUDDIVISOR(baudrate) ((F_CPU/((baudrate)*16UL)) - 1)

void InitializeSerialPort(uint16_t divisor);
void TransmitSerialByte(uint8_t data);
uint8_t IsSerialByteAvailable(void);
uint8_t GetSerialByte(void);
void SendSerialString(char *s);

#endif



Site Timeline