B168 Serial Input

Hi…

My objective is to read a character using serial interface and depending on the character read, turn ‘on’ or ‘off’ DC motor driven through PWM. Here is the code:

// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL	// Orangutan frequency (8MHz)
#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>

/*void delayms( uint16_t millis ) {
	while ( millis ) {
		_delay_ms( 1 );
		millis--;
	}
}

int main( void ) {
	DDRD |= 1 << PD1;			// set LED pin PD1 to output
	while ( 1 ) {
		PORTD &= ~( 1 << PD1 );	// LED off
		delayms( 100 );			// delay 900 ms
		PORTD |= 1 << PD1; 		// LED on
		delayms( 900 );			// delay 100 ms
	}
	return 0;
}*/

void M1_forward(unsigned char pwm)
{
  OCR0A = 0;
  OCR0B = pwm;
}

void M1_reverse(unsigned char pwm)
{
 OCR0B = 0;
 OCR0A = pwm;
}

void serial_init(unsigned int bittimer)
{
	/* Set the baud rate */
	UBRR0H = (unsigned char) (bittimer >> 8);
	UBRR0L = (unsigned char) bittimer;
	/* set the framing to 8N1 */
	UCSR0C = (3 << UCSZ00);
	/* Engage! */
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	return;
}

unsigned char serial_read(void)
{
	while( !(UCSR0A & (1 << RXC0)) )
		;
	
	return UDR0;
}

void serial_write(unsigned char c)
{
	while ( !(UCSR0A & (1 << UDRE0)) )
		;
	UDR0 = c;
}

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
	/* let the preprocessor calculate this */
	serial_init( ( F_CPU / SPEED / 16 ) - 1);

	while (1) {
		/* read a character and echo back the next one */
	//	serial_write( serial_read() + 1);
	bite=serial_read();
	
	if (bite=='g'){
	{
	for (i = 0; i<257; i+=1)
     {
        M1_forward((256-((i-128)*(i-128))/64));  
      _delay_ms(500/256);  
     }
    for (i = 0; i<257; i+=1)
      {
        M1_reverse((256-((i-128)*(i-128))/64));  
        _delay_ms(500/256);  
	  }
	}
		
	}
	}
	return 0;
}

For some reason, the code is not working. Please some one help me in this regard.

Thanks
Shivakanth

Hello.

If you want our help, please read our forum guidelines on asking a question and make another post in this thread that meets these guidelines (although if you follow the general troubleshooting advice at the top, you’ll probably figure out the problem on your own). Do you not see how inadequate your post is when it comes to providing people with the information they need to help you?

If you want to try to solve the problem yourself, you should look into using the Pololu AVR library. If you use functions from the library, you could probably reduce your program to a few lines.

- Ben

Hi Ben…

I am really sorry about the way I posted. Here is how I want to modify the code:

The following code reads a character and echos back the next character. Until I type the next character it will stay idle. But I want it to continue displaying next character until I type new one. Like If I type ‘A’ it should display ‘B’ continuously until I type another character.

// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL   // Orangutan frequency (8MHz)
#define F_CPU 20000000UL   // Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>


void serial_init(unsigned int bittimer)
{
   /* Set the baud rate */
   UBRR0H = (unsigned char) (bittimer >> 8);
   UBRR0L = (unsigned char) bittimer;
   /* set the framing to 8N1 */
   UCSR0C = (3 << UCSZ00);
   /* Engage! */
   UCSR0B = (1 << RXEN0) | (1 << TXEN0);
   return;
}

unsigned char serial_read(void)
{
   while( !(UCSR0A & (1 << RXC0)) )
      ;
   
   return UDR0;
}

void serial_write(unsigned char c)
{
   while ( !(UCSR0A & (1 << UDRE0)) )
      ;
   UDR0 = c;
}

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
   /* let the preprocessor calculate this */
   serial_init( ( F_CPU / SPEED / 16 ) - 1);

   while (1) {
      /* read a character and echo back the next one */
      serial_write( serial_read() + 1);  
   }
   return 0;
}

-Shivakanth

Hello,
Did you try modifying this code to do what you want? What happened? Can you post the simplest possible code that does not work for you?

-Paul

Hi Paul…

Here is how I modified the original code. My intention is to drive motor outputs if the character read is ‘g’. But it’s mot working. I don’t see any output on motor pins

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
   /* let the preprocessor calculate this */
   serial_init( ( F_CPU / SPEED / 16 ) - 1);

   while (1) {
      /* read a character and echo back the next one */
   //   serial_write( serial_read() + 1);
   bite=serial_read();
   
   if (bite=='g'){
   {
   for (i = 0; i<257; i+=1)
     {
        M1_forward((256-((i-128)*(i-128))/64)); 
      _delay_ms(500/256); 
     }
    for (i = 0; i<257; i+=1)
      {
        M1_reverse((256-((i-128)*(i-128))/64)); 
        _delay_ms(500/256); 
     }
   }

-Shivakanth

Hello,

That is obviously not the simplest possible code, and you did not post your entire code. How about you just try running the motors, with no serial code?

-Paul

By the way, we highly recommend using the Pololu AVR Library for your motor and serial control, especially if you have never done microcontroller programming before. If you are going to use your own functions, you need to make sure to include the source code to those functions in your post or we will not be able to give you much help!

-Paul

Hi Paul…

Here is complete source code:

// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL	// Orangutan frequency (8MHz)
#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>


void M1_forward(unsigned char pwm)
{
  OCR0A = 0;
  OCR0B = pwm;
}

void M1_reverse(unsigned char pwm)
{
 OCR0B = 0;
 OCR0A = pwm;
}

void serial_init(unsigned int bittimer)
{
	/* Set the baud rate */
	UBRR0H = (unsigned char) (bittimer >> 8);
	UBRR0L = (unsigned char) bittimer;
	/* set the framing to 8N1 */
	UCSR0C = (3 << UCSZ00);
	/* Engage! */
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	return;
}

unsigned char serial_read(void)
{
	while( !(UCSR0A & (1 << RXC0)) );
	
	return UDR0;
}

void serial_write(unsigned char c)
{
	while ( !(UCSR0A & (1 << UDRE0)) );
	UDR0 = c;
}

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
	/* let the preprocessor calculate this */
	serial_init( ( F_CPU / SPEED / 16 ) - 1);

	while (1) {
		/* read a character and echo back the next one */
	//	serial_write( serial_read() + 1);
	bite=serial_read();
	
	if (bite=='g'){
	{
	for (i = 0; i<257; i+=1)
     {
        M1_forward((256-((i-128)*(i-128))/64));  
      _delay_ms(500/256);  
     }
    for (i = 0; i<257; i+=1)
      {
        M1_reverse((256-((i-128)*(i-128))/64));  
        _delay_ms(500/256);  
	  }
	}
	}
	}
	return 0;
}

Hello,

I think you are ignoring most of what I am saying, which makes it hard to help you.

Specifically, I suggested that you:

  • Simplify your code as much as possible.
  • Find the smallest change that makes the program stop doing what you expect.
  • Try just running the motors, with no serial port.
  • Try the Pololu AVR Library.

These are very serious suggestions that I think will help you figure out what you are doing wrong. If you do not like them for some reason, you should tell me that, rather than silently ignoring them.

-Paul

Hi Paul…

Thanks for your suggestion. I followed all the steps except the last one, and the code is kind of working fine. It can read the character but the motor is not running continuously. When I disable the serial read, write commands, the motor is running continuously. I unable to figure out how to make the dc motor run continuously until we pass a different character. I am sorry but, due to limited knowledge in C programming, I could not simplify the code further. Here is complete code

// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL	// Orangutan frequency (8MHz)
#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>


void M1_forward(unsigned char pwm)
{
  OCR0A = 0;
  OCR0B = pwm;
}

void M1_reverse(unsigned char pwm)
{
 OCR0B = 0;
 OCR0A = pwm;
}

void motors_init()
{
    // configure for inverted PWM output on motor control pins:
    //  set OCxx on compare match, clear on timer overflow
    //  Timer0 and Timer2 count up from 0 to 255
    TCCR0A = TCCR2A = 0xF3;
	// use the system clock (=20 MHz) as the timer clock
    TCCR0B = TCCR2B = 0x01;
    // initialize all PWMs to 0% duty cycle (braking)
    OCR0A = OCR0B = OCR2A = OCR2B = 0;
    // set PWM pins as digital outputs (the PWM signals will not
    // appear on the lines if they are digital inputs)
    DDRD |= (1 << PD3) | (1 << PD5) | (1 << PD6);
    DDRB |= (1 << PB3);
}

void serial_init(unsigned int bittimer)
{
	/* Set the baud rate */
	UBRR0H = (unsigned char) (bittimer >> 8);
	UBRR0L = (unsigned char) bittimer;
	/* set the framing to 8N1 */
	UCSR0C = (3 << UCSZ00);
	/* Engage! */
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	return;
}

unsigned char serial_read(void)
{
	while( !(UCSR0A & (1 << RXC0)) );
	
	return UDR0;
}

void serial_write(unsigned char c)
{
	while ( !(UCSR0A & (1 << UDRE0)) );
	UDR0 = c;
}

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
unsigned int k;
int i10;
	/* let the preprocessor calculate this */
	serial_init( ( F_CPU / SPEED / 16 ) - 1);
	  motors_init();

	while (1) {
		/* read a character and echo back the next one */
	//	serial_write( serial_read() + 1);
	
	bite=serial_read();
	
	i10=strcmp(bite,'g');
	
	if (i10==0){
	//for(k = 0; k<500; k+=1)
	//{
	{
	for (i = 0; i<257; i+=1)
     {
        M1_forward((256-((i-128)*(i-128))/64));  
      _delay_ms(500/256);  
     }
    for (i = 0; i<257; i+=1)
      {
        M1_reverse((256-((i-128)*(i-128))/64));  
        _delay_ms(500/256);  
	  }
	}
	}	
	//}
	}
	return 0;
}

-Shivakanth

When i is 256, M1_reverse((256-((i-128)*(i-128))/64)) becomes M1_reverse(0) and the motor will stop and you then exit the for loop. After that control resumes at bite=serial_read(); which will wait for another character.

Mike

Hello,

I suggested that you simplify your code, and it became 26 lines longer. Surely you can get rid of a lot of lines that are distracting you from seeing what is going on! For example, you could start by removing all lines that are commented out. You could replace “500/256” with its value, which is just 1. Can you remove the complicated formulas for motor speed right now and just try to get it to switch between, say, 100 and 0?

I looked through the first few lines of the code and found that you were trying to use strcmp() on arguments that were not strings. That is not going to work at all. Does this not give you a warning when you compile it?

-Paul

Hi Paul…

Here is the simplified code. It’s working the way I want, like when it reads the character ‘g’, for two iterations i.e for k=1:2, it prints 10 ‘x’ characters and 10 ‘y’ characters. Now, I want to modify it in such a way that, instead of two iterations (k=2), it should continue printing x, y characters until the character read is other than ‘g’. Any thoughts on how to implement this?

// F_CPU tells util/delay.h our clock frequency
#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>

void serial_init(unsigned int bittimer)
{
	/* Set the baud rate */
	UBRR0H = (unsigned char) (bittimer >> 8);
	UBRR0L = (unsigned char) bittimer;
	/* set the framing to 8N1 */
	UCSR0C = (3 << UCSZ00);
	/* Engage! */
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	return;
}

unsigned char serial_read(void)
{
	while( !(UCSR0A & (1 << RXC0)) );
	
	return UDR0;
}

void serial_write(unsigned char c)
{
	while ( !(UCSR0A & (1 << UDRE0)) );
	UDR0 = c;
}

#define SPEED 9600
int main (void)
{
char bite;
unsigned int i;
unsigned int k;
int i10;
	/* let the preprocessor calculate this */
	serial_init( ( F_CPU / SPEED / 16 ) - 1);
	while (1) {
	bite=serial_read();
	if (bite=='g'){
	for(k = 0; k<2; k+=1)
	 {
	for (i = 0; i<10; i+=1)
           {
		serial_write('x');
           }
       for (i = 0; i<10; i+=1)
          {
	serial_write('y');
          }
	}
	}
	}
	
	return 0;
}

-Shivakanth

Hello,

It sounds like you are now asking about how to do other things while waiting for serial bytes to come in. You could define a function like

unsigned char is_byte_available()
{
   return UCSR0A & (1 << RXC0);
}

Then try writing a program to print ‘x’ until a character other than ‘g’ is pressed:

while(!is_byte_available() || serial_read() == 'g')
{
  serial_write('x');
}

If that works for you, try writing a program that waits for a ‘g’ (you have that part already) and then runs that loop. Then you should be able to modify it to do whatever you want.

If you get stuck at some point, and you want help, please post the last step that worked and the first step that did not work.

-Paul