NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Serial setup for wireless transmission

August 03, 2010
by lsoltmann
lsoltmann's Avatar

I recently got the CY2196R transceivers that many people on this forum have gotten for wireless transmission. I'm planning on using them to build a wireless telemetry system for aircraft. I'm new to C programming and microcontrollers so this is probably a daunting task for a newbie but I thought I would give it a shot. I have read through the USART stuff in the ATMega168 data sheet but am still having trouble setting it up. I was wondering if anyone could push me in the right direction. In the code below, the UCSRnA ,UDREn, and UDRn registers are undeclared when I try to compile. Do I need to declare these? or am I going about all of this the wrong way?

The transceivers require the baud rate to be 19200.

#define F_CPU 14745600
#define BAUD 19200
#define MYUBRR F_CPU/16/BAUD-1

#include <stdio.h>
#include <math.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

char data;

void USART_Init(ubrr){

    UBRR0H=(ubrr>>8);
    UBRR0L=ubrr;
    UCSR0B=(1<<RXEN0)|(1<<TXEN0);
    UCSR0C=(1<<USBS0)|(3<<UCSZ00);
}

void USART_Transmit(data){
    while(!(UCSRnA & (1<<UDREn)))
        UDRn=data;
}

int main(){

    USART_Init(MYUBRR);

    while(1){
    data="test";
    USART_Transmit(data);
    }

    return 0;
}
August 03, 2010
by mongo
mongo's Avatar

I have a pair of those as well... Never got them to talk. I found a blog page that has some interesting info. Here it is:

link

I am going to give it one more try myself before writing the whole thing off.

August 04, 2010
by lsoltmann
lsoltmann's Avatar

I've read the blog before and the hardware side I don't have a problem with ... its the software side. I wrote the code above to be a simple test to see if I could transmit the word "test" from one MCU to the other. Not knowing that much about C programming I don't know why I can't compile the above code.

August 04, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi lsoltmann,

There are a couple of issues with your code that I see. Strings in C are a bit difficult to deal with, and I think are at the root of the problem. To simplify things, lets focus on sending a single character which is 8 bits, and is what the USART transmits at a time anyway. In both your functions you need to define the type for your inputs. C is a typed language, so every variable needs to be told what its type is when being defined.

void USART_Init(uint8_t ubrr){
    //code
}

void USART_Transmit(char data){
    //code
}

In your main loop you can send one character:

int main(){

    USART_Init(MYUBRR);

    while(1){
        data='t';
        USART_Transmit(data);
    }

    return 0;
}

This will get your code to compile. I think you will still need to look into the initialization you are doing a bit more. Right now it is set to 2 stop bits, which depending on your setup might not be what you want. If you take a look at uart.h in the libnerdkits folder you will see the way we initialize the UART. Hope that helps.

Humberto

August 06, 2010
by lsoltmann
lsoltmann's Avatar

I made the changes that you suggested but it still did not compile. I decided to abandon this route and look back at the tempsensor project as I remember seeing code in there for serial output to the computer. I rewrote the above code following the code used by the tempsensor project and was able to get the CY2196R to talk to the computer. The code that ended up working was this

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

char data;

int main(){

    uart_init();
    FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
    stdin = stdout = &uart_stream;

    while(1){
        delay_ms(1000);
        printf_P(PSTR("test "));
    }

    return 0;
}

Pretty simple piece of code but I figure I would post it for those that might be having trouble like me. I had the serial cable plugged directly from the computer to the other CY2196R module and had to use this line in the terminal (I'm on a Mac) to see the serial port.

screen /dev/tty.PL2303-0000101D 19200

I found this from the webiste http://www.tigoe.net/pcomp/resources/archives/avr/000749.shtml

Now that I've got the MCU talking wirelessly, time to get started with the telemetry system project!

August 06, 2010
by Ralphxyz
Ralphxyz's Avatar

Where can I get the CY2196R and Transmitter? Or similar wireless modules.

Everything I see on the web is in Chinese is there a usable datasheet the Google translations are lacking at best.

Ralph

August 06, 2010
by lsoltmann
lsoltmann's Avatar

The CY2196R is a transceiver so it does both Tx and Rx. I got them from

http://www.sureelectronics.net/goods.php?id=379

It says GP-GC010 but they shipped me the CY2196R ... according to a google search, this has happened to everyone. The translated data sheet I got from

http://www.zonemikel.com/wordpress/?p=535

which also has a good discussion on setup and use.

September 21, 2010
by lsoltmann
lsoltmann's Avatar

So I've got most of the telemetry system done, but am having trouble with the receiving end of the system. I read in the tractor sled pull forum on this site about sending and receiving serial over the wireless modules. After completing all the required math, I'm sending the data to the lcd screen wirelessly using the following code

printf_P(PSTR("%f %f %f %f\n"),tas_mph,alt_ft,temp_avg,vbatt_avg);

On the receiving end I'm using

scanf_P(PSTR("%f %f %f %f\n"),&tas_mph,&alt_ft,&temp_avg,&vbatt_avg);

to get the data. The data is displaying correctly except that it is not in the correct order. The "tas_mph" variable that I sent does not seem to be written to "&tas_mph" since on the screen the values are not in the right order. The code on the receiving end looks like this.

while(1){

        tas_mph=0;
        alt_ft=0;
        temp_avg=0;
        vbatt_avg=0;

        // Get data from wireless module
        scanf_P(PSTR("%f %f %f %f\n"),&tas_mph,&alt_ft,&temp_avg,&vbatt_avg);

        // Display data to LCD
        lcd_line_one();
        fprintf_P(&lcd_stream, PSTR("AS: %2.1f mph"),tas_mph);
        lcd_line_two();
        fprintf_P(&lcd_stream, PSTR("ALT: %4.1f ft"),alt_ft);
        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("VBAT: %2.2f V"),vbatt_avg);
        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("TEMP: %3.1f degF"),temp_avg);
                  }
        return 0;
}

So to summarize the problem ... the battery voltage is showing up on the airspeed line, the airspeed on the altitude line, temperature on the battery voltage line, and altitude in the temperature line. Does anyone know why the order is not the same as what I sent and how to get the sent data to remain in a certain order?

Thanks!

September 21, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi lsoltmann,

Sounds like you're very close! Based on your description and code, I think you were trying to send in this order:

TAS ALT TEMP VBATT [newline]

but seeing it as though the bytes were received in this order

VBATT TAS ALT TEMP [newline]

This is just the original shifted over by one position.

If you take a look at the avr-libc documentation for scanf, you'll see that it says, "The format string fmt is scanned for conversion specifications. Anything that doesn't comprise a conversion specification is taken as text that is matched literally against the input. White space in the format string will match any white space in the data (including none), all other characters match only itself. Processing is aborted as soon as the data and format string no longer match, or there is an error or end-of-file condition on stream."

So ultimately, I believe that the scanf_P function isn't "looking" for the n newline as you'd like it to. Instead, it's just getting started in one position and is then taking every whitespace (including newlines) as equivalent.

Can you try changing your code on the receiving side to look more like:

while(uart_read() != '\n') { 
  // keep reading characters until we find a newline
}

while(1){

        tas_mph=0;
        alt_ft=0;
        temp_avg=0;
        vbatt_avg=0;

        // Get data from wireless module
        scanf_P(PSTR("%f %f %f %f"),&tas_mph,&alt_ft,&temp_avg,&vbatt_avg);

        // Display data to LCD
        lcd_line_one();
        fprintf_P(&lcd_stream, PSTR("AS: %2.1f mph"),tas_mph);
        lcd_line_two();
        fprintf_P(&lcd_stream, PSTR("ALT: %4.1f ft"),alt_ft);
        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("VBAT: %2.2f V"),vbatt_avg);
        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("TEMP: %3.1f degF"),temp_avg);
                  }
        return 0;
}

I've made only two changes to your original code. First, I've added the block at the start that looks for a newline character before passing off control to your main loop. That way, the receiver starts at the right position (just after a newline). Second, I've removed the "n" from the scanf_P format string, because I think it is not useful in that position and you actually want it to fail to match against the newline character.

You may want to do something more advanced in case there is the possibility of mistransmission or restarting communication while the receiver is still running. However, I think this simple example will get you going for now!

Let me know if that works.

Mike

September 22, 2010
by lsoltmann
lsoltmann's Avatar

That worked ... but only for the first time that the transmitter was turned on. If I leave the receiver module turned on, and turn off and on the transmitter (simulating no signal), the display shows the voltage in the airspeed, airspeed in the altitude, temp in the voltage, and altitude in the voltage, ie. back to the same problem. You did write a small warning at the bottom of your reply about the changing the code to handle mistransmissions or temporary signal loss. Still being new to c programming, I'm not sure how to go about doing this.

Thanks for you help though, much appreciated!

Lars

September 23, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi Lars,

I think something like this might do what you want:

Change the printing code on the transmitter side to add the letter X before its sequence of lines:

printf_P(PSTR("X%f %f %f %f\n"),tas_mph,alt_ft,temp_avg,vbatt_avg);

Then, on the reader side, add something just before the scanf_P line that looks for the X character. (We can now omit that check for the newline.)

while(1) {
    tas_mph=0;
    alt_ft=0;
    temp_avg=0;
    vbatt_avg=0;

    // keep reading until we find an 'X'
    while(uart_read() != 'X') {
    }

    // Get data from wireless module
    if(scanf_P(PSTR("%f %f %f %f"),&tas_mph,&alt_ft,&temp_avg,&vbatt_avg) == 4) {

        // Display data to LCD
        lcd_line_one();
        fprintf_P(&lcd_stream, PSTR("AS: %2.1f mph"),tas_mph);
        lcd_line_two();
        fprintf_P(&lcd_stream, PSTR("ALT: %4.1f ft"),alt_ft);
        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("VBAT: %2.2f V"),vbatt_avg);
        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("TEMP: %3.1f degF"),temp_avg);
    }

    return 0;
}

Now, if the transmission is interrupted (error during transmission, or the transmitter is turned off and restarted), then the receiver will just sit around waiting for the next X.

Give that a try and let me know if it works!

Mike

September 27, 2010
by oldictguy
oldictguy's Avatar

The beauty of using uart_read() to check for a 'control character' is that it also makes scanf non-blocking. I have a similar approach in my project. I use the WIZ610wi module for serial - TCP transmissions to send POST data to a webserver.

@Mike; if the transmitter gets turned off during transmission, will scanf block and simply wait for the remaining data? Is there some kind of inherent 'timeout' feature?

September 28, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi olddictguy,

There is no way to time out a call to scanf. It will block until it receives another character to match (or not match) against the format string. However as soon as the transmitter comes back on scanf will get the X and not match it against its format string. This will cause the if statement to fail and it will loop back around to wait for the next X.

You are correct that using a lower level read function to read a character from UART would give you the ability to time out if you wanted to. Note however that the uart_read() we have in the NerdKits library (uart.c in libnerdkits) waits in a busy loop until it gets a new character, essentially making it a blocking call. There are ways to write interrupt driven uart loops if you feel the need for non-blocking uart excitement!

Humberto

April 06, 2011
by Schrat
Schrat's Avatar

Lsoltmann,

Your problem seems similar to what I was encountering. See http://www.nerdkits.com/forum/thread/1471/

Post a Reply

Please log in to post a reply.

Did you know that one NerdKits customer controlled a laser pointer with his computer using a microcontroller? Learn more...